├── misc ├── deprecated │ ├── AT_updateIssueType_singleselect.groovy │ ├── addParticipantsOLD.groovy │ ├── addPrimaryUserAsParticipant.groovy │ ├── copy-comment-1.0.groovy │ ├── everyone-voted.groovy │ ├── is-at.groovy │ ├── is-web.groovy │ ├── mergeIssues.groovy │ ├── mergeIssuesOLD.groovy │ ├── other-deny-request.groovy │ ├── raiseOnBehalfOf.groovy │ ├── testScript.groovy │ ├── updateIssueType.groovy │ └── updateIssueType2.groovy └── not-code │ └── ITS_onboard_offboard_stringlists ├── readme.md ├── script-fields ├── fullNameOfPrimaryUser_prod.groovy ├── lastCommentTruncated_prod.groovy ├── numberOfPublicComments.groovy ├── totalCostFormatted_prod.groovy └── truncatedDescription_prod.groovy ├── script-listeners ├── AT_addJennAsWatcherOnMove_prod.groovy ├── AT_updateIssueTypeCascade_prod.groovy ├── FMO_commentAssignee_prod.groovy ├── FMO_syncReqTypeToIssueType_prod.groovy ├── ITCM_copyCommentToParent_prod.groovy ├── ITS_generateChecklist.groovy ├── addWatcherAfterNComments.groovy ├── commentAssigneeANDaddJWolfAsWatcher.groovy └── script-listener-conditions │ ├── FMO_transitionConditions_prod.groovy │ ├── ITS_automateStartProgConditions.groovy │ └── ITS_generateChecklistCondition_prod.groovy ├── script-postfunctions ├── AT_mergeIssueIntoExisting.groovy ├── AT_raiseOnBehalfOf.groovy ├── FES_raiseOnBehalfOf.groovy ├── ITCM_createSubtasks_prod.groovy ├── ITCM_deleteSubtasks_prod.groovy ├── ITCM_parentToDeniedStatus_prod.groovy └── addPrimaryUserAsParticipant.groovy └── script-snippets ├── getAllUsers.groovy ├── getLinkedIssues.groovy ├── jqlSearch.groovy ├── newMerge.groovy ├── specific-snippets ├── getAllUsersNotInGroup.groovy ├── updateBrands.groovy └── writeToExistingConfPage.py └── updateLabels.groovy /misc/deprecated/AT_updateIssueType_singleselect.groovy: -------------------------------------------------------------------------------- 1 | import com.atlassian.jira.component.ComponentAccessor 2 | import com.atlassian.jira.issue.CustomFieldManager 3 | import com.atlassian.jira.issue.MutableIssue 4 | import com.atlassian.jira.issue.IssueManager 5 | import com.atlassian.jira.user.ApplicationUser 6 | import com.atlassian.jira.event.type.EventDispatchOption 7 | 8 | /* Debugging */ 9 | import org.apache.log4j.Logger 10 | def log = Logger.getLogger("com.acme.XXX") 11 | 12 | /* Establish context -- current issue and current logged in user */ 13 | MutableIssue thisIssue = issue 14 | ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 15 | 16 | /* Get value of each AT Issue Type field. Only one will have a value. */ 17 | CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager() 18 | 19 | def analyticsField = customFieldManager.getCustomFieldObject("customfield_12101") 20 | def analyticsValue = thisIssue.getCustomFieldValue(analyticsField) as String 21 | 22 | def avSupportField = customFieldManager.getCustomFieldObject("customfield_12102") 23 | def avSupportValue = thisIssue.getCustomFieldValue(avSupportField) as String 24 | 25 | def courseWebsiteSupportField = customFieldManager.getCustomFieldObject("customfield_12103") 26 | def courseWebsiteSupportValue = thisIssue.getCustomFieldValue(courseWebsiteSupportField) as String 27 | 28 | def mediaProductionField = customFieldManager.getCustomFieldObject("customfield_12104") 29 | def mediaProductionValue = thisIssue.getCustomFieldValue(mediaProductionField) as String 30 | 31 | def trainingField = customFieldManager.getCustomFieldObject("customfield_12105") 32 | def trainingValue = thisIssue.getCustomFieldValue(trainingField) as String 33 | 34 | def initIssueTypeName = thisIssue.getIssueType().getName() as String 35 | def desiredIssueTypeName = '' 36 | 37 | /* Determine which field has a value and get the value (desired Issue Type) */ 38 | if (analyticsValue) { 39 | desiredIssueTypeName = analyticsValue 40 | thisIssue.setCustomFieldValue(analyticsField, null) 41 | } else if (avSupportValue) { 42 | desiredIssueTypeName = avSupportValue 43 | thisIssue.setCustomFieldValue(avSupportField, null) 44 | } else if (courseWebsiteSupportValue) { 45 | desiredIssueTypeName = courseWebsiteSupportValue 46 | thisIssue.setCustomFieldValue(courseWebsiteSupportField, null) 47 | } else if (mediaProductionValue) { 48 | desiredIssueTypeName = mediaProductionValue 49 | thisIssue.setCustomFieldValue(mediaProductionField, null) 50 | } else if (trainingValue) { 51 | desiredIssueTypeName = trainingValue 52 | thisIssue.setCustomFieldValue(trainingField, null) 53 | } else { 54 | log.debug "No match found." 55 | } 56 | 57 | /* Get the actual Issue Type object whose name is equal to the value in the AT Issue Type field */ 58 | def desiredIssueType = ComponentAccessor.issueTypeSchemeManager.getIssueTypesForProject(thisIssue.getProjectObject()).find { 59 | it.getName() as String == desiredIssueTypeName 60 | } 61 | 62 | if (desiredIssueType) { 63 | if (initIssueTypeName != desiredIssueTypeName) { 64 | thisIssue.setIssueType(desiredIssueType) 65 | storeChanges(thisIssue, loggedInUser) 66 | return "Successfully updated issue type to " + desiredIssueTypeName 67 | } else { 68 | return "Issue type is already set correctly." 69 | } 70 | } else { 71 | return "Error determining a new issue type." 72 | } 73 | 74 | def storeChanges(MutableIssue issue, ApplicationUser user) { 75 | try { 76 | ComponentAccessor.getIssueManager().updateIssue( 77 | user, 78 | issue, 79 | EventDispatchOption.ISSUE_UPDATED, 80 | false 81 | ) 82 | } catch (Exception e) { 83 | log.debug "Exception: " + e 84 | } 85 | } -------------------------------------------------------------------------------- /misc/deprecated/addParticipantsOLD.groovy: -------------------------------------------------------------------------------- 1 | import com.atlassian.jira.component.ComponentAccessor 2 | import com.atlassian.jira.user.ApplicationUser 3 | import java.util.ArrayList 4 | import com.atlassian.jira.issue.ModifiedValue 5 | import com.atlassian.jira.issue.util.DefaultIssueChangeHolder 6 | import com.atlassian.jira.issue.MutableIssue 7 | import com.atlassian.jira.issue.IssueManager 8 | import com.atlassian.jira.issue.index.IssueIndexManager 9 | import org.apache.log4j.Logger 10 | import org.apache.log4j.Level 11 | def log = Logger.getLogger("com.acme.XXX") 12 | log.setLevel(Level.DEBUG) 13 | 14 | def PRIMARY_USER_FIELD = "customfield_10913" 15 | def REQUEST_PARTICIPANTS_FIELD = "customfield_10600" 16 | 17 | def customFieldManager = ComponentAccessor.getCustomFieldManager() 18 | def userManager = ComponentAccessor.getUserUtil() 19 | def issueManager = ComponentAccessor.getIssueManager()) 20 | 21 | MutableIssue issue = issueManager.getIssueObject() 22 | 23 | def primaryUserField = customFieldManager.getCustomFieldObject(PRIMARY_USER_FIELD) 24 | def requestParticipantsField = customFieldManager.getCustomFieldObject(REQUEST_PARTICIPANTS_FIELD) 25 | 26 | def primaryUserName = issue.getCustomFieldValue(primaryUserField) as String 27 | ApplicationUser user = userManager.getUserByName(primaryUser) 28 | 29 | thisIssue.setCustomFieldValue(requestParticipantsField, user) 30 | 31 | issue.getCustomFieldValue(componentManager.getCustomFieldManager().getCustomFieldObject("customfield_190"))?.displayName 32 | 33 | import com.atlassian.jira.component.ComponentAccessor 34 | import com.atlassian.jira.user.ApplicationUser 35 | import java.util.ArrayList 36 | import com.atlassian.jira.issue.ModifiedValue 37 | import com.atlassian.jira.issue.util.DefaultIssueChangeHolder 38 | import com.atlassian.jira.issue.MutableIssue 39 | import com.atlassian.jira.issue.IssueManager 40 | import com.atlassian.jira.issue.index.IssueIndexManager 41 | import org.apache.log4j.Logger 42 | import org.apache.log4j.Level 43 | def log = Logger.getLogger("com.acme.XXX") 44 | log.setLevel(Level.DEBUG) 45 | 46 | def PRIMARY_USER_FIELD = "customfield_10913" 47 | def REQUEST_PARTICIPANTS_FIELD = "customfield_10600" 48 | 49 | def customFieldManager = ComponentAccessor.getCustomFieldManager() 50 | def userManager = ComponentAccessor.getUserUtil() 51 | def issueManager = ComponentAccessor.getIssueManager() 52 | 53 | MutableIssue issue = issueManager.getIssueObject("ATW-31") 54 | 55 | def requestParticipantsField = customFieldManager.getCustomFieldObject(REQUEST_PARTICIPANTS_FIELD) 56 | 57 | 58 | def primaryUserField = customFieldManager.getCustomFieldObject(PRIMARY_USER_FIELD) 59 | def primaryUserName = issue.getCustomFieldValue(primaryUserField) 60 | 61 | ApplicationUser newReporter = userManager.getUserByName("ewinter_wsb") 62 | 63 | log.debug "PRIMARY USER FIELD: " + primaryUserField 64 | log.debug "PRIMARY USER NAME: " + primaryUserName 65 | 66 | ApplicationUser oldReporter = issue.getReporter() 67 | 68 | if (newReporter) { 69 | try { 70 | // issue.setCustomFieldValue(requestParticipantsField, reporter) 71 | log.debug newReporter.getName() 72 | issue.setReporter(newReporter) 73 | } catch (Exception e) { 74 | log.debug "Error" 75 | log.debug e as String 76 | } 77 | } else { log.debug "newReporter is null." } 78 | -------------------------------------------------------------------------------- /misc/deprecated/addPrimaryUserAsParticipant.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name addPrimaryUserAsParticipant.groovy 3 | * @type Script Post Function 4 | * @brief Adds the user in custom field "Primary User" to the field "Request Participants" 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | import com.atlassian.jira.event.type.EventDispatchOption 9 | import com.atlassian.jira.issue.CustomFieldManager 10 | import com.atlassian.jira.issue.MutableIssue 11 | import com.atlassian.jira.issue.IssueManager 12 | import java.util.ArrayList 13 | import com.atlassian.jira.user.ApplicationUser 14 | import org.apache.log4j.Logger 15 | 16 | def log = Logger.getLogger("com.acme.XXX") 17 | 18 | def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 19 | def REQUEST_PARTICIPANTS_FIELD = "customfield_10600" 20 | def PRIMARY_USER_FIELD = "customfield_10913" 21 | 22 | CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager() 23 | IssueManager issueManager = ComponentAccessor.getIssueManager() 24 | MutableIssue issue = issue // FOR TESTING IN CONSOLE replace `issue` with `issueManager.getIssueObject("{issuekey}")` 25 | 26 | /* Get field objects */ 27 | def requestParticipantsField = customFieldManager.getCustomFieldObject(REQUEST_PARTICIPANTS_FIELD) 28 | def primaryUserField = customFieldManager.getCustomFieldObject(PRIMARY_USER_FIELD) 29 | 30 | /* Get Primary User */ 31 | ApplicationUser primaryUser = issue.getCustomFieldValue(primaryUserField) as ApplicationUser 32 | 33 | if (primaryUser) { 34 | 35 | /* Create an empty arraylist and add Primary User */ 36 | ArrayList participants = [] 37 | participants.add(primaryUser) 38 | 39 | /* Assign the arraylist to the Request Participants field */ 40 | issue.setCustomFieldValue(requestParticipantsField, participants) 41 | 42 | /* Store to database. */ 43 | try { 44 | issueManager.updateIssue( 45 | currentUser, 46 | issue, 47 | EventDispatchOption.ISSUE_UPDATED, 48 | false 49 | ) 50 | } catch (Exception e) { 51 | log.debug "Exception: " + e 52 | } 53 | 54 | } else { 55 | log.debug "No Primary User specified." 56 | } -------------------------------------------------------------------------------- /misc/deprecated/copy-comment-1.0.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | This is a Post Function script that gets the current issue's most recent comment 3 | and copies it to its parent issue. If a user provides a comment during the transition 4 | in which this Post Function is embedded, that's the comment it will use. 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | import com.atlassian.jira.issue.Issue 9 | import com.atlassian.jira.issue.comments.CommentManager 10 | 11 | Issue parent = issue.getParentObject() 12 | def commentManager = ComponentAccessor.getCommentManager() 13 | 14 | def comment = commentManager.getLastComment(issue) 15 | 16 | if (comment) { 17 | commentManager.create(parent, comment.getAuthorApplicationUser(), comment.getBody(), true) 18 | } -------------------------------------------------------------------------------- /misc/deprecated/everyone-voted.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | This is a Script Condition that checks to see if everyone in a specified group has voted for an issue. It compares the number of users in the group specified by the Group Picker custom field "Needs approval from" to the number of votes for the current issue. 3 | 4 | Evaluates to TRUE if number of votes is greater than or equal to the number of users in the group. 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | 9 | def groupManager = ComponentAccessor.getGroupManager() 10 | def voteManager = ComponentAccessor.getVoteManager() 11 | def customFieldManager = ComponentAccessor.getCustomFieldManager() 12 | 13 | // get the group specified by the 'Needs approval from' group picker 14 | def cf = customFieldManager.getCustomFieldObjectByName('Needs approval from') 15 | def group = cf.getValue(issue) 16 | 17 | // get number of votes for the current issue, and get number of users in group 18 | int voteCount = voteManager.getVoteCount(issue) 19 | int numOfApprovers = groupManager.getUsersInGroupCount(group) 20 | 21 | // if every user in "Needs approval from" 22 | voteCount >= numOfApprovers -------------------------------------------------------------------------------- /misc/deprecated/is-at.groovy: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // File Name: is-at.groovy 3 | // 4 | // Author: Evan Winter 5 | // 6 | // Context: ATW 7 | // 8 | // Description: Condition that's true IFF issue of Issue Type "Academic Technology". 9 | // 10 | //////////////////////////////////////////////////////////////////////////////// 11 | 12 | issue.issueType.name == 'Academic Technology' -------------------------------------------------------------------------------- /misc/deprecated/is-web.groovy: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // File Name: is-web.groovy 3 | // 4 | // Author: Evan Winter 5 | // 6 | // Context: ATW 7 | // 8 | // Description: Condition that's true IFF issue of Issue Type "Web". 9 | // 10 | //////////////////////////////////////////////////////////////////////////////// 11 | 12 | issue.issueType.name == 'Web' -------------------------------------------------------------------------------- /misc/deprecated/mergeIssues.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: mergeIssues.groovy 3 | * Author: Evan Winter 4 | * 5 | * @brief Grabs description and comments from specified issue(s) and adds them to the 6 | * current issue. 7 | * 8 | */ 9 | 10 | import com.atlassian.jira.component.ComponentAccessor 11 | import com.atlassian.jira.issue.CustomFieldManager 12 | import com.atlassian.jira.issue.IssueManager 13 | import com.atlassian.jira.issue.Issue 14 | import java.util.ArrayList 15 | import com.atlassian.jira.issue.MutableIssue 16 | import com.atlassian.jira.user.ApplicationUser 17 | import com.atlassian.jira.issue.link.IssueLinkManager 18 | import com.atlassian.jira.event.type.EventDispatchOption 19 | import com.atlassian.jira.issue.comments.CommentManager 20 | import java.text.SimpleDateFormat 21 | 22 | /* Debugging */ 23 | import org.apache.log4j.Logger 24 | def log = Logger.getLogger("com.acme.XXX") 25 | 26 | /* Initialize variables */ 27 | MutableIssue thisIssue = issue 28 | ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 29 | 30 | def description = thisIssue.getDescription() 31 | def requestParticipantsField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("customfield_10600") 32 | def requestParticipants = thisIssue.getCustomFieldValue(requestParticipantsField) as ArrayList 33 | def linkedIssues = ComponentAccessor.getIssueLinkManager().getOutwardLinks(thisIssue.getId()) 34 | 35 | def date = new Date() 36 | def sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss") 37 | def formattedDate = sdf.format(date) 38 | 39 | if (linkedIssues) { 40 | description += ( 41 | '\n\n-------------------\n' + 42 | '*MERGE - ' + formattedDate + '*\n\n' 43 | ) 44 | for (linkedIssue in linkedIssues) { 45 | def iss = linkedIssue.getDestinationObject() 46 | description += ( 47 | iss.getKey() + ' - ' + iss.getSummary() + '\n' + 48 | iss.getDescription() + '\n\n' 49 | ) 50 | def commentsList = ComponentAccessor.getCommentManager().getComments(iss) 51 | if (commentsList.size() > 0) { 52 | String comments = '*MERGE* ' + formattedDate + ' - ' + iss.getKey() 53 | for (comment in commentsList) { 54 | comments += ('\n\n*' + comment.getAuthorFullName() + '*: ' + comment.getBody() + '\n_' + comment.getCreated() + '_') 55 | } 56 | ComponentAccessor.getCommentManager().create(thisIssue, loggedInUser, comments, false) 57 | } 58 | ApplicationUser reporter = iss.getReporter() 59 | if (reporter) { 60 | if (reporter != thisIssue.getReporter()) { 61 | requestParticipants.add(reporter) 62 | } 63 | } else { 64 | log.debug "That issue doesn't have a valid reporter!\n" 65 | } 66 | } 67 | thisIssue.setDescription(description) 68 | thisIssue.setCustomFieldValue(requestParticipantsField, requestParticipants) 69 | } else { 70 | log.debug "No linked issues." 71 | } 72 | 73 | try { 74 | ComponentAccessor.getIssueManager().updateIssue(loggedInUser, thisIssue, EventDispatchOption.ISSUE_UPDATED, false) 75 | } catch (Exception e) { 76 | log.debug "Exception: " + e 77 | return 'An error occured. Please contact your JIRA administrator.' 78 | } 79 | 80 | -------------------------------------------------------------------------------- /misc/deprecated/mergeIssuesOLD.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: mergeIssues.groovy 3 | * Author: Evan Winter 4 | * 5 | * @brief Grabs description and comments from specified issue(s) and adds them to the 6 | * current issue. 7 | * 8 | */ 9 | 10 | import com.atlassian.jira.component.ComponentAccessor 11 | import com.atlassian.jira.issue.CustomFieldManager 12 | import com.atlassian.jira.issue.IssueManager 13 | import com.atlassian.jira.issue.Issue 14 | import com.atlassian.jira.issue.MutableIssue 15 | import com.atlassian.jira.user.ApplicationUser 16 | import com.atlassian.jira.issue.link.IssueLinkManager 17 | import com.atlassian.jira.event.type.EventDispatchOption 18 | import com.atlassian.jira.issue.comments.CommentManager 19 | 20 | /* Debugging */ 21 | import org.apache.log4j.Logger 22 | def log = Logger.getLogger("com.acme.XXX") 23 | 24 | /* Set up Managers */ 25 | CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager() 26 | CommentManager commentManager = ComponentAccessor.getCommentManager() 27 | IssueManager issueManager = ComponentAccessor.getIssueManager() 28 | IssueLinkManager issueLinkManager = ComponentAccessor.getIssueLinkManager() 29 | 30 | /* Initialize variables */ 31 | MutableIssue thisIssue = issue 32 | ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 33 | 34 | mergeIssues(issueLinkManager, commentManager, thisIssue, loggedInUser) 35 | storeChanges(issueManager, loggedInUser, thisIssue) 36 | 37 | def mergeIssues(IssueLinkManager issueLinkManager, CommentManager commentManager, MutableIssue thisIssue, ApplicationUser loggedInUser) { 38 | def linkedIssues = issueLinkManager.getOutwardLinks(thisIssue.getId()) 39 | def initialDescription = thisIssue.getDescription() 40 | def mergedDescriptions = '' 41 | if (linkedIssues) { 42 | /* For each valid issue in "Issues to merge" field */ 43 | for (linkedIssue in linkedIssues) { 44 | def iss = linkedIssue.getDestinationObject() 45 | /* Append this issue description to main issue description */ 46 | def mergedDescriptions = getMergedDescriptions(iss, initialDescription) 47 | /* Get all comments from this issue and add as single comment on main issue */ 48 | mergeComments(thisIssue, iss, commentManager, loggedInUser) 49 | /* Add this issue's reporter to main issue's Request Participants */ 50 | addToParticipants(thisIssue) 51 | } 52 | /* Actually update the main issue's description to the newly merged description */ 53 | thisIssue.setDescription(mergedDescriptions) 54 | } else { 55 | log.debug "No linked issues." 56 | } 57 | } 58 | 59 | String getMergedDescriptions(Issue iss, String desc) { 60 | desc += ('\n\n-------------------\n' + 61 | '*FROM MERGE:* ' + iss.getKey() + ' - ' + iss.getSummary() + '\n' + 62 | iss.getDescription() + '\n') 63 | return desc 64 | } 65 | 66 | def mergeComments(MutableIssue thisIssue, Issue iss, CommentManager commentManager, ApplicationUser loggedInUser) { 67 | def commentsList = commentManager.getComments(iss) 68 | if (commentsList.size() > 0) { 69 | String comments = '*FROM MERGE:* ' + iss.getKey() + ' comments' 70 | for (comment in commentsList) { 71 | comments += ('\n\n*' + comment.getAuthorFullName() + ' (' + comment.getCreated() + ')*: ' + comment.getBody()) 72 | } 73 | commentManager.create(thisIssue, loggedInUser, comments, false) 74 | } 75 | } 76 | 77 | def addToParticipants(MutableIssue thisIssue) { 78 | def REQUEST_PARTICIPANTS_FIELD = "customfield_10600" 79 | } 80 | 81 | def storeChanges(IssueManager issueManager, ApplicationUser loggedInUser, MutableIssue thisIssue) { 82 | try { 83 | issueManager.updateIssue( 84 | loggedInUser, 85 | thisIssue, 86 | EventDispatchOption.ISSUE_UPDATED, 87 | false 88 | ) 89 | } catch (Exception e) { 90 | log.debug "Exception: " + e 91 | } 92 | } -------------------------------------------------------------------------------- /misc/deprecated/other-deny-request.groovy: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Name: deny-request.groovy 4 | // 5 | // Location: Workflows > ITCM Approver Feedback Workflow > Transition: Denied 6 | // > Add Post Function > Script Post-Function > Custom script post-function 7 | // 8 | // Description: If any of an issue's sub-tasks are denied, execute the parent's "Deny" transition too. 9 | // 10 | //////////////////////////////////////////////////////////////////////////////// 11 | 12 | import com.opensymphony.workflow.WorkflowContext 13 | import com.atlassian.jira.config.SubTaskManager 14 | import com.atlassian.jira.workflow.WorkflowTransitionUtil 15 | import com.atlassian.jira.workflow.WorkflowTransitionUtilImpl 16 | import com.atlassian.jira.util.JiraUtils 17 | import com.atlassian.jira.issue.MutableIssue 18 | import com.atlassian.jira.component.ComponentAccessor 19 | import org.apache.log4j.Logger 20 | import org.apache.log4j.Level 21 | 22 | def log = Logger.getLogger("com.acme.XXX") 23 | log.setLevel(Level.DEBUG) 24 | 25 | String currentUser = ((WorkflowContext) transientVars.get("context")).getCaller() 26 | WorkflowTransitionUtil workflowTransitionUtil = (WorkflowTransitionUtil) JiraUtils.loadComponent(WorkflowTransitionUtilImpl.class) 27 | MutableIssue parent = issue.getParentObject() as MutableIssue 28 | 29 | String originalParentStatus = parent.getStatus().getSimpleStatus().getName() 30 | def isAwaitingApproval = originalParentStatus in ['Awaiting approval'] 31 | 32 | // for current ITCM workflow 33 | int approveID = 21 34 | 35 | if (isAwaitingApproval) { 36 | workflowTransitionUtil.setIssue(parent) 37 | workflowTransitionUtil.setUserkey(currentUser) 38 | workflowTransitionUtil.setAction(approveID) 39 | if (workflowTransitionUtil.validate()) { 40 | workflowTransitionUtil.progress() 41 | } 42 | } -------------------------------------------------------------------------------- /misc/deprecated/raiseOnBehalfOf.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: raiseOnBehalfOf.groovy 3 | * Author: Evan Winter 4 | * 5 | * @brief Post function to add initial Reporter as Participant and set user in custom field "Primary User" to Reporter 6 | * 7 | */ 8 | 9 | import com.atlassian.jira.component.ComponentAccessor 10 | import com.atlassian.jira.event.type.EventDispatchOption 11 | import com.atlassian.jira.issue.CustomFieldManager 12 | import com.atlassian.jira.issue.MutableIssue 13 | import com.atlassian.jira.issue.IssueManager 14 | import java.util.ArrayList 15 | import com.atlassian.jira.user.ApplicationUser 16 | import org.apache.log4j.Logger 17 | def log = Logger.getLogger("com.acme.XXX") 18 | 19 | def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 20 | def REQUEST_PARTICIPANTS_FIELD = "customfield_10600" 21 | def PRIMARY_USER_FIELD = "customfield_10913" 22 | 23 | CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager() 24 | IssueManager issueManager = ComponentAccessor.getIssueManager() 25 | 26 | MutableIssue myIssue = issue // FOR TESTING IN CONSOLE -> .getIssueObject("KEY-000") 27 | 28 | // Get custom field objects. 29 | def requestParticipantsField = customFieldManager.getCustomFieldObject(REQUEST_PARTICIPANTS_FIELD) 30 | def primaryUserField = customFieldManager.getCustomFieldObject(PRIMARY_USER_FIELD) 31 | 32 | // Get initial Reporter. 33 | ApplicationUser reporter = myIssue.getReporter() 34 | 35 | // Add initial Reporter to array. 36 | ArrayList participants = [] 37 | participants.add(reporter) 38 | 39 | // Get initial Primary User. 40 | ApplicationUser primaryUser = myIssue.getCustomFieldValue(primaryUserField) as ApplicationUser 41 | 42 | if (primaryUser) { 43 | 44 | // Add initial Reporter to Request Participants field. 45 | myIssue.setCustomFieldValue( 46 | requestParticipantsField, 47 | participants 48 | ) 49 | 50 | // Set initial Primary User to Reporter field. 51 | myIssue.setReporter(primaryUser) 52 | 53 | // Clear the Primary User field. 54 | myIssue.setCustomFieldValue( 55 | primaryUserField, 56 | null 57 | ) 58 | 59 | // Store to database. 60 | try { 61 | issueManager.updateIssue( 62 | currentUser, 63 | myIssue, 64 | EventDispatchOption.ISSUE_UPDATED, 65 | false 66 | ) 67 | } catch (Exception e) { 68 | log.debug "Exception: " + e 69 | } 70 | } else { 71 | log.debug "No Primary User specified." 72 | } -------------------------------------------------------------------------------- /misc/deprecated/testScript.groovy: -------------------------------------------------------------------------------- 1 | import com.atlassian.jira.component.ComponentAccessor 2 | import com.atlassian.jira.issue.CustomFieldManager 3 | import com.atlassian.jira.issue.IssueManager 4 | import com.atlassian.jira.issue.Issue 5 | import java.util.ArrayList 6 | import com.atlassian.jira.issue.MutableIssue 7 | import com.atlassian.jira.user.ApplicationUser 8 | import com.atlassian.jira.issue.link.IssueLinkManager 9 | import com.atlassian.jira.event.type.EventDispatchOption 10 | import com.atlassian.jira.issue.comments.CommentManager 11 | import java.text.SimpleDateFormat 12 | 13 | /* Debugging */ 14 | import org.apache.log4j.Logger 15 | def log = Logger.getLogger("com.acme.XXX") 16 | 17 | /* Initialize variables */ 18 | MutableIssue thisIssue = issue 19 | ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 20 | 21 | def description = thisIssue.getDescription() 22 | 23 | description = "Changing the description via code" 24 | 25 | thisIssue.setDescription(description) 26 | 27 | try { 28 | ComponentAccessor.getIssueManager().updateIssue(loggedInUser, thisIssue, EventDispatchOption.ISSUE_UPDATED, false) 29 | } catch (Exception e) { 30 | log.debug "Exception: " + e 31 | return 'An error occured. Please contact your JIRA administrator.' 32 | } -------------------------------------------------------------------------------- /misc/deprecated/updateIssueType.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: updateIssueTypeAT.groovy 3 | * Author: Evan Winter 4 | * 5 | * @brief Sets issue type during issue creation, based on customer input. 6 | * 7 | */ 8 | 9 | import com.atlassian.jira.component.ComponentAccessor 10 | import com.atlassian.jira.issue.CustomFieldManager 11 | import com.atlassian.jira.issue.MutableIssue 12 | import com.atlassian.jira.issue.IssueManager 13 | import com.atlassian.jira.user.ApplicationUser 14 | import com.atlassian.jira.event.type.EventDispatchOption 15 | 16 | /* Debugging */ 17 | import org.apache.log4j.Logger 18 | def log = Logger.getLogger("com.acme.XXX") 19 | 20 | /* Set up Managers */ 21 | CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager() 22 | IssueManager issueManager = ComponentAccessor.getIssueManager() 23 | 24 | //MutableIssue thisIssue = issue 25 | MutableIssue thisIssue = issueManager.getIssueObject("AT-12") 26 | ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 27 | 28 | /* Determine Customer Request Type */ 29 | def customerRequestTypeField = customFieldManager.getCustomFieldObjectByName("Customer Request Type") 30 | log.debug "Customer Request Type Field: " + customerRequestTypeField 31 | def customerRequestTypeKey = thisIssue.getCustomFieldValue(customerRequestTypeField) 32 | log.debug "Customer Request Type Key: " + customerRequestTypeKey 33 | def customerRequestType = getCustomerRequestTypeFromKey(customerRequestTypeKey) 34 | log.debug "Customer Request Type: " + customerRequestType 35 | 36 | /* Determine if current issue type matchings desired issue type */ 37 | def currentIssueTypeName = thisIssue.getIssueType().getName() as String 38 | log.debug "Current Issue Type: " + currentIssueTypeName 39 | def desiredIssueTypeFieldName = getIssueTypeFieldIDFromRequestType(customerRequestType) as String 40 | log.debug "Desired Issue Type Field Name: " + desiredIssueTypeFieldName 41 | def desiredIssueTypeField = customFieldManager.getCustomFieldObject(desiredIssueTypeFieldName) 42 | log.debug "Desired Issue Type Field: " + desiredIssueTypeField 43 | def desiredIssueTypeName = thisIssue.getCustomFieldValue(desiredIssueTypeField) as String // Got a NullPointer here. Maybe the RT IDs are different? 44 | log.debug "Desired Issue Type: " + desiredIssueTypeName 45 | def desiredIssueType = ComponentAccessor.issueTypeSchemeManager.getIssueTypesForProject(thisIssue.getProjectObject()).find { 46 | it.getName() == desiredIssueTypeName 47 | } 48 | 49 | if (currentIssueTypeName != desiredIssueTypeName) { 50 | if (desiredIssueType) { 51 | log.debug "Setting issue type to " + desiredIssueTypeName + "..." 52 | thisIssue.setIssueType(desiredIssueType) 53 | storeChanges(issueManager, loggedInUser, thisIssue) 54 | } else { 55 | log.debug "Couldn't find matching issue type. Please ensure that the value selected in the [AT] Issue Type dropdown is identical to an issue type in this project." 56 | } 57 | } else { 58 | log.debug "Issue type is already correct." 59 | } 60 | 61 | /* Methods */ 62 | def getCustomerRequestTypeFromKey(key) { 63 | // TODO: Use map instead. {FIELD: id} 64 | def ANALYTICS_REQUESTTYPE_FIELD = "at/2cdf64db-3f5c-402a-91ae-28cf3b0d0a86" 65 | def AVSUPPORT_REQUESTTYPE_FIELD = " at/ee716c88-d729-466f-a50f-035aba1b33dd" 66 | def COURSEWEBSITESUPPORT_REQUESTTYPE_FIELD = "at/d0c946ed-f60c-467b-9e22-dd3330a731c2" 67 | def MEDIAPRODUCTION_REQUESTTYPE_FIELD = "at/fdb2594b-e9a6-407b-bda0-277df2b7084f" 68 | def TRAINING_REQUESTTYPE_FIELD = "at/35e2ee3f-90eb-4617-be7b-226b7ec82738" 69 | def result 70 | log.debug key 71 | switch (key) { 72 | case ANALYTICS_REQUESTTYPE_FIELD as String: 73 | result = "Analytics" 74 | break 75 | case AVSUPPORT_REQUESTTYPE_FIELD as String: 76 | result = "AV Support" 77 | break 78 | case COURSEWEBSITESUPPORT_REQUESTTYPE_FIELD as String: 79 | result = "Course Website Support" 80 | break 81 | case MEDIAPRODUCTION_REQUESTTYPE_FIELD as String: 82 | result = "Media Production" 83 | break 84 | case TRAINING_REQUESTTYPE_FIELD as String: 85 | result = "Training" 86 | break 87 | default: 88 | log.debug "Request Type not found." 89 | break 90 | } 91 | log.debug "Request Type: " + result 92 | return result 93 | } 94 | 95 | def getIssueTypeFieldIDFromRequestType(requestType) { 96 | def ANALYTICS_ISSUETYPE_FIELD = "customfield_12101" 97 | def AVSUPPORT_ISSUETYPE_FIELD = "customfield_12102" 98 | def COURSEWEBSITESUPPORT_ISSUETYPE_FIELD = "customfield_12103" 99 | def MEDIAPRODUCTION_ISSUETYPE_FIELD = "customfield_12104" 100 | def TRAINING_ISSUETYPE_FIELD = "customfield_12105" 101 | def result 102 | log.debug requestType 103 | switch (requestType) { 104 | case "Analytics": 105 | result = ANALYTICS_ISSUETYPE_FIELD 106 | break 107 | case "AV Support": 108 | result = AVSUPPORT_ISSUETYPE_FIELD 109 | break 110 | case "Course Website Support": 111 | result = COURSEWEBSITESUPPORT_ISSUETYPE_FIELD 112 | break 113 | case "Media Production": 114 | result = MEDIAPRODUCTION_ISSUETYPE_FIELD 115 | break 116 | case "Training": 117 | result = TRAINING_ISSUETYPE_FIELD 118 | break 119 | } 120 | log.debug "Issue Type Field ID: " + result 121 | return result 122 | } 123 | 124 | def storeChanges(IssueManager issueManager, ApplicationUser loggedInUser, MutableIssue thisIssue) { 125 | try { 126 | issueManager.updateIssue( 127 | loggedInUser, 128 | thisIssue, 129 | EventDispatchOption.ISSUE_UPDATED, 130 | false 131 | ) 132 | } catch (Exception e) { 133 | log.debug "Exception: " + e 134 | } 135 | } -------------------------------------------------------------------------------- /misc/deprecated/updateIssueType2.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: mergeIssues.groovy 3 | * Author: Evan Winter 4 | * 5 | * @brief Grabs description and comments from specified issue(s) and adds them to the 6 | * current issue. 7 | * 8 | */ 9 | 10 | import com.atlassian.jira.component.ComponentAccessor 11 | import com.atlassian.jira.issue.CustomFieldManager 12 | import com.atlassian.jira.issue.IssueManager 13 | import com.atlassian.jira.issue.Issue 14 | import java.util.ArrayList 15 | import com.atlassian.jira.issue.MutableIssue 16 | import com.atlassian.jira.user.ApplicationUser 17 | import com.atlassian.jira.issue.link.IssueLinkManager 18 | import com.atlassian.jira.event.type.EventDispatchOption 19 | import com.atlassian.jira.issue.comments.CommentManager 20 | import java.text.SimpleDateFormat 21 | 22 | /* Debugging */ 23 | import org.apache.log4j.Logger 24 | def log = Logger.getLogger("com.acme.XXX") 25 | 26 | /* Initialize variables */ 27 | MutableIssue thisIssue = issue 28 | ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 29 | 30 | def description = thisIssue.getDescription() -------------------------------------------------------------------------------- /misc/not-code/ITS_onboard_offboard_stringlists: -------------------------------------------------------------------------------- 1 | ["New Grainger account", "New or refreshed computer / extra software needed?", "Schedule onboard meeting", "Email address", "Create VOIP line", "Add to Wisclist", "Invite to service calendars", "Populate AD with email address, office number, title and phone number"] 2 | 3 | ["Disable Grainger account", "Remove from WiscLists", "Remove from service calendars", "Are they in LRM_Users group? If so, move ticket to LRM Team", "If faculty or lecturer > disable in Digital Measures: Joannie Bonazza"] -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Custom scripts, fields, snippets, etc for a more powerful JIRA workflow. Written in 2017 to address very specific business objectives, but maybe you can find something helpful in here. 2 | -------------------------------------------------------------------------------- /script-fields/fullNameOfPrimaryUser_prod.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name fullNameOfPrimaryUser_prod.groovy 3 | * @type Script Field 4 | * @brief Return the full (display) name of the user in the Primary User custom field. 5 | */ 6 | 7 | import com.atlassian.jira.user.ApplicationUser 8 | 9 | ApplicationUser primaryUser = getCustomFieldValue("Primary User") as ApplicationUser 10 | return (primaryUser) ? primaryUser.getDisplayName() : null -------------------------------------------------------------------------------- /script-fields/lastCommentTruncated_prod.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name lastCommentTrucated_prod.groovy 3 | * @type Script Field 4 | * @brief Renders the last comment added to this issues, truncated to 140 chars. 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | import com.atlassian.jira.issue.Issue 9 | 10 | /* Debugging */ 11 | import org.apache.log4j.Logger 12 | def log = Logger.getLogger("com.acme.XXX") 13 | 14 | def loggedInUser = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser() 15 | Issue thisIssue = issue 16 | 17 | int START = 0 18 | def TARGET_LENGTH = 140 19 | 20 | def comments = ComponentAccessor.getCommentManager().getCommentsForUser(thisIssue, loggedInUser) 21 | 22 | if (!comments || comments.size() == 0) { return } 23 | 24 | def lastComment = comments.last() 25 | def lastCommentClean = lastComment.body.replace("\n", " ") 26 | def author = lastComment.getAuthorApplicationUser().displayName 27 | 28 | boolean isTooLong = (lastComment.body.length() > TARGET_LENGTH) 29 | 30 | def newComment = (isTooLong) ? lastCommentClean.substring(START, TARGET_LENGTH) + "..." : lastCommentClean 31 | 32 | ComponentAccessor.getRendererManager().getRenderedContent( 33 | "atlassian-wiki-renderer", 34 | "*" + author + "*: " + newComment, 35 | thisIssue.issueRenderContext 36 | ) -------------------------------------------------------------------------------- /script-fields/numberOfPublicComments.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name numberOfPublicComments.groovy 3 | * @type Script Field 4 | * @brief The number of public (non-internal/visible to customer) comments on this issue. 5 | */ 6 | 7 | 8 | import com.atlassian.jira.component.ComponentAccessor 9 | import com.atlassian.jira.bc.issue.comment.property.CommentPropertyService 10 | import com.atlassian.jira.issue.comments.Comment 11 | import groovy.json.JsonSlurper 12 | 13 | final SD_PUBLIC_COMMENT = "sd.public.comment" 14 | 15 | def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 16 | def commentPropertyService = ComponentAccessor.getComponent(CommentPropertyService) 17 | def commentManager = ComponentAccessor.getCommentManager() 18 | 19 | def isInternal = { Comment c -> 20 | def commentProperty = commentPropertyService.getProperty(user, c.id, SD_PUBLIC_COMMENT) 21 | .getEntityProperty().getOrNull() 22 | 23 | if (commentProperty) { 24 | def props = new JsonSlurper().parseText(commentProperty.getValue()) 25 | props['internal'].toBoolean() 26 | } 27 | else { 28 | null 29 | } 30 | } 31 | 32 | def numComments = 0 33 | 34 | def comments = commentManager.getComments(issue) 35 | if (comments) { 36 | for (c in comments) { 37 | if (!(isInternal(c))) { 38 | numComments++ 39 | } 40 | } 41 | } 42 | 43 | return numComments -------------------------------------------------------------------------------- /script-fields/totalCostFormatted_prod.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name totalCostFormatted_prod.groovy 3 | * @type Script Field 4 | * @brief Return the value in custom field "Total Cost", adding a 5 | * dollar sign at the front if not already present. 6 | */ 7 | 8 | import com.atlassian.jira.user.ApplicationUser 9 | 10 | def totalCost = getCustomFieldValue("Total Cost") as String 11 | 12 | if (!totalCost) { return } 13 | 14 | if (totalCost == "\$") { 15 | // if Total Cost is only a dollar sign w/ no value, clear it. 16 | return '' 17 | } else if (totalCost[0] != "\$") { 18 | // if Total Cost has chars and the first char is not a dollar sign, add one. 19 | return ("\$" + totalCost) 20 | } else { 21 | // if Total Cost has chars and the first char is a dollar sign, do nothing. 22 | return totalCost 23 | } -------------------------------------------------------------------------------- /script-fields/truncatedDescription_prod.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name descriptionTruncated_prod.groovy 3 | * @type Script Field 4 | * @brief Renders a shortened and compacted version of the issue description. 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | import com.atlassian.jira.issue.Issue 9 | 10 | /* Debugging */ 11 | import org.apache.log4j.Logger 12 | def log = Logger.getLogger("com.acme.XXX") 13 | 14 | def loggedInUser = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser() 15 | Issue thisIssue = issue 16 | String description = thisIssue.getDescription().replace("\u00a0", "") // get rid of extra newlines 17 | 18 | int START = 0 19 | def TARGET_LENGTH = 600 20 | 21 | /* True if Description is longer than TARGET_LENGTH */ 22 | boolean isTooLong = (description.length() > TARGET_LENGTH) 23 | 24 | def newDescription = (isTooLong) ? description.substring(START, TARGET_LENGTH) + '...' : description 25 | ComponentAccessor.getRendererManager().getRenderedContent("atlassian-wiki-renderer", newDescription, thisIssue.issueRenderContext) -------------------------------------------------------------------------------- /script-listeners/AT_addJennAsWatcherOnMove_prod.groovy: -------------------------------------------------------------------------------- 1 | import com.atlassian.jira.component.ComponentAccessor 2 | import com.atlassian.jira.issue.MutableIssue 3 | import com.atlassian.jira.user.ApplicationUser 4 | import com.atlassian.jira.event.type.EventDispatchOption 5 | 6 | /* Debugging */ 7 | import org.apache.log4j.Logger 8 | def log = Logger.getLogger("com.acme.XXX") 9 | 10 | MutableIssue issue = ComponentAccessor.getIssueManager().getIssueObject(event.getIssue().getId()) 11 | ApplicationUser user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 12 | 13 | def userManager = ComponentAccessor.getUserManager() 14 | ApplicationUser jenn = userManager.getUserByKey('asselin') 15 | 16 | def watcherManager = ComponentAccessor.getWatcherManager() 17 | if (!watcherManager.isWatching(jenn, issue)) { 18 | watcherManager.startWatching(jenn, issue) 19 | try { 20 | ComponentAccessor.getIssueManager().updateIssue(user, issue, EventDispatchOption.ISSUE_UPDATED, false) 21 | } catch (Exception e) { 22 | log.debug "Exception: " + e 23 | return 'An error occured. Please contact your JIRA administrator.' 24 | } 25 | } else { 26 | log.debug "Jenn is already a watcher." 27 | } -------------------------------------------------------------------------------- /script-listeners/AT_updateIssueTypeCascade_prod.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name AT_updateIssueType_cascade_prod.groovy 3 | * @type Script Listener 4 | * @brief Updates Issue Type based on the child value of the cascading select 5 | * custom field "AT Issue Categories". 6 | */ 7 | 8 | import com.atlassian.jira.component.ComponentAccessor 9 | import com.atlassian.jira.issue.CustomFieldManager 10 | import com.atlassian.jira.issue.MutableIssue 11 | import com.atlassian.jira.user.ApplicationUser 12 | import com.atlassian.jira.issue.fields.CustomField 13 | import com.atlassian.jira.event.type.EventDispatchOption 14 | 15 | /* Debugging */ 16 | import org.apache.log4j.Logger 17 | def log = Logger.getLogger("com.acme.XXX") 18 | 19 | CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager() 20 | 21 | MutableIssue thisIssue = issue 22 | ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 23 | CustomField issueCategorizationsField = customFieldManager.getCustomFieldObject("customfield_12201") 24 | Map issueCategorizationsValues = thisIssue.getCustomFieldValue(issueCategorizationsField) as Map 25 | 26 | if (!issueCategorizationsValues) { return "No value set for Issue Categorizations." } 27 | 28 | String level1 = issueCategorizationsValues.get(null) // parent 29 | String level2 = issueCategorizationsValues.get("1") // child 30 | 31 | def desiredIssueType = ComponentAccessor.issueTypeSchemeManager.getIssueTypesForProject(thisIssue.getProjectObject()).find { 32 | it.getName() as String == level2 33 | } 34 | 35 | if (desiredIssueType) { 36 | if (desiredIssueType.name != thisIssue.getIssueType().getName() as String) { 37 | thisIssue.setIssueType(desiredIssueType) 38 | storeChanges(thisIssue, loggedInUser) 39 | } else { return "Issue type is already correctly set."} 40 | } else { return "Invalid or nonexistent issue type."} 41 | 42 | def storeChanges(MutableIssue issue, ApplicationUser user) { 43 | try { 44 | ComponentAccessor.getIssueManager().updateIssue( 45 | user, 46 | issue, 47 | EventDispatchOption.ISSUE_UPDATED, 48 | false 49 | ) 50 | } catch (Exception e) { 51 | log.debug "Exception: " + e 52 | } 53 | } -------------------------------------------------------------------------------- /script-listeners/FMO_commentAssignee_prod.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name FMO_commentAssignee_prod.groovy 3 | * @type Script Listener 4 | * @brief When an issue is assigned, add a comment and mention the assignee. 5 | */ 6 | 7 | import com.atlassian.jira.issue.MutableIssue 8 | import com.atlassian.jira.ComponentManager 9 | import com.atlassian.jira.user.ApplicationUser 10 | import com.atlassian.jira.component.ComponentAccessor 11 | import com.atlassian.jira.issue.comments.CommentManager 12 | import com.atlassian.jira.user.util.UserManager 13 | import com.atlassian.jira.security.groups.GroupManager 14 | import com.atlassian.jira.event.type.EventDispatchOption 15 | import org.apache.log4j.Logger 16 | import org.apache.log4j.Level 17 | 18 | def log = Logger.getLogger("com.acme.XXX") 19 | log.setLevel(Level.DEBUG) 20 | 21 | MutableIssue thisIssue = event.issue as MutableIssue 22 | def loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 23 | def fmoAdmin = ComponentAccessor.getUserManager().getUserByName("fmoadmin") 24 | 25 | // If changed to Unassigned, do nothing 26 | def assignee = thisIssue.getAssignee() 27 | if (!assignee) { return } 28 | 29 | // If assignee is an FMO student, add Jonathan Wolff as Watcher 30 | GroupManager groupManager = ComponentAccessor.getGroupManager() 31 | def watcherManager = ComponentAccessor.getWatcherManager() 32 | ApplicationUser jonathan = ComponentAccessor.getUserManager().getUserByKey('jwolf5') 33 | if (groupManager.isUserInGroup(assignee, 'fmo-students')) { 34 | if (!watcherManager.isWatching(jonathan, thisIssue)) { 35 | watcherManager.startWatching(jonathan, thisIssue) 36 | } 37 | } 38 | 39 | // Create the comment and add it to the issue 40 | def comment = "This issue has been assigned to [~$assignee.username]." 41 | try { 42 | ComponentAccessor.getCommentManager().create(thisIssue, fmoAdmin, comment, true) 43 | } catch (Exception e) { 44 | log.debug "Error adding comment: " + e 45 | } 46 | 47 | // Update the issue again to ensure Jonathan Wolf is a Watcher 48 | try { 49 | ComponentAccessor.getIssueManager().updateIssue(loggedInUser, thisIssue, EventDispatchOption.ISSUE_UPDATED, false) 50 | } catch (Exception e) { 51 | log.debug "Exception: " + e 52 | return 'An error occured. Please contact your JIRA administrator.' 53 | } -------------------------------------------------------------------------------- /script-listeners/FMO_syncReqTypeToIssueType_prod.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name FMO_syncReqTypeToIssueType_prod.groovy 3 | * @type Script Listener 4 | * @brief Update "FMO Request Type" based on the current Issue Type. 5 | */ 6 | 7 | import com.atlassian.jira.issue.MutableIssue 8 | import com.atlassian.jira.user.ApplicationUser 9 | import com.atlassian.jira.component.ComponentAccessor 10 | import com.atlassian.jira.event.type.EventDispatchOption 11 | 12 | /* Debugging */ 13 | import org.apache.log4j.Logger 14 | import org.apache.log4j.Level 15 | def log = Logger.getLogger("com") 16 | log.setLevel(Level.DEBUG) 17 | 18 | /* These are the four main categories of requests ("FMO Request Type") and their underlying Issue Types. */ 19 | /* Each Issue Type listed here must be IDENTICAL to the corresponding Issue Type object in FMO's Issue Type Scheme. */ 20 | def BUSINESS_SERVICES_ISSUETYPES = ["Academic Support Services Agreements", "Accounts Payable", "ACH and Wire Transfers (In and Out Going)", "Business Services", "Conference Services Billing", "Contract Only Request", "Contracting for Credit Instruction", "Custodial Funds", "Direct Payment (DP) to Vendors", "e-Re Division Coordinator", "e-Reimbursement Request", "Gift Cards", "Group Travel", "New Faculty and Staff - Financial Overview Onboarding", "Non-Contract Purchases > \$50,000", "Payment to Individual (PIR)", "P-Card", "Purchase Orders & Requisitions - Between \$5,000 & \$50,000", "Purchasing Requests < \$5,000", "Records Retention", "Relocations", "Shop@UW", "Travel", "UW Corporate Credit Card", "UWF Check Requests and Deposits (Audit)"] 21 | def ACCOUNTING_AND_OPERATIONS_ISSUETYPES = ["Accounting and Operations", "Asset Management", "Business Operations Systems", "Campus Compliance", "Cost Transfer (Audit)", "Foundation Funds", "General Accounting", "Post-Award Administration", "Revenue Producing Contracts", "Scholarship Management", "WISDM (Setup, Inquiry)"] 22 | def BUDGET_ANALYSIS_REPORTING_ISSUETYPES = ["Budget, Analysis and Reporting", "Budget, Analysis, and Reporting Advisory Services", "Campus Planning and Reporting", "Financial Analysis", "Financial Reporting", "WSB Budget Process"] 23 | def MISCELLANEOUS_ISSUETYPES = ["Miscellaneous"] 24 | 25 | MutableIssue thisIssue = ComponentAccessor.getIssueManager().getIssueObject("FMO-761") 26 | ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 27 | 28 | def reqTypeField = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("FMO Request Type") 29 | def reqTypeValue = thisIssue.getCustomFieldValue(reqTypeField) 30 | def reqTypeConfig = reqTypeField.getRelevantConfig(thisIssue) 31 | def reqTypeOptions = ComponentAccessor.getOptionsManager().getOptions(reqTypeConfig) 32 | 33 | def businessServices = reqTypeOptions.find{it.toString() == 'Business Services'} 34 | def accountingOperations = reqTypeOptions.find{it.toString() == 'Accounting and Operations'} 35 | def budgetAnalysisReporting = reqTypeOptions.find{it.toString() == 'Budget, Analysis and Reporting'} 36 | def miscellaneous = reqTypeOptions.find{it.toString() == 'Miscellaneous'} 37 | 38 | def thisIssueTypeName = thisIssue.getIssueType().getName() 39 | def newReqType 40 | 41 | if (thisIssueTypeName in BUSINESS_SERVICES_ISSUETYPES) { 42 | newReqType = businessServices 43 | } else if (thisIssueTypeName in ACCOUNTING_AND_OPERATIONS_ISSUETYPES) { 44 | newReqType = accountingOperations 45 | } else if (thisIssueTypeName in BUDGET_ANALYSIS_REPORTING_ISSUETYPES) { 46 | newReqType = budgetAnalysisReporting 47 | } else if (thisIssueTypeName in MISCELLANEOUS_ISSUETYPES) { 48 | newReqType = miscellaneous 49 | } else { 50 | return "Issue Type was not located within any FMO Request Type list of issue types." 51 | } 52 | 53 | log.debug "Issue Type is '$thisIssueTypeName', so $reqTypeField should be '$newReqType'" 54 | 55 | if (thisIssue.getCustomFieldValue(reqTypeField) != newReqType) { 56 | log.debug "$reqTypeField is already correct. No update necessary" 57 | return 58 | } 59 | 60 | log.debug "Updating $reqTypeField from '$reqTypeValue' to '$newReqType'" 61 | thisIssue.setCustomFieldValue(reqTypeField, newReqType) 62 | 63 | // Store to DB. 64 | try { 65 | ComponentAccessor.getIssueManager().updateIssue( 66 | loggedInUser, 67 | thisIssue, 68 | EventDispatchOption.ISSUE_UPDATED, 69 | false 70 | ) 71 | } catch (Exception e) { 72 | log.debug "Exception: " + e 73 | } -------------------------------------------------------------------------------- /script-listeners/ITCM_copyCommentToParent_prod.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name ITCM_copyCommentToParent_prod.groovy 3 | * @type Script Listener 4 | * @brief Copies new comments added to a subtask to the subtask's parent issue. 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | import com.atlassian.jira.issue.Issue 9 | import com.atlassian.jira.issue.comments.CommentManager 10 | 11 | Issue thisIssue = issue 12 | if (!thisIssue.isSubTask()) { return "Not a subtask - don't copy comment."} 13 | 14 | Issue parentIssue = thisIssue.getParentObject() 15 | 16 | CommentManager commentManager = ComponentAccessor.getCommentManager() 17 | def commentToCopy = commentManager.getLastComment(thisIssue) 18 | 19 | if (commentToCopy) { 20 | try { 21 | commentManager.create( 22 | parentIssue, 23 | commentToCopy.getAuthorApplicationUser(), 24 | commentToCopy.getBody(), 25 | true 26 | ) 27 | } catch (Exception e) { 28 | log.debug "Exception: " + e 29 | } 30 | } else { 31 | log.debug "Comment is null." 32 | } -------------------------------------------------------------------------------- /script-listeners/ITS_generateChecklist.groovy: -------------------------------------------------------------------------------- 1 | import com.atlassian.jira.component.ComponentAccessor 2 | import com.atlassian.jira.issue.MutableIssue 3 | import com.atlassian.jira.user.ApplicationUser 4 | import com.atlassian.jira.event.type.EventDispatchOption 5 | import java.util.ArrayList 6 | 7 | def issueFactory = ComponentAccessor.getIssueFactory() 8 | def constantsManager = ComponentAccessor.getConstantsManager() 9 | def issueManager = ComponentAccessor.getIssueManager() 10 | def subTaskManager = ComponentAccessor.getSubTaskManager() 11 | 12 | ApplicationUser user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 13 | MutableIssue parent = event.issue as MutableIssue 14 | def type = parent.issueType.name 15 | 16 | if (!(type == 'Onboarding' || type == 'Offboarding')) { 17 | return 'This script only runs on issues of Onboarding and Offboarding issue types.' 18 | } 19 | 20 | if (parent.getSubTaskObjects().size() != 0) { 21 | return 'This script only runs when the parent issue has no existing sub-tasks.' 22 | } 23 | 24 | def onboardChecklist = ["New Grainger account", "New or refreshed computer / extra software needed?", "Schedule onboard meeting", "Email address", "Create VOIP line", "Add to Wisclist", "Invite to service calendars", "Populate AD with email address, office number, title and phone number", "If Faculty or PhD, add research drive", "Send Follow-up Summary"] 25 | def offboardChecklist = ["Disable Grainger account", "Remove from WiscLists", "Remove from service calendars", "Are they in LRM_Users group? If so, move ticket to LRM Team", "If faculty or lecturer > disable in Digital Measures: Joannie Bonazza", "Remove VoIP account"] 26 | def checklist = (type == 'Onboarding') ? onboardChecklist : offboardChecklist 27 | 28 | // For each item in the asserted checklist 29 | for (task in checklist) { 30 | 31 | // Get an issue object for the new sub-task 32 | MutableIssue taskObj = issueFactory.getIssue() 33 | 34 | // Set necessary fields 35 | taskObj.setSummary(task) 36 | taskObj.setDescription('For issue ' + parent.getKey()) 37 | taskObj.setParentObject(parent) 38 | taskObj.setProjectObject(parent.getProjectObject()) 39 | 40 | // Make it a sub-task by setting the issue type ID 41 | taskObj.setIssueTypeId(constantsManager.getAllIssueTypeObjects().find{ 42 | it.getName() == "Sub-task" 43 | }.id) 44 | 45 | Map newIssueParams = ["issue" : taskObj] as Map 46 | issueManager.createIssueObject(user, newIssueParams) 47 | subTaskManager.createSubTaskIssueLink(parent, taskObj, user) 48 | 49 | } 50 | 51 | // Store to DB. 52 | try { 53 | issueManager.updateIssue( 54 | user, 55 | parent, 56 | EventDispatchOption.ISSUE_UPDATED, 57 | false 58 | ) 59 | } catch (Exception e) { 60 | log.debug "Exception: " + e 61 | } -------------------------------------------------------------------------------- /script-listeners/addWatcherAfterNComments.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name addWatcherAfterNComments.groovy 3 | * @type Script Listener 4 | * @brief When a new comment is added, add Jonathan Wolf (jwolf5) as a Watcher 5 | if the total number of PUBLIC comments is >= 4. 6 | */ 7 | 8 | import com.atlassian.jira.bc.issue.comment.property.CommentPropertyService 9 | import com.atlassian.jira.component.ComponentAccessor 10 | import com.atlassian.jira.event.issue.IssueEvent 11 | import com.atlassian.jira.issue.MutableIssue 12 | import com.atlassian.jira.user.ApplicationUser 13 | import com.atlassian.jira.issue.comments.Comment 14 | import com.atlassian.jira.issue.comments.CommentManager 15 | import com.atlassian.jira.event.type.EventDispatchOption 16 | import groovy.json.JsonSlurper 17 | 18 | final SD_PUBLIC_COMMENT = "sd.public.comment" 19 | 20 | def event = event as IssueEvent 21 | def issue = event.issue as MutableIssue 22 | log.debug(issue) 23 | 24 | def user = event.getUser() 25 | def comment = event.getComment() 26 | def commentPropertyService = ComponentAccessor.getComponent(CommentPropertyService) 27 | 28 | def isInternal = { Comment c -> 29 | def commentProperty = commentPropertyService.getProperty(user, c.id, SD_PUBLIC_COMMENT) 30 | .getEntityProperty().getOrNull() 31 | 32 | if (commentProperty) { 33 | def props = new JsonSlurper().parseText(commentProperty.getValue()) 34 | props['internal'].toBoolean() 35 | } 36 | else { 37 | null 38 | } 39 | } 40 | 41 | def commentManager = ComponentAccessor.getCommentManager() 42 | def watcherManager = ComponentAccessor.getWatcherManager() 43 | def watcher = ComponentAccessor.getUserManager().getUserByName('jwolf5') 44 | def admin = ComponentAccessor.getUserManager().getUserByName("fmoadmin") 45 | 46 | log.debug "User to add as watcher: ${watcher}" 47 | log.debug "User to make action: ${admin}" 48 | 49 | if (comment) { 50 | 51 | // Count number of PUBLIC COMMENTS 52 | def numComments = 0 53 | def comments = commentManager.getComments(event.issue) 54 | for (c in comments) { 55 | if (!(isInternal(c))) { 56 | numComments++ 57 | } 58 | } 59 | 60 | log.debug "Number of comments: ${numComments}" 61 | 62 | // If 4 or more PUBLIC COMMENTS and the selected user isn't already a Watcher, 63 | // add them as a Watcher. 64 | if (numComments >= 4) { 65 | if (!watcherManager.isWatching(watcher, issue)) { 66 | log.debug "Adding ${watcher} as a Watcher." 67 | watcherManager.startWatching(watcher, issue) 68 | try { 69 | ComponentAccessor.getIssueManager().updateIssue(admin, issue, EventDispatchOption.ISSUE_UPDATED, false) 70 | return true; 71 | } 72 | catch (Exception e) { 73 | return 'An error occurred: ' + e + '\n\nPlease contact your JIRA administrator.' 74 | } 75 | } 76 | } 77 | } 78 | return false -------------------------------------------------------------------------------- /script-listeners/commentAssigneeANDaddJWolfAsWatcher.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name FMO_commentAssignee_prod.groovy 3 | * @type Script Listener 4 | * @brief When an issue is assigned, add a comment and mention the assignee. 5 | */ 6 | 7 | import com.atlassian.jira.issue.MutableIssue 8 | import com.atlassian.jira.ComponentManager 9 | import com.atlassian.jira.user.ApplicationUser 10 | import com.atlassian.jira.component.ComponentAccessor 11 | import com.atlassian.jira.issue.comments.CommentManager 12 | import com.atlassian.jira.user.util.UserManager 13 | import com.atlassian.jira.security.groups.GroupManager 14 | import com.atlassian.jira.event.type.EventDispatchOption 15 | import org.apache.log4j.Logger 16 | import org.apache.log4j.Level 17 | 18 | def log = Logger.getLogger("com.acme.XXX") 19 | log.setLevel(Level.DEBUG) 20 | 21 | MutableIssue thisIssue = event.issue as MutableIssue 22 | def loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 23 | def fmoAdmin = ComponentAccessor.getUserManager().getUserByName("fmoadmin") 24 | 25 | def assignee = thisIssue.getAssignee() 26 | if (!assignee) { return } 27 | 28 | // If assignee is an FMO student, add Jonathan Wolff as Watcher 29 | GroupManager groupManager = ComponentAccessor.getGroupManager() 30 | def watcherManager = ComponentAccessor.getWatcherManager() 31 | ApplicationUser jonathan = ComponentAccessor.getUserManager().getUserByKey('jwolf5') 32 | if (groupManager.isUserInGroup(assignee, 'fmo-students')) { 33 | if (!watcherManager.isWatching(jonathan, thisIssue)) { 34 | watcherManager.startWatching(jonathan, thisIssue) 35 | } 36 | } 37 | 38 | def comment = "This issue has been assigned to [~$assignee.username]." 39 | try { 40 | ComponentAccessor.getCommentManager().create(thisIssue, fmoAdmin, comment, true) 41 | } catch (Exception e) { 42 | log.debug "Error adding comment: " + e 43 | } 44 | 45 | try { 46 | ComponentAccessor.getIssueManager().updateIssue(loggedInUser, thisIssue, EventDispatchOption.ISSUE_UPDATED, false) 47 | } catch (Exception e) { 48 | log.debug "Exception: " + e 49 | return 'An error occured. Please contact your JIRA administrator.' 50 | } 51 | 52 | 53 | -------------------------------------------------------------------------------- /script-listeners/script-listener-conditions/FMO_transitionConditions_prod.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name FMO_transitionConditions_prod.groovy 3 | * @type Script Listener (Condition) 4 | * @brief Determine if an issue should be allowed to transition to a given status 5 | * by checking to see if the current Issue Type exists in that status's 6 | * corresponding String array. 7 | */ 8 | 9 | String[] fmoIssueTypesMasterList = [ "Contracting for Credit Instruction", "Gift Cards", "Shop@UW", "Non-Contract Purchases > \$50,000", "Contract Only Request", "Purchase Orders & Requisitions - Between \$5,000 & \$50,000", "Purchasing Requests < \$5,000", "P-Card", "UW Corporate Credit Card", "e-Re Division Coordinator", "e-Reimbursement Request", "Group Travel", "Travel", "Accounts Payable", "Payment to Individual (PIR)", "ACH and Wire Transfers (In and Out Going)", "Conference Services Billing", "Custodial Funds", "Direct Payment (DP) to Vendors", "UWF Check Requests and Deposits (Audit)", "New Faculty and Staff - Financial Overview Onboarding", "Relocations", "Records Retention", "General Accounting", "Asset Management", "Revenue Producing Contracts", "Business Operations Systems", "WISDM (Setup, Inquiry)", "Post-Award Administration", "Scholarship Management", "Campus Compliance", "Foundation Funds", "WSB Budget Process", "Campus Planning and Reporting", "Financial Analysis", "Financial Reporting", "Budget, Analysis, and Reporting Advisory Services", "Cost Transfer (Audit)", "Academic Support Services Agreements", "Business Services", "Accounting and Operations", "Budget, Analysis and Reporting", "Miscellaneous"] 10 | 11 | String[] wsbexternal = [ "Academic Support Services Agreements", "Contracting for Credit Instruction", "Non-Contract Purchases > \$50,000", "Purchase Orders & Requisitions - Between \$5,000 & \$50,000", "Purchasing Requests < \$5,000", "Post-Award Administration", "Revenue Producing Contracts", "Campus Planning and Reporting", "Financial Analysis", "Financial Reporting", "Asset Management", "Business Services", "Accounts Payable", "Conference Services Billing", "Contract Only Request", "Relocations", "Travel", "Group Travel", "Records Retention", "Accounting and Operations", "Business Operations Systems", "Budget, Analysis and Reporting", "WSB Budget Process", "Miscellaneous", "e-Reimbursement Request", "Scholarship Management"] 12 | String[] foundation = [ "e-Re Division Coordinator", "UWF Check Requests and Deposits (Audit)", "Foundation Funds", "Budget, Analysis and Reporting Advisory Services", "Business Services", "Accounts Payable", "Conference Services Billing", "Contract Only Request", "Relocations", "Travel", "Group Travel", "Records Retention", "Accounting and Operations", "Business Operations Systems", "Budget, Analysis and Reporting", "WSB Budget Process", "Miscellaneous", "e-Reimbursement Request", "Scholarship Management"] 13 | String[] campus = [ "Direct Payment (DP) to Vendors", "P-Card", "Shop@UW", "UW Corporate Credit Card", "Gift Cards", "ACH and Wire Transfers (In and Out Going)", "Custodial Funds", "Cost Transfer (Audit)", "General Accounting", "Payment to Individual (PIR)", "WISDM (Setup, Inquiry)", "Campus Compliance", "Academic Support Services Agreements", "Contracting for Credit Instruction", "Non-Contract Purchases > \$50,000", "Purchase Orders & Requisitions - Between \$5,000 & \$50,000", "Purchasing Requests < \$5,000", "Post-Award Administration", "Revenue Producing Contracts", "Campus Planning and Reporting", "Financial Analysis", "Financial Reporting", "Asset Management", "e-Re Division Coordinator", "UWF Check Requests and Deposits (Audit)", "Foundation Funds", "Budget, Analysis and Reporting Advisory Services", "Business Services", "Accounts Payable", "Conference Services Billing", "Contract Only Request", "Relocations", "Travel", "Group Travel", "Records Retention", "Accounting and Operations", "Business Operations Systems", "Budget, Analysis and Reporting", "WSB Budget Process", "Miscellaneous", "e-Reimbursement Request", "Scholarship Management"] 14 | 15 | (issue.getIssueType().name in wsbexternal) // if current issue's Issue Type is in the WSB External array, allow transitions to the WSB External status 16 | (issue.getIssueType().name in foundation) // if current issue's Issue Type is in the Foundation array, allow transitions to the Foundation status 17 | (issue.getIssueType().name in campus) // if current issue's Issue Type is in the Campus array, allow transitions to the Campus status -------------------------------------------------------------------------------- /script-listeners/script-listener-conditions/ITS_automateStartProgConditions.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name ITS_automateInProgress_prod.groovy 3 | * @type Script Listener (Condition) 4 | * @brief Return true if all of the following conditions are true: 5 | * - Issue Type is not "ITS-Null" 6 | * - ITIL Category is not "Not-Assigned" 7 | * - Assignee is not null 8 | * - Status is "Pending" 9 | */ 10 | 11 | def issueTypeIsNull = (issue.issueType == "ITS-Null") 12 | def itilCategoryIsNull = (cfValues["ITIL Category"]?.value == "Not-Assigned") 13 | def assigneeIsNull = (issue.assignee == null) 14 | def isPending = (issue.getStatus().getName() == "Pending") 15 | 16 | return (!issueTypeIsNull && !itilCategoryIsNull && !assigneeIsNull && isPending) -------------------------------------------------------------------------------- /script-listeners/script-listener-conditions/ITS_generateChecklistCondition_prod.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name ITS_generateChecklist_prod.groovy 3 | * @type Script Listener (Condition) 4 | * @brief Return true if all of the following conditions are true: 5 | * - This issue has no subtasks. 6 | * - Issue Type = "Onboarding" or "Offboarding" 7 | */ 8 | 9 | return (issue.subTaskObjects.size() == 0 && (issue.issueType.name == "Onboarding" || issue.issueType.name == "Offboarding")) -------------------------------------------------------------------------------- /script-postfunctions/AT_mergeIssueIntoExisting.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name AT_mergeIssueIntoExisting_prod.groovy 3 | * @type Post function 4 | * @brief Merges current issue into target issue by appending the current issue's 5 | * description, comments and Reporter to the target issue's corresponding 6 | * fields. The current issue's Reporter is added to the target issue as 7 | * a Request Participant. 8 | */ 9 | 10 | import com.atlassian.jira.component.ComponentAccessor 11 | import java.text.SimpleDateFormat 12 | import com.atlassian.jira.issue.MutableIssue 13 | import com.atlassian.jira.user.ApplicationUser 14 | import java.util.ArrayList 15 | import com.atlassian.jira.event.type.EventDispatchOption 16 | 17 | /* Debugging */ 18 | import org.apache.log4j.Logger 19 | def log = Logger.getLogger("com.acme.XXX") 20 | 21 | /* Get timestamp */ 22 | def date = new Date() 23 | def sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss") 24 | def formattedDate = sdf.format(date) 25 | 26 | /* Initialize variables */ 27 | MutableIssue thisIssue = issue 28 | ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 29 | 30 | def linkedIssues = ComponentAccessor.getIssueLinkManager().getOutwardLinks(thisIssue.getId()) 31 | MutableIssue mainIssue = linkedIssues[0].getDestinationObject() as MutableIssue 32 | 33 | if (mainIssue.getKey() == thisIssue.getKey()) { 34 | log.debug "Can't merge with self." 35 | return false 36 | } 37 | 38 | /* Merge descriptions (this -> main) */ 39 | def mainDescription = mainIssue.getDescription() 40 | def thisDescription = thisIssue.getDescription() 41 | mainDescription += ('\n\n *MERGE* ' + thisIssue.getKey() + ' | ' + formattedDate + '\n----- \n' + thisDescription) 42 | mainIssue.setDescription(mainDescription) 43 | 44 | /* Merge comments (this -> main) */ 45 | def thisComments = ComponentAccessor.getCommentManager().getComments(thisIssue) 46 | if (thisComments.size() > 0) { 47 | def newMainComment = '*MERGE* ' + thisIssue.getKey() + ' | ' + formattedDate + '\n----- \n' 48 | for (comment in thisComments) { 49 | newMainComment += ('*' + comment.getAuthorFullName() + '*: ' + comment.getBody() + '\n_' + comment.getCreated() + '_\n') 50 | } 51 | ComponentAccessor.getCommentManager().create(mainIssue, loggedInUser, newMainComment, false) 52 | } 53 | 54 | /* Merge participants (this Reporter -> main Request Participants) */ 55 | ApplicationUser thisReporter = thisIssue.getReporter() 56 | def mainRequestParticipantsField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("customfield_10600") 57 | ArrayList mainRequestParticipants = mainIssue.getCustomFieldValue(mainRequestParticipantsField) as ArrayList 58 | mainRequestParticipants.add(thisReporter) 59 | mainIssue.setCustomFieldValue(mainRequestParticipantsField, mainRequestParticipants) 60 | 61 | /* Comment on this issue to tag as merged */ 62 | ComponentAccessor.getCommentManager().create(thisIssue, loggedInUser, "MERGED into " + mainIssue.getKey(), false) 63 | 64 | /* Persist changes */ 65 | try { 66 | ComponentAccessor.getIssueManager().updateIssue( 67 | loggedInUser, 68 | mainIssue, 69 | EventDispatchOption.ISSUE_UPDATED, 70 | false 71 | ) 72 | } catch (Exception e) { 73 | log.debug "Exception: " + e 74 | return 'An error occured. Please contact your JIRA administrator.' 75 | } -------------------------------------------------------------------------------- /script-postfunctions/AT_raiseOnBehalfOf.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name AT_raiseOnBehalfOf.groovy 3 | * @type Post function 4 | * @brief Adds initial Reporter to Request Participants field, and assigns user 5 | * in "Raise on behalf of" field to the Reporter field. 6 | */ 7 | 8 | import com.atlassian.jira.component.ComponentAccessor 9 | import com.atlassian.jira.user.ApplicationUser 10 | import com.atlassian.jira.issue.MutableIssue 11 | import java.util.ArrayList 12 | import com.atlassian.jira.event.type.EventDispatchOption 13 | 14 | /* Debugging */ 15 | import org.apache.log4j.Logger 16 | def log = Logger.getLogger("com.acme.XXX") 17 | 18 | def REQUEST_PARTICIPANTS_FIELD = "customfield_10600" 19 | def RAISE_ON_BEHALF_OF_FIELD = "customfield_12131" 20 | 21 | ApplicationUser currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 22 | MutableIssue thisIssue = issue 23 | 24 | def requestParticipantsField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(REQUEST_PARTICIPANTS_FIELD) 25 | def raiseOnBehalfOfField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(RAISE_ON_BEHALF_OF_FIELD) 26 | 27 | ApplicationUser thisReporter = thisIssue.getReporter() 28 | ApplicationUser newReporter = thisIssue.getCustomFieldValue(raiseOnBehalfOfField) as ApplicationUser 29 | 30 | /* If "Raise on behalf of" field isn't set, exit and do nothing */ 31 | if (!newReporter) { return "No new reporter specified." } 32 | 33 | ArrayList requestParticipants = [] 34 | requestParticipants.add(thisReporter) 35 | 36 | thisIssue.setCustomFieldValue(requestParticipantsField, requestParticipants) 37 | thisIssue.setReporter(newReporter) 38 | thisIssue.setCustomFieldValue(raiseOnBehalfOfField, null) 39 | 40 | try { 41 | ComponentAccessor.getIssueManager().updateIssue( 42 | currentUser, 43 | thisIssue, 44 | EventDispatchOption.ISSUE_UPDATED, 45 | false 46 | ) 47 | } catch (Exception e) { 48 | log.debug "Exception: " + e 49 | } -------------------------------------------------------------------------------- /script-postfunctions/FES_raiseOnBehalfOf.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name FES_raiseOnBehalfOf.groovy 3 | * @type Post function 4 | * @brief Adds initial Reporter to Request Participants field, and assigns user 5 | * in "Primary User" field to the Reporter field. 6 | */ 7 | 8 | import com.atlassian.jira.component.ComponentAccessor 9 | import com.atlassian.jira.user.ApplicationUser 10 | import com.atlassian.jira.issue.MutableIssue 11 | import java.util.ArrayList 12 | import com.atlassian.jira.event.type.EventDispatchOption 13 | 14 | /* Debugging */ 15 | import org.apache.log4j.Logger 16 | def log = Logger.getLogger("com.acme.XXX") 17 | 18 | def REQUEST_PARTICIPANTS_FIELD_ID = "customfield_10600" 19 | def PRIMARY_USER_FIELD_ID = "customfield_10913" 20 | 21 | ApplicationUser currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 22 | MutableIssue thisIssue = issue 23 | 24 | def requestParticipantsField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(REQUEST_PARTICIPANTS_FIELD_ID) 25 | def primaryUserField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(PRIMARY_USER_FIELD_ID) 26 | 27 | ApplicationUser thisReporter = thisIssue.getReporter() 28 | ApplicationUser newReporter = thisIssue.getCustomFieldValue(primaryUserField) as ApplicationUser 29 | 30 | /* If Primary User field isn't set, exit and do nothing */ 31 | if (!newReporter) { return "No new reporter specified." } 32 | 33 | ArrayList requestParticipants = [] 34 | requestParticipants.add(thisReporter) 35 | 36 | thisIssue.setCustomFieldValue(requestParticipantsField, requestParticipants) 37 | thisIssue.setReporter(newReporter) 38 | thisIssue.setCustomFieldValue(primaryUserField, null) 39 | 40 | try { 41 | ComponentAccessor.getIssueManager().updateIssue( 42 | currentUser, 43 | thisIssue, 44 | EventDispatchOption.ISSUE_UPDATED, 45 | false 46 | ) 47 | } catch (Exception e) { 48 | log.debug "Exception: " + e 49 | } -------------------------------------------------------------------------------- /script-postfunctions/ITCM_createSubtasks_prod.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name ITCM_createSubtasks_prod.groovy 3 | * @type Post function 4 | * @brief Creates and self-assigns a subtask for each user in the group specified by the 5 | * "Needs approval from" group picker custom field. 6 | */ 7 | 8 | import com.atlassian.jira.component.ComponentAccessor 9 | import com.atlassian.jira.issue.Issue 10 | import com.atlassian.jira.issue.MutableIssue 11 | import com.atlassian.crowd.embedded.api.Group 12 | import com.atlassian.jira.user.ApplicationUsers 13 | import com.atlassian.jira.user.util.UserUtil 14 | import com.atlassian.crowd.embedded.api.User 15 | import org.apache.log4j.Logger 16 | import org.apache.log4j.Level 17 | 18 | def log = Logger.getLogger("com.acme.XXX") 19 | log.setLevel(Level.DEBUG) 20 | 21 | Issue parent = issue 22 | 23 | // don't run on subtasks 24 | if (parent.isSubTask()) { 25 | log.debug "Sub-task ignored." 26 | return 27 | } 28 | 29 | def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 30 | 31 | // define managers 32 | def cfManager = ComponentAccessor.getCustomFieldManager() 33 | def groupManager = ComponentAccessor.getGroupManager() 34 | def issueManager = ComponentAccessor.getIssueManager() 35 | def issueFactory = ComponentAccessor.getIssueFactory() 36 | def subTaskManager = ComponentAccessor.getSubTaskManager() 37 | def constantsManager = ComponentAccessor.getConstantsManager() 38 | 39 | // get information about the approver group 40 | def approversCf = cfManager.getCustomFieldObjectByName("Approver Group") 41 | def approvers = issue.getCustomFieldValue(approversCf) 42 | def approversName = approvers ? approvers[0].name : log.debug("Approver Group is null.") 43 | int approversSize = groupManager.getUsersInGroup(approversName).size() 44 | 45 | def assignee 46 | def assigneeName 47 | 48 | // define custom fields so they can be copied from parent and set for subtasks later 49 | def category = cfManager.getCustomFieldObject('customfield_11401') 50 | def impact = cfManager.getCustomFieldObject('customfield_10804') 51 | def risk = cfManager.getCustomFieldObject('customfield_10806') 52 | def changeStartDate = cfManager.getCustomFieldObject('customfield_10808') 53 | def changeEndDate = cfManager.getCustomFieldObject('customfield_10809') 54 | def businessCase = cfManager.getCustomFieldObject('customfield_11500') 55 | def changeType = cfManager.getCustomFieldObject('customfield_10805') 56 | 57 | // for each user in the approver group 58 | for (int i = 0; i < approversSize; i++) { 59 | 60 | assignee = groupManager.getUsersInGroup(approvers).get(i).getName() 61 | assigneeName = groupManager.getUsersInGroup(approvers).get(i).getDisplayName() 62 | 63 | log.debug "Creating subtask for " + assigneeName 64 | 65 | // create a new mutable issue (soon to be a subtask) 66 | MutableIssue newSubTask = issueFactory.getIssue() 67 | 68 | // set summary and copy fields from parent to each subtask 69 | newSubTask.setSummary(assigneeName+": Approval requested") 70 | newSubTask.setDescription("*"+parent.getSummary()+"* \n\n" + parent.getDescription()) 71 | newSubTask.setAssigneeId(assignee) 72 | newSubTask.setReporter(user) 73 | newSubTask.setParentObject(parent) 74 | newSubTask.setProjectObject(parent.getProjectObject()) 75 | 76 | // copy custom fields from parent to each subtask 77 | newSubTask.setCustomFieldValue( category, issue.getCustomFieldValue(category) ) 78 | newSubTask.setCustomFieldValue( impact, issue.getCustomFieldValue(impact) ) 79 | newSubTask.setCustomFieldValue( risk, issue.getCustomFieldValue(risk) ) 80 | newSubTask.setCustomFieldValue( changeStartDate, issue.getCustomFieldValue(changeStartDate) ) 81 | newSubTask.setCustomFieldValue( changeEndDate, issue.getCustomFieldValue(changeEndDate) ) 82 | newSubTask.setCustomFieldValue( businessCase, issue.getCustomFieldValue(businessCase) ) 83 | newSubTask.setCustomFieldValue( changeType, issue.getCustomFieldValue(changeType) ) 84 | 85 | // set this issue's Issue Type ID to that of a sub-task 86 | newSubTask.setIssueTypeId(constantsManager.getAllIssueTypeObjects().find{ 87 | it.getName() == "Sub-task" 88 | }.id) 89 | 90 | Map newIssueParams = ["issue" : newSubTask] as Map 91 | issueManager.createIssueObject(user, newIssueParams) 92 | subTaskManager.createSubTaskIssueLink(parent, newSubTask, user) 93 | 94 | log.debug "Subtask created for " + assigneeName 95 | 96 | } -------------------------------------------------------------------------------- /script-postfunctions/ITCM_deleteSubtasks_prod.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name ITCM_deleteSubtasks_prod.groovy 3 | * @type Post function 4 | * @brief Deletes all subtasks associated with the current issue. 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | import com.atlassian.jira.event.type.EventDispatchOption 9 | import org.apache.log4j.Logger 10 | import org.apache.log4j.Level 11 | 12 | def log = Logger.getLogger("com.acme.XXX") 13 | log.setLevel(Level.DEBUG) 14 | 15 | def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 16 | def issueManager = ComponentAccessor.getIssueManager() 17 | 18 | // returns a Collection with all the subtasks of the current issue 19 | def subTasksList = issue.getSubTaskObjects() 20 | 21 | // delete each subtask 22 | for (subTask in subTasksList) { 23 | log.debug "Deleting subtask: "+subTask.getKey() 24 | issueManager.deleteIssue(user, subTask, EventDispatchOption.ISSUE_DELETED, false) 25 | } -------------------------------------------------------------------------------- /script-postfunctions/ITCM_parentToDeniedStatus_prod.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name ITCM_parentToDeniedStatus_prod.groovy 3 | * @type Post function 4 | * @brief If ANY of this issue's sibling subtasks are 'Denied', move its parent 5 | * issue to status 'Denied' 6 | */ 7 | 8 | 9 | import com.opensymphony.workflow.WorkflowContext 10 | import com.atlassian.jira.config.SubTaskManager 11 | import com.atlassian.jira.workflow.WorkflowTransitionUtil 12 | import com.atlassian.jira.workflow.WorkflowTransitionUtilImpl 13 | import com.atlassian.jira.util.JiraUtils 14 | import com.atlassian.jira.issue.MutableIssue 15 | import com.atlassian.jira.component.ComponentAccessor 16 | import org.apache.log4j.Logger 17 | import org.apache.log4j.Level 18 | 19 | def log = Logger.getLogger("com.acme.XXX") 20 | log.setLevel(Level.DEBUG) 21 | 22 | String currentUser = ((WorkflowContext) transientVars.get("context")).getCaller() 23 | WorkflowTransitionUtil workflowTransitionUtil = (WorkflowTransitionUtil) JiraUtils.loadComponent(WorkflowTransitionUtilImpl.class) 24 | MutableIssue parent = issue.getParentObject() as MutableIssue 25 | 26 | String originalParentStatus = parent.getStatus().getSimpleStatus().getName() 27 | def isWaitingForApproval = originalParentStatus in ['Waiting for approval'] 28 | 29 | // for current ITCM workflow 30 | int denyID = 21 31 | 32 | if (isWaitingForApproval) { 33 | workflowTransitionUtil.setIssue(parent) 34 | workflowTransitionUtil.setUserkey(currentUser) 35 | workflowTransitionUtil.setAction(denyID) 36 | if (workflowTransitionUtil.validate()) { 37 | workflowTransitionUtil.progress() 38 | } 39 | } else { 40 | log.debug("Not in Waiting for approval.") 41 | } -------------------------------------------------------------------------------- /script-postfunctions/addPrimaryUserAsParticipant.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name addPrimaryUserAsParticipant.groovy 3 | * @type Script Post Function 4 | * @brief Adds the user in custom field "Primary User" to the field "Request Participants" 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | import com.atlassian.jira.event.type.EventDispatchOption 9 | import com.atlassian.jira.issue.CustomFieldManager 10 | import com.atlassian.jira.issue.MutableIssue 11 | import com.atlassian.jira.issue.IssueManager 12 | import java.util.ArrayList 13 | import com.atlassian.jira.user.ApplicationUser 14 | import org.apache.log4j.Logger 15 | 16 | def log = Logger.getLogger("com.acme.XXX") 17 | 18 | def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 19 | def REQUEST_PARTICIPANTS_FIELD = "customfield_10600" 20 | def PRIMARY_USER_FIELD = "customfield_10913" 21 | 22 | CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager() 23 | IssueManager issueManager = ComponentAccessor.getIssueManager() 24 | MutableIssue issue = issue // FOR TESTING IN CONSOLE replace `issue` with `issueManager.getIssueObject("{issuekey}")` 25 | 26 | /* Get field objects */ 27 | def requestParticipantsField = customFieldManager.getCustomFieldObject(REQUEST_PARTICIPANTS_FIELD) 28 | def primaryUserField = customFieldManager.getCustomFieldObject(PRIMARY_USER_FIELD) 29 | 30 | /* Get Primary User */ 31 | ApplicationUser primaryUser = issue.getCustomFieldValue(primaryUserField) as ApplicationUser 32 | 33 | if (primaryUser) { 34 | 35 | /* Create an empty arraylist and add Primary User */ 36 | ArrayList participants = [] 37 | participants.add(primaryUser) 38 | 39 | /* Assign the arraylist to the Request Participants field */ 40 | issue.setCustomFieldValue(requestParticipantsField, participants) 41 | 42 | /* Store to database. */ 43 | try { 44 | issueManager.updateIssue( 45 | currentUser, 46 | issue, 47 | EventDispatchOption.ISSUE_UPDATED, 48 | false 49 | ) 50 | } catch (Exception e) { 51 | log.debug "Exception: " + e 52 | } 53 | 54 | } else { 55 | log.debug "No Primary User specified." 56 | } -------------------------------------------------------------------------------- /script-snippets/getAllUsers.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name getLinkedIssues.groovy 3 | * @type script snippet 4 | * @brief Get all users in this instance of JIRA and print out each username. 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | import com.atlassian.jira.user.util.UserManager 9 | 10 | /* Debugging */ 11 | import org.apache.log4j.Logger 12 | def log = Logger.getLogger("com.acme.XXX") 13 | 14 | UserManager userManager = ComponentAccessor.getUserManager() 15 | userManager.getAllApplicationUsers().each{ u -> 16 | log.debug u.username 17 | } -------------------------------------------------------------------------------- /script-snippets/getLinkedIssues.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name getLinkedIssues.groovy 3 | * @type script snippet 4 | * @brief Get all Issues objects that are linked to a specified issue and print out each summary. 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | import com.atlassian.jira.issue.MutableIssue 9 | import com.atlassian.jira.issue.IssueManager 10 | import com.atlassian.jira.issue.CustomFieldManager 11 | 12 | /* Debugging */ 13 | import org.apache.log4j.Logger 14 | def log = Logger.getLogger("com.acme.XXX") 15 | 16 | MutableIssue issue = ComponentAccessor.getIssueManager().getIssueObject('ISSUE-100') 17 | IssueManager issueManager = ComponentAccessor.getIssueManager() 18 | CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager() 19 | 20 | def linkedIssues = ComponentAccessor.issueLinkManager.getInwardLinks(issue.getId()) 21 | if (linkedIssues.size() > 0) { 22 | linkedIssues.each{ iss -> 23 | def linkedIssue = issueManager.getIssueObject(iss.destinationId) 24 | 25 | // Do something with each linked issue. 26 | log.debug(linkedIssue.getSummary()) 27 | 28 | } 29 | return true 30 | } else { 31 | log.debug("No 'inward link' linked issues found.") 32 | return "This issue has no inward-linked issues. Please try a different issue or contact a JIRA administrator." 33 | } -------------------------------------------------------------------------------- /script-snippets/jqlSearch.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name jqlSearch.groovy 3 | * @type script snippet 4 | * @brief Gets all issues which match a JQL query and print out each summary. 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | import com.atlassian.jira.user.ApplicationUser 9 | import com.atlassian.jira.issue.search.SearchProvider 10 | import com.atlassian.jira.issue.IssueManager 11 | import com.atlassian.jira.jql.parser.JqlQueryParser 12 | import com.atlassian.jira.web.bean.PagerFilter 13 | import com.atlassian.jira.issue.MutableIssue 14 | import org.apache.log4j.Logger 15 | def log = Logger.getLogger("com.acme.XXX") 16 | 17 | JqlQueryParser jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser) 18 | SearchProvider searchProvider = ComponentAccessor.getComponent(SearchProvider) 19 | IssueManager issueManager = ComponentAccessor.getIssueManager() 20 | ApplicationUser user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 21 | 22 | // Replace this string with your desired JQL query. 23 | String queryString = "assignee = currentUser()" 24 | 25 | def query = jqlQueryParser.parseQuery(queryString) 26 | def results = searchProvider.search(query, user, PagerFilter.getUnlimitedFilter()) 27 | 28 | log.debug("Returned ${results.total} issues that matched the query.") 29 | 30 | if (results.total > 0) { 31 | results.getIssues().each {documentIssue -> 32 | MutableIssue issue = issueManager.getIssueObject(documentIssue.id) 33 | 34 | // Do something with each issue. 35 | log.debug("Summary: ${issue.summary}") 36 | 37 | } 38 | } else { 39 | log.debug("No issues matched this query. Please try another or contact a JIRA administrator.") 40 | return false 41 | } 42 | 43 | return true -------------------------------------------------------------------------------- /script-snippets/newMerge.groovy: -------------------------------------------------------------------------------- 1 | import com.atlassian.jira.component.ComponentAccessor 2 | import com.atlassian.jira.issue.fields.CustomField 3 | import com.atlassian.jira.issue.MutableIssue 4 | import java.text.SimpleDateFormat 5 | 6 | /* Debugging */ 7 | import org.apache.log4j.Logger 8 | def log = Logger.getLogger("com.acme.XXX") 9 | 10 | /* Get timestamp */ 11 | def date = new Date() 12 | def sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss") 13 | def formattedDate = sdf.format(date) 14 | 15 | // The current issue 16 | MutableIssue mergingIssue = ComponentAccessor.getIssueManager().getIssueObject('AT-3082') 17 | 18 | CustomField mainIssueField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject('customfield_12108') 19 | String mainIssueValue = mergingIssue.getCustomFieldValue(mainIssueField) 20 | MutableIssue mainIssue = ComponentAccessor.getIssueManager().getIssueObject(mainIssueValue) 21 | 22 | // Merge styles 23 | String mergeHeader = '\n\n*MERGE* ' + mergingIssue.getKey() + ' | ' + formattedDate + '\n---------------------------------------\n' 24 | 25 | // Merge descriptions 26 | String description = mainIssue.getDescription() 27 | description += (mergeHeader + mergingIssue.getDescription()) 28 | mainIssue.setDescription(description) 29 | 30 | // Merge comments 31 | def mergingIssueComments = ComponentAccessor.getCommentManager().getComments(mergingIssue) 32 | for (comment in mergingIssueComments) { 33 | log.debug comment.getBody() 34 | } 35 | 36 | -------------------------------------------------------------------------------- /script-snippets/specific-snippets/getAllUsersNotInGroup.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name getAllUsersNotInGroup.groovy 3 | * @type script snippet 4 | * @brief Get all users in this instance of JIRA that aren't in a specified group, and print out each username. 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | import com.atlassian.jira.user.util.UserManager 9 | import com.atlassian.jira.security.groups.GroupManager 10 | 11 | /* Debugging */ 12 | import org.apache.log4j.Logger 13 | def log = Logger.getLogger("com.acme.XXX") 14 | 15 | UserManager userManager = ComponentAccessor.getUserManager() 16 | GroupManager groupManager = ComponentAccessor.getGroupManager() 17 | 18 | userManager.getAllApplicationUsers().each{ u -> 19 | if (groupManager.isUserInGroup(u.username, 'group-name')) { 20 | // Do something with each user. 21 | log.debug u.username 22 | } 23 | } -------------------------------------------------------------------------------- /script-snippets/specific-snippets/updateBrands.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name updateBrands.groovy 3 | * @type Script snippet 4 | * @brief For every issue matching a JQL query, copy the value in "Brand" to the custom label field "Brand (ATW)". 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | import com.atlassian.jira.issue.MutableIssue 9 | import com.atlassian.jira.user.ApplicationUser 10 | import com.atlassian.jira.event.type.EventDispatchOption 11 | import com.atlassian.jira.issue.search.SearchProvider 12 | import com.atlassian.jira.jql.parser.JqlQueryParser 13 | import com.atlassian.jira.web.bean.PagerFilter 14 | import com.atlassian.jira.issue.label.LabelManager 15 | import com.atlassian.jira.issue.label.Label 16 | import java.util.Set 17 | 18 | /* Debugging */ 19 | import org.apache.log4j.Logger 20 | def log = Logger.getLogger("com.acme.XXX") 21 | 22 | JqlQueryParser jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser) 23 | SearchProvider searchProvider = ComponentAccessor.getComponent(SearchProvider) 24 | IssueManager issueManager = ComponentAccessor.getIssueManager() 25 | ApplciationUser user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 26 | 27 | LabelManager labelManager = ComponentAccessor.getComponent(LabelManager) 28 | 29 | String queryString = "issuetype = 'ATW Equipment' and brand is not empty" 30 | 31 | def query = jqlQueryParser.parseQuery(queryString) 32 | def results = searchProvider.search(query, user, PagerFilter.getUnlimitedFilter()) 33 | log.debug("Total issues: ${results.total}") 34 | 35 | results.getIssues().each {documentIssue -> 36 | 37 | MutableIssue issue = issueManager.getIssueObject(documentIssue.id) 38 | String brand = issue.getCustomFieldValue(ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName('Brand')) 39 | 40 | def brandLabelField = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName('Brand (ATW)') 41 | def brandLabels = labelManager.getLabels(issue.id, brandLabelField.getIdAsLong()).collect{ it.getLabel() } 42 | 43 | brandLabels += brand 44 | 45 | labelManager.setLabels(user, issue.id, brandLabelField.getIdAsLong(), brandLabels.toSet(), false, false) 46 | // storeChanges(issue, user) 47 | 48 | } 49 | 50 | // Persist changes in the database. 51 | def storeChanges(MutableIssue issue, ApplicationUser user) { 52 | try { 53 | ComponentAccessor.getIssueManager().updateIssue( 54 | user, 55 | issue, 56 | EventDispatchOption.ISSUE_UPDATED, 57 | false 58 | ) 59 | } catch (Exception e) { 60 | log.debug "Exception: " + e 61 | } 62 | } -------------------------------------------------------------------------------- /script-snippets/specific-snippets/writeToExistingConfPage.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import getpass 3 | import sys 4 | 5 | import json 6 | import keyring 7 | import requests 8 | 9 | #----------------------------------------------------------------------------- 10 | # Globals 11 | 12 | BASE_URL = "https://example.com" 13 | 14 | VIEW_URL = "https://example.com" 15 | 16 | 17 | def pprint(data): 18 | ''' 19 | Pretty prints json data. 20 | ''' 21 | print json.dumps( 22 | data, 23 | sort_keys = True, 24 | indent = 4, 25 | separators = (', ', ' : ')) 26 | 27 | 28 | def get_page_ancestors(auth, pageid): 29 | 30 | # Get basic page information plus the ancestors property 31 | 32 | url = '{base}/{pageid}?expand=ancestors'.format( 33 | base = BASE_URL, 34 | pageid = pageid) 35 | 36 | r = requests.get(url, auth = auth) 37 | 38 | r.raise_for_status() 39 | 40 | return r.json()['ancestors'] 41 | 42 | 43 | def get_page_info(auth, pageid): 44 | 45 | url = '{base}/{pageid}'.format( 46 | base = BASE_URL, 47 | pageid = pageid) 48 | 49 | r = requests.get(url, auth = auth) 50 | 51 | r.raise_for_status() 52 | 53 | return r.json() 54 | 55 | 56 | def write_data(auth, html, pageid, title = None): 57 | 58 | info = get_page_info(auth, pageid) 59 | 60 | ver = int(info['version']['number']) + 1 61 | 62 | ancestors = get_page_ancestors(auth, pageid) 63 | 64 | anc = ancestors[-1] 65 | del anc['_links'] 66 | del anc['_expandable'] 67 | del anc['extensions'] 68 | 69 | if title is not None: 70 | info['title'] = title 71 | 72 | data = { 73 | 'id' : str(pageid), 74 | 'type' : 'page', 75 | 'title' : info['title'], 76 | 'version' : {'number' : ver}, 77 | 'ancestors' : [anc], 78 | 'body' : { 79 | 'storage' : 80 | { 81 | 'representation' : 'storage', 82 | 'value' : str(html), 83 | } 84 | } 85 | } 86 | 87 | data = json.dumps(data) 88 | 89 | url = '{base}/{pageid}'.format(base = BASE_URL, pageid = pageid) 90 | 91 | r = requests.put( 92 | url, 93 | data = data, 94 | auth = auth, 95 | headers = { 'Content-Type' : 'application/json' } 96 | ) 97 | 98 | r.raise_for_status() 99 | 100 | print "Wrote '%s' version %d" % (info['title'], ver) 101 | print "URL: %s%d" % (VIEW_URL, pageid) 102 | 103 | 104 | def get_login(username = None): 105 | ''' 106 | Get the password for username out of the keyring. 107 | ''' 108 | 109 | if username is None: 110 | username = getpass.getuser() 111 | 112 | passwd = keyring.get_password('confluence_script', username) 113 | 114 | if passwd is None: 115 | passwd = getpass.getpass() 116 | keyring.set_password('confluence_script', username, passwd) 117 | 118 | return (username, passwd) 119 | 120 | 121 | def main(): 122 | 123 | parser = argparse.ArgumentParser() 124 | 125 | parser.add_argument( 126 | "-u", 127 | "--user", 128 | default = getpass.getuser(), 129 | help = "Specify the username to log into Confluence") 130 | 131 | parser.add_argument( 132 | "-t", 133 | "--title", 134 | default = None, 135 | type = str, 136 | help = "Specify a new title") 137 | 138 | parser.add_argument( 139 | "-f", 140 | "--file", 141 | default = None, 142 | type = str, 143 | help = "Write the contents of FILE to the confluence page") 144 | 145 | parser.add_argument( 146 | "pageid", 147 | type = int, 148 | help = "Specify the Conflunce page id to overwrite") 149 | 150 | parser.add_argument( 151 | "html", 152 | type = str, 153 | default = None, 154 | nargs = '?', 155 | help = "Write the immediate html string to confluence page") 156 | 157 | options = parser.parse_args() 158 | 159 | auth = get_login(options.user) 160 | 161 | if options.html is not None and options.file is not None: 162 | raise RuntimeError( 163 | "Can't specify both a file and immediate html to write to page!") 164 | 165 | if options.html: 166 | html = options.html 167 | 168 | else: 169 | 170 | with open(options.file, 'r') as fd: 171 | html = fd.read() 172 | 173 | write_data(auth, html, options.pageid, options.title) 174 | 175 | 176 | if __name__ == "__main__" : main() 177 | -------------------------------------------------------------------------------- /script-snippets/updateLabels.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * @name updateLabels.groovy 3 | * @type script snippet 4 | * @brief Add labels to a custom field of type Labels for a specified issue. 5 | */ 6 | 7 | import com.atlassian.jira.component.ComponentAccessor 8 | import com.atlassian.jira.issue.label.LabelManager 9 | import com.atlassian.jira.user.ApplicationUser 10 | import com.atlassian.jira.issue.MutableIssue 11 | import com.atlassian.jira.issue.fields.CustomField 12 | 13 | /* Debugging */ 14 | import org.apache.log4j.Logger 15 | Logger log = Logger.getLogger("com.acme.XXX") 16 | 17 | LabelManager labelManager = ComponentAccessor.getComponent(LabelManager) 18 | ApplicationUser user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() 19 | MutableIssue issue = ComponentAccessor.getIssueManager().getIssueObject('ISSUE-100') 20 | 21 | if (issue) { 22 | CustomField customLabelField = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName('AT Labels') 23 | if (customLabelField) { 24 | def customLabels = labelManager.getLabels(issue.id, customLabelField.getIdAsLong()).collect{ it.getLabel() } 25 | customLabels += 'your-new-label' 26 | labelManager.setLabels(user, issue.id, customLabelField.getIdAsLong(), customLabels.toSet(), false, false) 27 | return "No errors occurred while updating labels." 28 | } else { 29 | log.debug('customLabelField is null, meaning the field name referenced is not valid.') 30 | return "Couldn't find the field you're looking for. Please contact a JIRA administrator." 31 | } 32 | } else { 33 | log.debug('issue is null, meaning the issue key referenced is not valid.') 34 | return "There was an error finding this Issue. Please contact a JIRA administrator." 35 | } --------------------------------------------------------------------------------