Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions .github/scripts/classify-release-notes.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -94,26 +94,29 @@ function main() {
(typeof label === 'string' ? label : label.name).toLowerCase() ===
AUTO_LABEL,
);
// REST, not `gh pr edit`: that command's GraphQL lookup requests
// repository.pullRequest.projectCards, which GitHub rejects on gh
// builds that still send the query — the mutation then exits 1 before
// applying anything, and this step's continue-on-error turned that
// into a silent skip on every affected release. The REST label
// endpoints never touch that query. The label is a path segment in
// the DELETE, hence encodeURIComponent.
if (shouldSkip && !hasAutoLabel) {
execFileSync('gh', [
'pr',
'edit',
number,
'--repo',
repo,
'--add-label',
AUTO_LABEL,
'api',
'-X',
'POST',
`repos/${repo}/issues/${number}/labels`,
'-f',
`labels[]=${AUTO_LABEL}`,
]);
labeled.push(number);
} else if (!shouldSkip && hasAutoLabel) {
execFileSync('gh', [
'pr',
'edit',
number,
'--repo',
repo,
'--remove-label',
AUTO_LABEL,
'api',
'-X',
'DELETE',
`repos/${repo}/issues/${number}/labels/${encodeURIComponent(AUTO_LABEL)}`,
]);
unlabeled.push(number);
}
Expand Down
9 changes: 6 additions & 3 deletions .github/scripts/classify-release-notes.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,12 @@ describe('release note classification', () => {
" process.stdout.write('.github/workflows/ci.yml\\n');",
' process.exit(0);',
'}',
"if (args[0] === 'pr' && args[1] === 'edit') {",
` const action = args.includes('--remove-label') ? 'remove' : 'add';`,
` require('node:fs').appendFileSync(${JSON.stringify(updates)}, args[2] + ' ' + action + '\\n');`,
// Label mutations arrive as REST calls (gh pr edit is banned for
// labels — its projectCards lookup fails on affected gh builds).
"if (args[0] === 'api' && args[1] === '-X' && (args[2] === 'POST' || args[2] === 'DELETE') && /\\/issues\\/\\d+\\/labels/.test(args[3])) {",
" const action = args[2] === 'DELETE' ? 'remove' : 'add';",
" const number = args[3].match(/\\/issues\\/(\\d+)\\/labels/)[1];",
` require('node:fs').appendFileSync(${JSON.stringify(updates)}, number + ' ' + action + '\\n');`,
' process.exit(0);',
'}',
'process.exit(1);',
Expand Down
23 changes: 21 additions & 2 deletions .github/workflows/pr-self-report-label.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,37 @@ jobs:
HAS_LABEL="$(gh pr view "${PR}" --repo "${REPO}" --json labels \
--jq "[.labels[].name] | index(\"${LABEL}\") != null" 2> /dev/null || echo 'false')"

# Label mutations go through REST, NOT `gh pr edit`: that command's
# GraphQL lookup requests repository.pullRequest.projectCards, and
# GitHub answers the Projects (classic) deprecation as an ERROR on
# the gh builds that still send that query — this job's runner
# image does, so `gh pr edit` exits 1 before mutating anything.
# Every add/remove path of this job failed that way from
# 2026-08-04 on (43 runs); the green runs were all the no-change
# arm. REST never touches that query.
if [[ "${SELF}" == 'true' && "${HAS_LABEL}" != 'true' ]]; then
# Create the label on first use (idempotent), then apply it.
gh label create "${LABEL}" --repo "${REPO}" --color 'BFD4F2' \
--description 'The linked issue was opened by the PR author (self-reported)' \
2> /dev/null || true
gh pr edit "${PR}" --repo "${REPO}" --add-label "${LABEL}"
gh api -X POST "repos/${REPO}/issues/${PR}/labels" -f "labels[]=${LABEL}" > /dev/null
Comment thread
wenshao marked this conversation as resolved.
echo "🏷️ #${PR}: added ${LABEL} — a closed issue was opened by ${PR_AUTHOR}"
elif [[ "${SELF}" != 'true' && "${HAS_LABEL}" == 'true' && "${API_OK}" == 'true' ]]; then
# The link was removed or re-pointed to someone else's issue — clear
# the now-stale label so it never lies. Only when the query itself
# succeeded: an API failure must not look like "no self-reported link".
gh pr edit "${PR}" --repo "${REPO}" --remove-label "${LABEL}"
# The label name is a PATH SEGMENT here, and it contains a slash —
# unencoded, the request hits …/labels/review/self-reported (404).
# The presence check above is not atomic with this DELETE: if the
# label was removed in the gap, the 404 only says the desired end
# state already holds and must not fail the step. Any other
# failure (403 rate limit, 5xx, network) also keeps the step
# green — the job only re-runs on the next PR event — but must
# not disappear: without the warning, the log claims "removed"
# while the label stays on the PR.
if ! REMOVE_ERR="$(gh api -X DELETE "repos/${REPO}/issues/${PR}/labels/$(jq -rn --arg l "${LABEL}" '$l|@uri')" 2>&1)"; then
[[ "${REMOVE_ERR}" == *404* ]] || echo "::warning::#${PR}: ${LABEL} removal failed — ${REMOVE_ERR}"
fi
echo "🏷️ #${PR}: removed ${LABEL} — no self-reported linked issue"
else
echo "#${PR}: no change (self=${SELF}, labeled=${HAS_LABEL}, api=${API_OK})"
Expand Down
30 changes: 28 additions & 2 deletions .github/workflows/qwen-autofix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1733,7 +1733,22 @@ jobs:
gh pr comment "${PR}" --repo "${REPO}" --body "$(printf '🔄 Takeover re-armed: the round counter starts a fresh window (previous rounds no longer count toward the cap); management continues.\n\n<details>\n<summary>中文说明</summary>\n\n🔄 已重新武装:轮次计数开启新窗口(此前轮次不再计入上限),托管继续。\n\n</details>\n\n<!-- takeover-ack engaged -->')"
echo "🔄 re-armed ${TAKEOVER_LABEL} window on #${PR}"
else
gh pr edit "${PR}" --repo "${REPO}" --add-label "${TAKEOVER_LABEL}"
# REST for consistency and runner-version independence: `gh pr
# edit`'s GraphQL lookup requests
# repository.pullRequest.projectCards, which GitHub rejects on
# the gh builds that still send that query (demonstrated on the
# ECS pool — see pr-self-report-label.yml). This job runs on
# ubuntu-latest, where the command still worked; REST behaves
# the same on every runner image.
# Idempotent create first, with the label's real color: the
# REST add would silently create a missing label with a RANDOM
# color (gh pr edit failed loud there), and this was the one
# POST site without the guard its siblings carry
# (pr-self-report-label.yml creates; repo-hygiene.yml probes).
gh label create "${TAKEOVER_LABEL}" --repo "${REPO}" --color '1D76DB' \
--description 'Summon the autofix loop to manage this PR (remove to release; needs triage+)' \
2> /dev/null || true
gh api -X POST "repos/${REPO}/issues/${PR}/labels" -f "labels[]=${TAKEOVER_LABEL}" > /dev/null
Comment thread
wenshao marked this conversation as resolved.
echo "🏷️ applied ${TAKEOVER_LABEL} to #${PR}"
# Ack HERE, not via the pull_request:labeled round-trip: that
# event has been observed to simply not fire (#7999 — the
Expand All @@ -1759,7 +1774,18 @@ jobs:
if [[ "${HAS}" != 'true' ]]; then
echo "ℹ️ #${PR} does not carry ${TAKEOVER_LABEL} — nothing to do"
else
gh pr edit "${PR}" --repo "${REPO}" --remove-label "${TAKEOVER_LABEL}"
# REST for the same reason as the add above; the label name is a
# path segment and contains a slash, so it must be URI-encoded.
# A concurrent removal between the presence check and this
# DELETE already reached the end state — the 404 must not abort
# the step and drop the release ack below. Other failures (403,
# 5xx, network) also must not drop the ack — a later
# `/takeover stop` retries the removal — but must not disappear
# silently either: masked, the ack reads "released" while the
# loop keeps managing the PR.
if ! REMOVE_ERR="$(gh api -X DELETE "repos/${REPO}/issues/${PR}/labels/$(jq -rn --arg l "${TAKEOVER_LABEL}" '$l|@uri')" 2>&1)"; then
[[ "${REMOVE_ERR}" == *404* ]] || echo "::warning::#${PR}: ${TAKEOVER_LABEL} removal failed — ${REMOVE_ERR}"
fi
echo "🏷️ removed ${TAKEOVER_LABEL} from #${PR}"
# Release ack, direct from the command — the exact mirror of
# the engage side above, for the same reason: the unlabeled
Expand Down
17 changes: 15 additions & 2 deletions .github/workflows/repo-hygiene.yml
Original file line number Diff line number Diff line change
Expand Up @@ -842,8 +842,21 @@ jobs:

# Label requested by issue #7383. Non-fatal: never create labels,
# and a repo without it should not fail the run.
gh pr edit "${PR_URL}" --add-label 'autofix/repo-hygiene' \
|| echo '⚠️ Could not add label autofix/repo-hygiene (missing in this repo?)'
# REST, not `gh pr edit`: its GraphQL lookup requests
# repository.pullRequest.projectCards, which GitHub rejects on the
# gh builds that still send that query (see
# pr-self-report-label.yml). The label autofix/repo-hygiene has
# never been created in this repo, and the existence probe
# preserves the no-create promise: the REST add alone would create
# a missing label. The probe cannot tell a 404 from any other API
# failure, so the skip message claims neither.
if gh api "repos/${GITHUB_REPOSITORY}/labels/autofix%2Frepo-hygiene" > /dev/null 2>&1; then
Comment thread
wenshao marked this conversation as resolved.
gh api -X POST "repos/${GITHUB_REPOSITORY}/issues/${PR_URL##*/}/labels" \
Comment thread
wenshao marked this conversation as resolved.
-f 'labels[]=autofix/repo-hygiene' > /dev/null \
|| echo '⚠️ Could not add label autofix/repo-hygiene'
else
echo '⚠️ Could not verify label autofix/repo-hygiene; skipping'
fi

if [[ -s "${WORKDIR}/report-only.md" ]]; then
{
Expand Down
Loading
Loading