windows+jdk1.8+jenkins+jira+远程生成问题工单

需求来源:近公司要求项目中对接jenkins,使用jenkins与jira交互,将项目中扫描出的漏洞自动在Jira上生成Bug工单,指定人员去修复,之前项目我也没参与,这两个工具也没使用过,但要求一周内完成对接,着实焦虑,下面是在开发过程中的一些步骤,希望能给其他同行少走一点弯路。

本文相关工具下载 windows+jdk.18+jenkins+jira+java+cmd+jira自动生成问题工单-Java文档类资源-CSDN文库icon-default.png?t=M85Bhttps://download.csdn.net/download/qq_31497435/86831955

 

一:在windows系统上安装jdk1.8(如何安装自行摸索)

二:安装Jira

① 双击exe文件,打开后,点击next

 ②  选择Custom Install,next

 ③. 设置安装路径,next

④. 设置home文件夹路径  next

⑤. next

 ⑥. 修改默认端口 next

⑦. next

 ⑧ . next

⑨. 安装中,等待...

 ⑩ 安装完成 next

 ⑩①. 软件启动中,稍等...

 ⑩②. 完成,点击Finish,将会自动打开Jira网页

 此处自动打开的Jira网页不要动,后面还要破解

三:Jira破解

①. 关闭Jira软件

②. 将破解的jar包与mysql数据库的连接jar包,放置安装目录中,是在Jira SoftWare\atlassian-jira\WEB-INF\lib下,与前面的安装目录对应,路径看下图,然后重启Jira

 ③. 重启后稍等几秒后,刷新Jira网页,会看到Jira正在启动并初始化...

 ④. 启动并初始化成功后,需要对Jira数据库进行配置,可选Jira的内置数据库,可以自己配置数据库,在配置数据库的时候我选了自己的,但发现版本过高时总是连接不上,于是选了mysql5.6版,这个库一般用不着。(如果想选自己的库,需要安装mysql5.6,具体安装步骤与安装包自行摸索),信息填写完后,点击“测试连接”,在上方出现如图中的连接测试成功,则点击下一步。

 ⑤. 设置Jira应用程序属性,记住这两个属性,做好不要改,在后面Jenkins中要使用,点击下一步

 ⑥. 记住这个页面的服务器ID,这里要输入许可证,我们没有许可证,需要去官网获取,获取时后面要使用这个服务器ID,要用邮箱注册

 ⑦. 注册成功会打开管理,点击“New Trial License”

 ⑧. 之后进入以下页面,按图操作,选择Jira Software - Jira Software(Data Center),生成许可证

 ⑨. 复制生成的许可证,填写到Jira中(此处获得的许可证其实是使用许可证,但上面添加的破解Jar包会改变使用日期)

 

 ⑩. 添加管理员账号,完成,等待Jira自动执行安装的最后一步

 

 安装成功之后会让你选择语言(中国)、头像等,最终进入以下界面:

选择 “导入问题”,然后 “跳过”  ,去往Jira主界面

 四:Jira 创建项目与集成

①. 在主界面创建项目,选择“任务管理”,下一步。(我主要是用来自动发布bug任务给指定的人去修复)

 

 ②. 直接点“选择”进入下一阶段,填写项目名称与关键字,要记住这个关键字,后面Jenkins要用到.  然后提交即可。

 

 ③. 前面忘记查看许可证了,这里说一下,点击右上角的齿轮设置按钮-选择应用程序,可能让你重新登录,登录输入管理员密码即可,进入应用程序界面,可以看到许可证还有十几年才过期。

 ④. 点击“问题”,可以看到四种问题类型,分别为:Epic、任务、故事、子任务。  我是要创建BUG,那么我们来新增一个BUG类型,点击右边的“添加问题类型”

 

 ⑤. 新增类型成功后你还可以编辑它,给它一个图标。现在我们要进入“问题类型方案”模块,可以看到BUG这个类型并不在我创建的项目中,代表这个项目还无法使用它,点击编辑

以拖拽的形式将BUG类型拖到左边来,保存。

 ⑥. 让Jira可以访问Jenkins,点击应用程序链接,进行配置

