manual-approval/approval.go
2022-03-24 20:41:13 -04:00

96 lines
2.6 KiB
Go

package main
import (
"context"
"fmt"
"strings"
"github.com/google/go-github/v43/github"
)
type approvalEnvironment struct {
client *github.Client
repoFullName string
repo string
repoOwner string
runID int
approvers []string
approvalIssue *github.Issue
approvalIssueNumber int
}
func newApprovalEnvironment(client *github.Client, repoFullName, repoOwner string, runID int, approvers []string) (*approvalEnvironment, error) {
repoOwnerAndName := strings.Split(repoFullName, "/")
if len(repoOwnerAndName) != 2 {
return nil, fmt.Errorf("repo owner and name in unexpected format: %s", repoFullName)
}
repo := repoOwnerAndName[1]
return &approvalEnvironment{
client: client,
repoFullName: repoFullName,
repo: repo,
repoOwner: repoOwner,
runID: runID,
approvers: approvers,
}, nil
}
func (a approvalEnvironment) runURL() string {
return fmt.Sprintf("https://github.com/%s/actions/runs/%d", a.repoFullName, a.runID)
}
func (a *approvalEnvironment) createApprovalIssue(ctx context.Context) error {
issueTitle := fmt.Sprintf("Manual approval required for workflow run %d", a.runID)
issueBody := fmt.Sprintf(`Workflow is pending manual review.
URL: %s
Required approvers: %s
Respond '%s' to continue workflow or '%s' to cancel.
`, a.runURL(), a.approvers, approvalStatusApproved, approvalStatusDenied)
var err error
a.approvalIssue, _, err = a.client.Issues.Create(ctx, a.repoOwner, a.repo, &github.IssueRequest{
Title: &issueTitle,
Body: &issueBody,
Assignees: &a.approvers,
})
a.approvalIssueNumber = a.approvalIssue.GetNumber()
return err
}
func approvalFromComments(comments []*github.IssueComment, approvers []string) approvalStatus {
remainingApprovers := make([]string, len(approvers))
copy(remainingApprovers, approvers)
for _, comment := range comments {
commentUser := comment.User.GetLogin()
approverIdx := approversIndex(remainingApprovers, commentUser)
if approverIdx < 0 {
continue
}
commentBody := comment.GetBody()
if commentBody == string(approvalStatusApproved) {
if len(remainingApprovers) == 1 {
return approvalStatusApproved
}
remainingApprovers[approverIdx] = remainingApprovers[len(remainingApprovers)-1]
remainingApprovers = remainingApprovers[:len(remainingApprovers)-1]
continue
} else if commentBody == string(approvalStatusDenied) {
return approvalStatusDenied
}
}
return approvalStatusPending
}
func approversIndex(approvers []string, name string) int {
for idx, approver := range approvers {
if approver == name {
return idx
}
}
return -1
}