forked from vendurehq/vendure
-
Notifications
You must be signed in to change notification settings - Fork 0
167 lines (150 loc) · 6.99 KB
/
back_merge.yml
File metadata and controls
167 lines (150 loc) · 6.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
name: Back-merge
on:
push:
branches:
- master
# NOTE: The minor → major cascade is disabled because GitHub's
# "Automatically delete head branches" setting deletes the `minor`
# branch when a conflict-resolution PR (minor → major) is merged.
# There is no exclusion list for that setting, and rulesets' "Restrict
# deletions" rule does not reliably prevent it.
#
# Merge minor → major manually instead:
# git checkout major && git pull && git merge origin/minor && git push
#
# See:
# - https://github.com/orgs/community/discussions/135012
# - https://github.com/orgs/community/discussions/152926
#
# - minor
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
resolve-branches:
name: Resolve merge target
runs-on: ubuntu-latest
outputs:
source: ${{ github.ref_name }}
target: ${{ steps.target.outputs.branch }}
steps:
- name: Determine target branch
id: target
env:
BRANCH: ${{ github.ref_name }}
run: |
if [ "$BRANCH" = "master" ]; then
echo "branch=minor" >> "$GITHUB_OUTPUT"
fi
# Disabled: see comment at top of file
# elif [ "$BRANCH" = "minor" ]; then
# echo "branch=major" >> "$GITHUB_OUTPUT"
# fi
back-merge:
name: 'Merge ${{ needs.resolve-branches.outputs.source }} → ${{ needs.resolve-branches.outputs.target }}'
runs-on: ubuntu-latest
needs: resolve-branches
permissions:
contents: write
pull-requests: write
steps:
- name: Generate CI Bot Token
id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.CI_BOT_APP_ID }}
private-key: ${{ secrets.CI_BOT_APP_PRIVATE_KEY }}
- name: Checkout target branch
uses: actions/checkout@v4
with:
token: ${{ steps.app-token.outputs.token }}
ref: ${{ needs.resolve-branches.outputs.target }}
fetch-depth: 0
- name: Get CI Bot user ID
id: get-user-id
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
APP_SLUG: ${{ steps.app-token.outputs.app-slug }}
run: |
echo "user-id=$(gh api "/users/${APP_SLUG}%5Bbot%5D" --jq .id)" >> "$GITHUB_OUTPUT"
- name: Attempt merge
id: merge
env:
SOURCE: ${{ needs.resolve-branches.outputs.source }}
TARGET: ${{ needs.resolve-branches.outputs.target }}
APP_SLUG: ${{ steps.app-token.outputs.app-slug }}
USER_ID: ${{ steps.get-user-id.outputs.user-id }}
run: |
git config user.name "${APP_SLUG}[bot]"
git config user.email "${USER_ID}+${APP_SLUG}[bot]@users.noreply.github.com"
git fetch origin "$SOURCE"
if git merge-base --is-ancestor "origin/$SOURCE" HEAD; then
echo "result=up-to-date" >> "$GITHUB_OUTPUT"
echo "::notice::$TARGET is already up to date with $SOURCE"
elif git merge "origin/$SOURCE" --no-edit; then
echo "result=clean" >> "$GITHUB_OUTPUT"
else
git merge --abort
echo "result=conflict" >> "$GITHUB_OUTPUT"
fi
# App token is used for the push (not GITHUB_TOKEN) so that
# the push triggers downstream workflow runs for the cascade.
- name: Push merge
if: steps.merge.outputs.result == 'clean'
env:
TARGET: ${{ needs.resolve-branches.outputs.target }}
run: git push origin "$TARGET"
# GITHUB_TOKEN is sufficient for PR operations — they don't need
# to trigger downstream workflows, and it avoids burning App token quota.
- name: Check for existing back-merge PR
if: steps.merge.outputs.result == 'conflict'
id: check-pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SOURCE: ${{ needs.resolve-branches.outputs.source }}
TARGET: ${{ needs.resolve-branches.outputs.target }}
run: |
EXISTING_PR=$(gh pr list \
--base "$TARGET" \
--head "$SOURCE" \
--state open \
--json number \
--jq '.[0].number // empty')
if [ -n "$EXISTING_PR" ]; then
echo "found=true" >> "$GITHUB_OUTPUT"
echo "pr_number=$EXISTING_PR" >> "$GITHUB_OUTPUT"
echo "::notice::Found existing back-merge PR #$EXISTING_PR"
else
echo "found=false" >> "$GITHUB_OUTPUT"
fi
- name: Create back-merge PR
if: steps.merge.outputs.result == 'conflict' && steps.check-pr.outputs.found != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SOURCE: ${{ needs.resolve-branches.outputs.source }}
TARGET: ${{ needs.resolve-branches.outputs.target }}
run: |
gh pr create \
--base "$TARGET" \
--head "$SOURCE" \
--title "chore(repo): Back-merge $SOURCE into $TARGET (conflicts)" \
--body "Automatic back-merge of \`$SOURCE\` into \`$TARGET\` failed due to merge conflicts.
To resolve: check out \`$TARGET\`, merge \`$SOURCE\`, resolve the conflicts, and push to \`$TARGET\`.
\`\`\`sh
git checkout $TARGET
git merge origin/$SOURCE
# resolve conflicts
git push origin $TARGET
\`\`\`
> Created automatically by the back-merge workflow."
- name: Comment on existing back-merge PR
if: steps.merge.outputs.result == 'conflict' && steps.check-pr.outputs.found == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ steps.check-pr.outputs.pr_number }}
SOURCE: ${{ needs.resolve-branches.outputs.source }}
TARGET: ${{ needs.resolve-branches.outputs.target }}
run: |
gh pr comment "$PR_NUMBER" \
--body "New conflicts detected during back-merge of \`$SOURCE\` into \`$TARGET\`. Please resolve the conflicts in this PR."