PageRenderTime 58ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/sorin/jira-plugin-intellij
Groovy | 242 lines | 206 code | 31 blank | 5 comment | 34 complexity | d98b675598ee1e44863ff56993d5b285 MD5 | raw file
  1. package com.onresolve.jira.groovy.canned.admin
  2. import com.atlassian.jira.ComponentManager
  3. import com.atlassian.jira.ManagerFactory
  4. import com.atlassian.jira.bc.JiraServiceContext
  5. import com.atlassian.jira.bc.JiraServiceContextImpl
  6. import com.atlassian.jira.bc.filter.SearchRequestService
  7. import com.atlassian.jira.config.ConstantsManager
  8. import com.atlassian.jira.issue.CustomFieldManager
  9. import com.atlassian.jira.issue.Issue
  10. import com.atlassian.jira.issue.IssueManager
  11. import com.atlassian.jira.issue.ModifiedValue
  12. import com.atlassian.jira.issue.customfields.MultipleSettableCustomFieldType
  13. import com.atlassian.jira.issue.customfields.impl.MultiSelectCFType
  14. import com.atlassian.jira.issue.customfields.impl.MultiUserCFType
  15. import com.atlassian.jira.issue.customfields.impl.SelectCFType
  16. import com.atlassian.jira.issue.customfields.impl.TextCFType
  17. import com.atlassian.jira.issue.customfields.manager.OptionsManager
  18. import com.atlassian.jira.issue.fields.CustomField
  19. import com.atlassian.jira.issue.fields.config.FieldConfig
  20. import com.atlassian.jira.issue.index.IssueIndexManager
  21. import com.atlassian.jira.issue.search.SearchProvider
  22. import com.atlassian.jira.issue.search.SearchRequest
  23. import com.atlassian.jira.issue.search.SearchResults
  24. import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
  25. import com.atlassian.jira.issue.util.IssueChangeHolder
  26. import com.atlassian.jira.security.JiraAuthenticationContext
  27. import com.atlassian.jira.util.BuildUtils
  28. import com.atlassian.jira.util.ErrorCollection
  29. import com.atlassian.jira.util.ImportUtils
  30. import com.atlassian.jira.util.SimpleErrorCollection
  31. import com.atlassian.jira.web.bean.PagerFilter
  32. import com.onresolve.jira.groovy.canned.CannedScript
  33. import com.onresolve.jira.groovy.canned.utils.CannedScriptUtils
  34. import org.apache.log4j.Category
  35. import com.atlassian.crowd.embedded.api.User
  36. public class CopyCustomField implements CannedScript {
  37. public static String FIELD_FILTER_ID = "FIELD_FILTER_IID"
  38. public static String FIELD_SOURCE_FIELD_ID = "FIELD_SOURCE_FIELD_ID"
  39. public static String FIELD_TARGET_FIELD_ID = "FIELD_TARGET_FIELD_ID"
  40. public static List MULTI_TYPE_LIST = [MultiSelectCFType.class]
  41. ComponentManager componentManager = ComponentManager.getInstance()
  42. JiraAuthenticationContext authenticationContext = componentManager.getJiraAuthenticationContext()
  43. JiraServiceContext ctx = new JiraServiceContextImpl(authenticationContext.getUser());
  44. SearchProvider searchProvider = componentManager.getSearchProvider()
  45. IssueManager issueManager = componentManager.getIssueManager()
  46. IssueIndexManager indexManager = ComponentManager.getInstance().getIndexManager()
  47. ConstantsManager constantsManager = componentManager.getConstantsManager()
  48. def searchRequestService = componentManager.getSearchRequestService()
  49. CustomFieldManager customFieldManager = componentManager.getCustomFieldManager()
  50. Category log = Category.getInstance(CopyCustomField.class)
  51. void doScript() {
  52. println("CopyCustomField.doScript");
  53. }
  54. public String getHelpUrl() {
  55. "https://studio.plugins.atlassian.com/wiki/display/GRV/Built-In+Scripts#Built-InScripts-CopyCustomFieldValues"
  56. }
  57. public String getName() {
  58. "Copy custom field values"
  59. }
  60. List getCategories() {
  61. ["ADMIN"]
  62. }
  63. public String getDescription() {
  64. """Copy custom field values from one field to another in bulk, to support changing a field type without
  65. using SQL or restarting.
  66. """
  67. }
  68. public List getParameters(Map params) {
  69. [
  70. [
  71. Name:FIELD_FILTER_ID,
  72. Label: "Filter ID",
  73. Description:"""All issues returned by this filter will be modified, if they have both
  74. the source and the target custom field. Press preview to see the number of issues affected.""",
  75. Type:"list",
  76. Values: CannedScriptUtils.getAllOwnedFilters(true),
  77. ],
  78. [
  79. Name:FIELD_SOURCE_FIELD_ID,
  80. Label: "Source Field ID",
  81. Description:"""E.g. customfield_10001.""",
  82. ],
  83. [
  84. Name:FIELD_TARGET_FIELD_ID,
  85. Label: "Target Field ID",
  86. Description:"""E.g. customfield_10002.""",
  87. ],
  88. ]
  89. }
  90. public ErrorCollection doValidate(Map params, boolean forPreview) {
  91. ErrorCollection errorCollection = new SimpleErrorCollection()
  92. if (! params[FIELD_FILTER_ID]) {
  93. errorCollection.addError(FIELD_FILTER_ID, "Please enter the filter ID")
  94. }
  95. else {
  96. long filterId = params[FIELD_FILTER_ID] as Long
  97. SearchRequest sr = searchRequestService.getFilter(ctx, filterId)
  98. if (! sr) {
  99. errorCollection.addError(FIELD_FILTER_ID, "Invalid filter ID... do you own this?")
  100. }
  101. }
  102. if (! params[FIELD_SOURCE_FIELD_ID]) {
  103. errorCollection.addError(FIELD_SOURCE_FIELD_ID, "Please enter the filter ID")
  104. }
  105. else {
  106. CustomField cfSource = customFieldManager.getCustomFieldObject(params[FIELD_SOURCE_FIELD_ID] as String)
  107. if (!cfSource) {
  108. errorCollection.addError(FIELD_SOURCE_FIELD_ID, "Cannot find source field.")
  109. }
  110. }
  111. if (! params[FIELD_TARGET_FIELD_ID]) {
  112. errorCollection.addError(FIELD_TARGET_FIELD_ID, "Please enter the filter ID")
  113. }
  114. else {
  115. CustomField cfTarget = customFieldManager.getCustomFieldObject(params[FIELD_TARGET_FIELD_ID] as String)
  116. if (!cfTarget) {
  117. errorCollection.addError(FIELD_TARGET_FIELD_ID, "Cannot find source field.")
  118. }
  119. }
  120. if (params[FIELD_SOURCE_FIELD_ID] == params[FIELD_TARGET_FIELD_ID]) {
  121. errorCollection.addErrorMessage("Source and target fields must be different.")
  122. }
  123. return errorCollection
  124. }
  125. Map doScript(Map params) {
  126. SearchRequest sr = searchRequestService.getFilter(ctx, params[FIELD_FILTER_ID] as Long)
  127. SearchResults results = getSearchResults(sr)
  128. List issues = results.getIssues();
  129. CustomField cfSource = customFieldManager.getCustomFieldObject(params[FIELD_SOURCE_FIELD_ID] as String)
  130. CustomField cfTarget = customFieldManager.getCustomFieldObject(params[FIELD_TARGET_FIELD_ID] as String)
  131. OptionsManager optionsManager = ComponentManager.getComponentInstanceOfType(OptionsManager.class)
  132. Long nModIssues = 0
  133. for (Issue issue in issues)
  134. {
  135. issue = issueManager.getIssueObject(issue.getId())
  136. if (!issue) {
  137. log.warn ("No issue found from DocumentIssue.")
  138. return
  139. }
  140. Object srcFieldValue = issue.getCustomFieldValue(cfSource)
  141. List customFieldList = customFieldManager.getCustomFieldObjects(issue)
  142. if (customFieldList.contains(cfSource) && customFieldList.contains(cfTarget)) {
  143. log.debug "Fix issue on ${issue.key} - ${issue.summary}"
  144. boolean wasIndexing = ImportUtils.isIndexIssues();
  145. ImportUtils.setIndexIssues(true);
  146. IssueChangeHolder changeHolder = new DefaultIssueChangeHolder();
  147. try {
  148. // lossy handle multi to single conversions
  149. if (cfTarget.getCustomFieldType() instanceof SelectCFType && cfSource.getCustomFieldType() instanceof MultiSelectCFType) {
  150. def list = srcFieldValue as List
  151. srcFieldValue = list ? list.first() : null
  152. }
  153. // handle multi to text conversions
  154. else if (cfTarget.getCustomFieldType() instanceof TextCFType && srcFieldValue instanceof Collection) {
  155. srcFieldValue = (srcFieldValue as List).join(", ")
  156. }
  157. else if (srcFieldValue instanceof User && cfTarget.getCustomFieldType() instanceof MultiUserCFType) {
  158. srcFieldValue = [srcFieldValue]
  159. }
  160. // handle to select list for 4.4 - need to set the Option not the string
  161. else if ((BuildUtils.getCurrentBuildNumber() as Long) >= 649 && cfTarget.getCustomFieldType() instanceof MultipleSettableCustomFieldType) {
  162. FieldConfig fieldConfig = cfTarget.getRelevantConfig(issue)
  163. srcFieldValue = optionsManager.getOptions(fieldConfig)?.find{it.toString() == srcFieldValue?.toString()}
  164. if (cfTarget.getCustomFieldType() instanceof MultiSelectCFType) {
  165. srcFieldValue = [srcFieldValue]
  166. }
  167. if (!srcFieldValue) {
  168. log.warn("No option available with value ${issue.getCustomFieldValue(cfSource)} for target field ${cfTarget.getName()} on issue ${issue.getKey()}")
  169. }
  170. }
  171. // handle single to multi conversions
  172. else if (MULTI_TYPE_LIST.contains (cfTarget.getCustomFieldType().class)) {
  173. // todo: check that srcFieldValue is not already a collection
  174. srcFieldValue = [srcFieldValue]
  175. }
  176. cfTarget.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(cfTarget), srcFieldValue), changeHolder)
  177. nModIssues++
  178. }
  179. finally {
  180. if ((BuildUtils.getCurrentBuildNumber() as Long) < 614) {
  181. ManagerFactory.getCacheManager().flush(com.atlassian.jira.issue.cache.CacheManager.ISSUE_CACHE, issue)
  182. }
  183. indexManager.reIndex(issue);
  184. ImportUtils.setIndexIssues(wasIndexing);
  185. }
  186. }
  187. }
  188. ["output":"$nModIssues issue(s) modified."]
  189. }
  190. String getDescription(Map params, boolean forPreview) {
  191. SearchRequest sr = searchRequestService.getFilter(ctx, params[FIELD_FILTER_ID] as Long)
  192. SearchResults results = getSearchResults(sr)
  193. CustomField cfSource = customFieldManager.getCustomFieldObject(params[FIELD_SOURCE_FIELD_ID] as String)
  194. CustomField cfTarget = customFieldManager.getCustomFieldObject(params[FIELD_TARGET_FIELD_ID] as String)
  195. """Will operate on ${results.getTotal()} issue(s) from the \"${sr.getName()}\" filter...
  196. copying source field \"${cfSource.getName()} to target field \"${cfTarget.getName()}\"."""
  197. }
  198. private SearchResults getSearchResults(SearchRequest sr) {
  199. SearchResults results
  200. if (sr.getMetaClass().getMetaMethod("getQuery", [] as Object[])) {
  201. results = searchProvider.search(sr.getQuery(), authenticationContext.getUser(), PagerFilter.getUnlimitedFilter())
  202. }
  203. else {
  204. results = searchProvider.search(sr, authenticationContext.getUser(), PagerFilter.getUnlimitedFilter())
  205. }
  206. return results
  207. }
  208. public Boolean isFinalParamsPage(Map params) {
  209. true
  210. }
  211. }