git在CICD实践中的应用10:Gitee仓库webhook使用(上)
一、背景
本系列前面的文章,主要集中在国外的服务器,本文尝试在国内git托管平台Gitee上进行实验。
Gitee官网为:https://gitee.com。因其在国内,对于速度要求较高的团队,可以考虑该平台。
Gitee拥有很多第三方集成,如Jenkins、阿里云、华为、Azure等,同时也提供了WebHook(Web钩子)。WebHook可以理解为一个处理post请求的机制,甚至简单理解为一个http地址。当提交代码后,Gitee会自动回调这个地址,这个地址需要我们编写程序进响应,以便处理(如编译代码、发邮件,自动部署等)。WebHook支持很多种触发事件,如Push、Tag Push、Issue等,可根据需要选择。
本文抛却第三方集成,使用自己写程序的来测试WebHook。以一个简单的实用功能为例:当提交代码到Gitee仓库后,自动发送通知邮件。
本文需要具备云主机服务器,以便提供公网的响应地址。如无,考虑第三方集成服务。
二、知识点
WebHook数据格式说明在这里。
WebHook数据类型分头部(Request Headers)和数据体(Request Payload)。
头部说明如下:
Content-Type: application/json # 默认为 application/json , 若是旧版钩子(已不维护)为 application/x-www-form-urlencoded
User-Agent: git-oschina-hook # 固定为 git-oschina-hook,可用于标识为来自 gitee 的请求
X-Gitee-Token: webhook password # 用户新建 WebHook 时提供的密码
X-Gitee-Event: Merge Request Hook # 标识触发的钩子类型
不过在实测中没有找到方法读取。
不同的钩子类型,其数据体亦不同。具体参考官方示例,以Push类型为例进行简单说明:
- hook_name:钩子名称,如"push_hooks"。
- password:密码,在设置WebHook时指定,可通过密码判断请求合法性。
- commits为数组,如果多次commit,但只有一次push,则所有的commit在此数组中。第0个元素为最新提交的信息。有用的字段: id:提交的哈希值,可不理会。
- message:提交信息,需要记录。
- timestamp:提交时间,格式为"2018-02-05T23:46:46+08:00"。
- url:本次提交的具体地址。
- author:作者信息(结构体)。
- committer:提交者信息(结构体)。与author可能是相同的。
-
owner:仓库所有者信息。
三、webhook脚本文件
当仓库有Push时,Gitee会自动将上述信息post到指定的地址,我们获取消息体并解析出来需要的字段:
仓库名称、提交者、提交日志、提交时间。
将这些信息组装后,发送到指定邮箱地址中。完成本文提到的功能。
下面使用NodeJS来实现。需要依赖的库有koa(提供web服务)以及nodemailer(提供email功能)。
package.json文件内容:
{ "name": "foobar", "version": "0.0.1", "description": "hello world", "main": "server.js", "scripts": { "test": "run.sh" }, "author": "Late Lee", "license": "MIT", "dependencies": { "koa": "^2.11.0", "koa-bodyparser": "^4.2.1", "koa-router": "^7.4.0", "nodemailer": "^6.3.1" } }
实现文件:
/* 文件名:server.js 功能: gitee仓库Webhook应用实例:提交代码时发送邮件。 */ const koa_router = require("koa-router"); const Koa = require("koa"); const koa_bodyparser = require("koa-bodyparser"); const router = koa_router(); const nodemailer = require("nodemailer"); const g_port = 4000; // 创建与邮件对应列表 var g_list = [ ["latelee/webhook.git", "foo@bar.com"], ["latelee/autoci.git", "hello@163.com"], ["", "foo@foo.org"] // 最后一个为默认邮箱 ]; // 参数:发件人名称,收件人,主题,正文(支持html格式) function sendMail(aliasName, tos, subject, msg) { var from = "cicd@latelee.org"; const smtpTransport = nodemailer.createTransport({ host: 'smtp.exmail.qq.com', secureConnection: true, // use SSL secure: true, port: 465, auth: { user: from, pass: '1qaz@WSX', } }); smtpTransport.sendMail({ from : aliasName + ' ' + '<' + from + '>', to : tos, subject : subject, html : msg }, function(err, res) { if (err) { console.log('error: ', err); } }); } function nl2br(str, isXhtml) { var breakTag = (isXhtml || typeof isXhtml === 'undefined') ? '<br />' : '<br>'; var str = (str + '').replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"); return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2'); }; // 响应地址为foobar router.post("/foobar", async (ctx) => { var ret = 0; var passwd = ctx.request.body.password; console.log(`got reuqest. body:`); console.log(ctx.request.body); // 在设置WebHook时指定,此处判断,不合法直接返回 if (passwd != "helloworldpasswd") { ret = -1; } else { var commit = ctx.request.body.commits[0]; var respo = ctx.request.body.repository; var url = respo.git_http_url; var output = new Object(); output = '<h2>' + respo.name + '仓库代码有提交,请及时更新。</h2>地址为:<a href=\"' + url + '\"target=\"_blank\">' + url + '</a><br>'; output += '<h3>Committer:</h3>' + commit.committer.username + "<br>"; output += '<h3>Commit time:</h3>' + commit.timestamp + "<br>"; output += '<h3>Commit log:</h3>' + nl2br(commit.message) + "<br>"; console.log(output); // 匹配仓库及对应的邮箱列表 for (var i = 0; i < g_list.length; i++) { //console.log(`item: ${item[0]}, ${item[1]}`); var found = url.includes(g_list[i][0]); if (found) { console.log(`found at ${i} of ${g_list.length}`); break; } } console.log(`will sendto: ${g_list[i][1]}`); // 发邮件通知 // TODO:参数可配置 sendMail('CI自动邮件通知', g_list[i][1], respo.name + '仓库代码更新', output); } var res = new Object(); res['ret'] = ret; res['timestamp'] = Date.now(); // 当前时间戳 ctx.body = res; // 返回的是json,以便gitee获取,否则可能认为失败 }); function main() { var app = new Koa(); app.use(koa_bodyparser({ enableTypes:["json","test","form"], onerror:function (err,ctx){ console.log("api service body parse error",err); ctx.throw(400,"body parse error"); }, })); app.use(router.routes()); app.listen(g_port); console.log('Running a koa server at localhost[v1.0]: ', g_port) } main();
代码说明:
- 使用koa监听4000端口,响应页面地址为foobar。
- 判断请求数据的passwd字段,不合法直接返回。
- 针对不同项目使用g_list存储仓库地址及对应的邮箱地址(实际中不同项目组,其成员亦不同)。简单起见,可直接使用统一的邮箱地址。
- 需要返回值,否则Gitee页面提供Not found,不过已经处理完结,不返回亦可。
- 仓库和邮件地址根据实际情况修改。
在服务器运行:
npm install node server.js
即可启动服务。
四、配置
在Gitee上建立仓库后,进入WebHook配置界面,过程如图1所示:
图1
WebHook配置过程如图2所示:
图2
点击添加后,可以进行测试,如果没有运行服务,则连接测试失败。成功会显示返回值。
五、测试
当提交代码后(触发Push钩子),服务器响应信息如图3所示:
图3
片刻后,收到邮件,如图4所示:
图4
小结
根据Gitee文档描述,执行的超时时长为5秒。笔者仅做简单测试,在其范围之内。
发件人无法自由快捷选择。只能通过列表进行匹配。
本文的方法,在小团队中可使用。如果复杂大型项目,考虑Jenkins等第三方服务。
- 点赞
- 收藏
- 分享
- 文章举报
- git在CICD实践中的应用11:gitee仓库webhook使用(下)
- 在windows下,git webhook使用php拉取代码的学习总结
- 使用 IDEA + Maven + Git 快速开发 Web 应用
- 使用 IDEA + Maven + Git 快速开发 Java Web 应用
- 使用 IDEA + Maven + Git 快速开发 Java Web 应用
- 使用 IDEA + Maven + Git 快速开发 Java Web 应用
- (git)Bitbucket使用WebHook实现自动部署PHP代码
- 《Web 标准和SEO应用实践 》-使用免费的搜索系统
- 使用 IDEA + Maven + Git 快速开发 Web 应用
- 使用 IDEA + Maven + Git 快速开发 Java Web 应用
- tornado学习笔记11 Web应用中模板(Template)使用应用实践
- Gitee使用示例之~2台电脑1个账户1个仓库的交互更新
- 使用 IDEA + Maven + Git 快速开发 Web 应用
- 基础架构四-APP1:使用代码仓库、应用仓库、yum本地源完成CICD
- 使用 IDEA + Maven + Git 快速开发 Java Web 应用
- 使用 IDEA + Maven + Git 快速开发 Java Web 应用
- 使用 IDEA + Maven + Git 快速开发 Java Web 应用
- 玩转git之webhook应用初探
- 随心所欲生成git仓库任意一段commit的专用patch应用小实践
- 使用 IDEA + Maven + Git 快速开发 JAVA或者Web 应用(转)