Skip to content

Commit 7076131

Browse files
Copilotpetesramek
andauthored
feat(branch-protection): add bypass-users + parameterize lock/unlock actions
Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/1e1019c3-ba0c-46d6-8fb2-aaa0952eddba Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com>
1 parent b816431 commit 7076131

2 files changed

Lines changed: 53 additions & 20 deletions

File tree

.github/actions/github/branch-protection/lock/action.yml

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: 'Lock branch'
22
author: 'Pete Sramek'
3-
description: 'Apply branch protection to prevent direct pushes. Requires PRs but no approvals (solo-maintainer friendly).'
3+
description: 'Apply branch protection to prevent direct pushes. Requires PRs with configurable approval count; optional bypass actors let trusted users merge without a review.'
44
inputs:
55
branch:
66
description: 'Branch name to lock.'
@@ -9,9 +9,21 @@ inputs:
99
description: 'GitHub token with administration:write (repo admin) permission. Use a PAT; GITHUB_TOKEN cannot call the branch protection API.'
1010
required: true
1111
lock-branch:
12-
description: 'When true, sets lock_branch to prevent even PR merges (use during automated operations). When false (default), only direct pushes are blocked; PRs with required reviews can still be merged.'
12+
description: 'When true, sets lock_branch to prevent even PR merges (use during automated operations). When false (default), only direct pushes are blocked; PRs can still be merged.'
1313
required: false
1414
default: 'false'
15+
required-approving-review-count:
16+
description: 'Number of approving reviews required before a PR can be merged. Set to 0 to require PRs without requiring approvals.'
17+
required: false
18+
default: '1'
19+
dismiss-stale-reviews:
20+
description: 'When true, approved reviews are dismissed when new commits are pushed to the branch.'
21+
required: false
22+
default: 'true'
23+
bypass-users:
24+
description: 'Comma-separated list of GitHub user logins that are allowed to bypass pull request requirements (e.g. "petesramek,bot-user").'
25+
required: false
26+
default: ''
1527

1628
runs:
1729
using: composite
@@ -21,23 +33,36 @@ runs:
2133
env:
2234
GH_TOKEN: ${{ inputs.token }}
2335
run: |
24-
if ! gh api --method PUT /repos/${{ github.repository }}/branches/${{ inputs.branch }}/protection \
25-
--input - << 'EOF'
26-
{
27-
"required_status_checks": null,
28-
"enforce_admins": false,
29-
"required_pull_request_reviews": {
30-
"dismiss_stale_reviews": true,
31-
"require_code_owner_reviews": false,
32-
"required_approving_review_count": 0
33-
},
34-
"restrictions": null,
35-
"allow_force_pushes": false,
36-
"allow_deletions": false,
37-
"lock_branch": ${{ inputs.lock-branch }}
38-
}
39-
EOF
40-
then
36+
BYPASS_USERS_JSON="[]"
37+
if [ -n "${{ inputs.bypass-users }}" ]; then
38+
BYPASS_USERS_JSON=$(echo "${{ inputs.bypass-users }}" | tr ',' '\n' | sed 's/^ *//;s/ *$//' | jq -R . | jq -s .)
39+
fi
40+
41+
PAYLOAD=$(jq -n \
42+
--argjson review_count '${{ inputs.required-approving-review-count }}' \
43+
--argjson dismiss_stale '${{ inputs.dismiss-stale-reviews }}' \
44+
--argjson bypass_users "$BYPASS_USERS_JSON" \
45+
--argjson lock_branch '${{ inputs.lock-branch }}' \
46+
'{
47+
"required_status_checks": null,
48+
"enforce_admins": false,
49+
"required_pull_request_reviews": {
50+
"dismiss_stale_reviews": $dismiss_stale,
51+
"require_code_owner_reviews": false,
52+
"required_approving_review_count": $review_count,
53+
"bypass_pull_request_allowances": {
54+
"users": $bypass_users,
55+
"teams": [],
56+
"apps": []
57+
}
58+
},
59+
"restrictions": null,
60+
"allow_force_pushes": false,
61+
"allow_deletions": false,
62+
"lock_branch": $lock_branch
63+
}')
64+
65+
if ! echo "$PAYLOAD" | gh api --method PUT /repos/${{ github.repository }}/branches/${{ inputs.branch }}/protection --input -; then
4166
echo "::error::Failed to apply branch protection to '${{ inputs.branch }}'. Ensure the token has 'administration: write' permission and the branch exists."
4267
exit 1
4368
fi

.github/actions/github/branch-protection/unlock/action.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ inputs:
88
token:
99
description: 'GitHub token with administration:write (repo admin) permission. Use a PAT; GITHUB_TOKEN cannot call the branch protection API.'
1010
required: true
11+
fail-on-error:
12+
description: 'When true, the step fails if branch protection cannot be removed. When false (default), errors are silently ignored.'
13+
required: false
14+
default: 'false'
1115

1216
runs:
1317
using: composite
@@ -17,5 +21,9 @@ runs:
1721
env:
1822
GH_TOKEN: ${{ inputs.token }}
1923
run: |
20-
gh api --method DELETE /repos/${{ github.repository }}/branches/${{ inputs.branch }}/protection || true
24+
if [ '${{ inputs.fail-on-error }}' = 'true' ]; then
25+
gh api --method DELETE /repos/${{ github.repository }}/branches/${{ inputs.branch }}/protection
26+
else
27+
gh api --method DELETE /repos/${{ github.repository }}/branches/${{ inputs.branch }}/protection || true
28+
fi
2129
echo "🔓 Branch protection removed from '${{ inputs.branch }}'." >> $GITHUB_STEP_SUMMARY

0 commit comments

Comments
 (0)