golang实现GitHub和Bitbucket的Webhook接收功能插件库webhooks的使用

Golang实现GitHub和Bitbucket的Webhook接收功能插件库webhooks的使用

简介

webhooks库可以方便地接收和解析GitHub、Bitbucket、GitLab、Docker Hub、Gogs和Azure DevOps的Webhook事件。

主要特性:

  • 解析整个payload,而不仅仅是几个字段
  • 字段和结构直接对应webhook发布的json

注意事项:

  • 目前仅接受json payload

安装

使用go get安装:

go get -u github.com/go-playground/webhooks/v6

然后在代码中导入包:

import "github.com/go-playground/webhooks/v6"

使用示例

GitHub Webhook示例

package main

import (
	"fmt"
	"net/http"
	"github.com/go-playground/webhooks/v6/github"
)

const (
	path = "/webhooks"
)

func main() {
	// 创建GitHub webhook实例,设置secret
	hook, _ := github.New(github.Options.Secret("MyGitHubSuperSecretSecret...?"))

	// 设置HTTP处理函数
	http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
		// 解析请求,只处理ReleaseEvent和PullRequestEvent
		payload, err := hook.Parse(r, github.ReleaseEvent, github.PullRequestEvent)
		if err != nil {
			if err == github.ErrEventNotFound {
				// 事件不是我们要处理的类型
			}
		}
		
		// 根据事件类型处理
		switch payload.(type) {
		case github.ReleasePayload:
			release := payload.(github.ReleasePayload)
			// 处理release事件...
			fmt.Printf("%+v", release)

		case github.PullRequestPayload:
			pullRequest := payload.(github.PullRequestPayload)
			// 处理pull request事件...
			fmt.Printf("%+v", pullRequest)
		}
	})
	
	// 启动HTTP服务器
	http.ListenAndServe(":3000", nil)
}

Bitbucket Webhook示例

package main

import (
	"fmt"
	"net/http"
	"github.com/go-playground/webhooks/v6/bitbucket"
)

const (
	path = "/webhooks"
)

func main() {
	// 创建Bitbucket webhook实例
	hook, _ := bitbucket.New(bitbucket.Options.Secret("MyBitbucketSecret"))

	http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
		// 解析请求,处理Push和PullRequest事件
		payload, err := hook.Parse(r, bitbucket.RepoPushEvent, bitbucket.PullRequestCreatedEvent)
		if err != nil {
			if err == bitbucket.ErrEventNotFound {
				// 事件不是我们要处理的类型
			}
		}
		
		switch payload.(type) {
		case bitbucket.RepoPushPayload:
			push := payload.(bitbucket.RepoPushPayload)
			// 处理push事件...
			fmt.Printf("Received push: %+v", push)

		case bitbucket.PullRequestCreatedPayload:
			pr := payload.(bitbucket.PullRequestCreatedPayload)
			// 处理pull request创建事件...
			fmt.Printf("New PR created: %+v", pr)
		}
	})
	
	http.ListenAndServe(":3000", nil)
}

注意事项

  1. 确保在GitHub/Bitbucket的webhook设置中使用相同的secret
  2. 服务器需要能够从公网访问,才能接收webhook通知
  3. 根据实际需求处理不同的事件类型
  4. 生产环境中建议添加更多的错误处理和日志记录

贡献

欢迎提交其他服务的pull request!如果是破坏性变更,请先创建issue讨论。

许可证

基于MIT许可证分发,更多细节请查看代码中的许可证文件。


更多关于golang实现GitHub和Bitbucket的Webhook接收功能插件库webhooks的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现GitHub和Bitbucket的Webhook接收功能插件库webhooks的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用webhooks库实现GitHub和Bitbucket的Webhook接收

下面我将介绍如何使用golang的webhooks库来接收GitHub和Bitbucket的Webhook通知,并提供完整的示例代码。

安装webhooks库

首先安装webhooks库:

go get github.com/go-playground/webhooks/v6

GitHub Webhook接收实现

package main

import (
	"fmt"
	"net/http"
	"os"

	"github.com/go-playground/webhooks/v6/github"
)

const (
	path = "/webhooks"
)

