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] 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)