-
Notifications
You must be signed in to change notification settings - Fork 22
177 lines (159 loc) · 6.89 KB
/
Copy pathvnext-compat.yaml
File metadata and controls
177 lines (159 loc) · 6.89 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
168
169
170
171
172
173
174
175
176
177
name: vnext compatibility check
# Runs on every PR regardless of base branch, so this can safely be made a
# required status check without hanging PRs whose base isn't main. Simulates
# squashing the PR onto main, then attempts a dry-run rebase of vnext onto the
# result. If vnext would conflict, the check fails and posts a comment with
# exact commands to resolve it.
#
# Only PRs targeting main do that real work — compat-check is a no-op for
# anything else (including vnext→main release PRs, head_ref == 'vnext'). The
# noop job covers that inverse case, and both paths feed vnext-status so
# there's always a single, consistently-named check to require.
on:
pull_request:
types: [opened, reopened, synchronize, edited]
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
compat-check:
name: Check vnext compatibility
if: github.event.pull_request.base.ref == 'main' && github.head_ref != 'vnext'
runs-on: ubuntu-slim
permissions:
contents: read
pull-requests: write # Required to post conflict resolution instructions as a PR comment
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Simulate squash onto main, then rebase vnext
id: compat
env:
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
git config user.email "github-actions[bot]@users.noreply.github.com"
git config user.name "github-actions[bot]"
git fetch origin main vnext
# Build a throwaway squash commit of the PR on top of main.
git checkout -b sim-main origin/main
git merge --squash "$PR_HEAD_SHA"
git commit --allow-empty -m "sim: squash of PR #${PR_NUMBER}"
# Attempt to rebase vnext onto the squash commit.
git checkout -b sim-vnext origin/vnext
if git rebase sim-main 2>&1; then
echo "compatible=true" >> "$GITHUB_OUTPUT"
else
CONFLICTS=$(git diff --name-only --diff-filter=U 2>/dev/null || true)
git rebase --abort
echo "compatible=false" >> "$GITHUB_OUTPUT"
{
echo 'conflicted_files<<EOF'
echo "$CONFLICTS"
echo 'EOF'
} >> "$GITHUB_OUTPUT"
fi
- name: Post conflict resolution comment
if: steps.compat.outputs.compatible == 'false' && github.event.pull_request.head.repo.full_name == github.repository
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
PR_HEAD_REF: ${{ github.head_ref }}
CONFLICTED_FILES: ${{ steps.compat.outputs.conflicted_files }}
with:
script: |
const branch = process.env.PR_HEAD_REF;
const files = (process.env.CONFLICTED_FILES || '').trim();
const fileBlock = files
? `**Conflicting files:**\n\`\`\`\n${files}\n\`\`\`\n`
: '';
const fileList = files ? files.split('\n').filter(Boolean) : [];
const diffCmd = fileList.length
? `git diff origin/main...origin/vnext -- ${fileList.join(' ')}`
: 'git diff origin/main...origin/vnext';
const body = [
'## ⚠️ `vnext` compatibility conflict detected',
'',
'If this PR merges to `main`, `vnext` cannot be cleanly rebased on top.',
'Your changes conflict with something already on `vnext`.',
'',
fileBlock,
'**How to fix:**',
'',
'Do **not** rebase your branch onto `vnext` — that would pull unreleased breaking',
'changes into `main`. Instead:',
'',
'1. See exactly what `vnext` changes in the conflicting file(s):',
'```bash',
'git fetch origin',
diffCmd,
'```',
'2. Open each conflicting file in your editor. The diff above shows what `vnext` adds',
' or changes there — adjust your edits so they no longer overlap with those lines.',
'3. Commit the adjustment and push:',
'```bash',
`git add ${fileList.length ? fileList.join(' ') : '<conflicting files>'}`,
'git commit -m "fix: resolve vnext compatibility"',
`git push origin ${branch}`,
'```',
'',
'After pushing, this check will re-run automatically.',
].join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
- name: Emit conflict instructions to job summary (fork PRs)
if: steps.compat.outputs.compatible == 'false' && github.event.pull_request.head.repo.full_name != github.repository
env:
PR_HEAD_REF: ${{ github.head_ref }}
CONFLICTED_FILES: ${{ steps.compat.outputs.conflicted_files }}
run: |
{
echo "## ⚠️ vnext compatibility conflict detected"
echo ""
echo "This PR conflicts with \`vnext\` when rebased onto \`main\`."
echo ""
if [ -n "$CONFLICTED_FILES" ]; then
echo "**Conflicting files:**"
echo '```'
echo "$CONFLICTED_FILES"
echo '```'
echo ""
echo "Inspect the diff with:"
echo '```bash'
echo "git fetch origin"
echo "git diff origin/main...origin/vnext -- $CONFLICTED_FILES"
echo '```'
else
echo "Run \`git diff origin/main...origin/vnext\` to inspect the conflict."
fi
echo ""
echo "Edit overlapping lines in those files, then commit and push."
} >> "$GITHUB_STEP_SUMMARY"
- name: Fail on conflict
if: steps.compat.outputs.compatible == 'false'
run: |
echo "::error::This PR conflicts with 'vnext' when rebased onto main. See the PR comment for resolution instructions."
exit 1
noop:
name: Skip vnext compatibility check
if: github.event.pull_request.base.ref != 'main' || github.head_ref == 'vnext'
runs-on: ubuntu-slim
steps:
- run: echo "Base isn't main, or this is the vnext release PR — nothing to check here."
vnext-status:
name: vnext compatibility status
needs: [compat-check, noop]
if: always()
runs-on: ubuntu-slim
permissions: {}
steps:
- uses: lowlydba/are-we-good@f506ed6324f55ec5e4ff5d92204a72c7f1c2b4f8 # v1.0.5
with:
jobs: ${{ toJSON(needs) }}