Sunshine-jcy

JIRA Agile 脚本注解参考

1. 批量修改Summary为需求标题

import com.atlassian.jira.component.ComponentAccessor
import org.apache.log4j.Level
 
log.setLevel(Level.DEBUG)
 
def user = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def projectManager = ComponentAccessor.projectManager
def issueManager = ComponentAccessor.issueManager
def cfManager = ComponentAccessor.customFieldManager
 
def cfReqTitle = cfManager.getCustomFieldObjectsByName("需求标题").first()
 
def vpProjects = projectManager.projects.findAll {
    it.projectCategory?.name == "VP传统项目"
}
 
def issueList = vpProjects.collect { project ->
    issueManager.getIssueIdsForProject(project.id).findAll {
        def issue = issueManager.getIssueObject(it)
        def summary = issue.summary
        def reqTitle = issue.getCustomFieldValue(cfReqTitle)
        reqTitle != null && summary != reqTitle
    }
}.flatten()
 
issueList.each {
    def issue = issueManager.getIssueObject(it as Long)
    def reqTitle = issue.getCustomFieldValue(cfReqTitle)
    // issue.summary = reqTitle
    log.info "${issue.key}: summary: ${issue.summary} => 需求标题: ${reqTitle}"
}

2. 查找VPID重复的Issue

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import org.apache.log4j.Level
 
import com.atlassian.activeobjects.external.ActiveObjects
import com.onresolve.scriptrunner.runner.ScriptRunnerImpl
def ao = ScriptRunnerImpl.getOsgiService(ActiveObjects)
 
log.setLevel(Level.DEBUG)
 
def projectManager = ComponentAccessor.projectManager
def issueManager = ComponentAccessor.issueManager
def changeHistoryManager = ComponentAccessor.changeHistoryManager
def cfManager = ComponentAccessor.customFieldManager
def cfVPID = cfManager.getCustomFieldObjectsByName("VPID").first()
 
def getVPIssues = {
    projectManager.projects.findAll {
        it.projectCategory?.name == "VP传统项目"
    }.collect { project ->
        def ids = issueManager.getIssueIdsForProject(project.id)
        issueManager.getIssueObjects(ids)
    }.flatten()
}
 
def getVPIDIssueMap = {
    getVPIssues().findAll {
        def issue = it as Issue
        issue.getCustomFieldValue(cfVPID) != null
    }.groupBy {
        def issue = it as Issue
        issue.getCustomFieldValue(cfVPID)
    }
}
 
def vpidIssueMap = getVPIDIssueMap()

3. 查找关联需求

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import org.apache.log4j.Level
 
log.setLevel(Level.DEBUG)
 
def projectManager = ComponentAccessor.projectManager
def issueManager = ComponentAccessor.issueManager
 
def cfManager = ComponentAccessor.customFieldManager
def cfRelatedReqNo = cfManager.getCustomFieldObjectsByName("关联需求编号").first()
def cfReqNo = cfManager.getCustomFieldObjectsByName("VP需求编号").first()
 
def vpIssues = projectManager.projects.findAll {
    it.projectCategory?.name == "VP传统项目"
}.collectMany { project ->
    def ids = issueManager.getIssueIdsForProject(project.id)
    issueManager.getIssueObjects(ids)
}
 
def reqIssueMap = vpIssues.collectMany{
    def issue = it as Issue
    def reqNo = issue.getCustomFieldValue(cfReqNo) as String
    reqNo ? [[reqNo, issue]] : []
}.collectEntries()
 
vpIssues.each {
    def issue = it as Issue
    def relatedReqNo = issue.getCustomFieldValue(cfRelatedReqNo) as String
    if (relatedReqNo) {
        def reqNoList = relatedReqNo.split(";")
        reqNoList.each {
            Issue target = reqIssueMap[it]
            if (target) {
                log.info("${issue.key} => ${target.key}")
            }
        }
    }
}

 

4. 在【发布预告】issue created listener 中自动创建 2 个 Sprint(确认上线清单、待上线清单),并将该 issue 加入到第一个 Sprint 中

  • 脚本类型:监听
  • 作用范围:所有项目
  • 监听事件:Issue Created
