如何使用 gitlab api 触发 CI
Gitlab 是一个类似于 Github 用于托管和审查代码,管理项目和构建软件;相较于 Github,其源代码本身也开源,允许用户自行搭建部署,是很多公司管理代码首选。可以通过 Webhook 或者 api 来触发 ci,配合 gulp 等工具,以此来构建更加完整的自动化工作流。本文将带你初步学会使用 Gitlab api,更多深入使用请参考官方文档 。
准备
首先,对于我们需要通过 api 触发的项目 IDE
,来到项目页面,顺序点击图中 1.
、2.
、3.
来到设置界面。
然后就能打开添加 trigger 的页面,描述完 trigger 的用途后点击 add trigger
按钮就能生成我们的 token,我们需要使用此 token 来触发 ci。
然后我们就能通过以下方式来触发 ci。
curl -X POST -F token=TOKEN -F ref=REF_NAME https://gitlab.example.com/api/v4/projects/project_id/trigger/pipeline
如果你打开的设置页面与上图不同,可能是你没有该项目的权限,那你需要找同事帮你申请 token ,及上面这条链接。
上述命令中我们需要将 TOKEN
替换为 我们自己的 token,将 REF_NAME
替换为目标分支名,则将在该目标分支上触发 ci。
其中 https://gitlab.example.com/api/v4/projects/project_id/trigger/pipeline
是打开上述设置页面自动生成的,不需要我们修改,不同项目的连接不同。
如果想给 ci 传入环境变量,可通过以下方式。
curl -X POST -F token=TOKEN -F ref=REF_NAME "variables[v_toolkit]=${version}" https://gitlab.example.com/api/v4/projects/project_id/trigger/pipeline
然后在我们的代码中通过以下方式获取环境变量:
console.log(`process.env.v_toolkit: ${process.env.v_toolkit}`);
通过环境变量,我们还能控制只触发 ci 中特定的 job,而绕过其他的 job。需要注意的是,通过 api 的方式是不能触发需要手动触发的 job 的,所以我们不要将 job 设为手动触发,而是通过传入环境变量,来控制 ci 中特定的 job 的实际运行。
举例说明
我们可以通过 gulp 脚本来触发 ci 。
// gulpfile.js
const path = require("path");
const cp = require("child_process");
const gulp = require("gulp");
function runci(cb) {
const versionIndex = process.argv.indexOf("--ve");
// 读取我们命令行输入的版本号
const version = process.argv[versionIndex + 1];
const branchIndex = process.argv.indexOf("--br");
const branch = process.argv[branchIndex + 1];
console.log(`version: ${version}`);
console.log(`branch: ${branch}`);
cp.execSync(
`curl -X POST -F token=你的TOKEN -F "ref=${branch}" -F "variables[v_transformer]=${version}" https://gitlab.example.cn/api/v4/projects/1234/trigger/pipeline`
);
cb();
}
module.exports = {
runci
};
命令行输入:
npx gulp runci --ve 1.0.0 --br master
如此,即完成了通过 Gitlab api 触发 CI 相关工作。
深入一点
我们接着上面的讲,初步实现一个完整的工作流。以下是一个 CI 配置示例:
image: node:lts
cache:
paths:
- node_modules/
- your-toolkit/node_modules/
before_script:
- npm install --registry=https://registry.npm.taobao.org
- npx envinfo
stages:
- build
build-toolkit:
stage: build
# when: manual
script:
- cd your-toolkit && rm -rf ./*.vsix
- node build.js
artifacts:
paths:
- your-toolkit/*.vsix
when: on_success
expire_in: 3 weeks
tags:
- docker
安装了 gulp
后,命令行输入:
npx gulp runci --ve 1.0.0 --br master
会在 master
分支触发 build-toolkit
任务,然后会运行我们的 build.js
脚本来执行构建任务。
// build.js
const { execSync } = require("child_process");
const fs = require("fs");
const path = require("path");
// @xyz/xchat-node 外网不可用
const XChat = require("@xyz/xchat-node/dist/index.js").default;
const xchat = new XChat('yourAccount', 'yourSecretKeyForUserApi', '');
const fileName = "./package.json";
var file = require(fileName);
console.log(`process.env.v_toolkit: ${process.env.v_toolkit}`)
// process.env.v_toolkit = process.env.v_toolkit || "1.0.0"
if (!process.env.v_toolkit) {
console.log("请提供一个版本号文件。");
console.log("pass");
} else {
let version = process.env.v_toolkit;
console.log(`version: ${version}`)
// 可以在此执行咱们的构建任务
console.log(`很棒,已构建成功!`)
// 通知用户构建成功
xchat.sendMsgToUser({
account: "your account",
fromUserCode: "your account",
toUserCode: "target account",
chatType: "TEXT",
msgText: "build-toolkit success!",
showFlag: 0,
ts: new Date().toString()
}, 'build-toolkit success!').then(r => console.log(r));
}
构建成功后就会立即通过特定通讯工具通知给用户。而 Gitlab 也可以通过浏览器通知我们构建成功,不过相比较而言 gitlab 通知的就要慢很多了,而且通知的消息也没那么灵活。
如果贵公司有内部通信工具,将 @xyz/xchat-node
换成对应通信工具 node 封装库即可。或者直接将 xchat
换成 nodemailer
,构建完成后发 Email 通知用户,更加通用。
- 安装
nodemailer
npm install nodemailer --save
- 使用
nodemailer
"use strict";
const nodemailer = require("nodemailer");
let transporter = nodemailer.createTransport({
// host: 'smtp.ethereal.email',
service: "qq", // 使用了内置传输发送邮件 查看支持列表:https://nodemailer.com/smtp/well-known/
port: 465, // SMTP 端口
secureConnection: true, // 使用了 SSL
auth: {
user: "xxxxxx@qq.com",
// 这里密码不是qq密码,是你设置的smtp授权码
pass: "xxxxxx"
}
});
let mailOptions = {
from: '"我是小可爱" <xxxxx@qq.com>', // sender address
to: "xxxxxxxx@163.com", // list of receivers
subject: "Hello", // Subject line
// 发送text或者html格式
// text: '我是小可爱?', // plain text body
html: "<b>我是小可爱?</b>" // html body
};
// send mail with defined transport object
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log("Message sent: %s", info.messageId);
});
备注:关于 nodemailer
的更多使用,请参考其官网说明。