特别申明:此时应该停下来先安装好Jenkins,可查看下方第五大项

 

 

 ⑦. 应用程序链接创建成功后,再次编辑它,去配置 传出认证,开启,之后可以在列表上直接跳转到Jenkins。

 

五:Jenkins的安装与配置

①. 下载可兼容jdk1.8版本的jenkins.war,下载地址 https://get.jenkins.io/war-stable/ 这里有点坑,版本下低了,后面的jenkins上安装jira插件时会因为jdk版本原因导致失败,版本选高了又不符合项目的jdk设定,我尝试几个版本后选择的是 jenkins-2.346.1.war 

②. 将下载好的jenkins.war放在自定义磁盘目录,别误删了

③. 代开cmd窗口,用java -jar 启动jenkins.war,例如:java -jar D:/jenkins.war  默认的端口为8080,如果要修改可以用压缩工具打开看看,具体在哪里修改端口我没试过。(cmd窗口关闭则jenkins关闭)jenkins在启动时会打印登录密码,并生成一个密码文件,应该是在 C:\Users\主机名\.jenkins\secrets\initialAdminPassword 这个里面

④. 浏览器访问localhost:8080/jenkins ,之后输入管理员密码,之后开始安装Jira插件,Manage Jenkins - Manage Plugins 进入插件管理,选择Available,如下图,要安装的插件有:

Jira Issue Updater
Jira Pipeline Steps
Jira Trigger
JiraTestResultReporter
Pipeline
SSH

(前4个插件可与Jira交互,第5个可在Jenkins中编写工作流,语法比较难搞,第6个在第三方调用Jenkins Api时需要使用,否则远程调用会报错)

 ⑤. 安装插件比较耗时,在安装完之后,要重启Jenkins,关闭Jenkins的cmd窗口,打开重新java -jar启动它,让它重新加载刚才安装的插件。 之后开始填写与Jira的交互配置,进入系统配置 Manage Jenkins - Configure System,按下面几个图配置,之后保存

 

 

 ⑥. 进入全局配置,设置Jenkins被第三方访问时的限制。

 ⑦. 在Jenkins上创建一个项目,我在此处选择了Pipeline工作流形式的项目

 

 ⑧. 创建项目完成后,编写项目的构建等配置,让其可以与Jira交互

 

 

 脚本详情如下,%%中间的时参数,这些参数对应上面General创建的Choice Paramter、String Paramter等参数,命令中的http地址是Jira创建工单的API接口

 pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
               bat script {"""curl -u %jire_user%:%jire_password% --header "Content-Type:application/json" -X POST --data "{\\"fields\\":{\\"project\\":{\\"key\\":\\"%project_key%\\"},\\"summary\\":\\"%summary%\\",\\"description\\":\\"%description%\\",\\"duedate\\":\\"%duedate%\\",\\"priority\\":{\\"name\\":\\"%priority%\\"},\\"assignee\\":{\\"name\\":\\"%assignee%\\"},\\"issuetype\\":{\\"name\\":\\"%issuetype%\\"}}}" http://%jira_url%/rest/api/2/issue/"""}
            }          
        }
    }
}

 ⑨. 创建完成后保存,我们可以运行一下

 

 

 更改一下电脑的字符编码

 

每一个属性都对的上,成功了。 下面粘贴上Jenkins与Jira的各类API地址 

 Jira Api:  JIRA 7.2.8 (atlassian.com)

Jenkins Api: Jenkins - API详解 - Anliven - 博客园 (cnblogs.com)

六:JAVA代码调用Jenkins,让Jenkins项目自动运行,然后执行Pipeline脚本,自动在Jira上创建BUG工单

工具类:

package com.hdlh.supplychain.controller;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hdlh.common.utils.StringUtils;

/**
 * Jenkins 构建任务(此处的构建可理解为执行的意思)
 * @author LiuQingYuan
 *
 */
public class JenkinsBuild {
    private static final Logger log = LoggerFactory.getLogger(JenkinsBuild.class);
    
