/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
- package com.onresolve.jira.groovy.canned.admin
-
- import com.atlassian.core.ofbiz.util.OFBizPropertyUtils
- 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.project.ProjectService
- import com.atlassian.jira.bc.project.ProjectService.CreateProjectValidationResult
- import com.atlassian.jira.bc.project.ProjectService.UpdateProjectSchemesValidationResult
- import com.atlassian.jira.bc.project.component.ProjectComponent
- import com.atlassian.jira.bc.project.component.ProjectComponentManager
- import com.atlassian.jira.bc.projectroles.ProjectRoleService
- import com.atlassian.jira.issue.CustomFieldManager
- import com.atlassian.jira.issue.IssueFieldConstants
- import com.atlassian.jira.issue.context.manager.JiraContextTreeManager
- import com.atlassian.jira.issue.customfields.CustomFieldUtils
- import com.atlassian.jira.issue.fields.CustomField
- import com.atlassian.jira.issue.fields.FieldManager
- import com.atlassian.jira.issue.fields.config.FieldConfig
- import com.atlassian.jira.issue.fields.config.FieldConfigScheme
- import com.atlassian.jira.issue.fields.config.manager.FieldConfigManager
- import com.atlassian.jira.issue.fields.config.manager.FieldConfigSchemeManager
- import com.atlassian.jira.issue.fields.config.manager.IssueTypeSchemeManager
- import com.atlassian.jira.issue.fields.config.persistence.FieldConfigSchemePersisterImpl
- import com.atlassian.jira.issue.fields.layout.field.FieldLayoutManager
- import com.atlassian.jira.issue.fields.screen.issuetype.IssueTypeScreenSchemeManager
- import com.atlassian.jira.issue.security.IssueSecuritySchemeManager
- import com.atlassian.jira.notification.NotificationSchemeManager
- import com.atlassian.jira.permission.PermissionSchemeManager
- import com.atlassian.jira.project.Project
- import com.atlassian.jira.project.ProjectManager
- import com.atlassian.jira.project.version.Version
- import com.atlassian.jira.project.version.VersionManager
- import com.atlassian.jira.scheme.Scheme
- import com.atlassian.jira.security.roles.ProjectRole
- import com.atlassian.jira.security.roles.ProjectRoleActors
- import com.atlassian.jira.security.roles.actor.GroupRoleActorFactory
- import com.atlassian.jira.security.roles.actor.UserRoleActorFactory
- import com.atlassian.jira.util.ErrorCollection
- import com.atlassian.jira.util.SimpleErrorCollection
- import com.atlassian.jira.util.ofbiz.GenericValueUtils
-
- import com.atlassian.jira.workflow.WorkflowSchemeManager
- import com.opensymphony.module.propertyset.PropertySet
- import org.apache.log4j.Category
- import org.ofbiz.core.entity.GenericValue
- import com.atlassian.jira.issue.fields.layout.field.FieldConfigurationScheme
- import com.onresolve.jira.groovy.canned.CannedScript
- import com.onresolve.jira.groovy.canned.utils.CannedScriptUtils
- import com.atlassian.jira.avatar.AvatarManager
- import com.atlassian.jira.avatar.Avatar
- import com.atlassian.crowd.embedded.api.User
- import com.atlassian.jira.jql.builder.JqlQueryBuilder
- import com.atlassian.jira.issue.search.SearchRequest
- import com.atlassian.jira.issue.search.SearchResults
- import com.atlassian.jira.web.bean.PagerFilter
- import com.atlassian.jira.issue.search.SearchProvider
- import com.onresolve.jira.groovy.canned.workflow.postfunctions.CloneIssue
- import com.onresolve.jira.groovy.GroovyRunner
-
- class CopyProject implements CannedScript {
-
- private static final Category log = Category.getInstance("com.onresolve.jira.groovy.CopyProjectTool")
- public static final String EMAIL_SENDER = "jira.project.email.sender"
-
- public static String FIELD_SOURCE_PROJECT = "FIELD_SOURCE_PROJECT"
- public static String FIELD_TARGET_PROJECT = "FIELD_TARGET_PROJECT"
- public static String FIELD_TARGET_PROJECT_NAME = "FIELD_TARGET_PROJECT_NAME"
- public static String FIELD_COPY_VERSIONS = "FIELD_COPY_VERSIONS"
- public static String FIELD_COPY_COMPONENTS = "FIELD_COPY_COMPONENTS"
- public static String FIELD_COPY_ISSUES = "FIELD_COPY_ISSUES"
-
- String targetProjectKey = ""
- String sourceProjectKey = ""
- public String copyComponents = ""
- public String copyVersions = ""
- public String copyIssues = ""
- public String targetProjectName = "";
- ProjectManager projectManager = ComponentManager.getInstance().getProjectManager()
- def notificationSchemeManager = ManagerFactory.getNotificationSchemeManager()
- def permissionSchemeManager = ManagerFactory.getPermissionSchemeManager()
- def issueSecuritySchemeManager = ManagerFactory.getIssueSecuritySchemeManager()
- def projectComponentManager = ComponentManager.getInstance().getProjectComponentManager()
- def versionManager = ComponentManager.getInstance().getVersionManager()
- def itsm = (IssueTypeSchemeManager) ComponentManager.getInstance().getComponentInstanceOfType(IssueTypeSchemeManager.class)
- def fieldManager = ComponentManager.getInstance().getFieldManager()
- def fieldConfigSchemeManager = (FieldConfigSchemeManager) ComponentManager.getInstance().getComponentInstanceOfType(FieldConfigSchemeManager.class)
- def workflowSchemeManager = ComponentManager.getInstance().getWorkflowSchemeManager()
- def fieldLayoutManager = ComponentManager.getInstance().getFieldLayoutManager()
- def issueTypeScreenSchemeManager = ComponentManager.getInstance().getIssueTypeScreenSchemeManager()
- def fieldConfigManager = (FieldConfigManager) ComponentManager.getInstance().getComponentInstanceOfType(FieldConfigManager.class)
- def customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
- def projectService = (ProjectService) ComponentManager.getInstance().getComponentInstanceOfType(ProjectService.class)
- def scriptManager
-
- String getName() {
- "Copy project"
- }
-
- String getDescription() {
- """This tool will create a new project, from the configuration of another project.
- <br>This includes: Schemes, Role memberships, Custom field configurations, and optionally, versions and components.
- """
- }
-
- public String getHelpUrl() {
- "https://studio.plugins.atlassian.com/wiki/display/GRV/Built-In+Scripts#Built-InScripts-CopyProject"
- }
-
- List getCategories() {
- ['ADMIN']
- }
-
- List getParameters(Map params) {
- [
- [
- Name:FIELD_SOURCE_PROJECT,
- Label:"Source project",
- Description:"Project to copy",
- Type:"list",
- Values: CannedScriptUtils.getProjectOptions(true),
- ],
- [
- Name:FIELD_TARGET_PROJECT,
- Label:"Target project key",
- Description:"Enter the key of the project to be created"
- ],
- [
- Name:FIELD_TARGET_PROJECT_NAME,
- Label:"Target project name",
- Description:"Enter the name of the project to be created"
- ],
- [
- Name:FIELD_COPY_VERSIONS,
- Label:"Copy versions",
- Description:"Do you want versions to be replicated in the target project?",
- Type:"bool",
- ],
- [
- Name:FIELD_COPY_COMPONENTS,
- Label:"Copy components",
- Description:"Do you want components to be replicated in the target project?",
- Type:"bool",
- ],
- [
- Name:FIELD_COPY_ISSUES,
- Label:"Copy issues",
- Description:"Do you want all the issues to be copied to the target project? You must also opt to copy Components and Versions.",
- Type:"bool",
- ],
- ]
- }
-
- ErrorCollection doValidate(Map params, boolean forPreview) {
- log.debug ("doValidation()...")
-
- sourceProjectKey = params[FIELD_SOURCE_PROJECT]
- targetProjectKey = params[FIELD_TARGET_PROJECT]
- targetProjectName = params[FIELD_TARGET_PROJECT_NAME]
- copyComponents = params[FIELD_COPY_COMPONENTS]
- copyVersions = params[FIELD_COPY_VERSIONS]
- copyIssues = params[FIELD_COPY_ISSUES]
-
- log.debug ("sourceProjectKey: $sourceProjectKey")
- log.debug ("targetProjectKey: $targetProjectKey")
- log.debug ("copyComponents: $copyComponents")
- log.debug ("copyVersions: $copyVersions")
-
- SimpleErrorCollection errorCollection = new SimpleErrorCollection()
-
- if (! sourceProjectKey) {
- errorCollection.addError(FIELD_SOURCE_PROJECT, "Must enter source project.");
- }
- else {
- Project srcProject = projectManager.getProjectObjByKey(sourceProjectKey)
- if (! srcProject) {
- errorCollection.addError(FIELD_SOURCE_PROJECT, "Source project does not exist");
- }
- else {
- ErrorCollection projectConfigErrorCollection = new SimpleErrorCollection();
- JiraServiceContext projectConfigServiceContext = new JiraServiceContextImpl(getRemoteUser(), projectConfigErrorCollection);
- if (!projectService.isValidAllProjectData(
- projectConfigServiceContext, targetProjectName, targetProjectKey,
- srcProject.getLead().getName(), srcProject.getUrl(), srcProject.getAssigneeType())) {
- Map validationErrors = projectConfigErrorCollection.getErrors();
- log.debug validationErrors
- validationErrors.each {String key, String value ->
- log.debug ("$key : $value")
- if (key == "projectName")
- errorCollection.addError(FIELD_TARGET_PROJECT_NAME, value);
- if (key == "projectKey")
- errorCollection.addError(FIELD_TARGET_PROJECT, value);
-
- }
-
- //and add any unkeyed error messages
- errorCollection.addErrorMessages(projectConfigErrorCollection.getErrorMessages());
- }
- }
-
- // check not copying issues without versions
- // but there is a bug with checkboxes where we can't show that they're wrong
- if (copyIssues && !(copyComponents && copyVersions)) {
- errorCollection.addError(FIELD_COPY_ISSUES, "You can't copy issues unless you also copy components and versions.")
- }
- }
- errorCollection
- }
-
- Map doScript(Map params) {
- sourceProjectKey = params[FIELD_SOURCE_PROJECT]
- targetProjectKey = params[FIELD_TARGET_PROJECT]
- targetProjectName = params[FIELD_TARGET_PROJECT_NAME]
- copyComponents = params[FIELD_COPY_COMPONENTS]
- copyVersions = params[FIELD_COPY_VERSIONS]
- copyIssues = params[FIELD_COPY_ISSUES]
-
- Project newprojectObj = doCopyProject (sourceProjectKey, targetProjectKey, targetProjectName, copyComponents ? true : false, copyVersions ? true : false)
- [output:"Project copied to <a href=\"../project/ViewProject.jspa?pid=${newprojectObj.getId()}\">${newprojectObj.key}</b>"]
- }
-
- String getDescription(Map params, boolean forPreview) {
- "If validation passed press the Run button already"
- }
-
- public Project doCopyProject (String sourceProjectKey, String targetProjectKey, String targetProjectDesc, boolean copyComponents, boolean copyVersions) {
- log.debug ("CopyProject: $sourceProjectKey, $targetProjectKey, $targetProjectDesc, $copyComponents, $copyVersions ")
-
- Project srcProject = projectManager.getProjectObjByKey(sourceProjectKey)
-
- GenericValue srcProjectGV = srcProject.getGenericValue()
-
- final ProjectService projectService = ComponentManager.getComponentInstanceOfType(ProjectService.class);
-
- // can't create a project with a non-system avatar, imho there is a bug in validateCreateProject
- final AvatarManager avatarManager = ComponentManager.getInstance().getAvatarManager()
- Avatar srcProjectAvatar = srcProject.getAvatar()
-
- // use ID for system avatar if it is one, otherwise need to create a new db record for it
- // todo: this doesn't work because the source avatar already has an ID
- // Long newProjectAvatarId = srcProjectAvatar.isSystemAvatar() ? srcProjectAvatar.getId() : avatarManager.create(srcProjectAvatar).getId()
-
- final ProjectService.CreateProjectValidationResult result =
- projectService.validateCreateProject(getRemoteUser(), targetProjectName, targetProjectKey, srcProject.getDescription(), srcProject.getLeadUserName(),
- srcProject.url, srcProject.getAssigneeType(),
- srcProjectAvatar.isSystemAvatar() ? srcProjectAvatar.getId() : avatarManager.getDefaultAvatarId(Avatar.Type.PROJECT));
-
- final Project newprojectObj = projectService.createProject(result);
-
- final ProjectService.UpdateProjectSchemesValidationResult schemesResult =
- projectService.validateUpdateProjectSchemes(
- getRemoteUser(),
- permissionSchemeManager.getSchemes(srcProjectGV).size() == 0 ? null : permissionSchemeManager.getSchemes(srcProjectGV)[0].get("id"),
- notificationSchemeManager.getNotificationSchemeForProject(srcProjectGV) ? notificationSchemeManager.getNotificationSchemeForProject(srcProjectGV).getLong("id") : null,
- issueSecuritySchemeManager.getSchemes(srcProjectGV).size() == 0 ? null : issueSecuritySchemeManager.getSchemes(srcProjectGV)[0].get("id"));
-
- projectService.updateProjectSchemes(schemesResult, newprojectObj);
-
- GenericValue newprojectGV = newprojectObj.getGenericValue()
-
- // SET VERSIONS (OPTIONAL)
- if (copyVersions) {
- srcProject.getVersions().each {
- Version version = it
- log.debug (version.getClass())
- log.debug (version.getName())
- if (!version.isArchived()) {
- versionManager.createVersion(
- version.getName(),
- version.getReleaseDate(),
- version.getDescription(),
- newprojectObj.getId(),
- null
- )
- }
- }
- }
- // END SET VERSIONS
-
- // SET COMPONENTS (OPTIONAL)
- if (copyComponents) {
- projectComponentManager.findAllForProject(srcProject.getId()).each {ProjectComponent component ->
- log.debug (component.getClass())
- log.debug (component.dump())
-
- projectComponentManager.create(
- component.name,
- component.description,
- component.lead,
- component.assigneeType,
- newprojectObj.getId()
- )
- }
- }
- // END COMPONENTS (OPTIONAL)
-
- // SET MAIL CONFIG
- PropertySet ps = OFBizPropertyUtils.getPropertySet(srcProjectGV)
- PropertySet newps = OFBizPropertyUtils.getPropertySet(newprojectGV)
- newps.setString (EMAIL_SENDER, ps.getString(EMAIL_SENDER))
- // END SET MAIL CONFIG
-
- JiraContextTreeManager jiraContextTreeManager = new JiraContextTreeManager(projectManager, ComponentManager.getInstance().getConstantsManager())
-
- // SET ISSUE TYPE SCHEME
- FieldConfigScheme issueTypeScheme = itsm.getConfigScheme(srcProjectGV)
- if (issueTypeScheme != itsm.getDefaultIssueTypeScheme()) {
- List projectList = issueTypeScheme.getAssociatedProjects()
- projectList.add(newprojectGV)
- Long[] projectIds = GenericValueUtils.transformToLongIds (projectList)
- log.debug ("projectIds: $projectIds")
-
- // Set the contexts
- List contexts = CustomFieldUtils.buildJiraIssueContexts(false,
- null,
- projectIds,
- jiraContextTreeManager);
-
- fieldConfigSchemeManager.updateFieldConfigScheme(issueTypeScheme, contexts, fieldManager.getConfigurableField(IssueFieldConstants.ISSUE_TYPE));
- }
- // END ISSUE TYPE SCHEME
-
- // SET WORKFLOW SCHEME
- if (workflowSchemeManager.getSchemes(srcProjectGV)[0] != workflowSchemeManager.getDefaultScheme()) {
- workflowSchemeManager.addSchemeToProject (newprojectObj, (Scheme) workflowSchemeManager.getScheme(workflowSchemeManager.getSchemes(srcProjectGV)[0].get("id")))
- }
- // END SET WORKFLOW SCHEME
-
- // SET FIELD CONFIG (FIELD LAYOUT) SCHEME
- FieldConfigurationScheme srcProjectFieldLayout = fieldLayoutManager.getFieldConfigurationScheme(srcProjectGV)
- if (srcProjectFieldLayout) {
- fieldLayoutManager.addSchemeAssociation(newprojectGV, srcProjectFieldLayout.getId())
- }
- // END SET FIELD CONFIG (FIELD LAYOUT) SCHEME
-
- // SET ISSUE TYPE SCREEN SCHEME
- issueTypeScreenSchemeManager.addSchemeAssociation (newprojectGV, issueTypeScreenSchemeManager.getIssueTypeScreenScheme(srcProjectGV))
- // END ISSUE TYPE SCREEN SCHEME
-
- // CVS MODULES: DON'T USE IT SO DON'T CARE
-
- // Set PROJECT CATEGORY
- projectManager.setProjectCategory (newprojectGV, projectManager.getProjectCategoryFromProject(srcProjectGV))
-
- // SET CUSTOM FIELDS
- customFieldManager.getCustomFieldObjects().each {CustomField cf ->
- fieldConfigSchemeManager.getConfigSchemesForField(cf).each {FieldConfigScheme fcs ->
- if (!fcs.isGlobal()) {
-
- fcs.getAssociatedProjects().each {GenericValue project ->
- if (project.getLong("id") == srcProject.getId()) {
- log.debug (fcs.name + " associated with " + project.name + ", need to modify this")
-
- Long fcsId = fcs.id
- FieldConfigScheme cfConfigScheme = fieldConfigSchemeManager.getFieldConfigScheme(fcsId)
- FieldConfigScheme.Builder cfSchemeBuilder = new FieldConfigScheme.Builder(cfConfigScheme)
- FieldConfig config = fieldConfigManager.getFieldConfig(fcsId)
-
- Map configs = new HashMap()
- fcs.getAssociatedIssueTypes().each {
- GenericValue issueType = (GenericValue) it;
- String issueTypeId = issueType == null ? null : issueType.getString(FieldConfigSchemePersisterImpl.ENTITY_ID);
- configs.put(issueTypeId, config);
- }
- cfSchemeBuilder.setConfigs(configs)
- cfConfigScheme = cfSchemeBuilder.toFieldConfigScheme()
-
- // log.debug ("cf.getAssociatedProjects().size: " + cf.getAssociatedProjects().size())
- List projectList = fcs.getAssociatedProjects()
- projectList.add(newprojectGV)
- Long[] projectIds = GenericValueUtils.transformToLongIds (projectList)
-
- List contexts = CustomFieldUtils.buildJiraIssueContexts(false,
- null,
- projectIds,
- jiraContextTreeManager);
-
- log.debug ("Modifying cfConfigScheme: ${cfConfigScheme.getName()}")
- fieldConfigSchemeManager.updateFieldConfigScheme(cfConfigScheme, contexts, customFieldManager.getCustomFieldObject(cf.getGenericValue().getLong("id")))
- }
- }
- }
- else {
- // log.debug ("$cf.name is a global field , do nothing")
- }
- }
- }
- customFieldManager.refresh()
- // END SET CUSTOM FIELDS
-
- // SET PROJECT ROLES
- ProjectRoleService projectRoleService = (ProjectRoleService) ComponentManager.getComponentInstanceOfType(ProjectRoleService.class);
-
- SimpleErrorCollection errorCollection = new SimpleErrorCollection();
-
- projectRoleService.getProjectRoles(remoteUser, errorCollection).each {ProjectRole projectRole ->
- // Collection newProjectRoleActors = new ArrayList()
- log.debug (projectRole.name + ": " + projectRole.getId())
- ProjectRoleActors projectRoleActors = projectRoleService.getProjectRoleActors(remoteUser, projectRole, srcProject, errorCollection)
-
- // Copy users and groups, separately
- [UserRoleActorFactory.TYPE, GroupRoleActorFactory.TYPE].each {String actorFactoryType ->
- Collection newProjectRoleActors = new ArrayList()
- projectRoleActors.getRoleActorsByType(actorFactoryType).each {
- newProjectRoleActors.add(it.parameter)
- }
- projectRoleService.addActorsToProjectRole (remoteUser, newProjectRoleActors, projectRole, newprojectObj, actorFactoryType, errorCollection)
- }
- }
-
- if (copyIssues && copyVersions && copyComponents) {
- def componentManager = ComponentManager.getInstance()
- def issueManager = componentManager.getIssueManager()
- JqlQueryBuilder builder = JqlQueryBuilder.newBuilder()
- def query = builder.where().project(srcProject.id).buildQuery()
- SearchRequest sr = new SearchRequest(query)
- SearchProvider searchProvider = componentManager.getSearchProvider()
- SearchResults results = searchProvider.search(sr.getQuery(), componentManager.getJiraAuthenticationContext().getUser(), PagerFilter.getUnlimitedFilter())
-
- results.issues.each {documentIssue ->
-
- log.debug("Copy issue: ${documentIssue.key}")
- def issue = issueManager.getIssueObject(documentIssue.id)
- if (issue) {
- // Use clone issue but with no link type
- Map<String, Object> inputs = [
- issue: issue,
- (CloneIssue.FIELD_TARGET_PROJECT): newprojectObj.key,
- (CloneIssue.FIELD_LINK_TYPE): null,
- ] as Map<String, Object>
- log.debug ("inputs: $inputs")
-
- new CloneIssue().doScript(inputs)
- }
- else {
- // in test the issue can sometimes be null for some reason...
- log.warn "Null issue found."
- }
- }
- }
-
- return newprojectObj
- }
-
- public User getRemoteUser() {
- return ComponentManager.getInstance().getJiraAuthenticationContext().getUser()
- }
-
- public Boolean isFinalParamsPage(Map params) {
- true
- }
-
- public String toString() {
- "Copy project 41"
- }
- }