...
| Kodeblok |
|---|
| language | shell |
|---|
| title | UpdateShadowFieldsForIssue.sh |
|---|
|
#!/bin/bash
source automationpasswordpassword.txt
IFS=$(echo -en ",")
BASEURL="https://jira.server.dk"
REST="/rest/scriptrunner/latest/custom/UpdateShadowFieldsForIssue"
USERNAME=automation
DRYRUN="1"
EMPTYONLY="1"
SKIPINDEX=""
DAYSBACK=
#Loop projects
curl -s -u "$USERNAME:$PASSWORD" -X GET -H 'Content-Type: application/json' https://jira.server.dk$BASEURL/rest/api/2/project?maxResults=1000 > projects.json
cat projects.json | jq '.[].key' | while read -r PROJECTKEY;
do
PROJECTKEY=$(echo $PROJECTKEY | sed 's/\"//g')
#echo "$PROJECTKEY"
#Loop Issuetypes for the Project
curl -s -u "$USERNAME:$PASSWORD" -X GET -H 'Content-Type: application/json' https://jira.server.dk/$BASEURL/rest/api/2/issuetype/issue/createmeta/$PROJECTKEY/issuetypes?maxResults=1000 > issuetypes.json
cat issuetypes.json | jq '.values[].name' | while read -r ISSUETYPE;
do
ISSUETYPEISSUETYPE=$(echo $ISSUETYPE | sed 's/\"//g')
#echo $ISSUETYPE
#Loop Fields
declare -a FIELDMAP=("23321|29033|M" "23523|29020|S" "24523|29021|S" "23522|29022|S" "24623|29026|S" "24422|29023|S" "23726|29024|S" "23728|29034|M" "23729|29035|M" "23727|29025|S" "24920|29036|S" "24921|29037|S" "24624|29027|S" "24423|29028|S" "23320|29032|S" "24821|29031|S" "24625|29030|S" "24424|29029|S" "24922|29039|S" "24923|29038|S" "24924|29040|S" "24925|29041|S" "24926|29042|S" "25028|29043|S" "25027|29044|S")
for FIELD in "${FIELDMAP[@]}"
do
#echo "Field $FIELD"
ELEMENTSFIELD SOURCEFIELDID=$(echo $FIELD | cut -d '|' -f 1)
SHADOWFIELD SHADOWFIELDID=$(echo $FIELD | cut -d '|' -f 2)
TYPE=$(echo $FIELD | cut -d '|' -f 3)
ISSUETYPE=$(echo $ISSUETYPE | sed 's/ /%20/g')
#Sample: https://jira.server.dk/rest/scriptrunner/latest/custom/UpdateShadowFieldsForIssue?projectkey=NIS QUERYSTRING="projectkey=$PROJECTKEY&issuetype=Repeatable%20Task$ISSUETYPE&elementsfieldsourcefieldid=23321$SOURCEFIELDID&shadowfieldshadowfieldid=29033$SHADOWFIELDID&type=M$TYPE&emptyonly=1$EMPTYONLY&dryrun=0$DRYRUN&skipindex=$SKIPINDEX&daysback=10
QUERYSTRING="projectkey=$PROJECTKEY&issuetype=$ISSUETYPE&elementsfield=$ELEMENTSFIELD&shadowfield=$SHADOWFIELD&type=$TYPE&emptyonly=$EMPTYONLY&dryrun=$DRYRUN&skipindex=$SKIPINDEX&daysback=$DAYSBACK"
$DAYSBACK"
echo "curling.... $QUERYSTRING"
curl -u "$USERNAME:$PASSWORD" -X GET -H 'Content-Type: application/json' "$BASEURL$REST?$QUERYSTRING"
done
done
done
|
The scriptrunner REST code:
| Info |
|---|
This script is for field from the Elements App - hence the line:
| Kodeblok |
|---|
|
elementsFieldValue = extractValues(theIssue.getCustomFieldValue(elementsField),type) |
Extracts the value. This can be different, or just:
| Kodeblok |
|---|
|
elementsFieldValue = theIssue.getCustomFieldValue(elementsField) |
For normal copy
| Kodeblok |
|---|
| | title | UpdateShadowFieldsForIssue. |
|---|
| language | shell |
|---|
| title | UpdateShadowFieldsForIssue.groovy |
|---|
|
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.user.util.UserUtil
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.issue.search.SearchResults
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.event.type.EventDispatchOption
import groovy.json.JsonSlurper
import com.atlassian.jira.issue.index.IssueIndexingService
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.util.ImportUtils
import groovy.transform.BaseScript
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import javax.ws.rs.core.MultivaluedMap
import javax.servlet.http.HttpServletRequest
import javax.ws.rs.core.Response
@BaseScript CustomEndpointDelegate delegate
UpdateShadowFieldsForIssue(httpMethod: "GET", groups: ["automaticservices","jira-administrators"]) { MultivaluedMap queryParams ->
Random random = new Random()
String scriptRunIdent = Math.abs(random.nextInt() % 99999) + 1
String scriptName = "UpdateShadowFieldsForIssue.groovy"
String projectKey = queryParams.getFirst("projectkey") as String
String issueType = queryParams.getFirst("issuetype") as String
String elementsFieldIdsourceFieldId = queryParams.getFirst("elementsfieldsourcefieldid") as String
String shadowFieldId = queryParams.getFirst("shadowfieldshadowfieldid") as String
String type = queryParams.getFirst("type") as String
String emptyOnly = queryParams.getFirst("emptyonly") as String
String dryRun = queryParams.getFirst("dryrun") as String
String skipIndex = queryParams.getFirst("skipindex") as String
IntegerString currentNumberdaysBack = 0queryParams.getFirst("daysback") as String
Integer currentNumber = 0
def builder = new groovy.json.JsonBuilder()
String jql="Project=" + projectKey + " and issuetype='" + issueType + "' and cf[" + elementsFieldIdsourceFieldId + "] is not empty"
if (emptyOnly == "1")
{
jql=jql + " and cf[" + shadowFieldId + "] is empty"
}
if (daysBack != "")
{
jql=jql + " and updated > -" + daysBack + "d"
}
log.info "Script=" + scriptName + " ScriptRunIdent=" + scriptRunIdent + " Message='JQL: " + jql + "'"
ApplicationUser currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager()
IssueManager issueManager = ComponentAccessor.getIssueManager()
def issueIndexingService = ComponentAccessor.getComponent(IssueIndexingService)
CustomField elementsFieldsourceField = customFieldManager.getCustomFieldObject("customfield_" + elementsFieldId sourceFieldId)
String jiraSourceFieldType =sourceField.getCustomFieldType().getName()
CustomField shadowField = customFieldManager.getCustomFieldObject("customfield_" + shadowFieldId)
String jiraFieldTypejiraShadowFieldType = shadowField.getCustomFieldType().getName()
loglog.info "Script=" + scriptName + " ScriptRunIdent=" + scriptRunIdent + " Message='ShadowSource field Jira type: " + jiraFieldTypejiraSourceFieldType + "'"
//Make sure we copy to a text field. log.info "Script=" + scriptName + " ScriptRunIdent=" + scriptRunIdent + " Message='Shadow field Jira type: " + jiraShadowFieldType + "'"
if (jiraFieldTypejiraShadowFieldType == "Text Field (single line)" || jiraFieldTypejiraShadowFieldType == "Text Field (multi-line)")
{
SearchService searchService = SearchService searchService = ComponentAccessor.getComponent(SearchService.class)
SearchService.ParseResult parseResult = searchService.parseQuery(currentUser, jql)
if (parseResult.isValid())
{
SearchResults results = searchService.search(currentUser, parseResult.getQuery(), PagerFilter.getUnlimitedFilter())
final List issues = results?.results
totalIssues = issues.size()
issues.each { theIssue ->
log.info "Script=" + scriptName + " ScriptRunIdent=" + scriptRunIdent + " Message='Value " + + " Message='Value " + theIssue.getCustomFieldValue(sourceField) + "'"
//Extract value(s) here from Source field. Its possible to expand for another 'jiraSourceFieldType'
if (jiraSourceFieldType.contains("Elements Connect"))
{
sourceFieldValue = extractElementsValues(theIssue.getCustomFieldValue(sourceField),type)
}
else
{
sourceFieldValue = theIssue.getCustomFieldValue(elementsFieldsourceField)
+ "'"
elementsFieldValue = extractValues(theIssue.getCustomFieldValue(elementsField),type)
}
shadowFieldsValue = theIssue.getCustomFieldValue(shadowField)
if (elementsFieldValuesourceFieldValue != shadowFieldsValue)
{
currentNumber = currentNumber + 1
if (dryRun != "1")
{
log.info "Script=" + scriptName + " IssueKey=" + theIssue.getKey() + " ScriptRunIdent=" + scriptRunIdent + " Message='Copying " + elementsFieldIdsourceFieldId + " to " + shadowFieldId + ", value: " + elementsFieldValuesourceFieldValue + "'"
MutableIssue mIssue = issueManager.getIssueByCurrentKey(theIssue.getKey())
try {
mIssue.setCustomFieldValue(shadowField,elementsFieldValuesourceFieldValue)
ComponentAccessor.getIssueManager().updateIssue(currentUser, mIssue, EventDispatchOption.DO_NOT_DISPATCH, false)
}
catch (Exception ex)
{
log.info "Script=" + scriptName + " IssueKey=" + theIssue.getKey() + " ScriptRunIdent=" + scriptRunIdent + " Error='Error Updating: " + ex.getMessage() + "'"
}
//Reindex Issue
if (skipIndex != "1")
{
boolean wasIndexing = ImportUtils.isIndexIssues()
ImportUtils.setIndexIssues(true)
issueIndexingService.reIndex(mIssue)
ImportUtils.setIndexIssues(wasIndexing)
}
}
else
{
log.info "Script=" + scriptName + " IssueKey=" + theIssue.getKey() + " ScriptRunIdent=" + scriptRunIdent + " Message='DryRun - Copying " + elementsFieldIdsourceFieldId + " to " + shadowFieldId + ", value: " + elementsFieldValuesourceFieldValue + "'"
}
}
else
{
log.info "Script=" + scriptName + " IssueKey=" + theIssue.getKey() + " ScriptRunIdent=" + scriptRunIdent + " Message='Skipped copy due to identical values'"
}
}
if (dryRun != "1")
{
if (currentNumber > 0)
{
builder {success "Fields copied successfully. Copied " + currentNumber + " field(s)."}
}
else
{
builder {success "No Fields copied."}
}
}
else
{
builder {success "Dry Run. Woulf have copied " + currentNumber + " field(s)."}
}
Response.status(200).entity(builder.toString()).build()
}
else
{
builder {error "Not valid JQL"}
Response.status(500).entity(builder.toString()).build()
}
}
else
{
builder {error "Shadow field is not a Text Field."}
Response.status(500).entity(builder.toString()).build()
}
}
def extractValuesextractElementsValues(theValue,fieldType)
{
if (theValue == null)
{
return null
}
def slurper = new JsonSlurper().parseText(theValue)
if (fieldType == "M")
{
slurper.keys.join("\n").toString()
}
else
{
slurper.keys[0].toString()
}
} |
...