func main() {
	// 从环境变量获取GitHub的webhook secret
	secret := os.Getenv("GITHUB_WEBHOOK_SECRET")
	if secret == "" {
		panic("GITHUB_WEBHOOK_SECRET environment variable not set")
	}

	// 创建GitHub webhook实例
	hook, err := github.New(github.Options.Secret(secret))
	if err != nil {
		panic(err)
	}

	// 注册HTTP处理函数
	http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
		// 解析GitHub事件
		payload, err := hook.Parse(r, 
			github.PushEvent, 
			github.PullRequestEvent,
			github.IssuesEvent,
		)
		if err != nil {
			if err == github.ErrEventNotFound {
				// 事件类型未注册
				fmt.Printf("Unregistered event: %v\n", err)
				w.WriteHeader(http.StatusOK)
				return
			}
			fmt.Printf("Error parsing webhook: %v\n", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		// 根据事件类型处理payload
		switch payload := payload.(type) {
		case github.PushPayload:
			// 处理push事件
			fmt.Printf("Received push event on %s\n", payload.Repository.FullName)
			fmt.Printf("Commit by %s: %s\n", payload.Pusher.Name, payload.HeadCommit.Message)
			
		case github.PullRequestPayload:
			// 处理pull request事件
			fmt.Printf("Received PR event: %s %s\n", payload.Action, payload.PullRequest.Title)
			
		case github.IssuesPayload:
			// 处理issues事件
			fmt.Printf("Received issue event: %s %s\n", payload.Action, payload.Issue.Title)
		}

		w.WriteHeader(http.StatusOK)
	})

	// 启动HTTP服务器
	fmt.Println("Server listening on :8080")
	http.ListenAndServe(":8080", nil)
}

Bitbucket Webhook接收实现

package main

import (
	"fmt"
	"net/http"
	"os"

	"github.com/go-playground/webhooks/v6/bitbucket"
)

const (
	path = "/webhooks"
)

func main() {
	// 从环境变量获取Bitbucket的webhook secret
	secret := os.Getenv("BITBUCKET_WEBHOOK_SECRET")
	if secret == "" {
		panic("BITBUCKET_WEBHOOK_SECRET environment variable not set")
	}

	// 创建Bitbucket webhook实例
	hook, err := bitbucket.New(bitbucket.Options.Secret(secret))
	if err != nil {
		panic(err)
	}

	// 注册HTTP处理函数
	http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
		// 解析Bitbucket事件
		payload, err := hook.Parse(r, 
			bitbucket.RepoPushEvent,
			bitbucket.PullRequestCreatedEvent,
			bitbucket.PullRequestUpdatedEvent,
		)
		if err != nil {
			if err == bitbucket.ErrEventNotFound {
				// 事件类型未注册
				fmt.Printf("Unregistered event: %v\n", err)
				w.WriteHeader(http.StatusOK)
				return
			}
			fmt.Printf("Error parsing webhook: %v\n", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		// 根据事件类型处理payload
		switch payload := payload.(type) {
		case bitbucket.RepoPushPayload:
			// 处理push事件
			fmt.Printf("Received push event on %s\n", payload.Repository.FullName)
			for _, change := range payload.Push.Changes {
				fmt.Printf("Change: %s -> %s\n", change.Old.Name, change.New.Name)
			}
			
		case bitbucket.PullRequestPayload:
			// 处理pull request事件
			fmt.Printf("Received PR event: %s %s\n", payload.PullRequest.Title, payload.Actor.DisplayName)
		}

		w.WriteHeader(http.StatusOK)
	})

	// 启动HTTP服务器
	fmt.Println("Server listening on :8080")
	http.ListenAndServe(":8080", nil)
}

配置说明

  1. Webhook Secret:

    • 从环境变量获取secret,确保安全性
    • 需要在GitHub/Bitbucket的webhook设置中配置相同的secret
  2. 事件类型:

    • 代码中只注册了部分事件类型,可以根据需要添加更多
    • 完整的事件类型列表参考webhooks库文档
  3. 部署:

    • 需要将服务部署到公网可访问的地址
    • 在GitHub/Bitbucket的仓库设置中配置webhook URL

高级功能

  1. 同时支持多个平台:
func main() {
	// 初始化GitHub和Bitbucket的hook
	githubHook, _ := github.New(github.Options.Secret(os.Getenv("GITHUB_SECRET")))
	bitbucketHook, _ := bitbucket.New(bitbucket.Options.Secret(os.Getenv("BITBUCKET_SECRET")))

	http.HandleFunc("/webhooks", func(w http.ResponseWriter, r *http.Request) {
		// 根据请求头判断来源
		switch r.Header.Get("X-GitHub-Event") {
		case "push", "pull_request":
			handleGitHub(githubHook, w, r)
		case "repo:push", "pullrequest:created":
			handleBitbucket(bitbucketHook, w, r)
		default:
			w.WriteHeader(http.StatusBadRequest)
		}
	})
	
	http.ListenAndServe(":8080", nil)
}
  1. 添加中间件:
func authMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// 验证IP白名单或其他认证逻辑
		if !isAllowed(r.RemoteAddr) {
			w.WriteHeader(http.StatusForbidden)
			return
		}
		next(w, r)
	}
}

func main() {
	http.HandleFunc("/webhooks", authMiddleware(handleWebhook))
}

总结

使用webhooks库可以方便地接收和处理GitHub和Bitbucket的webhook通知。主要步骤包括:

  1. 初始化对应平台的hook实例
  2. 注册需要处理的事件类型
  3. 实现HTTP处理函数解析payload
  4. 根据不同类型的事件进行相应处理

这个库简化了webhook的验证和解析过程,让开发者可以专注于业务逻辑的实现。

回到顶部