jira-plugin-intellij /src/main/resources/com/onresolve/jira/groovy/canned/admin/CopyCustomField.groovy

Language Groovy Lines 242
MD5 Hash d98b675598ee1e44863ff56993d5b285
Repository https://bitbucket.org/sorin/jira-plugin-intellij View Raw File View Project SPDX
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
package com.onresolve.jira.groovy.canned.admin

import com.atlassian.jira.ComponentManager
import com.atlassian.jira.ManagerFactory
import com.atlassian.jira.bc.JiraServiceContext
import com.atlassian.jira.bc.JiraServiceContextImpl
import com.atlassian.jira.bc.filter.SearchRequestService
import com.atlassian.jira.config.ConstantsManager
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.customfields.MultipleSettableCustomFieldType
import com.atlassian.jira.issue.customfields.impl.MultiSelectCFType
import com.atlassian.jira.issue.customfields.impl.MultiUserCFType
import com.atlassian.jira.issue.customfields.impl.SelectCFType
import com.atlassian.jira.issue.customfields.impl.TextCFType
import com.atlassian.jira.issue.customfields.manager.OptionsManager
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.fields.config.FieldConfig
import com.atlassian.jira.issue.index.IssueIndexManager
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.issue.search.SearchRequest
import com.atlassian.jira.issue.search.SearchResults
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.util.IssueChangeHolder
import com.atlassian.jira.security.JiraAuthenticationContext
import com.atlassian.jira.util.BuildUtils
import com.atlassian.jira.util.ErrorCollection
import com.atlassian.jira.util.ImportUtils
import com.atlassian.jira.util.SimpleErrorCollection
import com.atlassian.jira.web.bean.PagerFilter
import com.onresolve.jira.groovy.canned.CannedScript
import com.onresolve.jira.groovy.canned.utils.CannedScriptUtils
import org.apache.log4j.Category
import com.atlassian.crowd.embedded.api.User

public class CopyCustomField implements CannedScript {

    public static String FIELD_FILTER_ID = "FIELD_FILTER_IID"
    public static String FIELD_SOURCE_FIELD_ID = "FIELD_SOURCE_FIELD_ID"
    public static String FIELD_TARGET_FIELD_ID = "FIELD_TARGET_FIELD_ID"
    public static List MULTI_TYPE_LIST = [MultiSelectCFType.class]

    ComponentManager componentManager = ComponentManager.getInstance()
    JiraAuthenticationContext authenticationContext = componentManager.getJiraAuthenticationContext()
    JiraServiceContext ctx = new JiraServiceContextImpl(authenticationContext.getUser());
    SearchProvider searchProvider = componentManager.getSearchProvider()
    IssueManager issueManager = componentManager.getIssueManager()
    IssueIndexManager indexManager = ComponentManager.getInstance().getIndexManager()
    ConstantsManager constantsManager = componentManager.getConstantsManager()
    def searchRequestService = componentManager.getSearchRequestService()
    CustomFieldManager customFieldManager = componentManager.getCustomFieldManager()

    Category log = Category.getInstance(CopyCustomField.class)

    void doScript() {
        println("CopyCustomField.doScript");
    }

    public String getHelpUrl() {
        "https://studio.plugins.atlassian.com/wiki/display/GRV/Built-In+Scripts#Built-InScripts-CopyCustomFieldValues"
    }

    public String getName() {
        "Copy custom field values"
    }

    List getCategories() {
        ["ADMIN"]
    }

    public String getDescription() {
        """Copy custom field values from one field to another in bulk, to support changing a field type without
            using SQL or restarting.
        """
    }

    public List getParameters(Map params) {
        [
            [
                Name:FIELD_FILTER_ID,
                Label: "Filter ID",
                Description:"""All issues returned by this filter will be modified, if they have both
                    the source and the target custom field. Press preview to see the number of issues affected.""",
                Type:"list",
                Values: CannedScriptUtils.getAllOwnedFilters(true),
            ],
            [
                Name:FIELD_SOURCE_FIELD_ID,
                Label: "Source Field ID",
                Description:"""E.g. customfield_10001.""",
            ],
            [
                Name:FIELD_TARGET_FIELD_ID,
                Label: "Target Field ID",
                Description:"""E.g. customfield_10002.""",
            ],
        ]
    }

    public ErrorCollection doValidate(Map params, boolean forPreview) {
        ErrorCollection errorCollection = new SimpleErrorCollection()
        if (! params[FIELD_FILTER_ID]) {
            errorCollection.addError(FIELD_FILTER_ID, "Please enter the filter ID")
        }
        else {
            long filterId = params[FIELD_FILTER_ID] as Long
            SearchRequest sr = searchRequestService.getFilter(ctx, filterId)
            if (! sr) {
                errorCollection.addError(FIELD_FILTER_ID, "Invalid filter ID... do you own this?")
            }
        }

        if (! params[FIELD_SOURCE_FIELD_ID]) {
            errorCollection.addError(FIELD_SOURCE_FIELD_ID, "Please enter the filter ID")
        }
        else {
            CustomField cfSource = customFieldManager.getCustomFieldObject(params[FIELD_SOURCE_FIELD_ID] as String)
            if (!cfSource) {
                errorCollection.addError(FIELD_SOURCE_FIELD_ID, "Cannot find source field.")
            }
        }

        if (! params[FIELD_TARGET_FIELD_ID]) {
            errorCollection.addError(FIELD_TARGET_FIELD_ID, "Please enter the filter ID")
        }
        else {
            CustomField cfTarget = customFieldManager.getCustomFieldObject(params[FIELD_TARGET_FIELD_ID] as String)
            if (!cfTarget) {
                errorCollection.addError(FIELD_TARGET_FIELD_ID, "Cannot find source field.")
            }
        }

        if (params[FIELD_SOURCE_FIELD_ID] == params[FIELD_TARGET_FIELD_ID]) {
            errorCollection.addErrorMessage("Source and target fields must be different.")
        }


        return errorCollection
    }

