Skip to content

Commit

Permalink
Introduce a 'fail-on-denial' boolean (#147)
Browse files Browse the repository at this point in the history
* Introduce a 'fail-on-approval' boolean

* Use test docker image

* oops

* change default and fix logic

* Update action.yaml

* Fix linting error
  • Loading branch information
lizziemac authored Feb 15, 2025
1 parent d2e412d commit aba06e3
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 5 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
IMAGE_REPO=ghcr.io/trstringer/manual-approval
TARGET_PLATFORM=linux/amd64

.PHONY: build
build:
@if [ -z "$$VERSION" ]; then \
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:
Expand Down
9 changes: 8 additions & 1 deletion action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 3 additions & 1 deletion approval.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -40,6 +41,7 @@ func newApprovalEnvironment(client *github.Client, repoFullName, repoOwner strin
minimumApprovals: minimumApprovals,
issueTitle: issueTitle,
issueBody: issueBody,
failOnDenial: failOnDenial,
}, nil
}

Expand Down
1 change: 1 addition & 0 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
48 changes: 46 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down Expand Up @@ -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,
})
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down

0 comments on commit aba06e3

Please sign in to comment.