Repository navigation
ci(workflows): remind authors not to force-push active PRs #6035
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
bf2c244
ci(workflows): remind authors not to force-push active PRs
wenshao 1266743
ci(workflows): address review — add issues:write, serialize without c…
wenshao b7aa71f
ci(workflows): harden force-push detection per review
wenshao 48b6c46
test(ci): add structural test for the force-push reminder workflow
wenshao 6868e97
ci(workflows): drop concurrency group, rely on marker for idempotency
wenshao 3ba3169
test(ci): use Qwen Team header and assert the dedup skip path
wenshao be9e2db
test(ci): mechanically enforce KNOWN_AUTOMATION sync with qwen-autofix
wenshao File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| name: 'PR Force-Push Reminder' | ||
|
|
||
| on: | ||
| pull_request_target: | ||
| types: | ||
| - 'synchronize' | ||
|
|
||
| permissions: | ||
| contents: 'read' | ||
| pull-requests: 'write' | ||
|
wenshao marked this conversation as resolved.
|
||
|
|
||
| # One in-flight check per PR; a newer push supersedes the previous one so we | ||
| # never post the reminder twice for a rapid burst of force-pushes. | ||
| concurrency: | ||
|
wenshao marked this conversation as resolved.
Outdated
|
||
| group: 'pr-force-push-reminder-${{ github.event.pull_request.number }}' | ||
| cancel-in-progress: true | ||
|
wenshao marked this conversation as resolved.
Outdated
|
||
|
|
||
| jobs: | ||
| remind-on-force-push: | ||
| name: 'Remind on force-push' | ||
| timeout-minutes: 5 | ||
| if: |- | ||
| ${{ github.repository == 'QwenLM/qwen-code' }} | ||
| runs-on: 'ubuntu-latest' | ||
| steps: | ||
| - name: 'Detect force-push and post reminder' | ||
| uses: 'actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3' # v9.0.0 | ||
| with: | ||
| github-token: '${{ secrets.GITHUB_TOKEN }}' | ||
| script: | | ||
| const pr = context.payload.pull_request; | ||
| const before = context.payload.before; | ||
| const after = context.payload.after; | ||
|
|
||
| // A `synchronize` event should always carry both SHAs; bail out if | ||
| // either is missing or `before` is the all-zero (no parent) SHA. | ||
| if (!before || !after || /^0+$/.test(before)) { | ||
| console.log('No usable before/after SHA; nothing to do.'); | ||
| return; | ||
| } | ||
|
|
||
| // Skip automation-driven updates (e.g. integration/autofix bots). | ||
| // Only humans rebasing/force-pushing should get the reminder. | ||
| if (context.payload.sender?.type === 'Bot') { | ||
|
wenshao marked this conversation as resolved.
Outdated
|
||
| console.log(`Push made by bot "${context.payload.sender.login}"; skipping.`); | ||
| return; | ||
| } | ||
|
|
||
| // Compare the old tip (`before`) with the new tip (`after`): | ||
| // ahead -> new commits added on top of the old tip (normal push) | ||
| // identical -> no change | ||
| // behind -> reset to an older commit (force-push) | ||
| // diverged -> history rewritten, e.g. rebase/amend (force-push) | ||
| let status; | ||
| try { | ||
| const cmp = await github.rest.repos.compareCommitsWithBasehead({ | ||
| owner: context.repo.owner, | ||
|
wenshao marked this conversation as resolved.
|
||
| repo: context.repo.repo, | ||
| basehead: `${before}...${after}`, | ||
|
wenshao marked this conversation as resolved.
wenshao marked this conversation as resolved.
|
||
| }); | ||
| status = cmp.data.status; | ||
| } catch (err) { | ||
| // The compare can 404 if the old tip is no longer reachable. | ||
| // Stay conservative and skip rather than risk a false accusation. | ||
| const reason = err.status || err.message; | ||
|
wenshao marked this conversation as resolved.
Outdated
|
||
| console.log(`Could not compare ${before}...${after}: ${reason}. Skipping.`); | ||
| return; | ||
| } | ||
|
|
||
| console.log(`Compare ${before.slice(0, 7)}...${after.slice(0, 7)} => ${status}`); | ||
| if (status === 'ahead' || status === 'identical') { | ||
| console.log('Fast-forward push (not a force-push); nothing to do.'); | ||
| return; | ||
| } | ||
|
|
||
| // Force-push confirmed. Post the reminder at most once per PR; the | ||
| // hidden marker lets us detect a reminder we already left. | ||
| const MARKER = '<!-- pr-force-push-reminder -->'; | ||
| const comments = await github.paginate(github.rest.issues.listComments, { | ||
|
wenshao marked this conversation as resolved.
Outdated
|
||
| owner: context.repo.owner, | ||
|
wenshao marked this conversation as resolved.
Outdated
|
||
| repo: context.repo.repo, | ||
| issue_number: pr.number, | ||
| per_page: 100, | ||
| }); | ||
| if (comments.some((c) => c.body && c.body.includes(MARKER))) { | ||
|
wenshao marked this conversation as resolved.
Outdated
|
||
| console.log('Reminder already posted on this PR; skipping.'); | ||
| return; | ||
| } | ||
|
|
||
| const english = | ||
| 'Please do not rebase or force-push to an active PR as it invalidates ' + | ||
| 'existing review comments. Note for future reference, the bots always ' + | ||
| 'squash all changes into a single commit automatically as part of the ' + | ||
| 'integration.'; | ||
| const chinese = | ||
| '请勿对活跃的 PR 执行 rebase 或 force-push,因为这会使已有的评审评论失效。' + | ||
| '另外,供日后参考:作为集成流程的一部分,机器人始终会自动将所有改动' + | ||
| '压缩(squash)为单个提交。'; | ||
| const body = [ | ||
| MARKER, | ||
| '', | ||
| english, | ||
| '', | ||
| '<details>', | ||
| '<summary>中文</summary>', | ||
| '', | ||
| chinese, | ||
| '', | ||
| '</details>', | ||
| ].join('\n'); | ||
|
|
||
| await github.rest.issues.createComment({ | ||
|
wenshao marked this conversation as resolved.
Outdated
|
||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: pr.number, | ||
| body, | ||
| }); | ||
| console.log(`Posted force-push reminder on PR #${pr.number}.`); | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.