jenkins系列:获取jenkins 指定job最新结果并解析日志,整合成测试报告并发送邮件

背景: 

        公司使用jenkins进行环境部署、自动化定时执行完成持续集成流水线,但并不希望每天点开jenkins job去查看执行结果,这样很麻烦,希望对每日集成部署环境得自动化测试结果进行汇总,邮件接收每日整体结果即可,有异常时才会进行详细报告查看。所以我们需要对每日持续集成环境中得自动化结果收集并整合成一份整体报告,并以邮件得形式发送给相关人员。

一、通过jenkinsServer获取最新job日志

        本次实现用到得语言和技术为:  java、 JenkinsServer。 通过JenkinsServer可以获取指定job最后一次构建日志:

a, 首先是连接jenkins,这里使用token, 可绕开403 forbidden的问题

    /**
     * 连接 Jenkins
     */
    public static JenkinsServer connection() {
        JenkinsServer jenkinsServer = null;
        try {
            jenkinsServer = new JenkinsServer(new URI(jenkinsUrl), username,token);   // 使用token, 可绕开403 forbidden的问题
        } catch (URISyntaxException e) {
            e.printStackTrace();
		}
        return jenkinsServer;
    }

备注: jenkins用户得api token需要在jenkins中创建

 b, 获取指定job得最新构建日志:

 
	/**
	 * 获取最后一次构建的日志
	 * @param jenkinsServer
	 * @param jobName
	 * @return
	 * @throws Exception
	 */
	public static String getConsoleOutLog(JenkinsServer jenkinsServer, String jobName) throws Exception{
	         JobWithDetails jobWithDetails = jenkinsServer.getJob(jobName).details();
	         ConsoleLog consoleLog = jobWithDetails.getLastBuild().details().getConsoleOutputText(0);  //获取最后一次构建的日志
	         String consoleTxt = consoleLog.getConsoleLog();
	         return consoleTxt;
	    }

二、解析日志

        需要根据日志内容匹配执行结果,主要是用到正则匹配:

     /**
     * 解析日志获取ui自动化执行结果
     * @param log
     * @return
     */
    public String[] analysisUILogResult(String log) {
		String reg = "(Total tests run: )(\\d*, )(Failures: )(\\d*, )(Skips: )(\\d*)";
		Pattern p = Pattern.compile(reg);
		Matcher m = p.matcher(log);
		String logResult = "";
		while(m.find()){
			logResult = m.group();
			System.out.println(logResult);
		}
		String[] temp = logResult.split(",");
		for (int i = 0; i < temp.length; i++) {
			temp[i] = temp[i].split(":")[1].replace(" ", "");
		}
		String[] result = new String[5];
		if (temp.length !=0) {
			result[1] = temp[0];   //总数
			result[3] = temp[1];   //失败
			result[4] = temp[2];   //跳过
			result[2] = String.valueOf(Integer.valueOf(temp[0]) - Integer.valueOf(temp[1]) - Integer.valueOf(temp[2]));   //成功
			result[0] = String.valueOf((double)(Math.round(Integer.valueOf(result[2])*10000/Integer.valueOf(result[1]))/10000.0)*100) + "%";    //通过率
		}
		return result;
	}

