/src/main/resources/com/onresolve/jira/groovy/canned/admin/CopyCustomField.groovy
Groovy | 242 lines | 206 code | 31 blank | 5 comment | 34 complexity | d98b675598ee1e44863ff56993d5b285 MD5 | raw file
- 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
- }
- }