Close issue if action cancelled (#4)

* Close issue if kill signal received

* Refactor: Exiting main loop can close application without explicit call to os.Exit(0)

* Leave a comment on the closed issue if the close handler is triggered

* Accidentally deleted the final logging command

* Fix punctuation on the closing comment

* Handle the comment loop and interruption handling via channels and a select statement

* Update main.go
This commit is contained in:
Edmund Dipple 2022-04-28 13:20:50 +01:00 committed by GitHub
parent c4714a2254
commit c24bf80784
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

144
main.go
View file

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"os/signal"
"strconv"
"strings"
"time"
@ -12,6 +13,90 @@ import (
"golang.org/x/oauth2"
)
func handleInterrupt(client *github.Client, ctx context.Context, apprv *approvalEnvironment) {
newState := "closed"
closeComment := "Workflow cancelled, closing issue."
fmt.Println(closeComment)
_, _, err := client.Issues.CreateComment(ctx, apprv.repoOwner, apprv.repo, 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})
if err != nil {
fmt.Printf("error closing issue: %v\n", err)
return
}
}
func newCommentLoopChannel(ctx context.Context, apprv *approvalEnvironment, client *github.Client, approvers []string, minimumApprovals int) chan int {
channel := make(chan int)
go func() {
for {
comments, _, err := client.Issues.ListComments(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueListCommentsOptions{})
if err != nil {
fmt.Printf("error getting comments: %v\n", err)
channel <- 1
close(channel)
}
approved, err := approvalFromComments(comments, approvers, minimumApprovals)
if err != nil {
fmt.Printf("error getting approval from comments: %v\n", err)
channel <- 1
close(channel)
}
fmt.Printf("Workflow status: %s\n", approved)
switch approved {
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{
Body: &closeComment,
})
if err != nil {
fmt.Printf("error commenting on issue: %v\n", err)
channel <- 1
close(channel)
}
_, _, err = client.Issues.Edit(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueRequest{State: &newState})
if err != nil {
fmt.Printf("error closing issue: %v\n", err)
channel <- 1
close(channel)
}
channel <- 0
fmt.Println("Workflow manual approval completed")
close(channel)
case approvalStatusDenied:
newState := "closed"
closeComment := "Request denied. Closing issue and failing workflow."
_, _, err := client.Issues.CreateComment(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueComment{
Body: &closeComment,
})
if err != nil {
fmt.Printf("error commenting on issue: %v\n", err)
channel <- 1
close(channel)
}
_, _, err = client.Issues.Edit(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueRequest{State: &newState})
if err != nil {
fmt.Printf("error closing issue: %v\n", err)
channel <- 1
close(channel)
}
channel <- 1
close(channel)
}
time.Sleep(pollingInterval)
}
}()
return channel
}
func newGithubClient(ctx context.Context) *github.Client {
token := os.Getenv(envVarToken)
ts := oauth2.StaticTokenSource(
@ -64,57 +149,16 @@ func main() {
os.Exit(1)
}
commentLoop:
for {
comments, _, err := client.Issues.ListComments(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueListCommentsOptions{})
if err != nil {
fmt.Printf("error getting comments: %v\n", err)
os.Exit(1)
}
killSignalChannel := make(chan os.Signal, 1)
signal.Notify(killSignalChannel, os.Interrupt)
approved, err := approvalFromComments(comments, approvers, minimumApprovals)
if err != nil {
fmt.Printf("error getting approval from comments: %v\n", err)
os.Exit(1)
}
fmt.Printf("Workflow status: %s\n", approved)
switch approved {
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{
Body: &closeComment,
})
if err != nil {
fmt.Printf("error commenting on issue: %v\n", err)
os.Exit(1)
}
_, _, err = client.Issues.Edit(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueRequest{State: &newState})
if err != nil {
fmt.Printf("error closing issue: %v\n", err)
os.Exit(1)
}
break commentLoop
case approvalStatusDenied:
newState := "closed"
closeComment := "Request denied. Closing issue and failing workflow."
_, _, err := client.Issues.CreateComment(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueComment{
Body: &closeComment,
})
if err != nil {
fmt.Printf("error commenting on issue: %v\n", err)
os.Exit(1)
}
_, _, err = client.Issues.Edit(ctx, apprv.repoOwner, apprv.repo, apprv.approvalIssueNumber, &github.IssueRequest{State: &newState})
if err != nil {
fmt.Printf("error closing issue: %v\n", err)
os.Exit(1)
}
os.Exit(1)
}
commentLoopChannel := newCommentLoopChannel(ctx, apprv, client, approvers, minimumApprovals)
time.Sleep(pollingInterval)
select {
case exitCode := <-commentLoopChannel:
os.Exit(exitCode)
case _ = <-killSignalChannel:
handleInterrupt(client, ctx, apprv)
os.Exit(1)
}
fmt.Println("Workflow manual approval completed")
}