WebHook
Webhook 允许第三方应用监听 CODING 上的特定事件,在这些事件发生时通过 HTTP POST 方式通知(超时 5 秒)到第三方应用指定的 Web URL。 例如项目有新的内容 Push,或是 Merge Request 有更新等。基于 WebHook 可方便实现自动部署,自动测试,自动打包,监控项目变化等。
新建 WebHook
在【项目设置】->【开发者选项】->【 WebHook 】页面,点击右上角【新建 WebHook 】按钮。
目前支持的监听事件具体如下图所示,包括代码仓库的 Push 事件、 MR 事件、项目协同相关事件、持续集成任务相关、制品库变动等等。
填写 WebHook 配置相关信息:
- 填写 URL,WebHook 会将事件内容发送这个地址。
- 内容格式:默认为 coding,可选择钉钉。
- WebHook 发布的内容可以选择不同的类型:
选择 application/json,发布时会直接装载 JSON 数据到 POST 的 body 中。
选择 application/x-www-form-urlencoded,发布时会把 JSON 数据作为一个称为 “payload” 的表格参数。
选择最适合您的那个类型,默认的 application/json 内容类型就很合适。
- 填写令牌,非必填项。
- 按需勾选您要监听的事件,默认勾选 Push 和 MR 事件。
- 默认勾选开启事件开关,事件触发时发送请求。
数据结构说明
每个事件类型都具有与该事件相关的数据结构。 不同事件的数据结构有所不同,但是都会包含事件的执行者(sender)以及事件发生所属的项目(repository)。
发送 Headers 说明
Header | 说明 |
---|---|
X-Coding-Event | 事件名(例如: push, merge request) |
X-Coding-Signature | 通过 HMAC SHA1 加密算法、使用令牌作为 KEY 将发送内容加密后的值以十六进制显示(需要配置令牌),并包含前缀 sha1= |
X-Coding-Delivery | 标识此次发送的唯一 ID |
User-Agent | Coding.net Hook |
发送的具体内容示例
POST /payload HTTP/1.1
Host: localhost:4567
Request method: POST
User-Agent: Coding.net Hook
X-Coding-Event: push
X-Coding-Delivery: bf3f043a-3883-433c-8e20-312b04c49b46
X-Coding-WebHook-Version: v2
X-Coding-Signature: sha1=561d0f6d8762ebddc09e10f83c7aaad18a622121
{
"ref": "refs/heads/master",
"before": "0000000000000000000000000000000000000000",
"after": "9853d6bd3032c71413bd7914bb0696e186ea9d04",
"created": true,
"deleted": false,
"compare": "https://my-team.coding.net/p/demo/git/compare/0000000000000...9853d6bd3032c",
"head_commit": {
"id": "9853d6bd3032c71413bd7914bb0696e186ea9d04",
"distinct": false,
"message": "Initial commit\n",
"timestamp": 1587958379000,
"url": "https://my-team.coding.net/api/team/my-team/project/demo/git/commit/9853d6bd3032c71413bd7914bb0696e186ea9d04",
"author": {
"name": "tom",
"email": "tom@example.com",
"username": "tom"
},
"committer": {
"name": "tom",
"email": "tom@example.com",
"username": "tom"
},
"added": [
".gitignore",
"README.md"
],
"removed": [],
"modified": []
},
"pusher": {
"name": "tom",
"email": "tom@example.com",
"username": "KMRnIKgzbV"
},
"sender": {
"id": 183478,
"login": "KMRnIKgzbV",
"avatar_url": "https://coding-net-production-static-ci.codehub.cn/2cb665a3-bebc-4b09-aa00-2b6df3e33edc.jpg?imageMogr2/auto-orient/format/jpeg/cut/400x400x0x0",
"url": "https://my-team.coding.net/api/user/key/KMRnIKgzbV",
"html_url": "https://my-team.coding.net/u/KMRnIKgzbV",
"name": "tom",
"name_pinyin": "tom"
},
"repository": {
"id": 7510657,
"name": "hello-world",
"full_name": "my-team/demo/hello-world",
"owner": {
"id": 183478,
"login": "KMRnIKgzbV",
"avatar_url": "https://coding-net-production-static-ci.codehub.cn/2cb665a3-bebc-4b09-aa00-2b6df3e33edc.jpg?imageMogr2/auto-orient/format/jpeg/cut/400x400x0x0",
"url": "https://my-team.coding.net/api/user/key/KMRnIKgzbV",
"html_url": "https://my-team.coding.net/u/KMRnIKgzbV",
"name": "tom",
"name_pinyin": "tom"
},
"private": true,
"html_url": "https://my-team.coding.net/p/demo",
"description": "",
"fork": false,
"url": "https://my-team.coding.net/api/team/my-team/project/demo",
"created_at": 1572178283000,
"updated_at": 1572178283000,
"clone_url": "https://e.coding.net/my-team/demo/hello-world.git",
"ssh_url": "git@e.coding.net:my-team/demo/hello-world.git",
"default_branch": "master"
}
}
签名解析 Demo
每个事件都包含的属性
Key | Value |
---|---|
sender | 事件触发者 |
repository | 当前项目 |
Node.js 示例代码
var express = require('express');
var bodyParser = require('body-parser');
var multer = require('multer');
var process = require('child_process');
var bodyParser = require('body-parser');
var multer = require('multer');
var app = express();
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
app.use(multer()); // for parsing multipart/form-data
app.post('/webhook', function(req,res){
console.log('print', req.body);
console.info(req.body["token"]);
if('xxx' === req.body['token'] ){
console.info(process);
process.exec('git pull', {'cwd':'/home/coding/workspace'},
function (error, stdout, stderr) {
console.log('stdout========================\n' + stdout);
console.log('stderr========================\n' + stderr);
if (error !== null) {
res.send('fail!!!\n' + stdout + error + '
');
} else {
res.send('done!!!\n' + stdout + '
');
}
});
} else {
console.log(' failed token ')
res.send('token不正确?
');
}
});
app.set('port', 8080);
var server = app.listen( 8080, function() {
console.log('Listening on port %d', server.address().port);
})
Ruby 示例代码
基于 sinatra 框架实现的 webhook 处理。
#!/usr/bin/env ruby
require "sinatra"
require "json/stream"
get "/" do
'Hello world!'
end
post "/hook" do
@text = request.body.read
@data = JSON::Stream::Parser.parse(@text)
puts @data['token']
puts @data['ref']
puts @data['token']
puts @data['zen']
puts @data['commits']
puts @data['repository']
puts @data['url']
if "123" == @data['token']
puts `cd workspace`
puts `git pull `
end
end
get "/env" do
content_type :text/plain
html = ""
html << "System Environment:\n\n"
ENV.each do |key, value|
html << "#{key}: #{value}\n"
end
html
end
PHP 示例代码
< ?php
$input = json_decode(file_get_contents("php://input"), true);
$message = '';
switch ($_SERVER['HTTP_X_CODING_EVENT']) {
case 'ping':
$message = 'pong';
break;
case 'push':
$tmp = sys_get_temp_dir();
$path = "$tmp/{$input['repository']['name']}";
$cmd = "rm -rf $path; cd $tmp; git clone {$input['repository']['clone_url']}";
$message = shell_exec($cmd);
break;
}
header('Content-Type: application/json');
echo json_encode(compact('message'));
Ping 事件接口说明
当您创建一个新的 WebHook 时,我们将向您发送一个简单的 ping 事件,让您知道 WebHook 是否能够成功发送。您可以在 WebHooks 列表中,通过点击 ping 按钮再次触发 ping。
事件名: ping
Key | Value |
---|---|
zen | Coding! 让开发更简单 |
hook_id | 当前 WebHook 的 ID |
hook | 当前 WebHook 的配置数据 |
Push 事件接口说明
当您向您的仓库推送新的代码时,我们将向您发送一个的 Push 事件。
事件名: push
Key | Value |
---|---|
hook_id | 当前 WebHook 的 ID |
hook | 当前 WebHook 的配置数据 |
ref | 推送的 commit sha |
before | 该分支之前的 commit sha |
after | 该分支新的 commit sha |
compare | compare 的 url 地址 |
commits | 更新的 commits 内容 |
head_commit | 最新的 commit 内容 |
pusher | 推送者 |
MR 事件接口说明
当您进行一个代码合并相关操作时,我们将向您发送的 MR 事件。
事件名: merge request
Key | Value |
---|---|
action | (“synchronize”, “create”, “merge”) |
number | 项目内资源 id |
mergeRequest | 合并请求内容 |
Task 事件接口说明
当您进行任务相关操作时,我们将向您发送 Task 事件。
事件名: task
Key | Value |
---|---|
action | (“assigned”, “labeled”, “opened”, “edited”, “closed”, “reopened”, “deleted”) |
task | 任务内容 |
Document 事件接口说明
当您进行文件相关操作时,我们将向您发送 Document 事件。
事件名: document
Key | Value |
---|---|
action | (“create_file”, “create_dir”, “delete_file”, “delete_dir”, “update_file”, “update_dir”, “upload_file”, “move_file”, “delete_file_history”, “rename”, “move_folder”, “move_files_or_folders”, “share_file”, “stop_share_file”) |
document | 文件内容 |
Member 事件接口说明
当您新增或者删除项目成员时,我们将向您发送 Member 事件。
事件名: member
Key | Value |
---|---|
action | (“added”, “deleted”) |
member | member 内容 |
持续集成事件接口说明
持续集成提供持续集成任务创建、触发、停止、完成、删除等接口的 WebHook。
数据结构 - 钉钉格式
Header
Request URL: [hook url]
Request method: POST
User-Agent: Coding.net Hook
Body
{
"markdown": {
"title": "alexli 触发了 job job11, 构建号:8",
"text": "###### 项目 [ci-demo](https://alexli.coding.net/p/ci-demo)\n[alexli](https://alexli.coding.net/u/NeayPucMAz) 触发了 job \n> [job11](https://alexli.coding.net/p/ci-demo/ci/job/47379) 构建号:[8](https://alexli.coding.net/p/ci-demo/ci/job/47379/build/8/pipeline)"
},
"msgtype": "markdown"
}
数据结构 - coding 格式
Header
Header | 说明 |
---|---|
X-Coding-Event | WebHook Event 的类型 ci |
X-Coding-Delivery | 唯一标识 GUID |
X-Coding-WebHook-Version | Coding WebHook : v2 |
Request URL: [hook url]
Request method: POST
User-Agent: Coding.net Hook
Body
Body | 说明 |
---|---|
action | ci 动态描述:{trigger_build, update_job, delete_build, complete_build, delete_job} |
ci | ci 构建详情,详见示例 |
sender | 发送者详情,详见示例 |
repository | 仓库详情,详见示例 |
示例
{
"action": "trigger_build",
"ci": {
"id": 47379,
"name": "job1",
"branch_regex": "",
"cron_spec": "",
"creator_id": 134556,
"project_id": 185439,
"depot_id": 181722,
"execute_in": "CVM",
"jenkins_file_path": "Jenkinsfile",
"created_at": 1565143387000,
"updated_at": 1570504872000,
"trigger_method": "",
"branch_selector": "",
"hook_type": "DEFAULT",
"trigger_remind": "ALWAYS",
"build": {
"id": 257665,
"number": 7,
"cci_id": "cci-264261-576675",
"cause": "alexli 手动触发",
"commit_id": "ec107f22a99a3a850c55702ad06175850f114cfa",
"branch": "",
"uuid": "dacd59f1-aaaa-4c3d-b387-74d06df55aed",
"job_id": 47379,
"trigger_user_id": 134556,
"created_at": 1571377790000,
"updated_at": 1571377790000,
"pre_status": "NORMAL",
"failed_message": "",
"duration": 0,
"status": "QUEUED"
}
},
"sender": {
"id": 134556,
"login": "NeayPucMAz",
"avatar_url": "https://coding-net-production-static-ci.codehub.cn/bceaa53a-6a01-436d-b470-c90dfc92e478.jpg?imageMogr2/auto-orient/format/jpeg/cut/200x200x0x0",
"url": "https://alexli1.coding.net/api/user/key/NeayPucMAz",
"html_url": "https://alexli1.coding.net/u/NeayPucMAz",
"name": "alexli",
"name_pinyin": "alexli"
},
"repository": {
"id": 185439,
"name": "ci-demo",
"full_name": "alexli1/ci-demo",
"owner": {
"id": 134556,
"login": "NeayPucMAz",
"avatar_url": "https://coding-net-production-static-ci.codehub.cn/bceaa53a-6a01-436d-b470-c90dfc92e478.jpg?imageMogr2/auto-orient/format/jpeg/cut/200x200x0x0",
"url": "https://alexli1.coding.net/api/user/key/NeayPucMAz",
"html_url": "https://alexli1.coding.net/u/NeayPucMAz",
"name": "alexli",
"name_pinyin": "alexli"
},
"private": true,
"html_url": "https://alexli1.coding.net/p/ci-demo",
"description": "",
"fork": false,
"url": "https://alexli1.coding.net/api/team/alexli1/project/ci-demo",
"created_at": 1565143382000,
"updated_at": 1567398344000,
"clone_url": "https://e.coding.net/alexli1/ci-demo.git",
"ssh_url": "git@e.coding.net:alexli1/ci-demo.git",
"default_branch": "master"
}
}
制品库事件接口说明
制品库提供制品发布、更新版本的 WebHook。
数据结构 - 钉钉&格式
Header
Request URL: [hook url]
Request method: POST
User-Agent: Coding.net Hook
Body
{
"markdown": {
"title": "制品库动态",
"text": "###### 项目 [Test](https://test.coding.net/p/test)\n[Test](https://test.coding.net/u/testproject) 在```Docker```类型制品库 ```test-repo``` 中发布了制品 ```test``` 的版本 ```1.0.0```",
"content": "###### 项目 [Test](https://test.coding.net/p/test)\n[Test](https://test.coding.net/u/testproject) 在```Docker```类型制品库 ```test-repo``` 中发布了制品 ```test``` 的版本 ```1.0.0```"
},
"msgtype": "markdown"
}
数据结构 - coding 格式
Header
Header | 说明 |
---|---|
X-Coding-Event | WebHook Event 的类型 artifact |
X-Coding-Delivery | 唯一标识 GUID |
X-Coding-WebHook-Version | Coding WebHook : v2 |
Request URL: [hook url]
Request method: POST
User-Agent: Coding.net Hook
Body
Body | 说明 |
---|---|
action | 制品动态描述:create 或者 update |
artifact | 制品详情,详见示例 |
sender | 发送者详情,详见示例 |
repository | 仓库详情,详见示例 |
示例
{
"action": "update",
"artifact": {
"projectId": 872359,
"artifactRepoId": 21,
"artifactPkgId": 148135,
"artifactVersionId": 943729,
"userId": 571222,
"size": 7622367,
"artifactRepoName": "testRepo",
"artifactPkgName": "testPkg",
"artifactVersionName": "1.0.0",
"action": "update",
"artifactType": "docker",
"projectName": "xxx",
"userName": "xxx"
},
"sender": {
"id": 57122,
"login": "User Global Key",
"avatar_url": "https://coding-net-production-static-ci.codehub.cn/WM-TEXT-AVATAR-nYJfjngwaMZsAZXhgfcN.jpg",
"url": "https://codingcorp.coding.net/api/user/key/xxx",
"html_url": "https://codingcorp.coding.net/u/xxx",
"name": "Test User",
"name_pinyin": "Test User"
},
"repository": {
"id": 87239,
"name": "xxx",
"full_name": "xxx",
"owner": {
"id": 57122,
"login": "User Global Key",
"avatar_url": "https://coding-net-production-static-ci.codehub.cn/WM-TEXT-AVATAR-nYJfjngwaMZsAZXhgfcN.jpg",
"url": "https://codingcorp.coding.net/api/user/key/xxx",
"html_url": "https://codingcorp.coding.net/u/xxx",
"name": "xxx",
"name_pinyin": "xxx"
},
"private": true,
"html_url": "https://codingcorp.coding.net/p/xxx",
"description": "项目描述",
"fork": false,
"url": "https://codingcorp.coding.net/api/team/mai/project/xxx",
"created_at": 1554781241000,
"updated_at": 1567397098000,
"clone_url": "https://e.coding.net/xxx/xxx.git",
"ssh_url": "git@e.coding.net:xxx/xxx.git",
"default_branch": "master"
}
}
在阅读中是否遇到以下问题?*
您希望我们如何改进?*
如果您希望得到回复,请留下您的邮箱地址。