教你如何帅气地启动jenkins打包任务🤣
背景
在日常开发中经常会有需要构建多个打包任务的情况,每次都要打开jenkins客户端
,然后逐个输入打包,非常繁琐。特别是公司又安装了监控软件,每次打开浏览器都要卡顿几秒。于是便萌生了通过node命令行
来执行jenkins任务构建
的想法。
基本实现
安装
由于我们的服务依赖jenkins
包,所以需要在项目初始化之后对jenkins
进行安装,执行如下命令行:
npm i jenkins
jenkins依赖包的API文档在这里,大家可以参考官方文档:github.com/silas/node-…
获取jenkins服务信息
然后我们在根目录下创建index.js文件,通过写入jenkins服务地址与jenkins账号,进行第一次登录尝试:
// index.js
const Jenkins = require("jenkins")
// 账号
const account = 'admin'
// 密码
const password = 'admin'
// jenkins服务地址
const host = 'localhost:8080'
// 用来存放jenkins实例
let jenkins
// 初始化jenkins实例
function initJenkins({ account, password } = {}){
// 拼接baseUrl
const baseUrl = `http://${account}:${password}@${host}`;
// 创建Jenkins实例
jenkins = new Jenkins({ baseUrl, crumbIssuer: true })
// 获取实例信息
jenkins.info().then(res=>{
console.log(res)
})
}
initJenkins({account, password})
在根目录终端中执行node脚本文件:
node index.js
此时只要我们输入正确的账号密码和服务地址,应该就能看到控制台输出jenkins信息:
{
"assignedLabels": [{}],
"description": null,
"jobs": [
{
"color": "blue",
"name": "example",
"url": "http://localhost:8080/job/example/"
}
],
"mode": "NORMAL",
"nodeDescription": "the master Jenkins node",
"nodeName": "",
"numExecutors": 2,
"overallLoad": {},
"primaryView": {
"name": "All",
"url": "http://localhost:8080/"
},
"quietingDown": false,
"slaveAgentPort": 12345,
"unlabeledLoad": {},
"useCrumbs": false,
"useSecurity": false,
"views": [
{
"name": "All",
"url": "http://localhost:8080/"
}
]
}
构建打包任务
至此我们已经成功连接上了jenkins服务,是不是非常简单!此时我们快速构建jenkins任务只需要调用build
方法。
// index.js
const Jenkins = require("jenkins")
// 账号
const account = 'admin'
// 密码
const password = 'admin'
// jenkins服务地址
const host = 'localhost:8080'
// 用来存放jenkins实例
let jenkins
// 打包任务的名称,这里需要修改成你自己的任务名称哦!
let jobName = 'JOB_NAME'
// 初始化jenkins实例
async function initJenkins({ account, password } = {}){
// 拼接baseUrl
const baseUrl = `http://${account}:${password}@${host}`;
// 创建Jenkins实例
jenkins = new Jenkins({ baseUrl, crumbIssuer: true })
}
// 构建打包任务
async function hdBuild(){
await jenkins.job.build(jobName);
console.log('打包任务开始了!')
}
// 主入口函数
async function main (){
await initJenkins({account, password})
hdBuild()
}
main()
现在我们打开浏览器,访问jenkins就可以看到打包任务已经开始了!
交互式命令行工具 Inquirer
虽然我们通过node命令轻轻松松构建了jenkins打包任务,但是细究下来,这其中还是有很多小细节需要优化。比如:
- 这个脚本工具是打算给我们项目组成员使用的,应该支持大家登录自己的账号进行打包
- jenkins服务上面的任务有多个,应该支持选择job进行打包
- 打包任务应该支持调整参数
我们可以使用inquirer
来实现这些问答形式的交互,通过inquirer
我们可以根据用户的输入来执行对应的操作,执行依赖安装:
npm i inquirer
基本用法
const inquirer = require('inquirer')
inquirer
.prompt([
/* 输入问题 */
])
.then((answers) => {
// 通过用户输入执行操作!!
})
.catch((error) => {
// 捕获报错
})
关于inquirer
的使用方法这里不再赘述,大家可以参考官方文档:github.com/SBoudrias/I…
定义账号密码prompt配置
此处我们开始构建自己的prompt
数组,由于项目组使用的jenkins服务地址是固定的,账号密码则通过问答的方式由用户自己键入:
// 账号密码prompt
const prompt = [
{
type: 'input',
name: 'account',
message: '请输入jenkins账号',
validate(input) {
if (!input || input.length === 0) {
return '请输入jenkins账号!'
}
return true
}
},
{
type: 'password',
name: 'password',
message: '请输入jenkins密码',
validate(input) {
if (!input || input.length === 0) {
return '请输入jenkins密码!'
}
return true
}
}
]
定义打包仓库与打包参数prompt配置
// 打包仓库和打包参数prompt
// 需要获取jenkins的job列表来动态生成prompt数组,因此封装成函数生成
function getJobPrompt(list) {
return [
{
// 这里的打包仓库支持多选
type: 'list',
name: 'repository',
message: '请选择需要打包的仓库(空格选择)',
choices: list?.map(it => it.name) ?? [],
validate(input) {
if (!input || input.length === 0) {
return '请选择至少一个仓库!'
}
return true
}
},
// 如果job构建任务配置了参数
{
type: 'input',
name: 'params',
message: '请输入需要构建参数Demo-params',
validate(input) {
if (!input || input.length === 0) {
return '请输入需要构建参数Demo-params!'
}
return true
},
}
]
}
完整代码
// index.js
const Jenkins = require("jenkins")
const inquirer = require('inquirer')
// jenkins服务地址,TODO
const host = 'localhost:8080'
let jenkins;
let jobList = [];
// 问题数组
const prompt = [
{
type: 'input',
name: 'account',
message: '请输入jenkins账号',
validate(input) {
if (!input || input.length === 0) {
return '请输入jenkins账号!'
}
return true
}
},
{
type: 'password',
name: 'password',
message: '请输入jenkins密码',
validate(input) {
if (!input || input.length === 0) {
return '请输入jenkins密码!'
}
return true
}
}
]
// 可以根据自己项目需要设计对应的prompt,TODU
function getJobPrompt(list) {
return [
{
// 这里的打包仓库支持多选
type: 'list',
name: 'repository',
message: '请选择需要打包的仓库(空格选择)',
choices: list?.map(it => it.name) ?? [],
validate(input) {
if (!input || input.length === 0) {
return '请选择至少一个仓库!'
}
return true
}
},
// 如果job构建任务配置了参数
{
type: 'input',
name: 'params',
message: '请输入需要构建参数Demo-params',
validate(input) {
if (!input || input.length === 0) {
return '请输入需要构建参数Demo-params!'
}
return true
},
}
]
}
// 初始化jenkins实例
async function initJenkins({ account, password } = {}) {
try {
// 拼接baseUrl
const baseUrl = `http://${account}:${password}@${host}`;
// 创建Jenkins实例
jenkins = new Jenkins({ baseUrl, crumbIssuer: true })
// 通过获取jenkins信息验证登录结果
await jenkins.info()
// 获取jenkins服务的job任务列表
const res = await jenkins.job.list()
// 动态生成prompt
jobListPrompt = getJobPrompt(res)
return true
} catch (error) {
console.log('获取jenkins服务信息出错了!')
return false
}
}
async function hdBuild({ repository, params }) {
await jenkins.job.build(repository,
// 这里传入job构建时需要的参数信息
{
parameters: {
// 替换成自己job任务的配置参数
'Demo-params': params,
}
});
console.log('打包任务已经开始了!')
}
async function main() {
// 引导用户输入密码
const answers = await inquirer.prompt(prompt)
// 初始化jenkins
const isLogin = await initJenkins(answers)
// 登录状态
if(isLogin){
// 引导用户输入打包仓库和构建参数
const buildInfo = await inquirer.prompt(jobListPrompt)
// 执行打包任务
hdBuild(buildInfo)
}
}
main()
目前为止,我们已经完成了大部分的功能代码,大家可以将代码复制粘贴到本地,执行以下代码调整(上面注释中TODO部分代码):
- 将代码中的jenkins服务地址改成自己真实项目的服务地址(
host
) - 根据自己项目需要设计对应的prompt,也可以按照前面的代码进行调整(
getJobPrompt
)
运行脚本,便能够在本地进行功能验证了!
全局安装命令行
现在基本功能已经实现,我们还希望能够在随意的终端运行指令来实现打包功能,修改一下package.json
的代码:
// package.json
{
"name": "jk-build",
"version": "1.0.0",
"description": "",
"main": "index.js",
// 新增
"bin": {
"jk-build": "index.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"inquirer": "^7.1.4",
"jenkins": "^1.0.1"
}
}
修改index.js
文件,指定脚本应该使用node.js解释器
来运行:
// 新增
#!/usr/bin/env node
const Jenkins = require("jenkins")
const inquirer = require('inquirer')
...
保存文件后执行npm link
,这样我们就能在任意地方执行jk-build
命令行,启动脚本服务了。
功能优化
现在我们已经几乎可以抛弃jenkins客户端,直接使用node命令行调用jenkins服务了。把脚本 但是还是有一些功能优化可以去完善:
- 记住账号密码信息
- 输出当前任务的构建队列情况
目前只附上缓存账号密码信息的功能代码,输出当前任务的构建队列情况就只提供实现思路啦!
记住账号密码信息
使用node服务缓存信息可以使用node-localstorage
插件来完成:
安装
npm i node-localstorage
完整代码
#!/usr/bin/env node
const Jenkins = require("jenkins")
const inquirer = require('inquirer')
// 加载缓存包
if (typeof localStorage === "undefined" || localStorage === null) {
var LocalStorage = require('node-localstorage').LocalStorage;
// 如果该目录不存在则自动生成
localStorage = new LocalStorage('D:\/jk-build\/scratch');
}
// jenkins服务地址
const host = 'localhost:8080'
let jenkins;
let jobListPrompt = [];
// 问题数组
const prompt = [
{
type: 'input',
name: 'account',
message: '请输入jenkins账号',
validate(input) {
if (!input || input.length === 0) {
return '请输入jenkins账号!'
}
return true
}
},
{
type: 'password',
name: 'password',
message: '请输入jenkins密码',
validate(input) {
if (!input || input.length === 0) {
return '请输入jenkins密码!'
}
return true
}
}
]
function getJobPrompt(list) {
return [
{
// 这里的打包仓库支持多选
type: 'list',
name: 'repository',
message: '请选择需要打包的仓库(空格选择)',
choices: list?.map(it => it.name) ?? [],
validate(input) {
if (!input || input.length === 0) {
return '请选择至少一个仓库!'
}
return true
}
},
// 如果job构建任务配置了参数
{
type: 'input',
name: 'branchs',
message: '请输入需要构建参数Demo-params',
validate(input) {
if (!input || input.length === 0) {
return '请输入需要构建参数Demo-params!'
}
return true
},
}
]
}
// 初始化jenkins实例
async function initJenkins({ account, password } = {}) {
try {
// 拼接baseUrl
const baseUrl = `http://${account}:${password}@${host}`;
// 创建Jenkins实例
jenkins = new Jenkins({ baseUrl, crumbIssuer: true })
// 通过获取jenkins信息验证登录结果
await jenkins.info()
// 获取jenkins服务的job任务列表
const res = await jenkins.job.list()
// 动态生成prompt
jobListPrompt = getJobPrompt(res)
return true
} catch (error) {
console.log('获取jenkins服务信息出错了!')
return false
}
}
async function hdBuild({ repository, params }) {
await jenkins.job.build(repository,
// 这里传入job构建时需要的参数信息
{
parameters: {
// 替换成自己job任务的配置参数
'Demo-params': params,
}
});
console.log('打包任务已经开始了!')
}
function setLocalStorage({ account, password }){
localStorage.setItem('account',account)
localStorage.setItem('password',password)
}
function removeLocalStorage(){
localStorage.removeItem('account')
localStorage.removeItem('password')
}
async function main() {
// 读取缓存信息
const account = localStorage.getItem('account')
const password = localStorage.getItem('password')
let answers = {}
if(account && password){
// 使用缓存的账号密码
answers = {
account,
password
}
}else{
// 引导用户输入密码
answers = await inquirer.prompt(prompt)
}
// 初始化jenkins
const isLogin = await initJenkins(answers)
// 登录状态
if(isLogin){
// 缓存登录信息
setLocalStorage(answers)
// 引导用户输入打包仓库和构建参数
const buildInfo = await inquirer.prompt(jobListPrompt)
// 执行打包任务
hdBuild(buildInfo)
}else{
// 删除缓存信息
removeLocalStorage()
}
}
main()
输出当前任务的构建队列情况
开启打包任务之后在控制台打印出当前任务的构建队列情况,可以直接调用jenkins官网提供的/queue/api/json
和/api/json
获取指定任务的构建等待队列和构建历史,配合ora
做一些样式优化再进行输出即可。
写在最后
最后附上源码地址,大家可以根据自己平时实际项目需要,对代码进行一些调整,重点是分享一些简化开发工作流程的小思路哈,大家可以在评论区一起交流。
转载自:https://juejin.cn/post/7214735181171949627