Posted at

GitHubのPull Requestが作成されたら自動でレビューアをアサインする

More than 3 years have passed since last update.

WebHookから呼ばれることが前提


roulette.go

package main

import (
"encoding/json"
"io"
"log"
"math/rand"
"net/http"
"os"
"strings"
)

var (
githubToken = os.Getenv("GITHUB_TOKEN")
githubUsers = strings.Split(os.Getenv("GITHUB_REVIEWERS"), ",")
)

// assign reviewer
func assign(url string, user string) error {
assignBody := "{\"assignee\":\"" + user + "\"}"

// update state
r, _ := http.NewRequest("PATCH", url, strings.NewReader(assignBody))
r.Header.Add("Authorization", "token "+githubToken)
r.Header.Add("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(r)
defer resp.Body.Close()
if err != nil {
log.Print(err)
return err
}
return nil
}

func comment(url string, user string) error {
body := "{\"body\":\"@" + user + "please review\"}"
r, _ := http.NewRequest("POST", url, strings.NewReader(body))
r.Header.Add("Authorization", "token "+githubToken)
r.Header.Add("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(r)
defer resp.Body.Close()
if err != nil {
log.Print(err)
return err
}
return nil
}

func Hook(w http.ResponseWriter, req *http.Request) {
err := req.ParseForm()
if err != nil {
log.Print(err)
// TODO: 500 error
return
}

v := req.FormValue("payload")
var m map[string]interface{}
err = json.Unmarshal([]byte(v), &m)
if err != nil {
log.Print(err)
// TODO: 500 error
return
}

if m["action"] != "opened" {
return
}

links := m["pull_request"].(map[string]interface{})["_links"].(map[string]interface{})
assignUrl := links["issue"].(map[string]interface{})["href"].(string)
commentUrl := links["comments"].(map[string]interface{})["href"].(string)
reviewer := githubUsers[rand.Intn(len(githubUsers))]
assign(assignUrl, reviewer)
comment(commentUrl, reviewer)
}

func ping(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "pong\n")
}

func main() {
log.Printf("reviewer candidates are %v", githubUsers)
port := os.Getenv("PORT")
if len(port) == 0 {
port = "8000"
}
http.HandleFunc("/", Hook)
http.HandleFunc("/ping", ping)
log.Printf("start server. port: %v", port)
err := http.ListenAndServe(":"+port, nil)

if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}