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

Language Groovy Lines 457
MD5 Hash bbb54aa9320a34e28e0f50e5e101a135
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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
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"
    }
}
Back to Top