gogs推送入参如下
{
"ref": "refs/heads/develop",
"before": "28e1879d029cb852e4844d9c718537df08844e03",
"after": "bffeb74224043ba2feb48d137756c8a9331c449a",
"compare_url": "http://localhost:3000/unknwon/webhooks/compare/28e1879d029cb852e4844d9c718537df08844e03...bffeb74224043ba2feb48d137756c8a9331c449a",
"commits": [
{
"id": "bffeb74224043ba2feb48d137756c8a9331c449a",
"message": "!@#0^%\u003e\u003e\u003e\u003e\u003c\u003c\u003c\u003c\u003e\u003e\u003e\u003e\n",
"url": "http://localhost:3000/unknwon/webhooks/commit/bffeb74224043ba2feb48d137756c8a9331c449a",
"author": {
"name": "Unknwon",
"email": "u@gogs.io",
"username": "unknwon"
},
"committer": {
"name": "Unknwon",
"email": "u@gogs.io",
"username": "unknwon"
},
"timestamp": "2017-03-13T13:52:11-04:00"
}
],
"repository": {
"id": 140,
"owner": {
"id": 1,
"login": "unknwon",
"full_name": "Unknwon",
"email": "u@gogs.io",
"avatar_url": "https://secure.gravatar.com/avatar/d8b2871cdac01b57bbda23716cc03b96",
"username": "unknwon"
},
"name": "webhooks",
"full_name": "unknwon/webhooks",
"description": "",
"private": false,
"fork": false,
"html_url": "http://localhost:3000/unknwon/webhooks",
"ssh_url": "ssh://unknwon@localhost:2222/unknwon/webhooks.git",
"clone_url": "http://localhost:3000/unknwon/webhooks.git",
"website": "",
"stars_count": 0,
"forks_count": 1,
"watchers_count": 1,
"open_issues_count": 7,
"default_branch": "master",
"created_at": "2017-02-26T04:29:06-05:00",
"updated_at": "2017-03-13T13:51:58-04:00"
},
"pusher": {
"id": 1,
"login": "unknwon",
"full_name": "Unknwon",
"email": "u@gogs.io",
"avatar_url": "https://secure.gravatar.com/avatar/d8b2871cdac01b57bbda23716cc03b96",
"username": "unknwon"
},
"sender": {
"id": 1,
"login": "unknwon",
"full_name": "Unknwon",
"email": "u@gogs.io",
"avatar_url": "https://secure.gravatar.com/avatar/d8b2871cdac01b57bbda23716cc03b96",
"username": "unknwon"
}
}
对我们而言,有需要通知的就:谁推送了代码到哪个分支,什么时间,仓库地址和代码详情,还有就是变更的代码明细。
使用go中gin框架作为基础,将需要处理的参数声明成结构体
type Commit struct {
ID string `json:"id"`
Message string `json:"message"`
URL string `json:"url"`
Author Author `json:"author"`
Committer Committer `json:"committer"`
Modified []string `json:"modified"`
Timestamp string `json:"timestamp"`
}
type Author struct {
Name string `json:"name"`
Email string `json:"email"`
Username string `json:"username"`
}
type Committer struct {
Name string `json:"name"`
Email string `json:"email"`
Username string `json:"username"`
}
type Repository struct {
HTMLURL string `json:"html_url"`
}
type PushEvent struct {
Ref string `json:"ref"`
Commits []Commit `json:"commits"`
Repository Repository `json:"repository"`
}
处理请求参数
func GetMessage(c *gin.Context) {
body, err := io.ReadAll(c.Request.Body)
if err != nil {
c.JSON(500, gin.H{"error": "无法读取请求体"})
return
}
var pushEvent PushEvent
err = json.Unmarshal(body, &pushEvent)
if err != nil {
c.JSON(400, gin.H{"error": "JSON 解析错误"})
return
}
var times string
var info string
var author string
var link string
var timestamp int64
var sign string
now := time.Now()
// 获取时间戳(秒)
timestamp = now.Unix()
for _, commit := range pushEvent.Commits {
// 将时间字符串解析为时间对象
timeObj, err := time.Parse(time.RFC3339, commit.Timestamp)
if err != nil {
fmt.Println("时间解析错误:", err)
continue
}
// 格式化时间为 "2024/01/15"
formattedTime := timeObj.Format("2006/01/02")
times = formattedTime
info = commit.Message
link = commit.URL
author = commit.Author.Name
}
将入参读取,序列化成json,然后把json数据装回结构体,然后取出参数
并赋值
代码解耦再单独写一个推送飞书的方法,新建结构体
type MessageData struct {
Timestamp int64
Sign string
Author string
Stash string
Branch string
Time string
Info string
Link string
}
func pushFeiShu(data MessageData) {
url := “https://open.feishu.cn/open-apis/bot/v2/hook/你的机器人hookid”
// 构建飞书消息体
msg := map[string]interface{}{
"timestamp": data.Timestamp,
"sign": data.Sign, // 得到的签名字符串。
"msg_type": "interactive",
"card": map[string]interface{}{
"config": map[string]interface{}{
"wide_screen_mode": true,
},
"header": map[string]interface{}{
"template": "green",
"title": map[string]interface{}{
"tag": "plain_text",
"content": fmt.Sprintf("🟢 %s推送了代码", data.Author),
},
},
"elements": []map[string]interface{}{
{
"fields": []map[string]interface{}{
{
"is_short": false,
"text": map[string]interface{}{
"content": fmt.Sprintf("? 目标仓库: %s", data.Stash),
"tag": "lark_md",
},
},
{
"is_short": false,
"text": map[string]interface{}{
"content": fmt.Sprintf("🔀 目标分支: %s", data.Branch),
"tag": "lark_md",
},
},
{
"is_short": false,
"text": map[string]interface{}{
"content": fmt.Sprintf("📅 推送时间: %s", data.Time),
"tag": "lark_md",
},
},
{
"is_short": false,
"text": map[string]interface{}{
"content": fmt.Sprintf("📝 最新提交:%s", data.Info),
"tag": "lark_md",
},
},
},
"tag": "div",
},
{
"tag": "action",
"actions": []map[string]interface{}{
{
"tag": "button",
"text": map[string]interface{}{
"tag": "plain_text",
"content": "查看代码",
},
"type": "primary",
"multi_url": map[string]interface{}{
"url": data.Link,
},
},
},
},
},
},
}
// 将消息体转换为 JSON 字节数组
payload, err := json.Marshal(msg)
if err != nil {
fmt.Println("消息体转换失败:", err)
return
}
// 创建一个 HTTP 请求
req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
if err != nil {
fmt.Println("创建请求失败:", err)
return
}
// 设置请求头
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("请求发送失败:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("读取响应失败:", err)
return
}
fmt.Println("响应:", string(body))
}
push方法调用
data := MessageData{
Author: author,
Timestamp: timestamp,
Sign: sign,
Stash: pushEvent.Repository.HTMLURL,
Branch: pushEvent.Ref,
Time: times,
Info: info,
Link: link,
}
pushFeiShu(data)
c.JSON(200, gin.H{"message": "处理成功"})
注意:
如果飞书机器人配置了验证签名则需要单独处理添加签名,代码如下
package utils
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
)
func GenSign(secret string, timestamp int64) (string, error) {
//timestamp + key 做sha256, 再进行base64 encode
stringToSign := fmt.Sprintf("%v", timestamp) + "\n" + secret
var data []byte
h := hmac.New(sha256.New, []byte(stringToSign))
_, err := h.Write(data)
if err != nil {
return "", err
}
signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
return signature, nil
}
添加接口地址
测试推送