三、整合多个job得结果:

        通常会执行接口自动化和ui自动化,需要整合两个job得结果:

    /**
     * 获取整合后的执行结果信息
     * @param jobNames
     * @return
     */
    public HashMap<String, String[]> getConsolidateReport(String[] jobNames) {
		JenkinsServer jenkinsServer = connection();
		String log = "";
		String[] resultTemp = new String[5];
		HashMap<String, String[]> allResultMap = new HashMap<>();
		if (jobNames.length == 0) {
			jobNames = new String[]{"接口/AutoTest-YC-接口", "AutoTest-Selenium_AutoTest"};
		}
		try {
			for (int i = 0; i < jobNames.length; i++) {
				String[] resultMap = new String[6];   //多一个构建链接
				log = getConsoleOutLog(jenkinsServer, jobNames[i]);
				if (jobNames[i].contains("Selenium")) {
					System.out.println("UI自动化结果为(job名为"+ jobNames[i] +"):\n");
					resultTemp = analysisUILogResult(log);
					System.out.println("【成功率】:" + resultTemp[0] + "\n"+
										"【用例总数】:" + resultTemp[1] + "\n"+
										"【成功】:" + resultTemp[2] + "\n"+
										"【失败】:" + resultTemp[3] + "\n"+
										"【跳过】:" + resultTemp[4] + "\n");
					resultMap[5] = getLastBuildLink(jobNames[i]);
				}else if(jobNames[i].contains("-YC-")) {
					System.out.println("\n云测pub接口自动化结果为(job名为"+ jobNames[i] +"):\n");
					resultTemp = analysisYCLogResult(log);
					System.out.println("【成功率】:" + resultTemp[0] + "\n"+
							"【用例总数】:" + resultTemp[1] + "\n"+
							"【成功】:" + resultTemp[2] + "\n"+
							"【失败】:" + resultTemp[3] + "\n"+
							"【跳过】:" + resultTemp[4] + "\n");
					resultMap[5] = "https://yc.mingyuanyun.com/#/125/org_detail";
				}
				for (int j = 0; j < resultTemp.length; j++) {
					resultMap[j] = resultTemp[j];
				}
				allResultMap.put(jobNames[i], resultMap);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return allResultMap;
	}

四、编辑邮件模板并发送邮件

a, 模板:

<body style="color: #666; font-size: 14px; font-family: 'Open Sans',Helvetica,Arial,sans-serif;">
<div class="box-content" style="width: 80%; margin: 20px auto; max-width: 800px; min-width: 600px;">
    <div class="header-tip" style="font-size: 12px;
                                   color: #aaa;
                                   text-align: right;
                                   padding-right: 25px;
                                   padding-bottom: 10px;">
        自动化测试整合报告
    </div>
    <div class="info-top" style="padding: 15px 25px;
                                 border-top-left-radius: 10px;
                                 border-top-right-radius: 10px;
                                 background: {0};
                                 color: #fff;
                                 overflow: hidden;
                                 line-height: 32px;">
        <img src="cid:icon-alarm" style="float: left; margin: 0 10px 0 0; width: 32px;" /><div style="color:#010e07"><strong>自动化测试整合报告(UI+pub接口)</strong></div>
    </div>
    <div class="info-wrap" style="border-bottom-left-radius: 10px;
                                  border-bottom-right-radius: 10px;
                                  border:1px solid #ddd;
                                  overflow: hidden;
                                  padding: 15px 15px 20px;">
        <div class="tips" style="padding:15px;">
            <p style=" list-style: 160%; margin: 10px 0;">Hi All,</p>
            <p style=" list-style: 160%; margin: 10px 0;">{1}</p>
        </div>
        <table class="list" style="width: 100%; border-collapse: collapse; border-top:1px solid #eee; font-size:12px;">
            <thead>
            <tr style=" background: #fafafa; color: #333; border-bottom: 1px solid #eee;">
                {3}
            </tr>
            </thead>
            <tbody>
            {4}
            </tbody>
        </table>
		<br /> 
        <div class="time" style="text-align: right; color: #999; padding: 0 15px 15px;">{2}</div>
        <br>
    </div>
</div>
</body>

b, 设置邮件内容:

     /**
     * 设置邮件内容
     * @return
     * @throws IOException
     */
    private String buildContent(String[] jobNames) throws IOException {
        //加载邮件html模板
		String path = System.getProperty("user.dir") + "/conf/pod-scale-alarm.html";
        InputStream inputStream = new FileInputStream(path);;
        BufferedReader fileReader = new BufferedReader(new InputStreamReader(inputStream));
        StringBuffer buffer = new StringBuffer();
        String line = "";
        try {
            while ((line = fileReader.readLine()) != null) {
                buffer.append(line);
            }
        } catch (Exception e) {
//            LOGGER.error("读取文件失败,fileName:{}", fileName, e);
        } finally {
            inputStream.close();
            fileReader.close();
        }


        String contentText = "以下自动化测试整体执行结果(详情点击任务名称查看):<br>";
        //邮件表格header
        String header = "<td>自动化任务名称</td><td>成功率</td><td>用例总数</td><td>成功</td><td>失败</td><td>跳过</td>";
        StringBuilder linesBuffer = addResult(jobNames);

        //蓝色
        String emailHeadColor = "#9fc5e8";
        String date = DateFormatUtils.format(new Date(), "yyyy/MM/dd HH:mm:ss");
        //填充html模板中的五个参数
        String htmlText = MessageFormat.format(buffer.toString(), emailHeadColor, contentText, date, header, linesBuffer.toString());

        //改变表格样式
        htmlText = htmlText.replaceAll("<td>", "<td style=\"padding:6px 10px; line-height: 150%;\">");
        htmlText = htmlText.replaceAll("<tr>", "<tr style=\"border-bottom: 1px solid #eee; color:#666;\">");
        System.out.println(htmlText);
        return htmlText;
    }




    /**
     * 将jenkins报告结果拼接到html中
     * @param jobNames
     * @return
     */
    public StringBuilder addResult(String[] jobNames) {
		String jobName = "",key="", value="";
		String[] valueList = new String[5];
		//获取jenkins整合结果信息
		ConsolidateJenkinsReport jenkins = new ConsolidateJenkinsReport("http://10.5.10.154:8085/", "admin", "116a2d55eb2dd1768aec59defe3a8cf4c6");
		HashMap<String, String[]> resultContent = jenkins.getConsolidateReport(jobNames);

		// 将jenkins报告结果拼接到html中
        StringBuilder linesBuffer = new StringBuilder(); 
        for (Entry<String, String[]> entry : resultContent.entrySet()) {
        	jobName = entry.getKey();
        	valueList = entry.getValue();
        	linesBuffer.append("<tr><td><a href=" + valueList[5] + " target=\"_blank\">" + jobName +  "</a></td>");   //把job名称加入,并添加链接
			for (int i = 0; i < valueList.length-2; i++) {     //把总体结果信息加入
				linesBuffer.append("<td>" + valueList[i] +  "</td>");
			}
			linesBuffer.append("<td>" + valueList[4] +  "</td></tr>");  //最后一个属性格式单独处理
		}
    	return linesBuffer;
	}

c, 发送邮件:

    /**
	 * 发送html格式的邮件。普通常规方法
	 * @param receiverList
	 * @throws MessagingException
	 * @throws IOException
	 */
	  public void sendEmail(String[] jobNames, InternetAddress[] receiverList, String productVersion) throws MessagingException, IOException {
		  System.err.println(jobNames[0]);
	      Properties props = new Properties();
	      props.setProperty("mail.smtp.host", "smtp.exmail.qq.com");
	      props.setProperty("mail.transport.protocol", "smtp");
	      props.setProperty("mail.smtp.auth", "true");
	      props.setProperty("mail.smtp.connectiontimeout", "20000");
	      props.setProperty("mail.smtp.timeout", "20000");
	      // 得到回话对象
         Session session = Session.getInstance(props);
         // 获取邮件对象
         Message message = new MimeMessage(session);
         // 设置发件人邮箱地址
         message.setFrom(new InternetAddress("chengk02@mingyuanyun.com"));
         // 设置收件人邮箱地址 
         message.setRecipients(Message.RecipientType.TO, receiverList);
         message.setRecipients(Message.RecipientType.CC, receiverList);
//         message.setRecipient(Message.RecipientType.TO, new InternetAddress("chengk02@mingyuanyun.com"));//一个收件人
         // 设置邮件标题
         message.setSubject("自动化测试结果报告:" + productVersion);
         
         //邮箱内容以及附件
         Multipart multipart=new MimeMultipart();
         try {
			multipart.addBodyPart(createContent(buildContent(jobNames)));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	     message.setContent(multipart);
	     // 得到邮差对象
	     Transport transport = session.getTransport();
	     // 连接自己的邮箱账户
	     transport.connect("xxxxx@xxxx.com", "xxxxxFUBYBxCjw");// 密码为QQ邮箱开通的stmp服务后得到的客户端授权码
	     // 发送邮件
	     transport.sendMessage(message, message.getAllRecipients());
	     transport.close();
	  }

d, 邮件效果:

        点击自动化任务名称可跳转至jenkins中该job页面

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Jenkins 是一个流行的开源持续集成/持续部署 (CI/CD) 工具,它提供了丰富的插件生态系统来扩展其功能。其中一个常见的需求是通过邮件通知团队关于构建的状态,这可以通过使用 Jenkins 的 Email Extension 插件来实现。 **Jenkins Email Extension插件:** 这个插件允许你在 Jenkins 构建完成后自动发送电子邮件通知,内容包括构建的状态(成功、失败或异常)。发送邮件的前提通常需要使用 Groovy脚本作为构建步骤的一部分,因为 Groovy 是 Jenkins 集成脚本语言,可以方便地与 Jenkins API 进行交互。 **使用Groovy获取Jenkins状态并发送邮件:** 1. **安装和配置Email Extension插件:**首先在 Jenkins 管理界面安装并启用 Email Extension 插件。 2. **创建邮件通知步骤:**在你的 Jenkins 建筑流程(Pipeline)中添加一个 "Execute Shell" 或 "Script" 类型的步骤,编写 Groovy 脚本来获取当前构建的状态。例如: ```groovy def buildStatus = currentBuild.result ``` `currentBuild.result` 返回当前构建的结果,如 "SUCCESS", "FAILURE", 或者 "UNSTABLE"。 3. **设置邮件内容:**根据 `buildStatus` 变量决定邮件内容,比如如果状态是 "SUCCESS",邮件可以写明 "构建已成功"。 4. **调用发送邮件方法:**使用插件提供的 API(如 `sendEmail()` 函数),传入收件人、主题、以及包含状态信息的邮件正文,如下: ```groovy sendEmail recipients: 'team@example.com', subject: "Jenkins构建状态 - ${buildStatus}", body: "构建状态:${buildStatus}" ``` 5. **触发邮件发送:**确保在前面的步骤中获取状态后执行发送邮件的代码,确保邮件只在构建结束时发送

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值