From dd1555b1d17966cb58500676d79a181c53bb6c12 Mon Sep 17 00:00:00 2001 From: Augusto Melo <4723788+augustomelo@users.noreply.github.com> Date: Sun, 23 Apr 2023 16:02:50 +0100 Subject: [PATCH 01/27] fix(#75): display corect base URL if using GHE (#90) It was displaying the GH URL even though the GHE was configured, using the client.baseURL will correctly display a correct value. https://pkg.go.dev/github.com/google/go-github/v50/github#Client --- approval.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/approval.go b/approval.go index a720aef..a34c647 100644 --- a/approval.go +++ b/approval.go @@ -44,7 +44,7 @@ func newApprovalEnvironment(client *github.Client, repoFullName, repoOwner strin } func (a approvalEnvironment) runURL() string { - return fmt.Sprintf("https://github.com/%s/actions/runs/%d", a.repoFullName, a.runID) + return fmt.Sprintf("%s%s/actions/runs/%d", a.client.BaseURL.String(), a.repoFullName, a.runID) } func (a *approvalEnvironment) createApprovalIssue(ctx context.Context) error { From 315f51d8882cd7d255d4252fb40f94fd36a37ae2 Mon Sep 17 00:00:00 2001 From: Vanley Date: Thu, 13 Jun 2024 01:21:14 +0100 Subject: [PATCH 02/27] add timeout-minutes to valid imputs (#121) --- action.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/action.yaml b/action.yaml index cbd28ce..b0c705c 100644 --- a/action.yaml +++ b/action.yaml @@ -13,6 +13,9 @@ inputs: minimum-approvals: description: Minimum number of approvals to progress workflow required: false + timeout-minutes: + description: Force timeout of your workflow pause + required: false issue-title: description: The custom subtitle for the issue required: false From 662b3ddbc7685f897992051e87e1b4b58c07dc03 Mon Sep 17 00:00:00 2001 From: Thomas Stringer Date: Wed, 12 Jun 2024 20:42:28 -0400 Subject: [PATCH 03/27] Create new release (#123) --- Session.vim | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ action.yaml | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 Session.vim diff --git a/Session.vim b/Session.vim new file mode 100644 index 0000000..0cdd50a --- /dev/null +++ b/Session.vim @@ -0,0 +1,50 @@ +let SessionLoad = 1 +let s:so_save = &g:so | let s:siso_save = &g:siso | setg so=0 siso=0 | setl so=-1 siso=-1 +let v:this_session=expand(":p") +silent only +silent tabonly +cd ~/dev/manual-approval +if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == '' + let s:wipebuf = bufnr('%') +endif +let s:shortmess_save = &shortmess +if &shortmess =~ 'A' + set shortmess=aoOA +else + set shortmess=aoO +endif +badd +0 action.yaml +argglobal +%argdel +edit action.yaml +argglobal +balt action.yaml +setlocal fdm=expr +setlocal fde=nvim_treesitter#foldexpr() +setlocal fmr={{{,}}} +setlocal fdi=# +setlocal fdl=99 +setlocal fml=1 +setlocal fdn=20 +setlocal fen +let s:l = 36 - ((35 * winheight(0) + 20) / 41) +if s:l < 1 | let s:l = 1 | endif +keepjumps exe s:l +normal! zt +keepjumps 36 +normal! 058| +tabnext 1 +if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0 && getbufvar(s:wipebuf, '&buftype') isnot# 'terminal' + silent exe 'bwipe ' . s:wipebuf +endif +unlet! s:wipebuf +set winheight=1 winwidth=20 +let &shortmess = s:shortmess_save +let s:sx = expand(":p:r")."x.vim" +if filereadable(s:sx) + exe "source " . fnameescape(s:sx) +endif +let &g:so = s:so_save | let &g:siso = s:siso_save +doautoall SessionLoadPost +unlet SessionLoad +" vim: set ft=vim : diff --git a/action.yaml b/action.yaml index b0c705c..7866c0b 100644 --- a/action.yaml +++ b/action.yaml @@ -33,4 +33,4 @@ inputs: default: '' runs: using: docker - image: docker://ghcr.io/trstringer/manual-approval:1.9.0 + image: docker://ghcr.io/trstringer/manual-approval:1.9.1 From 287b77b4700056dbcf79cec3b2383612ac7e112a Mon Sep 17 00:00:00 2001 From: Yucel Okcu Date: Thu, 20 Jun 2024 00:20:51 +0300 Subject: [PATCH 04/27] fix: use correct base URL if not enterprise (#125) --- approval.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/approval.go b/approval.go index a34c647..4005004 100644 --- a/approval.go +++ b/approval.go @@ -44,7 +44,11 @@ func newApprovalEnvironment(client *github.Client, repoFullName, repoOwner strin } func (a approvalEnvironment) runURL() string { - return fmt.Sprintf("%s%s/actions/runs/%d", a.client.BaseURL.String(), a.repoFullName, a.runID) + baseUrl := a.client.BaseURL.String() + if strings.Contains(baseUrl, "github.com") { + baseUrl = "https://github.com/" + } + return fmt.Sprintf("%s%s/actions/runs/%d", baseUrl, a.repoFullName, a.runID) } func (a *approvalEnvironment) createApprovalIssue(ctx context.Context) error { From d2e412d84000579996fd00d7834a817f92af19d3 Mon Sep 17 00:00:00 2001 From: Florian Kaiser Date: Wed, 19 Jun 2024 23:22:23 +0200 Subject: [PATCH 05/27] Fix issue URL in job log (#112) --- approval.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/approval.go b/approval.go index 4005004..e2bb13f 100644 --- a/approval.go +++ b/approval.go @@ -93,7 +93,7 @@ Respond %s to continue workflow or %s to cancel.`, } a.approvalIssueNumber = a.approvalIssue.GetNumber() - fmt.Printf("Issue created: %s\n", a.approvalIssue.GetURL()) + fmt.Printf("Issue created: %s\n", a.approvalIssue.GetHTMLURL()) return nil } From aba06e32f19b0890e99cfd2a9af7868a671cba16 Mon Sep 17 00:00:00 2001 From: Liz MacLean <18120837+lizziemac@users.noreply.github.com> Date: Fri, 14 Feb 2025 20:23:48 -0500 Subject: [PATCH 06/27] Introduce a 'fail-on-denial' boolean (#147) * Introduce a 'fail-on-approval' boolean * Use test docker image * oops * change default and fix logic * Update action.yaml * Fix linting error --- Makefile | 3 ++- action.yaml | 9 ++++++++- approval.go | 4 +++- constants.go | 1 + main.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 60 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 3ec553a..8c3fc9b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ IMAGE_REPO=ghcr.io/trstringer/manual-approval +TARGET_PLATFORM=linux/amd64 .PHONY: build build: @@ -6,7 +7,7 @@ build: echo "VERSION is required"; \ exit 1; \ fi - docker build -t $(IMAGE_REPO):$$VERSION . + docker build --platform $(TARGET_PLATFORM) -t $(IMAGE_REPO):$$VERSION . .PHONY: push push: diff --git a/action.yaml b/action.yaml index 7866c0b..bef33d7 100644 --- a/action.yaml +++ b/action.yaml @@ -24,13 +24,20 @@ inputs: required: false exclude-workflow-initiator-as-approver: description: Whether or not to filter out the user who initiated the workflow as an approver if they are in the approvers list - default: false + required: false + default: 'false' additional-approved-words: description: Comma separated list of words that can be used to approve beyond the defaults. + required: false default: '' additional-denied-words: description: Comma separated list of words that can be used to deny beyond the defaults. + required: false default: '' + fail-on-denial: + description: Whether or not to fail the workflow if the approval is denied + required: false + default: 'true' runs: using: docker image: docker://ghcr.io/trstringer/manual-approval:1.9.1 diff --git a/approval.go b/approval.go index e2bb13f..d69df54 100644 --- a/approval.go +++ b/approval.go @@ -21,9 +21,10 @@ type approvalEnvironment struct { issueBody string issueApprovers []string minimumApprovals int + failOnDenial bool } -func newApprovalEnvironment(client *github.Client, repoFullName, repoOwner string, runID int, approvers []string, minimumApprovals int, issueTitle, issueBody string) (*approvalEnvironment, error) { +func newApprovalEnvironment(client *github.Client, repoFullName, repoOwner string, runID int, approvers []string, minimumApprovals int, issueTitle, issueBody string, failOnDenial bool) (*approvalEnvironment, error) { repoOwnerAndName := strings.Split(repoFullName, "/") if len(repoOwnerAndName) != 2 { return nil, fmt.Errorf("repo owner and name in unexpected format: %s", repoFullName) @@ -40,6 +41,7 @@ func newApprovalEnvironment(client *github.Client, repoFullName, repoOwner strin minimumApprovals: minimumApprovals, issueTitle: issueTitle, issueBody: issueBody, + failOnDenial: failOnDenial, }, nil } diff --git a/constants.go b/constants.go index 03e4b4e..0e08102 100644 --- a/constants.go +++ b/constants.go @@ -21,6 +21,7 @@ const ( envVarExcludeWorkflowInitiatorAsApprover string = "INPUT_EXCLUDE-WORKFLOW-INITIATOR-AS-APPROVER" envVarAdditionalApprovedWords string = "INPUT_ADDITIONAL-APPROVED-WORDS" envVarAdditionalDeniedWords string = "INPUT_ADDITIONAL-DENIED-WORDS" + envVarFailOnDenial string = "INPUT_FAIL-ON-DENIAL" ) var ( diff --git a/main.go b/main.go index 5aad15e..5349a87 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,19 @@ import ( "golang.org/x/oauth2" ) +func setActionOutput(name, value string) error { + f, err := os.OpenFile(os.Getenv("GITHUB_OUTPUT"), os.O_APPEND|os.O_WRONLY, 0600) + if err != nil { + return err + } + defer f.Close() + + if _, err = f.WriteString(fmt.Sprintf("%s=%s\n", name, value)); err != nil { + return err + } + return nil +} + func handleInterrupt(ctx context.Context, client *github.Client, apprv *approvalEnvironment) { newState := "closed" closeComment := "Workflow cancelled, closing issue." @@ -71,7 +84,14 @@ func newCommentLoopChannel(ctx context.Context, apprv *approvalEnvironment, clie close(channel) case approvalStatusDenied: newState := "closed" - closeComment := "Request denied. Closing issue and failing workflow." + closeComment := "Request denied. Closing issue " + if !apprv.failOnDenial { + closeComment += "but continuing" + } else { + closeComment += "and failing" + } + closeComment += " workflow." + _, _, err := client.Issues.CreateComment(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueComment{ Body: &closeComment, }) @@ -170,6 +190,16 @@ func main() { os.Exit(1) } + failOnDenial := true + failOnDenialRaw := os.Getenv(envVarFailOnDenial) + if failOnDenialRaw != "" { + failOnDenial, err = strconv.ParseBool(failOnDenialRaw) + if err != nil { + fmt.Printf("error parsing fail on denial: %v\n", err) + os.Exit(1) + } + } + issueTitle := os.Getenv(envVarIssueTitle) issueBody := os.Getenv(envVarIssueBody) minimumApprovalsRaw := os.Getenv(envVarMinimumApprovals) @@ -181,7 +211,7 @@ func main() { os.Exit(1) } } - apprv, err := newApprovalEnvironment(client, repoFullName, repoOwner, runID, approvers, minimumApprovals, issueTitle, issueBody) + apprv, err := newApprovalEnvironment(client, repoFullName, repoOwner, runID, approvers, minimumApprovals, issueTitle, issueBody, failOnDenial) if err != nil { fmt.Printf("error creating approval environment: %v\n", err) os.Exit(1) @@ -200,6 +230,20 @@ func main() { select { case exitCode := <-commentLoopChannel: + approvalStatus := "" + + if (!failOnDenial && exitCode == 1) { + approvalStatus = "denied" + exitCode = 0 + } else if (exitCode == 1) { + approvalStatus = "denied" + } else { + approvalStatus = "approved" + } + if err := setActionOutput("approval_status", approvalStatus); err != nil { + fmt.Printf("error setting action output: %v\n", err) + exitCode = 1 + } os.Exit(exitCode) case <-killSignalChannel: handleInterrupt(ctx, client, apprv) From 17c84dd68836c83380433bf434b73e094ddbfc04 Mon Sep 17 00:00:00 2001 From: Liz MacLean <18120837+lizziemac@users.noreply.github.com> Date: Mon, 17 Feb 2025 15:12:35 -0500 Subject: [PATCH 07/27] Remove default title if custom title is provided --- approval.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/approval.go b/approval.go index d69df54..c6e454e 100644 --- a/approval.go +++ b/approval.go @@ -57,7 +57,7 @@ func (a *approvalEnvironment) createApprovalIssue(ctx context.Context) error { issueTitle := fmt.Sprintf("Manual approval required for workflow run %d", a.runID) if a.issueTitle != "" { - issueTitle = fmt.Sprintf("%s: %s", issueTitle, a.issueTitle) + issueTitle = a.issueTitle } issueBody := fmt.Sprintf(`Workflow is pending manual review. From c17f1c63ff8c81f8b35f98be67488f5b2e3dd241 Mon Sep 17 00:00:00 2001 From: Sanskar Arora <55059942+sunny-1651@users.noreply.github.com> Date: Sun, 23 Feb 2025 00:20:00 +0530 Subject: [PATCH 08/27] Adding the capability to create the approval issue in the another repository (#142) * Adding the capability to create the approval issue in another repository * reverting testing changes * reverting test changes contd. * Updating readme and removing a debug line * Introduce a 'fail-on-denial' boolean (#147) * Introduce a 'fail-on-approval' boolean * Use test docker image * oops * change default and fix logic * Update action.yaml * Fix linting error * Adding the capability to create the approval issue in another repository * reverting testing changes * reverting test changes contd. * moving targetRepo inputs from env vars to action-args * Update constants.go * Update constants.go to resolve nuances created by inconsistent tab length settings --------- Co-authored-by: Liz MacLean <18120837+lizziemac@users.noreply.github.com> --- .github/workflows/ci.yaml | 1 + README.md | 19 +++++++++++++++++++ action.yaml | 6 ++++++ approval.go | 12 ++++++++---- constants.go | 2 ++ main.go | 27 +++++++++++++++++++-------- 6 files changed, 55 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a6ab720..5fa65b1 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -20,6 +20,7 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + - name: Build run: make build env: diff --git a/README.md b/README.md index 25218e9..68336f9 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,25 @@ steps: - `additional-approved-words` is a comma separated list of strings to expand the dictionary of words that indicate approval. This is optional and defaults to an empty string. - `additional-denied-words` is a comma separated list of strings to expand the dictionary of words that indicate denial. This is optional and defaults to an empty string. +### Creating Issues in a different repository + +```yaml +steps: + - uses: trstringer/manual-approval@v1 + with: + secret: ${{ github.TOKEN }} + approvers: user1,user2,org-team1 + minimum-approvals: 1 + issue-title: "Deploying v1.3.5 to prod from staging" + issue-body: "Please approve or deny the deployment of version v1.3.5." + exclude-workflow-initiator-as-approver: false + additional-approved-words: '' + additional-denied-words: '' + target-repository: repository-name + target-repository-owner: owner-id +``` +- if either of `target-repository` or `target-repository-owner` is missing or is an empty string then the issue will be created in the same repository where this step is used. + ### Using Custom Words GitHub has a rich library of emojis, and these all work in additional approved words or denied words. Some values GitHub will store in their text version - i.e. `:shipit:`. Other emojis, GitHub will store in their unicode emoji form, like βœ…. diff --git a/action.yaml b/action.yaml index bef33d7..c515b96 100644 --- a/action.yaml +++ b/action.yaml @@ -34,6 +34,12 @@ inputs: description: Comma separated list of words that can be used to deny beyond the defaults. required: false default: '' + target-repository-owner: + description: Owner of the repository in which the issue will be created. + default: '' + target-repository: + description: Name of the repository in which the issue will be created. + default: '' fail-on-denial: description: Whether or not to fail the workflow if the approval is denied required: false diff --git a/approval.go b/approval.go index d69df54..540cd71 100644 --- a/approval.go +++ b/approval.go @@ -21,10 +21,12 @@ type approvalEnvironment struct { issueBody string issueApprovers []string minimumApprovals int + targetRepoOwner string + targetRepoName string failOnDenial bool } -func newApprovalEnvironment(client *github.Client, repoFullName, repoOwner string, runID int, approvers []string, minimumApprovals int, issueTitle, issueBody string, failOnDenial bool) (*approvalEnvironment, error) { +func newApprovalEnvironment(client *github.Client, repoFullName, repoOwner string, runID int, approvers []string, minimumApprovals int, issueTitle, issueBody string, targetRepoOwner string, targetRepoName string, failOnDenial bool) (*approvalEnvironment, error) { repoOwnerAndName := strings.Split(repoFullName, "/") if len(repoOwnerAndName) != 2 { return nil, fmt.Errorf("repo owner and name in unexpected format: %s", repoFullName) @@ -41,6 +43,8 @@ func newApprovalEnvironment(client *github.Client, repoFullName, repoOwner strin minimumApprovals: minimumApprovals, issueTitle: issueTitle, issueBody: issueBody, + targetRepoOwner: targetRepoOwner, + targetRepoName: targetRepoName, failOnDenial: failOnDenial, }, nil } @@ -79,13 +83,13 @@ Respond %s to continue workflow or %s to cancel.`, var err error fmt.Printf( "Creating issue in repo %s/%s with the following content:\nTitle: %s\nApprovers: %s\nBody:\n%s\n", - a.repoOwner, - a.repo, + a.targetRepoOwner, + a.targetRepoName, issueTitle, a.issueApprovers, issueBody, ) - a.approvalIssue, _, err = a.client.Issues.Create(ctx, a.repoOwner, a.repo, &github.IssueRequest{ + a.approvalIssue, _, err = a.client.Issues.Create(ctx, a.targetRepoOwner, a.targetRepoName, &github.IssueRequest{ Title: &issueTitle, Body: &issueBody, Assignees: &a.issueApprovers, diff --git a/constants.go b/constants.go index 0e08102..027aafa 100644 --- a/constants.go +++ b/constants.go @@ -22,6 +22,8 @@ const ( envVarAdditionalApprovedWords string = "INPUT_ADDITIONAL-APPROVED-WORDS" envVarAdditionalDeniedWords string = "INPUT_ADDITIONAL-DENIED-WORDS" envVarFailOnDenial string = "INPUT_FAIL-ON-DENIAL" + envVarTargetRepoOwner string = "INPUT_TARGET-REPOSITORY-OWNER" + envVarTargetRepo string = "INPUT_TARGET-REPOSITORY" ) var ( diff --git a/main.go b/main.go index 5349a87..e9944bb 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "os" "os/signal" "strconv" + "strings" "time" "github.com/google/go-github/v43/github" @@ -29,14 +30,14 @@ func handleInterrupt(ctx context.Context, client *github.Client, apprv *approval newState := "closed" closeComment := "Workflow cancelled, closing issue." fmt.Println(closeComment) - _, _, err := client.Issues.CreateComment(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueComment{ + _, _, err := client.Issues.CreateComment(ctx, apprv.targetRepoOwner, apprv.targetRepoName, apprv.approvalIssueNumber, &github.IssueComment{ Body: &closeComment, }) if err != nil { fmt.Printf("error commenting on issue: %v\n", err) return } - _, _, err = client.Issues.Edit(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueRequest{State: &newState}) + _, _, err = client.Issues.Edit(ctx, apprv.targetRepoOwner, apprv.targetRepoName, apprv.approvalIssueNumber, &github.IssueRequest{State: &newState}) if err != nil { fmt.Printf("error closing issue: %v\n", err) return @@ -47,7 +48,7 @@ func newCommentLoopChannel(ctx context.Context, apprv *approvalEnvironment, clie channel := make(chan int) go func() { for { - comments, _, err := client.Issues.ListComments(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueListCommentsOptions{}) + comments, _, err := client.Issues.ListComments(ctx, apprv.targetRepoOwner, apprv.targetRepoName, apprv.approvalIssueNumber, &github.IssueListCommentsOptions{}) if err != nil { fmt.Printf("error getting comments: %v\n", err) channel <- 1 @@ -65,7 +66,7 @@ func newCommentLoopChannel(ctx context.Context, apprv *approvalEnvironment, clie case approvalStatusApproved: newState := "closed" closeComment := "All approvers have approved, continuing workflow and closing this issue." - _, _, err := client.Issues.CreateComment(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueComment{ + _, _, err := client.Issues.CreateComment(ctx, apprv.targetRepoOwner, apprv.targetRepoName, apprv.approvalIssueNumber, &github.IssueComment{ Body: &closeComment, }) if err != nil { @@ -73,7 +74,7 @@ func newCommentLoopChannel(ctx context.Context, apprv *approvalEnvironment, clie channel <- 1 close(channel) } - _, _, err = client.Issues.Edit(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueRequest{State: &newState}) + _, _, err = client.Issues.Edit(ctx, apprv.targetRepoOwner, apprv.targetRepoName, apprv.approvalIssueNumber, &github.IssueRequest{State: &newState}) if err != nil { fmt.Printf("error closing issue: %v\n", err) channel <- 1 @@ -92,7 +93,7 @@ func newCommentLoopChannel(ctx context.Context, apprv *approvalEnvironment, clie } closeComment += " workflow." - _, _, err := client.Issues.CreateComment(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueComment{ + _, _, err := client.Issues.CreateComment(ctx, apprv.targetRepoOwner, apprv.targetRepoName, apprv.approvalIssueNumber, &github.IssueComment{ Body: &closeComment, }) if err != nil { @@ -100,7 +101,7 @@ func newCommentLoopChannel(ctx context.Context, apprv *approvalEnvironment, clie channel <- 1 close(channel) } - _, _, err = client.Issues.Edit(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueRequest{State: &newState}) + _, _, err = client.Issues.Edit(ctx, apprv.targetRepoOwner, apprv.targetRepoName, apprv.approvalIssueNumber, &github.IssueRequest{State: &newState}) if err != nil { fmt.Printf("error closing issue: %v\n", err) channel <- 1 @@ -169,6 +170,9 @@ func main() { os.Exit(1) } + targetRepoName := os.Getenv(envVarTargetRepo) + targetRepoOwner := os.Getenv(envVarTargetRepoOwner) + repoFullName := os.Getenv(envVarRepoFullName) runID, err := strconv.Atoi(os.Getenv(envVarRunID)) if err != nil { @@ -177,6 +181,12 @@ func main() { } repoOwner := os.Getenv(envVarRepoOwner) + if targetRepoName == "" || targetRepoOwner == "" { + parts := strings.SplitN(repoFullName, "/", 2) + targetRepoOwner = parts[0] + targetRepoName = parts[1] + } + ctx := context.Background() client, err := newGithubClient(ctx) if err != nil { @@ -211,7 +221,8 @@ func main() { os.Exit(1) } } - apprv, err := newApprovalEnvironment(client, repoFullName, repoOwner, runID, approvers, minimumApprovals, issueTitle, issueBody, failOnDenial) + + apprv, err := newApprovalEnvironment(client, repoFullName, repoOwner, runID, approvers, minimumApprovals, issueTitle, issueBody, targetRepoOwner, targetRepoName, failOnDenial) if err != nil { fmt.Printf("error creating approval environment: %v\n", err) os.Exit(1) From 846a0ce970c14b5c4e23061e50e841d622a82913 Mon Sep 17 00:00:00 2001 From: Bailey Everts Date: Sat, 22 Feb 2025 11:53:00 -0700 Subject: [PATCH 09/27] feat: use blocks for issue-body (#137) --- approval.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/approval.go b/approval.go index 540cd71..c7b673d 100644 --- a/approval.go +++ b/approval.go @@ -64,12 +64,14 @@ func (a *approvalEnvironment) createApprovalIssue(ctx context.Context) error { issueTitle = fmt.Sprintf("%s: %s", issueTitle, a.issueTitle) } - issueBody := fmt.Sprintf(`Workflow is pending manual review. -URL: %s + issueBody := fmt.Sprintf(`> Workflow is pending manual review. +> URL: %s -Required approvers: %s +> [!IMPORTANT] +> Required approvers: %s -Respond %s to continue workflow or %s to cancel.`, +> [!TIP] +> Respond %s to continue workflow or %s to cancel.`, a.runURL(), a.issueApprovers, formatAcceptedWords(approvedWords), @@ -77,8 +79,9 @@ Respond %s to continue workflow or %s to cancel.`, ) if a.issueBody != "" { - issueBody = fmt.Sprintf("%s\n\n%s", a.issueBody, issueBody) + issueBody = fmt.Sprintf(">%s\n>\n%s", a.issueBody, issueBody) } + issueBody = fmt.Sprintf(">[!NOTE]\n%s", issueBody) var err error fmt.Printf( From 77d7e0184d4cb81961299ec47ce783cb96bde67d Mon Sep 17 00:00:00 2001 From: Bailey Everts Date: Sun, 23 Feb 2025 09:36:20 -0700 Subject: [PATCH 10/27] feat: dispaly users as a list (#138) --- approval.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/approval.go b/approval.go index c7b673d..f168ab6 100644 --- a/approval.go +++ b/approval.go @@ -64,16 +64,22 @@ func (a *approvalEnvironment) createApprovalIssue(ctx context.Context) error { issueTitle = fmt.Sprintf("%s: %s", issueTitle, a.issueTitle) } + approversBody := "" + for _, approver := range a.issueApprovers { + approversBody = fmt.Sprintf("%s> * @%s\n", approversBody, approver) + } + issueBody := fmt.Sprintf(`> Workflow is pending manual review. > URL: %s > [!IMPORTANT] -> Required approvers: %s +> Required approvers: +%s > [!TIP] > Respond %s to continue workflow or %s to cancel.`, a.runURL(), - a.issueApprovers, + approversBody, formatAcceptedWords(approvedWords), formatAcceptedWords(deniedWords), ) From 8b4df3f1bc12bd87945015fe497dce8f59c576b7 Mon Sep 17 00:00:00 2001 From: Sanskar Arora <55059942+sunny-1651@users.noreply.github.com> Date: Tue, 4 Mar 2025 05:56:53 +0530 Subject: [PATCH 11/27] Dependabot codeql patch (#152) * addding codecheck yamls * updating versions * code ql to run only on main repo not forks --- .github/dependabot.yml | 7 +++++++ .github/workflows/codeql.yml | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/codeql.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..21c0165 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 # default: 5 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..6d68125 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,37 @@ +name: "Code Analysis" + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + CodeQL-Build: + if: github.repository == 'trstringer/manual-approval' + permissions: + actions: read + contents: read + security-events: write + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Golang + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: go + + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 From 2177c2e2376645b3bad2dabd24d77b3af170f11f Mon Sep 17 00:00:00 2001 From: Sanskar Arora <55059942+sunny-1651@users.noreply.github.com> Date: Tue, 4 Mar 2025 21:54:44 +0530 Subject: [PATCH 12/27] Update codeql.yml --- .github/workflows/codeql.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6d68125..f5442a1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,6 +2,8 @@ name: "Code Analysis" on: push: + branches: + - "main" pull_request: permissions: From 824801926666d7718ae522c838704d64611ab80a Mon Sep 17 00:00:00 2001 From: Liz MacLean <18120837+lizziemac@users.noreply.github.com> Date: Thu, 6 Mar 2025 15:50:38 -0500 Subject: [PATCH 13/27] Cleanup README and add some more informative messaging (#149) --- README.md | 51 ++++++++++++++++++++++++++++++--------------------- action.yaml | 3 --- main.go | 3 ++- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 68336f9..37317e0 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ + # Manual Workflow Approval [![ci](https://github.com/trstringer/manual-approval/actions/workflows/ci.yaml/badge.svg)](https://github.com/trstringer/manual-approval/actions/workflows/ci.yaml) Pause a GitHub Actions workflow and require manual approval from one or more approvers before continuing. -This is a very common feature for a deployment or release pipeline, and while [this functionality is available from GitHub](https://docs.github.com/en/actions/managing-workflow-runs/reviewing-deployments), it requires the use of environments and if you want to use this for private repositories then you need GitHub Enterprise. This action provides manual approval without the use of environments, and is freely available to use on private repositories. +This is a very common feature for a deployment or release pipeline, and while [this functionality is available from GitHub](https://docs.github.com/en/actions/managing-workflow-runs/reviewing-deployments), it requires the use of environments and if you want to use this for private repositories, then you need GitHub Enterprise. This action provides manual approval without the use of environments, and is freely available to use on private repositories. -*Note: This approval duration is subject to the broader 72 hours timeout for a workflow. So keep that in mind when figuring out how quickly an approver must respond.* +*Note: This approval duration is subject to the broader 35 day timeout for a workflow, as well as usage costs. So keep that in mind when figuring out how quickly an approver must respond. See [limitations](#limitations) for more information.* The way this action works is the following: @@ -34,17 +35,23 @@ steps: issue-title: "Deploying v1.3.5 to prod from staging" issue-body: "Please approve or deny the deployment of version v1.3.5." exclude-workflow-initiator-as-approver: false + fail-on-denial: true additional-approved-words: '' additional-denied-words: '' ``` -- `approvers` is a comma-delimited list of all required approvers. An approver can either be a user or an org team. (*Note: Required approvers must have the ability to be set as approvers in the repository. If you add an approver that doesn't have this permission then you would receive an HTTP/402 Validation Failed error when running this action*) -- `minimum-approvals` is an integer that sets the minimum number of approvals required to progress the workflow. Defaults to ALL approvers. -- `issue-title` is a string that will be appended to the title of the issue. -- `issue-body` is a string that will be prepended to the body of the issue. -- `exclude-workflow-initiator-as-approver` is a boolean that indicates if the workflow initiator (determined by the `GITHUB_ACTOR` environment variable) should be filtered from the final list of approvers. This is optional and defaults to `false`. Set this to `true` to prevent users in the `approvers` list from being able to self-approve workflows. -- `additional-approved-words` is a comma separated list of strings to expand the dictionary of words that indicate approval. This is optional and defaults to an empty string. -- `additional-denied-words` is a comma separated list of strings to expand the dictionary of words that indicate denial. This is optional and defaults to an empty string. +* `approvers` is a comma-delimited list of all required approvers. An approver can either be a user or an org team. (*Note: Required approvers must have the ability to be set as approvers in the repository. If you add an approver that doesn't have this permission then you would receive an HTTP/402 Validation Failed error when running this action*) +* `minimum-approvals` is an integer that sets the minimum number of approvals required to progress the workflow. Defaults to ALL approvers. +* `issue-title` is a string that will be appended to the title of the issue. +* `issue-body` is a string that will be prepended to the body of the issue. +* `exclude-workflow-initiator-as-approver` is a boolean that indicates if the workflow initiator (determined by the `GITHUB_ACTOR` environment variable) should be filtered from the final list of approvers. This is optional and defaults to `false`. Set this to `true` to prevent users in the `approvers` list from being able to self-approve workflows. +* `fail-on-denial` is a boolean that indicates if the workflow should fail if any approver denies the approval. This is optional and defaults to `true`. Set this to `false` to allow the workflow to continue if any approver denies the approval. +* `additional-approved-words` is a comma separated list of strings to expand the dictionary of words that indicate approval. This is optional and defaults to an empty string. +* `additional-denied-words` is a comma separated list of strings to expand the dictionary of words that indicate denial. This is optional and defaults to an empty string. + +### Outputs + +* `approval_status` is a string that indicates the final status of the approval. This will be either `approved` or `denied`. ### Creating Issues in a different repository @@ -124,8 +131,10 @@ For more information on permissions, please look at the [GitHub documentation](h ## Limitations * While the workflow is paused, it will still continue to consume a concurrent job allocation out of the [max concurrent jobs](https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration#usage-limits). -* A job (including a paused job) will be failed [after 6 hours](https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration#usage-limits). * A paused job is still running compute/instance/virtual machine and will continue to incur costs. +* Expirations (also mentioned elsewhere in this document): + * A job (including a paused job) will be failed [after 6 hours, and a workflow will be failed after 35 days](https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration#usage-limits). + * GitHub App tokens expire after 1 hour which implies duration for the approval cannot exceed 60 minutes or the job will fail due to bad credentials. See [docs](https://docs.github.com/en/rest/apps/apps#create-an-installation-access-token-for-an-app) ## Development @@ -139,16 +148,16 @@ To test out your code in an action, you need to build the image and push it to a Build the image: -``` -$ VERSION=1.7.1-rc.1 make IMAGE_REPO=ghcr.io/trstringer/manual-approval-test build +```shell +VERSION=1.7.1-rc.1 make IMAGE_REPO=ghcr.io/trstringer/manual-approval-test build ``` *Note: The image version can be whatever you want, as this image wouldn't be pushed to production. It is only for testing.* Push the image to your container registry: -``` -$ VERSION=1.7.1-rc.1 make IMAGE_REPO=ghcr.io/trstringer/manual-approval-test push +```shell +VERSION=1.7.1-rc.1 make IMAGE_REPO=ghcr.io/trstringer/manual-approval-test push ``` To test out the image you will need to modify `action.yaml` so that it points to your new image that you're testing: @@ -174,10 +183,10 @@ For `uses`, this should point to your repo and dev branch. ### Create a release 1. Build the new version's image: `$ VERSION=1.7.0 make build` -1. Push the new image: `$ VERSION=1.7.0 make push` -1. Create a release branch and modify `action.yaml` to point to the new image -1. Open and merge a PR to add these changes to the default branch -1. Make sure to fetch the new changes into your local repo: `$ git checkout main && git fetch origin && git merge origin main` -1. Delete the `v1` tag locally and remotely: `$ git tag -d v1 && git push --delete origin v1` -1. Create and push new tags: `$ git tag v1.7.0 && git tag v1 && git push origin --tags` -1. Create the GitHub project release +2. Push the new image: `$ VERSION=1.7.0 make push` +3. Create a release branch and modify `action.yaml` to point to the new image +4. Open and merge a PR to add these changes to the default branch +5. Make sure to fetch the new changes into your local repo: `$ git checkout main && git fetch origin && git merge origin main` +6. Delete the `v1` tag locally and remotely: `$ git tag -d v1 && git push --delete origin v1` +7. Create and push new tags: `$ git tag v1.7.0 && git tag v1 && git push origin --tags` +8. Create the GitHub project release diff --git a/action.yaml b/action.yaml index c515b96..9998363 100644 --- a/action.yaml +++ b/action.yaml @@ -13,9 +13,6 @@ inputs: minimum-approvals: description: Minimum number of approvals to progress workflow required: false - timeout-minutes: - description: Force timeout of your workflow pause - required: false issue-title: description: The custom subtitle for the issue required: false diff --git a/main.go b/main.go index e9944bb..b771f92 100644 --- a/main.go +++ b/main.go @@ -29,6 +29,7 @@ func setActionOutput(name, value string) error { func handleInterrupt(ctx context.Context, client *github.Client, apprv *approvalEnvironment) { newState := "closed" closeComment := "Workflow cancelled, closing issue." + fmt.Println(closeComment) _, _, err := client.Issues.CreateComment(ctx, apprv.targetRepoOwner, apprv.targetRepoName, apprv.approvalIssueNumber, &github.IssueComment{ Body: &closeComment, @@ -65,7 +66,7 @@ func newCommentLoopChannel(ctx context.Context, apprv *approvalEnvironment, clie switch approved { case approvalStatusApproved: newState := "closed" - closeComment := "All approvers have approved, continuing workflow and closing this issue." + closeComment := fmt.Sprintf("The required number of approvals (%d) has been met; continuing workflow and closing this issue.", apprv.minimumApprovals) _, _, err := client.Issues.CreateComment(ctx, apprv.targetRepoOwner, apprv.targetRepoName, apprv.approvalIssueNumber, &github.IssueComment{ Body: &closeComment, }) From c10ec77612398b015cd669cfc6f931fbde744c8a Mon Sep 17 00:00:00 2001 From: Mateus Caruccio Date: Fri, 7 Mar 2025 06:46:54 +0000 Subject: [PATCH 14/27] Feature: Save output (#132) --- action.yaml | 7 ++++++ approval.go | 39 ++++++++++++++++++++++++++++++++ approval_test.go | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 28 +++++++++++------------ 4 files changed, 119 insertions(+), 14 deletions(-) diff --git a/action.yaml b/action.yaml index 9998363..a61c3c9 100644 --- a/action.yaml +++ b/action.yaml @@ -41,6 +41,13 @@ inputs: description: Whether or not to fail the workflow if the approval is denied required: false default: 'true' +outputs: + issue-number: + description: The number of the issue created + issue-url: + description: The URL of the issue created + approval-status: + description: The status of the approval ("approved" or "denied") runs: using: docker image: docker://ghcr.io/trstringer/manual-approval:1.9.1 diff --git a/approval.go b/approval.go index 1ed12d9..9516b64 100644 --- a/approval.go +++ b/approval.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "os" "regexp" "strings" @@ -112,6 +113,44 @@ func (a *approvalEnvironment) createApprovalIssue(ctx context.Context) error { return nil } +func (a *approvalEnvironment) SetActionOutputs(outputs map[string]string) (bool, error) { + outputFile := os.Getenv("GITHUB_OUTPUT") + if outputFile == "" { + return false, nil + } + + f, err := os.OpenFile(outputFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + + if err != nil { + return false, err + } + defer f.Close() + + var pairs []string + + for key, value := range outputs { + pairs = append(pairs, fmt.Sprintf("%s=%s", key, value)) + } + + // Add a newline before writing the new outputs if the file is not empty. This prevents + // two outputs from being written on the same line. + fileInfo, err := f.Stat() + if err != nil { + return false, err + } + if fileInfo.Size() > 0 { + if _, err := f.WriteString("\n"); err != nil { + return false, err + } + } + + if _, err := f.WriteString(strings.Join(pairs, "\n")); err != nil { + return false, err + } + + return true, nil +} + func approvalFromComments(comments []*github.IssueComment, approvers []string, minimumApprovals int) (approvalStatus, error) { remainingApprovers := make([]string, len(approvers)) copy(remainingApprovers, approvers) diff --git a/approval_test.go b/approval_test.go index afc215f..cefe1b0 100644 --- a/approval_test.go +++ b/approval_test.go @@ -1,6 +1,8 @@ package main import ( + "errors" + "os" "testing" "github.com/google/go-github/v43/github" @@ -427,3 +429,60 @@ func TestDeniedCommentBody(t *testing.T) { }) } } + +func TestSaveOutput(t *testing.T) { + testCases := []struct { + name string + approvalIssueNumber int + env_github_output string + isSuccess bool + }{ + { + name: "save_output_with_env", + approvalIssueNumber: 123, + env_github_output: "./output.txt", + isSuccess: true, + }, + { + name: "fail_save_output_without_env", + approvalIssueNumber: 123, + env_github_output: "", + isSuccess: false, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + os.Setenv("GITHUB_OUTPUT", testCase.env_github_output) + a := approvalEnvironment{ + client: nil, + repoFullName: "", + repo: "", + repoOwner: "", + runID: -1, + approvalIssueNumber: testCase.approvalIssueNumber, + issueTitle: "", + issueBody: "", + issueApprovers: nil, + minimumApprovals: 0, + } + + os.Remove(testCase.env_github_output) + actual, err := a.SetActionOutputs(nil) + + if err != nil { + t.Fatalf("error creating output file: %v: %v", testCase.env_github_output, err) + } + + if actual != testCase.isSuccess { + t.Fatalf("expected %v but got %v", testCase.isSuccess, actual) + } + + if actual == true { + if _, err := os.Stat(testCase.env_github_output); errors.Is(err, os.ErrNotExist) { + t.Fatalf("expected create output file %v but it was not", testCase.env_github_output) + } + } + }) + } +} diff --git a/main.go b/main.go index b771f92..e439961 100644 --- a/main.go +++ b/main.go @@ -13,19 +13,6 @@ import ( "golang.org/x/oauth2" ) -func setActionOutput(name, value string) error { - f, err := os.OpenFile(os.Getenv("GITHUB_OUTPUT"), os.O_APPEND|os.O_WRONLY, 0600) - if err != nil { - return err - } - defer f.Close() - - if _, err = f.WriteString(fmt.Sprintf("%s=%s\n", name, value)); err != nil { - return err - } - return nil -} - func handleInterrupt(ctx context.Context, client *github.Client, apprv *approvalEnvironment) { newState := "closed" closeComment := "Workflow cancelled, closing issue." @@ -235,6 +222,16 @@ func main() { os.Exit(1) } + outputs := map[string]string { + "issue-number": fmt.Sprintf("%d", apprv.approvalIssueNumber), + "issue-url": apprv.approvalIssue.GetHTMLURL(), + } + _, err = apprv.SetActionOutputs(outputs) + if err != nil { + fmt.Printf("error saving output: %v", err) + os.Exit(1) + } + killSignalChannel := make(chan os.Signal, 1) signal.Notify(killSignalChannel, os.Interrupt) @@ -252,7 +249,10 @@ func main() { } else { approvalStatus = "approved" } - if err := setActionOutput("approval_status", approvalStatus); err != nil { + outputs := map[string]string { + "approval-status": approvalStatus, + } + if _, err := apprv.SetActionOutputs(outputs); err != nil { fmt.Printf("error setting action output: %v\n", err) exitCode = 1 } From e6592a6b3284d0b354d3fa087600e76af66bb238 Mon Sep 17 00:00:00 2001 From: sunny-1651 Date: Fri, 7 Mar 2025 04:38:42 +0530 Subject: [PATCH 15/27] create go sum at build-time with fresh hashes --- .github/workflows/ci.yaml | 2 + .gitignore | 1 + Dockerfile | 1 + Makefile | 4 + go.sum | 383 -------------------------------------- 5 files changed, 8 insertions(+), 383 deletions(-) delete mode 100644 go.sum diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5fa65b1..dbcfa1a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -21,6 +21,8 @@ jobs: - name: Checkout uses: actions/checkout@v2 + - name: Refresh module hashsums + run: make tidy - name: Build run: make build env: diff --git a/.gitignore b/.gitignore index a9ad188..03ad3d9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .env .idea/ +go.sum diff --git a/Dockerfile b/Dockerfile index 6ec73aa..da0f22e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM golang:1.17 AS builder COPY . /var/app WORKDIR /var/app +RUN go mod tidy RUN CGO_ENABLED=0 go build -o app . FROM alpine:3.14 diff --git a/Makefile b/Makefile index 8c3fc9b..56ba8bc 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,10 @@ IMAGE_REPO=ghcr.io/trstringer/manual-approval TARGET_PLATFORM=linux/amd64 +.PHONY: tidy +tidy: + go mod tidy + .PHONY: build build: @if [ -z "$$VERSION" ]; then \ diff --git a/go.sum b/go.sum deleted file mode 100644 index fdb1ce0..0000000 --- a/go.sum +++ /dev/null @@ -1,383 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/bradleyfalzon/ghinstallation/v2 v2.0.4/go.mod h1:B40qPqJxWE0jDZgOR1JmaMy+4AY1eBP+IByOvqyAKp0= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg= -github.com/google/go-github/v43 v43.0.0 h1:y+GL7LIsAIF2NZlJ46ZoC/D1W1ivZasT0lnWHMYPZ+U= -github.com/google/go-github/v43 v43.0.0/go.mod h1:ZkTvvmCXBvsfPpTHXnH/d2hP9Y0cTbvN9kr5xqyXOIc= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From 330ce9b42bd3ee087d843f64b239f2b8e6ffaaff Mon Sep 17 00:00:00 2001 From: Liz MacLean <18120837+lizziemac@users.noreply.github.com> Date: Mon, 17 Mar 2025 10:58:39 -0400 Subject: [PATCH 16/27] Create CONTRIBUTING.md (#160) --- CONTRIBUTING.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..bf270b3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,44 @@ +# Contribution Guide + +Thank you for your interest in contributing to this project! We appreciate your efforts to make this project better. Please follow the guidelines below to ensure a smooth contribution process. + +## Guidelines + +### Code Contributions +- Follow the existing code style and conventions. +- Write meaningful PR titles. +- Ensure your changes do not break existing functionality. +- Run tests before submitting a pull request (PR). +- Build and run your changes in your own environment to ensure they work as expected. +- Add or update documentation if necessary. + +### Submitting a Pull Request +1. Ensure your branch is up to date with the main branch: + + ```sh + git fetch upstream + git checkout main + git merge upstream/main + ``` + +2. Push your changes to your fork: + + ```sh + git push origin feature-branch-name + ``` + +3. Open a PR on GitHub, describing your changes clearly. +4. If your PR is related to an issue, use the [GitHub key words](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests#linking-a-pull-request-to-an-issue). +This will ensure that the related issue will automatically close when your change is merged. +5. Address any feedback and update your PR as necessary. + +### Issue Reporting +- **Check for existing issues before opening a new one.** +- Provide clear, concise descriptions with steps to reproduce. +- Include logs, screenshots, or example code if relevant. +- Suggest possible solutions if applicable. + +## License +By contributing, you agree that your contributions will be licensed under the project's [LICENSE](LICENSE). + +Thank you for contributing! From ef4dddd64bf9eca035ffe51d23f12d20e3a83613 Mon Sep 17 00:00:00 2001 From: Liz MacLean <18120837+lizziemac@users.noreply.github.com> Date: Mon, 17 Mar 2025 10:58:51 -0400 Subject: [PATCH 17/27] Issue templates (#161) --- .github/ISSUE_TEMPLATE/bug_report.md | 29 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 22 +++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..d0c25c5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +- [ ] I have searched through the current issues and did not find any that were related. + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..6089845 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,22 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +- [ ] I have searched through the current feature requests and did not find any that were related. + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From c1ebf589e26f42869b0ee9f5fde3cf15e6fef997 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Sun, 20 Apr 2025 08:36:57 -0700 Subject: [PATCH 18/27] Make name comparison case-insensitive (#172) Signed-off-by: Simeon Widdis --- approval.go | 10 +++++----- approval_test.go | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/approval.go b/approval.go index 9516b64..8487e26 100644 --- a/approval.go +++ b/approval.go @@ -136,12 +136,12 @@ func (a *approvalEnvironment) SetActionOutputs(outputs map[string]string) (bool, // two outputs from being written on the same line. fileInfo, err := f.Stat() if err != nil { - return false, err + return false, err } if fileInfo.Size() > 0 { - if _, err := f.WriteString("\n"); err != nil { - return false, err - } + if _, err := f.WriteString("\n"); err != nil { + return false, err + } } if _, err := f.WriteString(strings.Join(pairs, "\n")); err != nil { @@ -194,7 +194,7 @@ func approvalFromComments(comments []*github.IssueComment, approvers []string, m func approversIndex(approvers []string, name string) int { for idx, approver := range approvers { - if approver == name { + if strings.EqualFold(approver, name) { return idx } } diff --git a/approval_test.go b/approval_test.go index cefe1b0..efddf7f 100644 --- a/approval_test.go +++ b/approval_test.go @@ -3,6 +3,7 @@ package main import ( "errors" "os" + "strings" "testing" "github.com/google/go-github/v43/github" @@ -16,6 +17,8 @@ func TestApprovalFromComments(t *testing.T) { bodyDenied := "Denied" bodyPending := "not approval or denial" + login1u := strings.ToUpper(login1) + testCases := []struct { name string comments []*github.IssueComment @@ -160,6 +163,17 @@ func TestApprovalFromComments(t *testing.T) { expectedStatus: approvalStatusPending, minimumApprovals: 2, }, + { + name: "single_approver_single_comment_approved_case_insensitive", + comments: []*github.IssueComment{ + { + User: &github.User{Login: &login1u}, + Body: &bodyApproved, + }, + }, + approvers: []string{login1}, + expectedStatus: approvalStatusApproved, + }, } for _, testCase := range testCases { From bfb0ba38d02a528a2c101381809dc6c3062732c1 Mon Sep 17 00:00:00 2001 From: Sunny <55059942+snskArora@users.noreply.github.com> Date: Sat, 26 Apr 2025 12:02:02 +0530 Subject: [PATCH 19/27] Adding support for issue-body with more than 65536 words, issue body to be created as an issue comment (#167) * push a built package to ghcr * adding err catch * auth check * auth update * update uname * update uname * testing with splitted issues * minor fix * revert testing changes * Update approval.go --- .github/workflows/ci.yaml | 1 + Makefile | 6 +-- approval.go | 86 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 87 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index dbcfa1a..c0d4e03 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,6 +27,7 @@ jobs: run: make build env: VERSION: latest + - name: Test run: make test - name: Lint diff --git a/Makefile b/Makefile index 56ba8bc..54f20b9 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ tidy: .PHONY: build build: - @if [ -z "$$VERSION" ]; then \ + @if [ -z "$(VERSION)" ]; then \ echo "VERSION is required"; \ exit 1; \ fi @@ -15,11 +15,11 @@ build: .PHONY: push push: - @if [ -z "$$VERSION" ]; then \ + @if [ -z "$(VERSION)" ]; then \ echo "VERSION is required"; \ exit 1; \ fi - docker push $(IMAGE_REPO):$$VERSION + docker push $(IMAGE_REPO):$(VERSION) .PHONY: test test: diff --git a/approval.go b/approval.go index 8487e26..2b7baa1 100644 --- a/approval.go +++ b/approval.go @@ -85,9 +85,6 @@ func (a *approvalEnvironment) createApprovalIssue(ctx context.Context) error { formatAcceptedWords(deniedWords), ) - if a.issueBody != "" { - issueBody = fmt.Sprintf(">%s\n>\n%s", a.issueBody, issueBody) - } issueBody = fmt.Sprintf(">[!NOTE]\n%s", issueBody) var err error @@ -109,6 +106,16 @@ func (a *approvalEnvironment) createApprovalIssue(ctx context.Context) error { } a.approvalIssueNumber = a.approvalIssue.GetNumber() + bodyChunks := splitLongString(a.issueBody) + for _, chunk := range bodyChunks { + _, _, err = a.client.Issues.CreateComment(ctx, a.targetRepoOwner, a.targetRepoName, *a.approvalIssue.Number, &github.IssueComment{ + Body: &chunk, + }) + if err != nil { + return fmt.Errorf("failed to add comment chunk to issue: %w", err) + } + } + fmt.Printf("Issue created: %s\n", a.approvalIssue.GetHTMLURL()) return nil } @@ -244,3 +251,76 @@ func formatAcceptedWords(words []string) string { return strings.Join(quotedWords, ", ") } + +func splitLongLine(line string, maxL int) ([]string, bool) { + if len(line) <= maxL { + return []string{line}, false + } + + words := strings.Fields(line) + var result []string + var currentLine string + + for _, word := range words { + if len(currentLine)+len(word)+1 > maxL { + result = append(result, currentLine) + currentLine = word + } else { + if currentLine != "" { + currentLine += " " + } + currentLine += word + } + } + if currentLine != "" { + result = append(result, currentLine) + } + return result, true +} + +func splitLongString(input string) []string { + maxLength := 65536 + var result []string + + lines := strings.Split(input, "\n") + currentChunk := strings.Builder{} + currentLength := 0 + + for i, line := range lines { + lineLength := len(line) + if i < len(lines)-1 { + lineLength++ + } + + if currentLength+lineLength > maxLength { + if currentChunk.Len() > 0 { + result = append(result, currentChunk.String()) + currentChunk.Reset() + currentLength = 0 + } + } + + lineSplit, isLongLine := splitLongLine(line, maxLength) + if isLongLine { + if currentChunk.Len() > 0 { + result = append(result, currentChunk.String()) + currentChunk.Reset() + } + result = append(result, lineSplit[:len(lineSplit)-1]...) + currentChunk.WriteString(lineSplit[len(lineSplit)-1]) + currentLength = len(lineSplit[len(lineSplit)-1]) + } else { + currentChunk.WriteString(line) + currentLength += lineLength + } + + if i < len(lines)-1 { + currentChunk.WriteString("\n") + } + } + if currentChunk.Len() > 0 { + result = append(result, currentChunk.String()) + } + return result +} + From 9ef3307c2579bc7ba1c3f292c7942b9ce57a4186 Mon Sep 17 00:00:00 2001 From: Liz MacLean <18120837+lizziemac@users.noreply.github.com> Date: Sat, 10 May 2025 11:10:29 -0400 Subject: [PATCH 20/27] Update README.md to have a more explicit callout about timeout-minutes (#180) --- README.md | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 37317e0..4c87544 100644 --- a/README.md +++ b/README.md @@ -108,14 +108,30 @@ jobs: If you'd like to force a timeout of your workflow pause, you can specify `timeout-minutes` at either the [step](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepstimeout-minutes) level or the [job](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes) level. +> **Note:** The `timeout-minutes` option has been removed from the `manual-approval` inputs, as it did nothing and incorrectly assured users that they were in fact +> getting timeout behavior. Please use one of the below two approaches instead. +> +> If you are currently using `timeout-minutes` as a `manual-approval` input, you may see a warning, but this will not break your action. + For instance, if you want your manual approval step to timeout after an hour you could do the following: ```yaml -steps: - - uses: trstringer/manual-approval@v1 - timeout-minutes: 60 +jobs: + approval: + steps: + - uses: trstringer/manual-approval@v1 + timeout-minutes: 60 ... ``` +or +```yaml +jobs: + approval: + timeout-minutes: 10 + steps: + - uses: trstringer/manual-approval@v1 + +``` ## Permissions From fb0bfeda5ff2d043dcad82c10be2db6e46086662 Mon Sep 17 00:00:00 2001 From: Liz MacLean <18120837+lizziemac@users.noreply.github.com> Date: Tue, 20 May 2025 18:17:01 -0400 Subject: [PATCH 21/27] Fix typo in README related to the action output of approval status (#181) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c87544..86a2034 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ steps: ### Outputs -* `approval_status` is a string that indicates the final status of the approval. This will be either `approved` or `denied`. +* `approval-status` is a string that indicates the final status of the approval. This will be either `approved` or `denied`. ### Creating Issues in a different repository From a1f96b91e22565d2730d88ae055c8dc333e471c1 Mon Sep 17 00:00:00 2001 From: Sunny <55059942+snskArora@users.noreply.github.com> Date: Tue, 27 May 2025 01:44:38 +0530 Subject: [PATCH 22/27] Updates for release 1.10.0 (#183) --- Dockerfile | 2 +- action.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index da0f22e..d757e2e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ RUN go mod tidy RUN CGO_ENABLED=0 go build -o app . FROM alpine:3.14 -LABEL org.opencontainers.image.source https://github.com/trstringer/manual-approval +LABEL org.opencontainers.image.source=https://github.com/trstringer/manual-approval RUN apk update && apk add ca-certificates COPY --from=builder /var/app/app /var/app/app CMD ["/var/app/app"] diff --git a/action.yaml b/action.yaml index a61c3c9..0126c0a 100644 --- a/action.yaml +++ b/action.yaml @@ -50,4 +50,4 @@ outputs: description: The status of the approval ("approved" or "denied") runs: using: docker - image: docker://ghcr.io/trstringer/manual-approval:1.9.1 + image: docker://ghcr.io/trstringer/manual-approval:1.10.0 From 3441ed44b6da65234eadb26bd056be8c1996e8b3 Mon Sep 17 00:00:00 2001 From: Sunny <55059942+snskArora@users.noreply.github.com> Date: Fri, 13 Jun 2025 19:16:46 +0530 Subject: [PATCH 23/27] Multi arch build & Version bump (#185) * Upgrading versions * mod tidy * LInting * Linting * Update action.yaml * [skip ci] Reverting test changes * msc chnages * Update Makefile * Update README.md * Update README.md * Update README.md * Update Makefile * [skip ci] Update README.md * cosmetic changes --- Dockerfile | 2 +- Makefile | 13 ++++++++----- README.md | 28 +++++++++++++++++++--------- approval.go | 6 ++++-- approval_test.go | 7 +++++-- go.mod | 10 +++------- 6 files changed, 40 insertions(+), 26 deletions(-) diff --git a/Dockerfile b/Dockerfile index d757e2e..4fa74dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.17 AS builder +FROM golang:1.24 AS builder COPY . /var/app WORKDIR /var/app RUN go mod tidy diff --git a/Makefile b/Makefile index 54f20b9..4a5a791 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ IMAGE_REPO=ghcr.io/trstringer/manual-approval -TARGET_PLATFORM=linux/amd64 +TARGET_PLATFORM=linux/amd64,linux/arm64,linux/arm/v8 .PHONY: tidy tidy: @@ -11,15 +11,18 @@ build: echo "VERSION is required"; \ exit 1; \ fi - docker build --platform $(TARGET_PLATFORM) -t $(IMAGE_REPO):$$VERSION . + docker build -t $(IMAGE_REPO):$(VERSION) . -.PHONY: push +.PHONY: build_push push: @if [ -z "$(VERSION)" ]; then \ echo "VERSION is required"; \ exit 1; \ fi - docker push $(IMAGE_REPO):$(VERSION) + docker buildx create --use --name mybuilder + docker buildx build --push --platform $(TARGET_PLATFORM) -t $(IMAGE_REPO):$(VERSION) . + docker buildx rm mybuilder + .PHONY: test test: @@ -27,4 +30,4 @@ test: .PHONY: lint lint: - docker run --rm -v $$(pwd):/app -w /app golangci/golangci-lint:v1.46.2 golangci-lint run -v + docker run --rm -v $$(pwd):/app -w /app golangci/golangci-lint:v2.1.6 golangci-lint run -v diff --git a/README.md b/README.md index 86a2034..b0ad57a 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,15 @@ These are case insensitive with optional punctuation either a period or an excla In all cases, `manual-approval` will close the initial GitHub issue. +πŸ–₯️ Supported Runners, The action is compatible with the following runner types: +- Linux/amd64 β€” 64-bit Intel/AMD (x86_64) +- Linux/arm64 β€” 64-bit ARM (Apple M1) +- Linux/arm/v8 β€” 64-bit ARM + +🚫 Unsupported +- Windows/amd64 β€” 64-bit Windows systems are currently not supported. +- Non-Linux runners of any architecture. + ## Usage ```yaml @@ -108,7 +117,9 @@ jobs: If you'd like to force a timeout of your workflow pause, you can specify `timeout-minutes` at either the [step](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepstimeout-minutes) level or the [job](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes) level. -> **Note:** The `timeout-minutes` option has been removed from the `manual-approval` inputs, as it did nothing and incorrectly assured users that they were in fact +> [!Note] +> +> The `timeout-minutes` option has been removed from the `manual-approval` inputs, as it did nothing and incorrectly assured users that they were in fact > getting timeout behavior. Please use one of the below two approaches instead. > > If you are currently using `timeout-minutes` as a `manual-approval` input, you may see a warning, but this will not break your action. @@ -198,11 +209,10 @@ For `uses`, this should point to your repo and dev branch. ### Create a release -1. Build the new version's image: `$ VERSION=1.7.0 make build` -2. Push the new image: `$ VERSION=1.7.0 make push` -3. Create a release branch and modify `action.yaml` to point to the new image -4. Open and merge a PR to add these changes to the default branch -5. Make sure to fetch the new changes into your local repo: `$ git checkout main && git fetch origin && git merge origin main` -6. Delete the `v1` tag locally and remotely: `$ git tag -d v1 && git push --delete origin v1` -7. Create and push new tags: `$ git tag v1.7.0 && git tag v1 && git push origin --tags` -8. Create the GitHub project release +1. Build and push the new image: `$ VERSION=1.7.0 make build_push` +2. Create a release branch and modify `action.yaml` to point to the new image +3. Open and merge a PR to add these changes to the default branch +4. Make sure to fetch the new changes into your local repo: `$ git checkout main && git fetch origin && git merge origin main` +5. Delete the `v1` tag locally and remotely: `$ git tag -d v1 && git push --delete origin v1` +6. Create and push new tags: `$ git tag v1.7.0 && git tag v1 && git push origin --tags` +7. Create the GitHub project release diff --git a/approval.go b/approval.go index 2b7baa1..6391ad2 100644 --- a/approval.go +++ b/approval.go @@ -127,11 +127,13 @@ func (a *approvalEnvironment) SetActionOutputs(outputs map[string]string) (bool, } f, err := os.OpenFile(outputFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { return false, err } - defer f.Close() + + defer func() { + _ = f.Close() // Error explicitly ignored as there is nothing to handle if file close fails. + }() var pairs []string diff --git a/approval_test.go b/approval_test.go index efddf7f..086a6fa 100644 --- a/approval_test.go +++ b/approval_test.go @@ -467,7 +467,7 @@ func TestSaveOutput(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - os.Setenv("GITHUB_OUTPUT", testCase.env_github_output) + t.Setenv("GITHUB_OUTPUT", testCase.env_github_output) a := approvalEnvironment{ client: nil, repoFullName: "", @@ -481,7 +481,10 @@ func TestSaveOutput(t *testing.T) { minimumApprovals: 0, } - os.Remove(testCase.env_github_output) + if err := os.Remove(testCase.env_github_output); err != nil && !os.IsNotExist(err) { + t.Fatalf("failed to remove file: %v", err) + } + actual, err := a.SetActionOutputs(nil) if err != nil { diff --git a/go.mod b/go.mod index 413e6d2..9c0d645 100644 --- a/go.mod +++ b/go.mod @@ -1,17 +1,13 @@ module github.com/trstringer/manual-approval -go 1.17 +go 1.24 require ( github.com/google/go-github/v43 v43.0.0 - golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a + golang.org/x/oauth2 v0.30.0 ) require ( - github.com/golang/protobuf v1.4.2 // indirect github.com/google/go-querystring v1.1.0 // indirect - golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.25.0 // indirect + golang.org/x/crypto v0.35.0 // indirect ) From dd3e4e00d2123a2587991c60f29d3edec3c2fc5c Mon Sep 17 00:00:00 2001 From: Marco Stuurman Date: Fri, 13 Jun 2025 21:08:17 +0200 Subject: [PATCH 24/27] Add option for using a file as input for the issue body (#140) * Add option for using a file as input for the issue body * Revert irrelevant version bumps --- action.yaml | 3 +++ constants.go | 1 + main.go | 12 +++++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/action.yaml b/action.yaml index 0126c0a..7918c1b 100644 --- a/action.yaml +++ b/action.yaml @@ -19,6 +19,9 @@ inputs: issue-body: description: The custom body for the issue required: false + issue-body-file-path: + description: The file path to a custom body for the issue + required: false exclude-workflow-initiator-as-approver: description: Whether or not to filter out the user who initiated the workflow as an approver if they are in the approvers list required: false diff --git a/constants.go b/constants.go index 027aafa..88867e3 100644 --- a/constants.go +++ b/constants.go @@ -18,6 +18,7 @@ const ( envVarMinimumApprovals string = "INPUT_MINIMUM-APPROVALS" envVarIssueTitle string = "INPUT_ISSUE-TITLE" envVarIssueBody string = "INPUT_ISSUE-BODY" + envVarIssueBodyFilePath string = "INPUT_ISSUE-BODY-FILE-PATH" envVarExcludeWorkflowInitiatorAsApprover string = "INPUT_EXCLUDE-WORKFLOW-INITIATOR-AS-APPROVER" envVarAdditionalApprovedWords string = "INPUT_ADDITIONAL-APPROVED-WORDS" envVarAdditionalDeniedWords string = "INPUT_ADDITIONAL-DENIED-WORDS" diff --git a/main.go b/main.go index e439961..e18a395 100644 --- a/main.go +++ b/main.go @@ -199,7 +199,17 @@ func main() { } issueTitle := os.Getenv(envVarIssueTitle) - issueBody := os.Getenv(envVarIssueBody) + var issueBody string + if os.Getenv(envVarIssueBodyFilePath) != "" { + fileContents, err := os.ReadFile(os.Getenv(envVarIssueBodyFilePath)) + if err != nil { + fmt.Printf("error reading issue body file: %v\n", err) + os.Exit(1) + } + issueBody = string(fileContents) + } else { + issueBody = os.Getenv(envVarIssueBody) + } minimumApprovalsRaw := os.Getenv(envVarMinimumApprovals) minimumApprovals := 0 if minimumApprovalsRaw != "" { From e2f9040b95adbec8aa77ea7ba7f583ef29e9a77d Mon Sep 17 00:00:00 2001 From: Sunny <55059942+snskArora@users.noreply.github.com> Date: Sat, 14 Jun 2025 02:06:37 +0530 Subject: [PATCH 25/27] Updates for release 1.11.0 (#187) * Updates for release 1.11.0 * [skip ci] Update README.md * [skip ci] Update README.md --- Makefile | 2 +- README.md | 17 +++++++++++++++-- action.yaml | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 4a5a791..420c847 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ build: docker build -t $(IMAGE_REPO):$(VERSION) . .PHONY: build_push -push: +build_push: @if [ -z "$(VERSION)" ]; then \ echo "VERSION is required"; \ exit 1; \ diff --git a/README.md b/README.md index b0ad57a..3aa07ac 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ steps: minimum-approvals: 1 issue-title: "Deploying v1.3.5 to prod from staging" issue-body: "Please approve or deny the deployment of version v1.3.5." + issue-body-file-path: relative/file_path/wrt/repo/root exclude-workflow-initiator-as-approver: false fail-on-denial: true additional-approved-words: '' @@ -51,13 +52,25 @@ steps: * `approvers` is a comma-delimited list of all required approvers. An approver can either be a user or an org team. (*Note: Required approvers must have the ability to be set as approvers in the repository. If you add an approver that doesn't have this permission then you would receive an HTTP/402 Validation Failed error when running this action*) * `minimum-approvals` is an integer that sets the minimum number of approvals required to progress the workflow. Defaults to ALL approvers. -* `issue-title` is a string that will be appended to the title of the issue. -* `issue-body` is a string that will be prepended to the body of the issue. +* `issue-title` is a string that will be used as the title of the approval-issue. +* `issue-body` is a string that will be added as comments on the approval-issue. +* `issue-body-file-path` is a string which is the file path, this file's content will be added as comments on the approval-issue. If both issue-body and issue-body-file-path are given then the file contents are considered for issue comments. * `exclude-workflow-initiator-as-approver` is a boolean that indicates if the workflow initiator (determined by the `GITHUB_ACTOR` environment variable) should be filtered from the final list of approvers. This is optional and defaults to `false`. Set this to `true` to prevent users in the `approvers` list from being able to self-approve workflows. * `fail-on-denial` is a boolean that indicates if the workflow should fail if any approver denies the approval. This is optional and defaults to `true`. Set this to `false` to allow the workflow to continue if any approver denies the approval. * `additional-approved-words` is a comma separated list of strings to expand the dictionary of words that indicate approval. This is optional and defaults to an empty string. * `additional-denied-words` is a comma separated list of strings to expand the dictionary of words that indicate denial. This is optional and defaults to an empty string. +> [!Note] +> 1. If You are using issue-body-file-path then please make sure the file is reachable, for example, idf the file is in your repo then please checkout to your repo in the same job as the approval issue. +> 2. When using issue-body, the content string is passed as an arguent which is limited by github at 10kb. For content >= 10kb, use files for passing the issue body. + +> [!CAUTION] +> When using file please make sure that the file size remains under 125 KB (A safe limit, to stay under the threshold), If the file size is huge then the file content will be broken into a lot chunks representing an issue comment each, With theese many api requests the API rate limit is exceeded and the actions will be temporarily blocked resulting in an error message like: `403 You have exceeded a secondary rate limit and have been temporarily blocked from content creation. Please retry your request again later.` +> 5 MB is a crude estimate as secondary rate limits apply to a user so your user (usually the bot using app token for authentication) will not be able to do anything for some time. Primary limit might still reset quickly but secondary limits will need some cool-off time. + + +The file method works unless the file itself is very big that after breaking it into chunks of 65k characters, it exceeds the API limit + ### Outputs * `approval-status` is a string that indicates the final status of the approval. This will be either `approved` or `denied`. diff --git a/action.yaml b/action.yaml index 7918c1b..a8b661b 100644 --- a/action.yaml +++ b/action.yaml @@ -53,4 +53,4 @@ outputs: description: The status of the approval ("approved" or "denied") runs: using: docker - image: docker://ghcr.io/trstringer/manual-approval:1.10.0 + image: docker://ghcr.io/trstringer/manual-approval:1.11.0 From 65197b14118ec3026025207d608c6f9fc112948b Mon Sep 17 00:00:00 2001 From: Sunny <55059942+snskArora@users.noreply.github.com> Date: Sat, 14 Jun 2025 02:17:44 +0530 Subject: [PATCH 26/27] Issue Content handling -> README update (#188) * Updates for release 1.11.0 * [skip ci] Update README.md * [skip ci] Update README.md * Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 3aa07ac..86508e1 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,12 @@ steps: GitHub has a rich library of emojis, and these all work in additional approved words or denied words. Some values GitHub will store in their text version - i.e. `:shipit:`. Other emojis, GitHub will store in their unicode emoji form, like βœ…. For a seamless experience, it is recommended that you add the custom words to a GitHub comment, and then copy it back out of the comment into your actions configuration yaml. +# v1.9.x β†’ v1.10.0 +🚨 Update: Approval Issue Content Handling 🚨 +Starting from v1.10.0, the behaviour for issue contents has changed: +- The issue-body and issue-body-file-path are now added as comments on the issue instead of being set as the issue’s main description/body. +- The issue title is now exactly what is provided as input, instead of being appended to or wrapped in a predefined string. + ## Org team approver If you want to have `approvers` set to an org team, then you need to take a different approach. The default [GitHub Actions automatic token](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) does not have the necessary permissions to list out team members. If you would like to use this then you need to generate a token from a GitHub App with the correct set of permissions. From 809247d487a2518d55f6e931da23d98bd51d28ee Mon Sep 17 00:00:00 2001 From: Sunny <55059942+snskArora@users.noreply.github.com> Date: Sat, 14 Jun 2025 02:23:59 +0530 Subject: [PATCH 27/27] Update README.md (#189) --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 86508e1..d1303d8 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,12 @@ In all cases, `manual-approval` will close the initial GitHub issue. - Windows/amd64 β€” 64-bit Windows systems are currently not supported. - Non-Linux runners of any architecture. +# v1.9.x β†’ v1.10.0 +🚨 Update: Approval Issue Content Handling 🚨 +Starting from v1.10.0, the behaviour for issue contents has changed: +- The issue-body and issue-body-file-path are now added as comments on the issue instead of being set as the issue’s main description/body. +- The issue title is now exactly what is provided as input, instead of being appended to or wrapped in a predefined string. + ## Usage ```yaml @@ -65,7 +71,8 @@ steps: > 2. When using issue-body, the content string is passed as an arguent which is limited by github at 10kb. For content >= 10kb, use files for passing the issue body. > [!CAUTION] -> When using file please make sure that the file size remains under 125 KB (A safe limit, to stay under the threshold), If the file size is huge then the file content will be broken into a lot chunks representing an issue comment each, With theese many api requests the API rate limit is exceeded and the actions will be temporarily blocked resulting in an error message like: `403 You have exceeded a secondary rate limit and have been temporarily blocked from content creation. Please retry your request again later.` +> When using file please make sure that the file size remains under 125 KB (A safe limit, to stay under the threshold), If the file size is huge then the file content will be broken into a lot chunks representing an issue comment each, With theese many api requests the API rate limit is exceeded and the actions will be temporarily blocked resulting in an error message like: `403 You have exceeded a secondary rate limit and have been temporarily blocked from content creation. Please retry your request again later.` +> > 5 MB is a crude estimate as secondary rate limits apply to a user so your user (usually the bot using app token for authentication) will not be able to do anything for some time. Primary limit might still reset quickly but secondary limits will need some cool-off time. @@ -99,12 +106,6 @@ steps: GitHub has a rich library of emojis, and these all work in additional approved words or denied words. Some values GitHub will store in their text version - i.e. `:shipit:`. Other emojis, GitHub will store in their unicode emoji form, like βœ…. For a seamless experience, it is recommended that you add the custom words to a GitHub comment, and then copy it back out of the comment into your actions configuration yaml. -# v1.9.x β†’ v1.10.0 -🚨 Update: Approval Issue Content Handling 🚨 -Starting from v1.10.0, the behaviour for issue contents has changed: -- The issue-body and issue-body-file-path are now added as comments on the issue instead of being set as the issue’s main description/body. -- The issue title is now exactly what is provided as input, instead of being appended to or wrapped in a predefined string. - ## Org team approver If you want to have `approvers` set to an org team, then you need to take a different approach. The default [GitHub Actions automatic token](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) does not have the necessary permissions to list out team members. If you would like to use this then you need to generate a token from a GitHub App with the correct set of permissions.