Skip to content

Commit 6a21db9

Browse files
authored
fix: backtrack workflow fails with 403 — lock/unlock steps are inverted (#187)
- [x] Understand the gap: base branch (`github.base_ref`) was not locked during backtracking, allowing new PR merges into it concurrently - [x] Lock base branch (`github.base_ref`) with `lock-branch: 'true'` before the merge steps - [x] Restore permanent protection on base branch after backtrack (always, guarded by lock step outcome)
1 parent 906ca64 commit 6a21db9

2 files changed

Lines changed: 55 additions & 12 deletions

File tree

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

Lines changed: 5 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+
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.'
13+
required: false
14+
default: 'false'
1115

1216
runs:
1317
using: composite
@@ -30,7 +34,7 @@ runs:
3034
"restrictions": null,
3135
"allow_force_pushes": false,
3236
"allow_deletions": false,
33-
"lock_branch": false
37+
"lock_branch": ${{ inputs.lock-branch }}
3438
}
3539
EOF
3640
then

.github/workflows/backtrack.yml

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,36 +61,75 @@ jobs:
6161
echo "::warning::Develop branch '${{ steps.targets.outputs.develop-branch }}' not found, skipping backtrack."
6262
fi
6363
64+
- name: 'Lock base branch'
65+
id: lock-base
66+
uses: './.github/actions/github/branch-protection/lock'
67+
with:
68+
branch: ${{ github.base_ref }}
69+
token: ${{ secrets.GH_ADMIN_TOKEN }}
70+
lock-branch: 'true'
71+
72+
- name: 'Lock preview branch'
73+
id: lock-preview
74+
if: ${{ steps.targets.outputs.preview-branch != '' }}
75+
uses: './.github/actions/github/branch-protection/lock'
76+
with:
77+
branch: ${{ steps.targets.outputs.preview-branch }}
78+
token: ${{ secrets.GH_ADMIN_TOKEN }}
79+
lock-branch: 'true'
80+
6481
- name: 'Lock develop branch'
6582
id: lock-develop
6683
if: ${{ steps.check-develop.outputs.exists == 'true' }}
6784
uses: './.github/actions/github/branch-protection/lock'
6885
with:
6986
branch: ${{ steps.targets.outputs.develop-branch }}
7087
token: ${{ secrets.GH_ADMIN_TOKEN }}
88+
lock-branch: 'true'
7189

7290
- name: 'Backtrack: merge ${{ github.base_ref }} into ${{ steps.targets.outputs.preview-branch }}'
7391
if: ${{ steps.targets.outputs.preview-branch != '' }}
92+
env:
93+
GH_TOKEN: ${{ secrets.GH_ADMIN_TOKEN }}
7494
run: |
75-
git fetch origin
76-
git checkout -B ${{ steps.targets.outputs.preview-branch }} origin/${{ steps.targets.outputs.preview-branch }}
77-
git merge --no-ff origin/${{ github.base_ref }} -m "Backtrack: merge ${{ github.base_ref }} into ${{ steps.targets.outputs.preview-branch }}"
78-
git push origin ${{ steps.targets.outputs.preview-branch }}
95+
gh api --method POST /repos/${{ github.repository }}/merges \
96+
--field base="${{ steps.targets.outputs.preview-branch }}" \
97+
--field head="${{ github.base_ref }}" \
98+
--field commit_message="Backtrack: merge ${{ github.base_ref }} into ${{ steps.targets.outputs.preview-branch }}"
7999
80100
- name: 'Backtrack: merge ${{ steps.targets.outputs.merge-source }} into ${{ steps.targets.outputs.develop-branch }}'
81101
if: ${{ steps.check-develop.outputs.exists == 'true' }}
102+
env:
103+
GH_TOKEN: ${{ secrets.GH_ADMIN_TOKEN }}
82104
run: |
83-
git fetch origin
84-
git checkout -B ${{ steps.targets.outputs.develop-branch }} origin/${{ steps.targets.outputs.develop-branch }}
85-
git merge --no-ff origin/${{ steps.targets.outputs.merge-source }} -m "Backtrack: merge ${{ steps.targets.outputs.merge-source }} into ${{ steps.targets.outputs.develop-branch }}"
86-
git push origin ${{ steps.targets.outputs.develop-branch }}
105+
gh api --method POST /repos/${{ github.repository }}/merges \
106+
--field base="${{ steps.targets.outputs.develop-branch }}" \
107+
--field head="${{ steps.targets.outputs.merge-source }}" \
108+
--field commit_message="Backtrack: merge ${{ steps.targets.outputs.merge-source }} into ${{ steps.targets.outputs.develop-branch }}"
109+
110+
- name: 'Restore protection: base branch'
111+
if: ${{ always() && steps.lock-base.outcome == 'success' }}
112+
uses: './.github/actions/github/branch-protection/lock'
113+
with:
114+
branch: ${{ github.base_ref }}
115+
token: ${{ secrets.GH_ADMIN_TOKEN }}
116+
lock-branch: 'false'
87117

88-
- name: 'Unlock develop branch'
89-
if: ${{ always() && steps.lock-develop.outcome != 'skipped' }}
90-
uses: './.github/actions/github/branch-protection/unlock'
118+
- name: 'Restore protection: preview branch'
119+
if: ${{ always() && steps.lock-preview.outcome == 'success' }}
120+
uses: './.github/actions/github/branch-protection/lock'
121+
with:
122+
branch: ${{ steps.targets.outputs.preview-branch }}
123+
token: ${{ secrets.GH_ADMIN_TOKEN }}
124+
lock-branch: 'false'
125+
126+
- name: 'Restore protection: develop branch'
127+
if: ${{ always() && steps.lock-develop.outcome == 'success' }}
128+
uses: './.github/actions/github/branch-protection/lock'
91129
with:
92130
branch: ${{ steps.targets.outputs.develop-branch }}
93131
token: ${{ secrets.GH_ADMIN_TOKEN }}
132+
lock-branch: 'false'
94133

95134
- name: 'Write backtrack summary'
96135
if: ${{ always() }}

0 commit comments

Comments
 (0)