PageRenderTime 51ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/aschuma/scriptrunner-public-2.0.9
Groovy | 457 lines | 359 code | 65 blank | 33 comment | 32 complexity | bbb54aa9320a34e28e0f50e5e101a135 MD5 | raw file
  1. package com.onresolve.jira.groovy.canned.admin
  2. import com.atlassian.core.ofbiz.util.OFBizPropertyUtils
  3. import com.atlassian.jira.ComponentManager
  4. import com.atlassian.jira.ManagerFactory
  5. import com.atlassian.jira.bc.JiraServiceContext
  6. import com.atlassian.jira.bc.JiraServiceContextImpl
  7. import com.atlassian.jira.bc.project.ProjectService
  8. import com.atlassian.jira.bc.project.ProjectService.CreateProjectValidationResult
  9. import com.atlassian.jira.bc.project.ProjectService.UpdateProjectSchemesValidationResult
  10. import com.atlassian.jira.bc.project.component.ProjectComponent
  11. import com.atlassian.jira.bc.project.component.ProjectComponentManager
  12. import com.atlassian.jira.bc.projectroles.ProjectRoleService
  13. import com.atlassian.jira.issue.CustomFieldManager
  14. import com.atlassian.jira.issue.IssueFieldConstants
  15. import com.atlassian.jira.issue.context.manager.JiraContextTreeManager
  16. import com.atlassian.jira.issue.customfields.CustomFieldUtils
  17. import com.atlassian.jira.issue.fields.CustomField
  18. import com.atlassian.jira.issue.fields.FieldManager
  19. import com.atlassian.jira.issue.fields.config.FieldConfig
  20. import com.atlassian.jira.issue.fields.config.FieldConfigScheme
  21. import com.atlassian.jira.issue.fields.config.manager.FieldConfigManager
  22. import com.atlassian.jira.issue.fields.config.manager.FieldConfigSchemeManager
  23. import com.atlassian.jira.issue.fields.config.manager.IssueTypeSchemeManager
  24. import com.atlassian.jira.issue.fields.config.persistence.FieldConfigSchemePersisterImpl
  25. import com.atlassian.jira.issue.fields.layout.field.FieldLayoutManager
  26. import com.atlassian.jira.issue.fields.screen.issuetype.IssueTypeScreenSchemeManager
  27. import com.atlassian.jira.issue.security.IssueSecuritySchemeManager
  28. import com.atlassian.jira.notification.NotificationSchemeManager
  29. import com.atlassian.jira.permission.PermissionSchemeManager
  30. import com.atlassian.jira.project.Project
  31. import com.atlassian.jira.project.ProjectManager
  32. import com.atlassian.jira.project.version.Version
  33. import com.atlassian.jira.project.version.VersionManager
  34. import com.atlassian.jira.scheme.Scheme
  35. import com.atlassian.jira.security.roles.ProjectRole
  36. import com.atlassian.jira.security.roles.ProjectRoleActors
  37. import com.atlassian.jira.security.roles.actor.GroupRoleActorFactory
  38. import com.atlassian.jira.security.roles.actor.UserRoleActorFactory
  39. import com.atlassian.jira.util.ErrorCollection
  40. import com.atlassian.jira.util.SimpleErrorCollection
  41. import com.atlassian.jira.util.ofbiz.GenericValueUtils
  42. import com.atlassian.jira.workflow.WorkflowSchemeManager
  43. import com.opensymphony.module.propertyset.PropertySet
  44. import org.apache.log4j.Category
  45. import org.ofbiz.core.entity.GenericValue
  46. import com.atlassian.jira.issue.fields.layout.field.FieldConfigurationScheme
  47. import com.onresolve.jira.groovy.canned.CannedScript
  48. import com.onresolve.jira.groovy.canned.utils.CannedScriptUtils
  49. import com.atlassian.jira.avatar.AvatarManager
  50. import com.atlassian.jira.avatar.Avatar
  51. import com.atlassian.crowd.embedded.api.User
  52. import com.atlassian.jira.jql.builder.JqlQueryBuilder
  53. import com.atlassian.jira.issue.search.SearchRequest
  54. import com.atlassian.jira.issue.search.SearchResults
  55. import com.atlassian.jira.web.bean.PagerFilter
  56. import com.atlassian.jira.issue.search.SearchProvider
  57. import com.onresolve.jira.groovy.canned.workflow.postfunctions.CloneIssue
  58. import com.onresolve.jira.groovy.GroovyRunner
  59. class CopyProject implements CannedScript {
  60. private static final Category log = Category.getInstance("com.onresolve.jira.groovy.CopyProjectTool")
  61. public static final String EMAIL_SENDER = "jira.project.email.sender"
  62. public static String FIELD_SOURCE_PROJECT = "FIELD_SOURCE_PROJECT"
  63. public static String FIELD_TARGET_PROJECT = "FIELD_TARGET_PROJECT"
  64. public static String FIELD_TARGET_PROJECT_NAME = "FIELD_TARGET_PROJECT_NAME"
  65. public static String FIELD_COPY_VERSIONS = "FIELD_COPY_VERSIONS"
  66. public static String FIELD_COPY_COMPONENTS = "FIELD_COPY_COMPONENTS"
  67. public static String FIELD_COPY_ISSUES = "FIELD_COPY_ISSUES"
  68. String targetProjectKey = ""
  69. String sourceProjectKey = ""
  70. public String copyComponents = ""
  71. public String copyVersions = ""
  72. public String copyIssues = ""
  73. public String targetProjectName = "";
  74. ProjectManager projectManager = ComponentManager.getInstance().getProjectManager()
  75. def notificationSchemeManager = ManagerFactory.getNotificationSchemeManager()
  76. def permissionSchemeManager = ManagerFactory.getPermissionSchemeManager()
  77. def issueSecuritySchemeManager = ManagerFactory.getIssueSecuritySchemeManager()
  78. def projectComponentManager = ComponentManager.getInstance().getProjectComponentManager()
  79. def versionManager = ComponentManager.getInstance().getVersionManager()
  80. def itsm = (IssueTypeSchemeManager) ComponentManager.getInstance().getComponentInstanceOfType(IssueTypeSchemeManager.class)
  81. def fieldManager = ComponentManager.getInstance().getFieldManager()
  82. def fieldConfigSchemeManager = (FieldConfigSchemeManager) ComponentManager.getInstance().getComponentInstanceOfType(FieldConfigSchemeManager.class)
  83. def workflowSchemeManager = ComponentManager.getInstance().getWorkflowSchemeManager()
  84. def fieldLayoutManager = ComponentManager.getInstance().getFieldLayoutManager()
  85. def issueTypeScreenSchemeManager = ComponentManager.getInstance().getIssueTypeScreenSchemeManager()
  86. def fieldConfigManager = (FieldConfigManager) ComponentManager.getInstance().getComponentInstanceOfType(FieldConfigManager.class)
  87. def customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
  88. def projectService = (ProjectService) ComponentManager.getInstance().getComponentInstanceOfType(ProjectService.class)
  89. def scriptManager
  90. String getName() {
  91. "Copy project"
  92. }
  93. String getDescription() {
  94. """This tool will create a new project, from the configuration of another project.
  95. <br>This includes: Schemes, Role memberships, Custom field configurations, and optionally, versions and components.
  96. """
  97. }
  98. public String getHelpUrl() {
  99. "https://studio.plugins.atlassian.com/wiki/display/GRV/Built-In+Scripts#Built-InScripts-CopyProject"
  100. }
  101. List getCategories() {
  102. ['ADMIN']
  103. }
  104. List getParameters(Map params) {
  105. [
  106. [
  107. Name:FIELD_SOURCE_PROJECT,
  108. Label:"Source project",
  109. Description:"Project to copy",
  110. Type:"list",
  111. Values: CannedScriptUtils.getProjectOptions(true),
  112. ],
  113. [
  114. Name:FIELD_TARGET_PROJECT,
  115. Label:"Target project key",
  116. Description:"Enter the key of the project to be created"
  117. ],
  118. [
  119. Name:FIELD_TARGET_PROJECT_NAME,
  120. Label:"Target project name",
  121. Description:"Enter the name of the project to be created"
  122. ],
  123. [
  124. Name:FIELD_COPY_VERSIONS,
  125. Label:"Copy versions",
  126. Description:"Do you want versions to be replicated in the target project?",
  127. Type:"bool",
  128. ],
  129. [
  130. Name:FIELD_COPY_COMPONENTS,
  131. Label:"Copy components",
  132. Description:"Do you want components to be replicated in the target project?",
  133. Type:"bool",
  134. ],
  135. [
  136. Name:FIELD_COPY_ISSUES,
  137. Label:"Copy issues",
  138. Description:"Do you want all the issues to be copied to the target project? You must also opt to copy Components and Versions.",
  139. Type:"bool",
  140. ],
  141. ]
  142. }
  143. ErrorCollection doValidate(Map params, boolean forPreview) {
  144. log.debug ("doValidation()...")
  145. sourceProjectKey = params[FIELD_SOURCE_PROJECT]
  146. targetProjectKey = params[FIELD_TARGET_PROJECT]
  147. targetProjectName = params[FIELD_TARGET_PROJECT_NAME]
  148. copyComponents = params[FIELD_COPY_COMPONENTS]
  149. copyVersions = params[FIELD_COPY_VERSIONS]
  150. copyIssues = params[FIELD_COPY_ISSUES]
  151. log.debug ("sourceProjectKey: $sourceProjectKey")
  152. log.debug ("targetProjectKey: $targetProjectKey")
  153. log.debug ("copyComponents: $copyComponents")
  154. log.debug ("copyVersions: $copyVersions")
  155. SimpleErrorCollection errorCollection = new SimpleErrorCollection()
  156. if (! sourceProjectKey) {
  157. errorCollection.addError(FIELD_SOURCE_PROJECT, "Must enter source project.");
  158. }
  159. else {
  160. Project srcProject = projectManager.getProjectObjByKey(sourceProjectKey)
  161. if (! srcProject) {
  162. errorCollection.addError(FIELD_SOURCE_PROJECT, "Source project does not exist");
  163. }
  164. else {
  165. ErrorCollection projectConfigErrorCollection = new SimpleErrorCollection();
  166. JiraServiceContext projectConfigServiceContext = new JiraServiceContextImpl(getRemoteUser(), projectConfigErrorCollection);
  167. if (!projectService.isValidAllProjectData(
  168. projectConfigServiceContext, targetProjectName, targetProjectKey,
  169. srcProject.getLead().getName(), srcProject.getUrl(), srcProject.getAssigneeType())) {
  170. Map validationErrors = projectConfigErrorCollection.getErrors();
  171. log.debug validationErrors
  172. validationErrors.each {String key, String value ->
  173. log.debug ("$key : $value")
  174. if (key == "projectName")
  175. errorCollection.addError(FIELD_TARGET_PROJECT_NAME, value);
  176. if (key == "projectKey")
  177. errorCollection.addError(FIELD_TARGET_PROJECT, value);
  178. }
  179. //and add any unkeyed error messages
  180. errorCollection.addErrorMessages(projectConfigErrorCollection.getErrorMessages());
  181. }
  182. }
  183. // check not copying issues without versions
  184. // but there is a bug with checkboxes where we can't show that they're wrong
  185. if (copyIssues && !(copyComponents && copyVersions)) {
  186. errorCollection.addError(FIELD_COPY_ISSUES, "You can't copy issues unless you also copy components and versions.")
  187. }
  188. }
  189. errorCollection
  190. }
  191. Map doScript(Map params) {
  192. sourceProjectKey = params[FIELD_SOURCE_PROJECT]
  193. targetProjectKey = params[FIELD_TARGET_PROJECT]
  194. targetProjectName = params[FIELD_TARGET_PROJECT_NAME]
  195. copyComponents = params[FIELD_COPY_COMPONENTS]
  196. copyVersions = params[FIELD_COPY_VERSIONS]
  197. copyIssues = params[FIELD_COPY_ISSUES]
  198. Project newprojectObj = doCopyProject (sourceProjectKey, targetProjectKey, targetProjectName, copyComponents ? true : false, copyVersions ? true : false)
  199. [output:"Project copied to <a href=\"../project/ViewProject.jspa?pid=${newprojectObj.getId()}\">${newprojectObj.key}</b>"]
  200. }
  201. String getDescription(Map params, boolean forPreview) {
  202. "If validation passed press the Run button already"
  203. }
  204. public Project doCopyProject (String sourceProjectKey, String targetProjectKey, String targetProjectDesc, boolean copyComponents, boolean copyVersions) {
  205. log.debug ("CopyProject: $sourceProjectKey, $targetProjectKey, $targetProjectDesc, $copyComponents, $copyVersions ")
  206. Project srcProject = projectManager.getProjectObjByKey(sourceProjectKey)
  207. GenericValue srcProjectGV = srcProject.getGenericValue()
  208. final ProjectService projectService = ComponentManager.getComponentInstanceOfType(ProjectService.class);
  209. // can't create a project with a non-system avatar, imho there is a bug in validateCreateProject
  210. final AvatarManager avatarManager = ComponentManager.getInstance().getAvatarManager()
  211. Avatar srcProjectAvatar = srcProject.getAvatar()
  212. // use ID for system avatar if it is one, otherwise need to create a new db record for it
  213. // todo: this doesn't work because the source avatar already has an ID
  214. // Long newProjectAvatarId = srcProjectAvatar.isSystemAvatar() ? srcProjectAvatar.getId() : avatarManager.create(srcProjectAvatar).getId()
  215. final ProjectService.CreateProjectValidationResult result =
  216. projectService.validateCreateProject(getRemoteUser(), targetProjectName, targetProjectKey, srcProject.getDescription(), srcProject.getLeadUserName(),
  217. srcProject.url, srcProject.getAssigneeType(),
  218. srcProjectAvatar.isSystemAvatar() ? srcProjectAvatar.getId() : avatarManager.getDefaultAvatarId(Avatar.Type.PROJECT));
  219. final Project newprojectObj = projectService.createProject(result);
  220. final ProjectService.UpdateProjectSchemesValidationResult schemesResult =
  221. projectService.validateUpdateProjectSchemes(
  222. getRemoteUser(),
  223. permissionSchemeManager.getSchemes(srcProjectGV).size() == 0 ? null : permissionSchemeManager.getSchemes(srcProjectGV)[0].get("id"),
  224. notificationSchemeManager.getNotificationSchemeForProject(srcProjectGV) ? notificationSchemeManager.getNotificationSchemeForProject(srcProjectGV).getLong("id") : null,
  225. issueSecuritySchemeManager.getSchemes(srcProjectGV).size() == 0 ? null : issueSecuritySchemeManager.getSchemes(srcProjectGV)[0].get("id"));
  226. projectService.updateProjectSchemes(schemesResult, newprojectObj);
  227. GenericValue newprojectGV = newprojectObj.getGenericValue()
  228. // SET VERSIONS (OPTIONAL)
  229. if (copyVersions) {
  230. srcProject.getVersions().each {
  231. Version version = it
  232. log.debug (version.getClass())
  233. log.debug (version.getName())
  234. if (!version.isArchived()) {
  235. versionManager.createVersion(
  236. version.getName(),
  237. version.getReleaseDate(),
  238. version.getDescription(),
  239. newprojectObj.getId(),
  240. null
  241. )
  242. }
  243. }
  244. }
  245. // END SET VERSIONS
  246. // SET COMPONENTS (OPTIONAL)
  247. if (copyComponents) {
  248. projectComponentManager.findAllForProject(srcProject.getId()).each {ProjectComponent component ->
  249. log.debug (component.getClass())
  250. log.debug (component.dump())
  251. projectComponentManager.create(
  252. component.name,
  253. component.description,
  254. component.lead,
  255. component.assigneeType,
  256. newprojectObj.getId()
  257. )
  258. }
  259. }
  260. // END COMPONENTS (OPTIONAL)
  261. // SET MAIL CONFIG
  262. PropertySet ps = OFBizPropertyUtils.getPropertySet(srcProjectGV)
  263. PropertySet newps = OFBizPropertyUtils.getPropertySet(newprojectGV)
  264. newps.setString (EMAIL_SENDER, ps.getString(EMAIL_SENDER))
  265. // END SET MAIL CONFIG
  266. JiraContextTreeManager jiraContextTreeManager = new JiraContextTreeManager(projectManager, ComponentManager.getInstance().getConstantsManager())
  267. // SET ISSUE TYPE SCHEME
  268. FieldConfigScheme issueTypeScheme = itsm.getConfigScheme(srcProjectGV)
  269. if (issueTypeScheme != itsm.getDefaultIssueTypeScheme()) {
  270. List projectList = issueTypeScheme.getAssociatedProjects()
  271. projectList.add(newprojectGV)
  272. Long[] projectIds = GenericValueUtils.transformToLongIds (projectList)
  273. log.debug ("projectIds: $projectIds")
  274. // Set the contexts
  275. List contexts = CustomFieldUtils.buildJiraIssueContexts(false,
  276. null,
  277. projectIds,
  278. jiraContextTreeManager);
  279. fieldConfigSchemeManager.updateFieldConfigScheme(issueTypeScheme, contexts, fieldManager.getConfigurableField(IssueFieldConstants.ISSUE_TYPE));
  280. }
  281. // END ISSUE TYPE SCHEME
  282. // SET WORKFLOW SCHEME
  283. if (workflowSchemeManager.getSchemes(srcProjectGV)[0] != workflowSchemeManager.getDefaultScheme()) {
  284. workflowSchemeManager.addSchemeToProject (newprojectObj, (Scheme) workflowSchemeManager.getScheme(workflowSchemeManager.getSchemes(srcProjectGV)[0].get("id")))
  285. }
  286. // END SET WORKFLOW SCHEME
  287. // SET FIELD CONFIG (FIELD LAYOUT) SCHEME
  288. FieldConfigurationScheme srcProjectFieldLayout = fieldLayoutManager.getFieldConfigurationScheme(srcProjectGV)
  289. if (srcProjectFieldLayout) {
  290. fieldLayoutManager.addSchemeAssociation(newprojectGV, srcProjectFieldLayout.getId())
  291. }
  292. // END SET FIELD CONFIG (FIELD LAYOUT) SCHEME
  293. // SET ISSUE TYPE SCREEN SCHEME
  294. issueTypeScreenSchemeManager.addSchemeAssociation (newprojectGV, issueTypeScreenSchemeManager.getIssueTypeScreenScheme(srcProjectGV))
  295. // END ISSUE TYPE SCREEN SCHEME
  296. // CVS MODULES: DON'T USE IT SO DON'T CARE
  297. // Set PROJECT CATEGORY
  298. projectManager.setProjectCategory (newprojectGV, projectManager.getProjectCategoryFromProject(srcProjectGV))
  299. // SET CUSTOM FIELDS
  300. customFieldManager.getCustomFieldObjects().each {CustomField cf ->
  301. fieldConfigSchemeManager.getConfigSchemesForField(cf).each {FieldConfigScheme fcs ->
  302. if (!fcs.isGlobal()) {
  303. fcs.getAssociatedProjects().each {GenericValue project ->
  304. if (project.getLong("id") == srcProject.getId()) {
  305. log.debug (fcs.name + " associated with " + project.name + ", need to modify this")
  306. Long fcsId = fcs.id
  307. FieldConfigScheme cfConfigScheme = fieldConfigSchemeManager.getFieldConfigScheme(fcsId)
  308. FieldConfigScheme.Builder cfSchemeBuilder = new FieldConfigScheme.Builder(cfConfigScheme)
  309. FieldConfig config = fieldConfigManager.getFieldConfig(fcsId)
  310. Map configs = new HashMap()
  311. fcs.getAssociatedIssueTypes().each {
  312. GenericValue issueType = (GenericValue) it;
  313. String issueTypeId = issueType == null ? null : issueType.getString(FieldConfigSchemePersisterImpl.ENTITY_ID);
  314. configs.put(issueTypeId, config);
  315. }
  316. cfSchemeBuilder.setConfigs(configs)
  317. cfConfigScheme = cfSchemeBuilder.toFieldConfigScheme()
  318. // log.debug ("cf.getAssociatedProjects().size: " + cf.getAssociatedProjects().size())
  319. List projectList = fcs.getAssociatedProjects()
  320. projectList.add(newprojectGV)
  321. Long[] projectIds = GenericValueUtils.transformToLongIds (projectList)
  322. List contexts = CustomFieldUtils.buildJiraIssueContexts(false,
  323. null,
  324. projectIds,
  325. jiraContextTreeManager);
  326. log.debug ("Modifying cfConfigScheme: ${cfConfigScheme.getName()}")
  327. fieldConfigSchemeManager.updateFieldConfigScheme(cfConfigScheme, contexts, customFieldManager.getCustomFieldObject(cf.getGenericValue().getLong("id")))
  328. }
  329. }
  330. }
  331. else {
  332. // log.debug ("$cf.name is a global field , do nothing")
  333. }
  334. }
  335. }
  336. customFieldManager.refresh()
  337. // END SET CUSTOM FIELDS
  338. // SET PROJECT ROLES
  339. ProjectRoleService projectRoleService = (ProjectRoleService) ComponentManager.getComponentInstanceOfType(ProjectRoleService.class);
  340. SimpleErrorCollection errorCollection = new SimpleErrorCollection();
  341. projectRoleService.getProjectRoles(remoteUser, errorCollection).each {ProjectRole projectRole ->
  342. // Collection newProjectRoleActors = new ArrayList()
  343. log.debug (projectRole.name + ": " + projectRole.getId())
  344. ProjectRoleActors projectRoleActors = projectRoleService.getProjectRoleActors(remoteUser, projectRole, srcProject, errorCollection)
  345. // Copy users and groups, separately
  346. [UserRoleActorFactory.TYPE, GroupRoleActorFactory.TYPE].each {String actorFactoryType ->
  347. Collection newProjectRoleActors = new ArrayList()
  348. projectRoleActors.getRoleActorsByType(actorFactoryType).each {
  349. newProjectRoleActors.add(it.parameter)
  350. }
  351. projectRoleService.addActorsToProjectRole (remoteUser, newProjectRoleActors, projectRole, newprojectObj, actorFactoryType, errorCollection)
  352. }
  353. }
  354. if (copyIssues && copyVersions && copyComponents) {
  355. def componentManager = ComponentManager.getInstance()
  356. def issueManager = componentManager.getIssueManager()
  357. JqlQueryBuilder builder = JqlQueryBuilder.newBuilder()
  358. def query = builder.where().project(srcProject.id).buildQuery()
  359. SearchRequest sr = new SearchRequest(query)
  360. SearchProvider searchProvider = componentManager.getSearchProvider()
  361. SearchResults results = searchProvider.search(sr.getQuery(), componentManager.getJiraAuthenticationContext().getUser(), PagerFilter.getUnlimitedFilter())
  362. results.issues.each {documentIssue ->
  363. log.debug("Copy issue: ${documentIssue.key}")
  364. def issue = issueManager.getIssueObject(documentIssue.id)
  365. if (issue) {
  366. // Use clone issue but with no link type
  367. Map<String, Object> inputs = [
  368. issue: issue,
  369. (CloneIssue.FIELD_TARGET_PROJECT): newprojectObj.key,
  370. (CloneIssue.FIELD_LINK_TYPE): null,
  371. ] as Map<String, Object>
  372. log.debug ("inputs: $inputs")
  373. new CloneIssue().doScript(inputs)
  374. }
  375. else {
  376. // in test the issue can sometimes be null for some reason...
  377. log.warn "Null issue found."
  378. }
  379. }
  380. }
  381. return newprojectObj
  382. }
  383. public User getRemoteUser() {
  384. return ComponentManager.getInstance().getJiraAuthenticationContext().getUser()
  385. }
  386. public Boolean isFinalParamsPage(Map params) {
  387. true
  388. }
  389. public String toString() {
  390. "Copy project 41"
  391. }
  392. }