这篇主要系统的介绍一下 jenkins 的使用,这里jenkins是搭建在 windows上。
除了最开始安装jenkins时他推荐让你下载的插件,还有一些插件是需要我们自行下载的,所以在这part我就简单汇总下其他我们可能要用到的一些插件。
因为jenkins下载了插件只代表你目前的jenkins能够支持使用这个插件,但是具体的插件位置其实是你本地的,而环境变量的配置就是去找你本地的目录。
我这里只是简单介绍一个简单任务的创建,大家可以按照各自需求配置自己的任务。
一般情况下,我们都不会在master节点上面去运行任务,通常会新增slave节点运行,由于我jenkins搭建在windows上,我这里就简单写下windows节点的新增。
流程简单来说:
这两插件的作用即:帮助用户方便的设置格式化邮件。
Jenkins可以根据你配置的邮件模板格式发送结果邮件,通过Jenkins的参数定制自己的Email模板,常用的参数key值如下。
# 常用参数
$BUILD_STATUS -构建结果
$PROJECT_NAME -构建脚本名称
$BUILD_NUMBER -构建脚本编号
$JOB_DESCRIPTION -构建项目描述
$CAUSE - 脚本启动原因
$BUILD_URL - 脚本构建详情URL地址
模板内容,可以自行写
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
</head>
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
offset="0">
<table width="95%" cellpadding="0" cellspacing="0"
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
<tr>
<td>本邮件是Jenkins自动发送,请勿回复!</td>
</tr>
<tr>
<td><h3>
<font color="#e53935">    构建结果 - ${BUILD_STATUS}!</font>
</h3></td>
</tr>
<tr>
<td><br />
<b><font color="#3f51b5">构建信息:</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>项目名称 : ${PROJECT_NAME}</li>
<li>构建编号 : 第${BUILD_NUMBER}次构建</li>
<li>触发原因: ${CAUSE}</li>
<li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
<li>构建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
<li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
<li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></a></li>
</ul>
</td>
<tr>
<td><b><font color="#3f51b5">构建日志:</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td><textarea cols="160" rows="80" readonly="readonly"
style="font-family: Microsoft YaHei">${BUILD_LOG,maxLines=1000}</textarea>
</td>
</tr>
</html>
给你想要添加报警机制的任务添加即可
正常情况下,我们通常会有很多个任务,然后这些任务之间是有衔接的,比如先要执行一个任务,且这个任务是成功的状态下再去执行另一个任务
那下面我分别来详细讲下这三种情况的具体操作
Jenkins_API:即Jenkins对外暴露的动作交互入口,为外部程序提供入口,可以控制Jenkins。
这里简单介绍下request进行调用JenkinsAPI,详细看下注释,其实很简单。
"""
该类调用jenkins_api接口
1、获取任务的最新编号
2、获取任务的详细信息
"""
import json
import requests
# 注意:这个地址前面部分
# mikasa:yy1998123 是你的jenkins用户名和密码
# 127.0.0.1:8080 是本地jenkins域名+端口号
url = "http://mikasa:yy1998123@127.0.0.1:8080/jenkins/job/"
def get_jenkins_url(job_name):
"""
拼接url+任务job
:return:
"""
# print("拼接url为:", url + job_name)
return url + job_name
def send_api(req, tools="requests"):
"""
对发送接口测试的工具进行封装(可以使用urlib3/requests)
:param tools:
:param req:
:return:
"""
if tools == "requests":
return requests.request(**req)
def get_latest_job_number():
"""
1、获取最新任务编号
:return:
"""
req = {
"method": "GET",
"url": get_jenkins_url("mikasa_demo001") + "/lastBuild/buildNumber",
}
res = send_api(req)
print("最新任务编号:", res.json())
def get_job_info():
"""
2、获取job详细信息
:return:
"""
req = {
"method": "GET",
"url": get_jenkins_url("mikasa_demo001") + "/api/json",
}
res = send_api(req)
res_json = json.dumps(res.json(), indent=2)
print("返回结果:", res_json)
get_latest_job_number()
get_job_info()
-这里介绍下利用jenkins api库去调用,上面是我们自己去写request请求去调用,而其实目前已经存在了轮子,我们直接使用Jenkins api即可。
"""
封装jenkins调用类
"""
import configparser
import datetime
import logging
import os
import re
from jenkinsapi.jenkins import Jenkins
logging.basicConfig(level=logging.INFO, format='[%(asctime)s] - [%(name)s] - [%(levelname)s] - [%(message)s]')
log = logging.getLogger(__name__)
def get_jenkins_config(chose):
"""
读取Jenkins配置:从配置文件中jenkins_server.ini
:param chose:
:return:
"""
config = configparser.ConfigParser()
# 读取配置
config.read(os.path.join(os.getcwd(), 'jenkins_server.ini'))
username = config.get(chose, 'username')
password = config.get(chose, 'password')
host = config.get(chose, 'host')
port = config.get(chose, 'port')
url = "http://" + host + ":" + port
return url, username, password
class JenkinsDemo:
def __init__(self, job_name, chose='jenkins'):
"""
初始化,拿到jenkins配置
:param job_name:
:param chose:
"""
self.job_name = job_name
config = get_jenkins_config(chose)
print("config:", config)
# 解包元祖
self.jk = Jenkins(*config, useCrumb=True)
def __get_job_from_keys(self):
"""
拿到所有的job名称
:return: 返回一个列表
"""
choose_list = []
print(self.jk.keys())
for my_job_name in self.jk.keys():
# 遍历拿到所有的job,判断当前job是否在job列表里面,在的话添加到自定义列表
if self.job_name in my_job_name:
choose_list.append(my_job_name)
return choose_list
def __job_build(self, my_job_name):
"""
构建job
:param my_job_name:
:return:
"""
if self.jk.has_job(my_job_name):
# 如果有这个job拿到他里面的job对象
my_job = self.jk.get_job(my_job_name)
if not my_job.is_queued_or_running():
# 如果job当前没有在运行的话,就运行
try:
# 若当前没有在跑的话,拿到最后一次构建数
last_build = my_job.get_last_buildnumber()
except:
# 若没有获取到最后一次构建数的话,默认置为0
last_build = 0
# 最新构建数+1
build_num = last_build + 1
try:
# 开始打包
self.jk.build_job(my_job_name)
except Exception as e:
log.error(str(e))
# 循环判断Jenkins是否打包完成
while True:
# 若当前任务没有运行才获取信息
if not my_job.is_queued_or_running():
# 拿到最新一次的大奥信息
count_build = my_job.get_build(build_num)
# 获取打包开始时间
start_time = count_build.get_timestamp() + datetime.timedelta(hours=8)
# 获取打包日志
console_out = count_build.get_console()
# 获取打包状态
status = count_build.get_status()
# 获取变更内容
change = count_build.get_changeset_items()
log.info(" " + str(start_time) + " 发起的" + my_job_name + "构建已经完成,构建的状态为:" + status)
p2 = re.compile(r".*ERROR.*")
err_list = p2.findall(console_out)
log.info("打包日志为:" + str(console_out))
if status == "SUCCESS":
if len(change) > 0:
for data in change:
for file_list in data["affectedPaths"]:
log.info("发起的" + my_job_name + "变更的类:" + file_list)
log.info("发起的" + my_job_name + "变更的备注:" + data["msg"])
log.info("发起的" + my_job_name + "变更的提交人:" + data["author"]["fullName"])
else:
log.info("发起的" + my_job_name + "构建没有变更内容")
if len(err_list) > 0:
log.warning("构建的" + my_job_name + "构建状态为成功,但包含了以下错误:")
for error in err_list:
log.error(error)
else:
if len(err_list) > 0:
log.warning("构建的" + my_job_name + "包含了以下错误:")
for error in err_list:
log.error(error)
break
else:
log.warning("发起的" + my_job_name + "Jenkins is running")
else:
log.warning("发起的" + my_job_name + "没有该服务")
def run(self):
my_job_name = self.__get_job_from_keys()
if len(my_job_name) == 1:
self.__job_build(my_job_name[0])
elif len(my_job_name) == 0:
log.error("输入的job名称不正确!")
if __name__ == '__main__':
jk = JenkinsDemo("mikasa_demo001")
jk.run()
[jenkins]
username=mikasa
password=yy1998123
host=127.0.0.1
port=8080
正常一个项目部署中,为了节省时间,我们通常都可以将一些没有依赖关系的任务同步执行。
那本章就简单讲一个例子,多线程的情况下我们如何去写jenkinsfile。
pipeline {
agent none
stages {
stage('run parallel Stage') {
parallel {
stage('mikasa_Stage_1') {
agent { label "slave" }
steps {
echo "at agent slave run task 1."
bat "ipconfig"
sleep 10
}
}
stage('mikasa_Stage_2') {
agent { label "master" }
steps {
echo "at agent master run task 2."
bat "ipconfig"
sleep 10
}
}
}
}
}
}
参考文章:https://blog.csdn.net/makasa/category _10722865.html