import com.atlassian.jira.issue.Issue
import com.atlassian.greenhopper.service.rapid.view.RapidViewService
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.greenhopper.service.sprint.SprintService
import com.atlassian.greenhopper.service.sprint.SprintIssueService
import com.atlassian.greenhopper.model.rapid.RapidView
import com.atlassian.jira.component.ComponentAccessor
import com.onresolve.scriptrunner.runner.customisers.JiraAgileBean
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import org.apache.log4j.Level
  
log.setLevel(Level.DEBUG)
 
@WithPlugin("com.pyxis.greenhopper.jira")
  
@JiraAgileBean
RapidViewService rapidViewService
  
@JiraAgileBean
SprintService sprintService
 
@JiraAgileBean
SprintIssueService sprintIssueService
  
// 脚本功能介绍: 在【发布预告】issue created listener 中自动创建 2 个 Sprint(确认上线清单、待上线清单),并将该 issue 加入到第一个 Sprint 中
 
def currentUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
  
  
def createSprint = { String sprintName, RapidView rapidView ->
    Sprint sprint = Sprint.builder().with {
        name(sprintName)
        rapidViewId(rapidView.id)
    }.build()
  
    def result = sprintService.createSprint(currentUser, sprint)
    def s = result.value
    log.info("sprint 自动创建成功。sprint:" + s)
    return s
}
  
