Good to know
The script adds new table values as new options, and any deleted values become disabled options. If a table value is reentered, it will be reenabled.
import groovy.json.JsonSlurper
final SPACE_KEY = '~5f89cb49c07c880075bba803'
final PAGE_TITLE = 'Test Title'
// Update the select list customfield id from your Jira instance
final JIRA_CUSTOMFIELD_ID = 'customfield_10158'
if (page.spaceKey != SPACE_KEY || page.title != PAGE_TITLE) return
def getPageResponse = get("/wiki/api/v2/pages/${page.id}")
.queryString('body-format', 'atlas_doc_format')
.asObject(Map)
.body
def pageStorage = getPageResponse['body']['atlas_doc_format']['value'] as String
def contents = new JsonSlurper().parseText(pageStorage)['content'] as List
// Work through the page contents to read the only table, and values in second column, not including the table header row
def rows = contents.find { it['type'] == 'table' }['content'] as List
def tableCellRows = rows.findAll { it['content'].any { it['type'] == 'tableCell' } }
def cellValues = tableCellRows.collect { it['content'][1]['content'][0]['content']['text'] }.flatten() as List<String>
// Data validation to ensure now spaces or inconsistent capitalization
def optionNames = cellValues
*.trim() // Remove starting and trailling spaces if any
*.replaceAll(/\s+/, ' ') // Replace all type of white spaces with single space
.collect { it.split(' ').collect{ it.capitalize() }.join(' ') } // Capitalize first letter of each word
// Calling Jira REST APIs from Confluence requires authentication
// In practice, this involves creating and authenticated through a bot user
// Documentation on creating an API token:
// https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account/
// Save the token and access it in script using ScriptRunner's Script Variable feature:
// https://docs.adaptavist.com/sr4cc/latest/features/script-variables
def jiraBaseUrl = baseUrl.replace('/wiki', '')
def contexts = getAllJira("$jiraBaseUrl/rest/api/3/field/${JIRA_CUSTOMFIELD_ID}/context") as List
def globalContext = contexts.find { it['isGlobalContext'] }
def currentOptions = getAllJira("$jiraBaseUrl/rest/api/3/field/${JIRA_CUSTOMFIELD_ID}/context/${globalContext['id']}/option") as List
def currentEnabledOptions = currentOptions.findAll { !it['disabled'] } as List
def currentDisabledOptions = currentOptions - currentEnabledOptions
def newOptionNames = optionNames - (currentOptions.collect { it['value'] })
def enablableOptions = currentDisabledOptions.findAll { it['value'] in optionNames }
def disablableOptions = currentEnabledOptions.findAll { !(it['value'] in optionNames) }
logger.warn "newOptionNames: $newOptionNames"
logger.warn "enablableOptions: $enablableOptions"
logger.warn "disablableOptions: $disablableOptions"
// Do not allow more than 5 item updates at a time
// A safeguard in case the table is accidentally distorted and updated,
// This will prevent the script from massively changing the Jira options in case of user error
// You can set the number that matches your use case
assert newOptionNames.size() <= 5 && enablableOptions.size() <= 5 && disablableOptions.size() <= 5
if (newOptionNames) {
post("$jiraBaseUrl/rest/api/3/field/${JIRA_CUSTOMFIELD_ID}/context/${globalContext['id']}/option")
.header('Content-Type', 'application/json')
.basicAuth(BOT_USER_EMAIL, BOT_USER_API_TOKEN)
.body([
options: newOptionNames.collect { [value: it ]}
])
.asObject(Map)
}
if (enablableOptions + disablableOptions) {
put("$jiraBaseUrl/rest/api/3/field/${JIRA_CUSTOMFIELD_ID}/context/${globalContext['id']}/option")
.header('Content-Type', 'application/json')
.basicAuth(BOT_USER_EMAIL, BOT_USER_API_TOKEN)
.body([
options: (enablableOptions + disablableOptions).each { it['disabled'] = !it['disabled'] }
])
.asObject(Map)
}
// Work with paginations on Jira REST APIs
def getAllJira(String url) {
def items = []
def startAt = 0
def isLast = false
while (!isLast) {
def response = get(url).queryString('startAt', startAt)
.basicAuth(BOT_USER_EMAIL, BOT_USER_API_TOKEN)
.asObject(Map).body
items.addAll(response["values"])
isLast = response['isLast']
startAt = startAt + (response['maxResults'] as Integer)
}
items
}
customfield_xxxxx