    public static String username;
    public static String password;
    public static String url;
    public static String token;
    public static String jobName;
    private static String buildCmd;
    //private static String[] infoTypes = new String[] {"JSON","XML"};
    public static String projectKey;
    public static String issueType;
    public static String jiraUrl;
    public static String jiraUser;
    public static String jiraPassword;
    public static String defaultPriority;
    public static String defaultAssignee;
    
    public static void initJenkis() {
        if(StringUtils.isEmpty(username)) {
            try {
                 Properties properties = new Properties();
                 InputStream in = JenkinsBuild.class.getClassLoader().getResourceAsStream("com/hdlh/supplychain/controller/Jenkins.properties");
                 properties.load(in);
                 //Jenkis 地址
                 url = properties.getProperty("JENKINS_URL");
                 //Jenkis 任务名称
                 jobName = properties.getProperty("JENKINS_JOBNAME");
                 //Jenkis 任务调用Token
                 token =  properties.getProperty("JENKINS_TOKEN");
                 //Jenkis 登录用户
                 username = properties.getProperty("JENKINS_USERNAME");
                 //Jenkis 登录密码
                 password = properties.getProperty("JENKINS_PASSWORD");
                 //Jenkins 要对接的Jira地址
                 jiraUrl = properties.getProperty("JIRA_URL");
                //Jenkins 要对接的Jira登录用户
                 jiraUser = properties.getProperty("JIRA_USER");
                //Jenkins 要对接的Jira登录密码
                 jiraPassword = properties.getProperty("JIRA_PASSWORD");
                 //Jenkins 要对接的Jira项目Key
                 projectKey = properties.getProperty("JIRA_PROJECT_KEY");
                 //Jenkis 要对接的Jira有哪些工单类型,默认取第一个工单类型
                 issueType = properties.getProperty("JIRA_ISSUE_TYPE");
                 //Jira 默认的工单风险级别 Highest/High/Medium/Low/Lowest
                 defaultPriority = properties.getProperty("JIRA_DEFAULT_PRIORITY");
                 //Jira 默认的工单处理人
                 defaultAssignee = properties.getProperty("JIRA_DEFAULT_ASSIGNEE");
                 
                 buildCmd = "curl -X POST -v -u "+username+":"+password+" http://"+url+"/job/"+jobName;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * 无参构建
     * @param Jenkins中的任务名称
     */
    public static String jobBuildNoParam() {
        log.info("execute a no param's build for "+jobName);
        String NoParamBuildCmd = buildCmd + "/build?token="+token;
        return ExecuteCmd(NoParamBuildCmd);
    }
    
    /**
     * 有参构建
     * @param 参数集
     * 注意要点(踩过的坑)
     * 一、需要在cmd中添加crumb,否则无法远程调用;但添加之后依旧不通,查看了很多文档最后发现还要添加一个Cookie,
     * 如何获取Cookie与Crumb?多次测试后发现为->  curl -verbose -u user:password http://ip:port/crumbIssuer/api/json
     * 网上找到的唯一例子中的cmd命令也是错的,这里的-verbose -i输出了请求头信息,其中包含了Cookie,如果不添加则获取不到
     * 二、在获取到Cookie与Crumb后,将其添加到Cmd中,网上的版本大多不可信,方法中的命令经过多方测试为正确,切记传参时字符串不可
     * 用单引号包裹,需要用双引号或不添加,如果参数中有空格时,必须使用双引号,否则Jenkins任务会调用成功,但是参数会丢失
     * 三、请求方式POST,必须是大写,否则会失败
     * 四、经多次测试发现,cmd命令中-d或--data或--data-urlencode后面只能传一个参数,若想传递多个,需要在cmd命令中写多个-d或--data或--data-urlencode
     * @return
     */
    public static String jobBuildWithParam(Map<String,String> paramMap) {
        Map<String,String> map = getCookieAndCrumb();
        if(map.size() != 2) {
            System.out.println("未找到Cookie与Crumb,请核实Jenkins是否启动成功");
            return null;
        }
        log.info("execute a with param's build for "+jobName);
        String withParamBuildCmd = buildCmd + "/buildWithParameters?token="+token + " -H \"Jenkins-Crumb:"+map.get("crumb")+"\" --cookie \""+map.get("cookie")+"\" ";
        StringBuffer sb = new StringBuffer();
        for(String key:paramMap.keySet()) {
            String signParamStr = "--data-urlencode \""+key+"="+paramMap.get(key)+"\" ";
            sb.append(signParamStr);
        }
        withParamBuildCmd += sb.toString();
        return ExecuteCmd(withParamBuildCmd);
    }
    
    /**
     * 获取最后一次构建的ID
     * @return
     */
    public static String getLastBuildId() {
        log.info("get last build id for "+jobName);
        String getLastBuidIdCmd = buildCmd + "/lastBuild/buildNumber";
        return ExecuteCmd(getLastBuidIdCmd);
    }
    
    /**
     * 获取最后一次构建的结果
     * @param buildId
     * @return
     */
    public static String getBuildResult(int buildId,String type) {
        log.info("get build result for "+jobName+", and build id is "+buildId);
        String getLastBuildResultCmd = buildCmd;
        if("XML".equals(type)) {
            getLastBuildResultCmd += "/"+buildId+"/api/xml";
        }else {
            getLastBuildResultCmd += "/"+buildId+"/api/json?pretty=true";
        }
        return ExecuteCmd(getLastBuildResultCmd);
    }
    
    /**
     * 获取Cookie与Crumb
     * @return
     */
    public static Map<String,String> getCookieAndCrumb() {
        log.info("get cookie and crumb for "+jobName+"'s parametric construction");
        String getCookieAndCrumbCmd = "curl -verbose -i -u "+username+":"+password+" http://"+url+"/crumbIssuer/api/json";
        return ExecuteCmdForCookieAndCrumb(getCookieAndCrumbCmd);
    }
    
    
    /**
     * 执行CMD命令
     * @param command
     */
     public static String ExecuteCmd(String command) {
        String result = "";
        BufferedReader br = null;
        try {
            System.out.println("command:"+command);
            Process process = Runtime.getRuntime().exec("cmd /c "+command);
            br = new BufferedReader(new InputStreamReader(process.getInputStream(),Charset.forName("GBK")));
            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line + "\n");
            }
            System.out.println("command result:"+sb.toString());
            result = sb.toString().trim();
        }catch(IOException e) {
            e.printStackTrace();
        }finally {
            if (br != null){
                try {
                    br.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
     
     /**
     * 执行获取Cookie与Crumb的CMD命令
     * @param command
     */
     public static Map<String,String> ExecuteCmdForCookieAndCrumb(String command) {
         Map<String,String> returnMap = new HashMap<String, String>();
        BufferedReader br = null;
        try {
            System.out.println("command:"+command);
            Process process = Runtime.getRuntime().exec("cmd /c "+command);
            br = new BufferedReader(new InputStreamReader(process.getInputStream(),Charset.forName("GBK")));
            String line = null;
            while ((line = br.readLine()) != null) {
                if(line.toLowerCase().contains("cookie")) {
                    String cookie = line.substring(line.indexOf(":")+1,line.indexOf(";")).trim();
                    returnMap.put("cookie", cookie);
                }
                if(line.contains("\"crumb\"")) {
                    line = line.substring(line.indexOf("\"crumb\""));
                    String crumb = line.substring(line.indexOf(":")+1,line.indexOf(",")).replaceAll("\"", "");
                    returnMap.put("crumb", crumb);
                }
            }
            System.out.println("command result:{\"cookie\":\""+returnMap.get("cookie")+"\",\"crumb\":\""+returnMap.get("crumb")+"\"}");
        }catch(IOException e) {
            e.printStackTrace();
        }finally {
            if (br != null){
                try {
                    br.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return returnMap;
    }
    
    public static void main(String[] args) {
        /*
         * String buildIdStr = JenkinsBuild.getLastBuildId();
         * if(StringUtils.isNotEmpty(buildIdStr)) {
         * JenkinsBuild.getBuildResult(Integer.parseInt(buildIdStr),infoTypes[0]); }
         */
        //JenkinsBuild.getCookieAndCrumb();
        /*
         * Map<String, String> paramMap = new HashMap<String, String>();
         * paramMap.put("jira_url", "localhost:8088"); paramMap.put("jira_user",
         * username); paramMap.put("jira_password", password);
         * paramMap.put("project_key", projectKey); paramMap.put("issuetype", "BUG");
         * //paramMap.put("component", "file scan"); paramMap.put("summary", "测试");
         * paramMap.put("description", "这是一条测试数据"); paramMap.put("priority", "Lowest");
         * paramMap.put("duedate", "2022-10-21"); paramMap.put("assignee", "hcs");
         * 
         * JenkinsBuild.jobBuildWithParam(paramMap);
         */
        
        JenkinsBuild.initJenkis();
    }
}
 

Jira工单入参说明类:

package com.hdlh.supplychain.controller;

/**
 * 调用Jenkins构建build时的入参 (改实体在项目中没有使用,提供给调用Jenkins参数编写时参照,也可在搭建的Jenkins网页上查看)
 * @author LiuQingYuan
 *
 */
public class JenkinsBuildParam {
    /** Jira环境的地址,默认设置为localhost:8088,请根据实际情况调整 */
    private String jira_url;
    /** Jire环境的登录账号,默认设置为root,请根据实际情况调整 */
    private String jira_user;
    /** Jire环境的登录密码,默认设置为Hdlh@2605,请根据实际情况调整 */
    private String jira_password;
    /** 问题所属项目关键词-项目的KEY,默认设置为HDLH,请根据实际情况调整 */
    private String project_key;
    /** 问题类型 - 默认定义为BUG,填写时请确认Jira中的该项目是否有这个问题类型 */
    private String issuetype;
    /** 问题在哪个模块出现的 */
    //private String component; 当前版本好像不支持这个属性
    /** 问题概述/总结 */
    private String summary;
    /** 问题详情描述 */
    private String description;
    /** 问题风险等级 - 可取值 Highest/High/Medium/Low/Lowest */
    private String priority;
    /** 问题截止日期 格式 YYYY-MM-dd */
    private String duedate;
    /** 问题指派给谁 - 填写时请确认Jira中是否有改人员账号,此处填写的是账号,不是全名 */
    private String assignee;
    
    public String getJira_url() {
        return jira_url;
    }
    public void setJira_url(String jira_url) {
        this.jira_url = jira_url;
    }
    public String getJira_user() {
        return jira_user;
    }
    public void setJira_user(String jira_user) {
        this.jira_user = jira_user;
    }
    public String getJira_password() {
        return jira_password;
    }
    public void setJira_password(String jira_password) {
        this.jira_password = jira_password;
    }
    public String getProject_key() {
        return project_key;
    }
    public void setProject_key(String project_key) {
        this.project_key = project_key;
    }
    public String getIssuetype() {
        return issuetype;
    }
    public void setIssuetype(String issuetype) {
        this.issuetype = issuetype;
    }
    /*
     * public String getComponent() { return component; } public void
     * setComponent(String component) { this.component = component; }
     */
    public String getSummary() {
        return summary;
    }
    public void setSummary(String summary) {
        this.summary = summary;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getPriority() {
        return priority;
    }
    public void setPriority(String priority) {
        this.priority = priority;
    }
    public String getDuedate() {
        return duedate;
    }
    public void setDuedate(String duedate) {
        this.duedate = duedate;
    }
    public String getAssignee() {
        return assignee;
    }
    public void setAssignee(String assignee) {
        this.assignee = assignee;
    }
    
}
 

jenkins.properties文件中的属性

JENKINS_URL=localhost:8080
JENKINS_JOBNAME=Jira-HDLH-Pipeline
JENKINS_TOKEN=Hdlh@2605
JENKINS_USERNAME=admin
JENKINS_PASSWORD=你自己的Jenkins登录密码
JIRA_URL=localhost:8088
JIRA_USER=root
JIRA_PASSWORD=Hdlh@2605
JIRA_PROJECT_KEY=HDLH
JIRA_ISSUE_TYPE=BUG
JIRA_DEFAULT_PRIORITY=Medium
JIRA_DEFAULT_ASSIGNEE=hcs  可以在Jira中新建用户,此处是用户账号

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

crazy_monky

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值