if (issue.issueType.name == '发布预告') {
    def project = issue.projectObject
    def rapidViewName = "${project.key}发布面板"
    RapidView rapidView = rapidViewService.findRapidViewsByName(currentUser, rapidViewName).value.first()
    
    if (rapidView == null){
        log.error("sprint 自动创建失败。${project.key}发布面板  不存在。")
    else {
        // 注意:sprint 创建有先后顺序。先建  确认上线清单,再建  待上线清单
        Sprint s = createSprint("确认上线清单 ${issue.key}", rapidView)
        createSprint("待上线清单 ${issue.key}", rapidView)
         
        // 把刚刚创建的【发布预告】issue 加入其中的 确认上线清单
        if(s != null){
            log.info("把刚刚创建的【发布预告】issue ( ${issue.key} ) 加入确认上线清单。sprint:"+ s)
            Collection<Issue> issueList = new ArrayList<Issue>()
            issueList.add(issue)
            sprintIssueService.moveIssuesToSprint(currentUser, s, issueList)
        }
         
    }
     
}

5. 监听所有 “确认上线清单”、“待上线清单” sprint,一旦有 sprint Active 了,就发邮件通知这个 sprint 中所有 issue 的 reporter(此脚本已经不用了)

  • 脚本类型:监听
  • 作用范围:所有项目
  • 监听事件:Sprint Started Event
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.mail.Email
import com.atlassian.mail.server.SMTPMailServer
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.greenhopper.service.sprint.Sprint.State
import com.atlassian.greenhopper.service.sprint.SprintIssueService
import com.onresolve.scriptrunner.runner.customisers.JiraAgileBean
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import org.apache.log4j.Level
   
log.setLevel(Level.DEBUG)
  
@WithPlugin("com.pyxis.greenhopper.jira")
 
@JiraAgileBean
SprintIssueService sprintIssueService
 
// 功能描述: 监听所有 “确认上线清单”、“待上线清单” sprint,一旦有 sprint Active 了,就发邮件通知这个 sprint 中所有 issue 的 reporter
 
def currentUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
 
SMTPMailServer mailServer = ComponentAccessor.getMailServerManager().getDefaultSMTPMailServer()
 
def sprint = event.sprint as Sprint
 
if (sprint.state == Sprint.State.ACTIVE) {
     
    if (sprint.getName().contains("确认上线清单") || sprint.getName().contains("待上线清单")) {
         
        def emailSubject = "本周上线清单已更新,请留意上线预告仪表板"
        def emailBody = "您提交的需求/生产缺陷已加入“${sprint.getName()}”,请确认或查看。"
 
        def outcome = sprintIssueService.getIssuesForSprint(currentUser, sprint)
        Iterable<Issue> issues = outcome.getValue()
        LinkedHashSet<String> emails = new LinkedHashSet<String>()
        issues.each {
            def issue = it as Issue
            //def projectCategory = issue.getProjectObject().projectCategory
            //if (projectCategory != null){
              //  if (projectCategory.name == "VP传统项目" || projectCategory.name == "自研项目") {
                    ApplicationUser reporter = issue.getReporter()
                    if (reporter != null) {
                        def emailAddress = reporter.getEmailAddress()
                        if (emailAddress != null) {
                            emails.add(emailAddress)
                        }
                    }
                //}
            //}
        }
 
        emails.each {
            def emailAddress = it as String
            Email email = new Email(emailAddress)
            email.setSubject(emailSubject)
            email.setBody(emailBody)
            mailServer.send(email)
        }
     
    }
     
     
}

6. VP 【需求】已有 issue:申请人 → 申请人员  处理(本脚本只执行一次)

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.MutableIssue
import org.apache.log4j.Level
    
import com.atlassian.activeobjects.external.ActiveObjects
import com.onresolve.scriptrunner.runner.ScriptRunnerImpl
import com.atlassian.jira.bc.JiraServiceContextImpl;
import com.atlassian.jira.bc.JiraServiceContext;
import com.atlassian.jira.bc.issue.search.SearchService;
import com.atlassian.jira.bc.user.search.UserSearchParams;
import com.atlassian.jira.bc.user.search.UserSearchService;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.security.JiraAuthenticationContext;
import com.atlassian.jira.event.type.EventDispatchOption;
   
// 脚本功能说明:VP传统项目 【需求】已有 issue:申请人 → 申请人员  处理(本脚本只执行一次)
def ao = ScriptRunnerImpl.getOsgiService(ActiveObjects)
    
log.setLevel(Level.DEBUG)
   
def loggedInUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def projectManager = ComponentAccessor.projectManager
def issueManager = ComponentAccessor.issueManager
def userManager = ComponentAccessor.userManager
def userSearchService = ComponentAccessor.userSearchService
def changeHistoryManager = ComponentAccessor.changeHistoryManager
def cfManager = ComponentAccessor.customFieldManager
def cf_SQR = cfManager.getCustomFieldObjectsByName("申请人").first()
def cf_SQRY = cfManager.getCustomFieldObjectsByName("申请人员").first()
   
def getVPIssues = {
    projectManager.projects.findAll {
        it.projectCategory?.name == "VP传统项目"
    }.collect { project ->
        def ids = issueManager.getIssueIdsForProject(project.id)
        issueManager.getIssueObjects(ids)
    }.flatten()
}
   
getVPIssues().findAll {
    def issue = it as MutableIssue
      
    if (issue.issueType.name == "需求") {
        log.info("开始处理 VP传统项目 【需求】已有 issue(" + issue.key + "):“申请人”-->“申请人员”..." )
          
        def sqrValue = issue.getCustomFieldValue(cf_SQR)
        if (sqrValue != null && !"".equals(sqrValue)) {
            def s = sqrValue.toString();
            /**
            * “申请人员” 匹配规则:
            *
            * 0. 若“申请人”为空,则将“申请人员”设置为 IT_Service
            * 1. “申请人”里面,如果包含  中英文逗号、中英文分号、中文顿号  写了多个人名,那么只处理标点之前的第一个
            * 2. 根据人名,在 JIRA 里面找用户,如果能够找到唯一一个,那么就用这个用户
            * 3. 如果没有找到,则用 IT_Service
            * 4. 如果有多个,优先选择邮箱是 @tpl.cntaiping.com 的。若邮箱均不包含 @tpl.cntaiping.com,则用 IT_Service。
            * 5. 如果还有多个,判断部门(这条下一版本做)
            * 6. 还有多个,用 IT_Service(这条下一版本做)
            */
            // 只处理第一个人名
            if (s.contains(",")) {
                s = s.substring(0, s.indexOf(","));
            else if (s.contains(";")) {
                s = s.substring(0, s.indexOf(";"));
            else if (s.contains(",")) {
                s = s.substring(0, s.indexOf(","));
            else if (s.contains(";")) {
                s = s.substring(0, s.indexOf(";"));
            else if (s.contains("、")) {
                s = s.substring(0, s.indexOf("、"));
            }
            s = s.trim();
   
            JiraServiceContext jsc = new JiraServiceContextImpl(loggedInUser);
            UserSearchParams userSearchParams = new UserSearchParams(falsetruetrue);
            List<ApplicationUser> userList0 = userSearchService.findUsers(jsc, s, userSearchParams);
            // 上一行只是模糊搜索。接下来对姓名进行精准匹配:
            ArrayList<ApplicationUser> userList2 = new ArrayList<>();
            for (ApplicationUser u : userList0) {
                if (s.equals(u.getUsername()) || s.equals(u.getDisplayName())) {
                    userList2.add(u);
                }
            }
   
            ApplicationUser user = null;
            if (userList2.size() == 1) {
                // 只找到一个用户
                user = userList2.get(0);
            else if (userList2.size() > 1) {
                // 找到多个用户,优先选择邮箱是 @tpl.cntaiping.com 的。若邮箱均不包含 @tpl.cntaiping.com,则用 IT_Service。
                boolean foundByTPL = false;
                for (ApplicationUser u : userList2) {
                    if (u.getEmailAddress().contains("@tpl.cntaiping.com")) {
                        foundByTPL = true;
                        user = u;
                        break;
                    }
                }
                if (!foundByTPL) {
                    user = userManager.getUserByName("IT_Service");
                }
            else {
                // 找到 0 个用户
                user = userManager.getUserByName("IT_Service");
            }
            if (user != null) {
                issue.setCustomFieldValue(cf_SQRY, user);
                issueManager.updateIssue(loggedInUser,issue, EventDispatchOption.DO_NOT_DISPATCH, false)
            }
        else {
            issue.setCustomFieldValue(cf_SQRY, userManager.getUserByName("IT_Service"));
            issueManager.updateIssue(loggedInUser,issue, EventDispatchOption.DO_NOT_DISPATCH, false)
        }
    }  
}

7. 【发布预告】流转到需求管理人时,在点击 issue 界面中的 “已标记确认” 按钮后,状态变更时触发:post function 脚本中让【发布预告】所在 sprint 中的需求及生产缺陷的 “标签” 字段值变为 “确认上线”,并将该 sprint acitve

  • 脚本类型:工作流脚本
  • 作用范围:Launch Workflow 中的 action “已标记确认”,见下图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.label.Label
import com.atlassian.jira.issue.label.LabelManager
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.greenhopper.service.sprint.Sprint.State
import com.atlassian.greenhopper.service.sprint.SprintService
import com.atlassian.greenhopper.service.sprint.SprintIssueService
import com.onresolve.scriptrunner.runner.customisers.JiraAgileBean
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.atlassian.jira.event.type.EventDispatchOption
import org.apache.log4j.Level
import java.util.*
    
log.setLevel(Level.DEBUG)
   
@WithPlugin("com.pyxis.greenhopper.jira")
  
@JiraAgileBean
SprintIssueService sprintIssueService
 
@JiraAgileBean
SprintService sprintService
 
def issueManager = ComponentAccessor.issueManager
def labelManager = ComponentAccessor.getComponent(LabelManager)
def loggedInUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
 
// 功能描述:让【发布预告】所在 sprint 中的需求及生产缺陷的 “标签” 字段值变为 “确认上线”,并将该 sprint acitve。
 
log.info("------ 【发布预告】" + issue.getKey() + "“已标记确认”。开始查询该 issue 所属 sprint 中的 需求、生产缺陷:")
 
def sprints_outcome = sprintIssueService.getSprintsForIssue(loggedInUser, issue)
Iterable<Sprint> sprints = sprints_outcome.getValue()
sprints.each {
    def sprint = it as Sprint
    log.info("所属 sprint:" + sprint.getName())
    def issues_outcome = sprintIssueService.getIssuesForSprint(loggedInUser, sprint)
    Iterable<Issue> issues = issues_outcome.getValue()
    issues.each {
        def issue2 = it as Issue
        def mutableIssue = issueManager.getIssueObject(issue2.getId())
        def mutableIssue_issueTypeName = mutableIssue.getIssueType().getName()
        if ("需求".equals(mutableIssue_issueTypeName) || "生产缺陷".equals(mutableIssue_issueTypeName)) {
            log.info("找到符合要求的 issue:" + mutableIssue.getKey() + ",开始修改其 “标签” 字段值为 “确认上线”...")
            // 先清空原有 label
            mutableIssue.setLabels(new HashSet<Label>())
            issueManager.updateIssue(loggedInUser, mutableIssue, EventDispatchOption.DO_NOT_DISPATCH, false)
            // 再设置 label
            labelManager.addLabel(loggedInUser, mutableIssue.getId(), "确认上线", false)
        }
    }
     
    if (sprint.isFuture()) {
        log.info("开始 active 当前 sprint...")
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 24);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        // active sprint 之前,必须先设置开始时间和结束时间
        // 将 sprint 的开始时间设置为现在,结束时间设置为今晚 24 点
        Sprint sprint2 = Sprint.builder(sprint).startDate(new Date().getTime()).endDate(calendar.getTimeInMillis()).state(Sprint.State.ACTIVE).build();
        sprintService.updateSprint(loggedInUser, sprint2)
    }
    
}

 

8. VP传统项目 >> 【需求】工作流 >> “已发布” 的 post function:若 sprint 不为空且“用户确认发布”为空,则设置“用户确认发布”为发布,“确认上线操作用户”取“申请人员”。

import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.greenhopper.service.sprint.Sprint.State
import com.atlassian.greenhopper.service.sprint.SprintService
import com.atlassian.greenhopper.service.sprint.SprintIssueService
import com.onresolve.scriptrunner.runner.customisers.JiraAgileBean
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.util.UserManager
import org.apache.log4j.Level
 
log.setLevel(Level.DEBUG)
 
// 功能描述:若 sprint 不为空且“用户确认发布”为空,则设置“用户确认发布”为发布,“确认上线操作用户”取“申请人员”。
// 部署位置:VP传统项目  >>  【需求】工作流  >>  “已发布” 的 post function。
 
@WithPlugin("com.pyxis.greenhopper.jira")
 
@JiraAgileBean
SprintIssueService sprintIssueService
 
@JiraAgileBean
SprintService sprintService
 
def issueManager = ComponentAccessor.issueManager
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def userManager = ComponentAccessor.getUserManager()
def optionsManager = ComponentAccessor.getOptionsManager()
 
log.info("------ See if Sprint field is empty --------")
 
 
def sprints_outcome_iterator = sprintIssueService.getSprintsForIssue(userManager.getUserByName("IT_Service"), issue).getValue().iterator()
def confirm_field = customFieldManager.getCustomFieldObjectsByName("用户确认发布").iterator();
 
if (!confirm_field.hasNext()) {
    log.error("找不到 '用户确认发布' 自定义字段!!!")
    return
}
 
MutableIssue mutableIssue = issueManager.getIssueObject(issue.getId())
def cf = confirm_field.next()
def confirm = cf.getValue(issue)
 
log.info('sprints_outcome_iterator.hasNext() : ' + sprints_outcome_iterator.hasNext())
log.info('confirm : '+ confirm)
if (sprints_outcome_iterator.hasNext() && confirm == null) {
    log.info("------ sprint 不为空,但'用户确认发布'为空。需要自动修复 --------")
 
    def operator = customFieldManager.getCustomFieldObjectsByName("确认上线操作用户").iterator();
    def applier = customFieldManager.getCustomFieldObjectsByName("申请人员").iterator();
 
    if (!operator.hasNext() || !applier.hasNext()) {
        log.error("找不到 '确认上线操作用户' 自定义字段 或 '申请人员' 自定义字段!!!")
        return
    }
 
    // 设置 “用户确认发布” 为发布
    def optionVal = optionsManager.getOptions(cf.getRelevantConfig(issue)).getOptionForValue("发布"null)
    log.info("optionVal:" + optionVal)
    mutableIssue.setCustomFieldValue(cf, optionVal)
 
    // 设置 “确认上线操作用户” 取 “申请人员”
    def user_field = applier.next()
    if (user_field != null) {
        def user = issue.getCustomFieldValue(user_field) as ApplicationUser
        mutableIssue.setCustomFieldValue(operator.next(), user)
    }
 
    issueManager.updateIssue(userManager.getUserByName("IT_Service"), mutableIssue, EventDispatchOption.DO_NOT_DISPATCH, false)
}

posted on 2021-02-09 18:45  Sunshine-jcy  阅读(205)  评论(1编辑  收藏  举报

导航