    Map doScript(Map params) {
        SearchRequest sr = searchRequestService.getFilter(ctx, params[FIELD_FILTER_ID] as Long)
        SearchResults results = getSearchResults(sr)
        List issues = results.getIssues();

        CustomField cfSource = customFieldManager.getCustomFieldObject(params[FIELD_SOURCE_FIELD_ID] as String)
        CustomField cfTarget = customFieldManager.getCustomFieldObject(params[FIELD_TARGET_FIELD_ID] as String)
        OptionsManager optionsManager = ComponentManager.getComponentInstanceOfType(OptionsManager.class)

        Long nModIssues = 0

        for (Issue issue in issues)
        {
            issue = issueManager.getIssueObject(issue.getId())
            if (!issue) {
                log.warn ("No issue found from DocumentIssue.")
                return
            }
            Object srcFieldValue = issue.getCustomFieldValue(cfSource)

            List customFieldList = customFieldManager.getCustomFieldObjects(issue)
            if (customFieldList.contains(cfSource) && customFieldList.contains(cfTarget)) {
                log.debug "Fix issue on ${issue.key} - ${issue.summary}"
                boolean wasIndexing = ImportUtils.isIndexIssues();
                ImportUtils.setIndexIssues(true);

                IssueChangeHolder changeHolder = new DefaultIssueChangeHolder();

                try {
                    // lossy handle multi to single conversions
                    if (cfTarget.getCustomFieldType() instanceof SelectCFType && cfSource.getCustomFieldType() instanceof MultiSelectCFType) {
                        def list = srcFieldValue as List
                        srcFieldValue = list ? list.first() : null
                    }
                    // handle multi to text conversions
                    else if (cfTarget.getCustomFieldType() instanceof TextCFType && srcFieldValue instanceof Collection) {
                        srcFieldValue = (srcFieldValue as List).join(", ")
                    }
                    else if (srcFieldValue instanceof User && cfTarget.getCustomFieldType() instanceof MultiUserCFType) {
                        srcFieldValue = [srcFieldValue]
                    }
                    // handle to select list for 4.4 - need to set the Option not the string
                    else if ((BuildUtils.getCurrentBuildNumber() as Long) >= 649 && cfTarget.getCustomFieldType() instanceof MultipleSettableCustomFieldType) {
                        FieldConfig fieldConfig = cfTarget.getRelevantConfig(issue)
                        srcFieldValue = optionsManager.getOptions(fieldConfig)?.find{it.toString() == srcFieldValue?.toString()}
                        if (cfTarget.getCustomFieldType() instanceof MultiSelectCFType) {
                            srcFieldValue = [srcFieldValue]
                        }
                        
                        if (!srcFieldValue) {
                            log.warn("No option available with value ${issue.getCustomFieldValue(cfSource)} for target field ${cfTarget.getName()} on issue ${issue.getKey()}")
                        }
                    }
                    // handle single to multi conversions
                    else if (MULTI_TYPE_LIST.contains (cfTarget.getCustomFieldType().class)) {
                        // todo: check that srcFieldValue is not already a collection
                        srcFieldValue = [srcFieldValue]
                    }

                    cfTarget.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(cfTarget), srcFieldValue), changeHolder)
                    nModIssues++
                }
                finally {
                    if ((BuildUtils.getCurrentBuildNumber() as Long) < 614) {
                        ManagerFactory.getCacheManager().flush(com.atlassian.jira.issue.cache.CacheManager.ISSUE_CACHE, issue)
                    }
                    indexManager.reIndex(issue);
                    ImportUtils.setIndexIssues(wasIndexing);
                }
            }
        }

        ["output":"$nModIssues issue(s) modified."]
    }

    String getDescription(Map params, boolean forPreview) {
        SearchRequest sr = searchRequestService.getFilter(ctx, params[FIELD_FILTER_ID] as Long)
        SearchResults results = getSearchResults(sr)
        CustomField cfSource = customFieldManager.getCustomFieldObject(params[FIELD_SOURCE_FIELD_ID] as String)
        CustomField cfTarget = customFieldManager.getCustomFieldObject(params[FIELD_TARGET_FIELD_ID] as String)

        """Will operate on ${results.getTotal()} issue(s) from the \"${sr.getName()}\" filter...
            copying source field \"${cfSource.getName()} to target field \"${cfTarget.getName()}\"."""
    }

    private SearchResults getSearchResults(SearchRequest sr) {
        SearchResults results
        if (sr.getMetaClass().getMetaMethod("getQuery", [] as Object[])) {
            results = searchProvider.search(sr.getQuery(), authenticationContext.getUser(), PagerFilter.getUnlimitedFilter())
        }
        else {
            results = searchProvider.search(sr, authenticationContext.getUser(), PagerFilter.getUnlimitedFilter())
        }
        return results
    }

    public Boolean isFinalParamsPage(Map params) {
        true
    }
}
Back to Top