From d0c5d88421ff2dd9f36d1a447eeb2ddf952a769d Mon Sep 17 00:00:00 2001 From: Tomoya Chiba Date: Mon, 7 Jun 2021 17:57:29 +0900 Subject: [PATCH] Allow GitHub Actions to notify as pull request comments --- ci.go | 40 ++++++++++++++++ ci_test.go | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 173 insertions(+), 3 deletions(-) diff --git a/ci.go b/ci.go index f77cc03..9e3ffa0 100644 --- a/ci.go +++ b/ci.go @@ -1,7 +1,9 @@ package main import ( + "encoding/json" "fmt" + "io/ioutil" "os" "regexp" "strconv" @@ -20,6 +22,20 @@ type PullRequest struct { Number int } +type gitHubActionsEventIssue struct { + Number int `json:"number"` +} + +type gitHubActionsEventPullRequest struct { + Number int `json:"number"` +} + +type gitHubActionsEventPayload struct { + Issue *gitHubActionsEventIssue `json:"issue"` + PullRequest *gitHubActionsEventPullRequest `json:"pull_request"` + Number int `json:"number"` +} + func circleci() (ci CI, err error) { ci.PR.Number = 0 ci.PR.Revision = os.Getenv("CIRCLE_SHA1") @@ -144,6 +160,30 @@ func githubActions() (ci CI, err error) { os.Getenv("GITHUB_RUN_ID"), ) ci.PR.Revision = os.Getenv("GITHUB_SHA") + + // Extract the pull request number from the event payload that triggered the current workflow. + // See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows + ci.PR.Number = 0 + eventPath := os.Getenv("GITHUB_EVENT_PATH") + if eventPath != "" { + bytes, err := ioutil.ReadFile(eventPath) + if err != nil { + return ci, err + } + + eventPayload := gitHubActionsEventPayload{} + if err := json.Unmarshal(bytes, &eventPayload); err != nil { + return ci, err + } + + if eventPayload.Issue != nil { + ci.PR.Number = eventPayload.Issue.Number + } else if eventPayload.PullRequest != nil { + ci.PR.Number = eventPayload.PullRequest.Number + } else { + ci.PR.Number = eventPayload.Number + } + } return ci, err } diff --git a/ci_test.go b/ci_test.go index 7d0eac9..0c9e40d 100644 --- a/ci_test.go +++ b/ci_test.go @@ -1,6 +1,7 @@ package main import ( + "io/ioutil" "os" "reflect" "testing" @@ -708,11 +709,32 @@ func TestGitLabCI(t *testing.T) { } } +func createTempfile(content string) (*os.File, error) { + tempfile, err := ioutil.TempFile("", "") + if err != nil { + return tempfile, err + } + + _, err = tempfile.Write([]byte(content)) + if err != nil { + return tempfile, err + } + + err = tempfile.Close() + if err != nil { + return tempfile, err + } + + return tempfile, nil +} + func TestGitHubActions(t *testing.T) { + envs := []string{ "GITHUB_SHA", "GITHUB_REPOSITORY", "GITHUB_RUN_ID", + "GITHUB_EVENT_PATH", } saveEnvs := make(map[string]string) for _, key := range envs { @@ -727,15 +749,40 @@ func TestGitHubActions(t *testing.T) { // https://help.github.com/ja/actions/configuring-and-managing-workflows/using-environment-variables testCases := []struct { - fn func() + fn func() func() ci CI ok bool }{ { - fn: func() { + fn: func() func() { + os.Setenv("GITHUB_SHA", "abcdefg") + os.Setenv("GITHUB_REPOSITORY", "mercari/tfnotify") + os.Setenv("GITHUB_RUN_ID", "12345") + os.Setenv("GITHUB_EVENT_PATH", "") + + return func() {} + }, + ci: CI{ + PR: PullRequest{ + Revision: "abcdefg", + Number: 0, + }, + URL: "https://github.com/mercari/tfnotify/actions/runs/12345", + }, + ok: true, + }, + { + fn: func() func() { os.Setenv("GITHUB_SHA", "abcdefg") os.Setenv("GITHUB_REPOSITORY", "mercari/tfnotify") os.Setenv("GITHUB_RUN_ID", "12345") + + tempfile, _ := createTempfile("{}") + os.Setenv("GITHUB_EVENT_PATH", tempfile.Name()) + + return func() { + os.Remove(tempfile.Name()) + } }, ci: CI{ PR: PullRequest{ @@ -746,10 +793,93 @@ func TestGitHubActions(t *testing.T) { }, ok: true, }, + { + fn: func() func() { + os.Setenv("GITHUB_SHA", "abcdefg") + os.Setenv("GITHUB_REPOSITORY", "mercari/tfnotify") + os.Setenv("GITHUB_RUN_ID", "12345") + + tempfile, _ := createTempfile(` + { + "issue": { + "number": 123 + } + } + `) + os.Setenv("GITHUB_EVENT_PATH", tempfile.Name()) + + return func() { + os.Remove(tempfile.Name()) + } + }, + ci: CI{ + PR: PullRequest{ + Revision: "abcdefg", + Number: 123, + }, + URL: "https://github.com/mercari/tfnotify/actions/runs/12345", + }, + ok: true, + }, + { + fn: func() func() { + os.Setenv("GITHUB_SHA", "abcdefg") + os.Setenv("GITHUB_REPOSITORY", "mercari/tfnotify") + os.Setenv("GITHUB_RUN_ID", "12345") + + tempfile, _ := createTempfile(` + { + "pull_request": { + "number": 234 + } + } + `) + os.Setenv("GITHUB_EVENT_PATH", tempfile.Name()) + + return func() { + os.Remove(tempfile.Name()) + } + }, + ci: CI{ + PR: PullRequest{ + Revision: "abcdefg", + Number: 234, + }, + URL: "https://github.com/mercari/tfnotify/actions/runs/12345", + }, + ok: true, + }, + { + fn: func() func() { + os.Setenv("GITHUB_SHA", "abcdefg") + os.Setenv("GITHUB_REPOSITORY", "mercari/tfnotify") + os.Setenv("GITHUB_RUN_ID", "12345") + + tempfile, _ := createTempfile(` + { + "number": 345 + } + `) + os.Setenv("GITHUB_EVENT_PATH", tempfile.Name()) + + return func() { + os.Remove(tempfile.Name()) + } + }, + ci: CI{ + PR: PullRequest{ + Revision: "abcdefg", + Number: 345, + }, + URL: "https://github.com/mercari/tfnotify/actions/runs/12345", + }, + ok: true, + }, } for _, testCase := range testCases { - testCase.fn() + teardown := testCase.fn() + defer teardown() ci, err := githubActions() if !reflect.DeepEqual(ci, testCase.ci) { t.Errorf("got %q but want %q", ci, testCase.ci)