Versioner sammenlignet

Nøgle

  • Linjen blev tilføjet.
  • Denne linje blev fjernet.
  • Formatering blev ændret.

...

Kodeblok
languageshell
titleUpdateShadowFieldsForIssue.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:

This script is for field from the Elements App - hence the line:

Extracts the value. This can be different, or just:

Info
Kodeblok
languageshell
elementsFieldValue = extractValues(theIssue.getCustomFieldValue(elementsField),type)
Kodeblok
languageshell
elementsFieldValue = theIssue.getCustomFieldValue(elementsField)

For normal copy

Kodeblok
titleUpdateShadowFieldsForIssue.
languageshell
titleUpdateShadowFieldsForIssue.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()
    }   
}

...