From c4ecac2da23851db2a3b9602009593ecb04761d6 Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Sun, 27 Sep 2026 16:24:16 +0200 Subject: [PATCH] chore(github): ask issue authors without the fix checkbox about a PR (#16271) * chore(github): ask issue authors without the fix checkbox about a PR Issues filed through `gh issue create --body` or the API skip the issue form, so they never carry the "I am working on a fix" checkbox. When the "Contributing a fix" section is missing from the body, the triage workflow now comments asking the author whether they plan to open a pull request. The regression form gets the same checkbox, so its reports are not asked. Co-Authored-By: Claude Opus 5.5 * test(github): cover the issue fix-intent classifier The classifier moves from the triage workflow into .github/scripts/issue-fix-intent.sh, with a test that CI runs next to the other workflow script tests. The workflow checks out the default branch before the step so the script is available. A "Contributing a fix" heading without its checkbox now counts as missing. A hand-written body containing only the heading was classified as unchecked and got neither an assignment nor the question. Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- .github/ISSUE_TEMPLATE/regression-report.yaml | 7 ++++ .github/scripts/issue-fix-intent.sh | 19 ++++++++++ .github/scripts/issue-fix-intent.test.sh | 24 +++++++++++++ .github/workflows/ci.yml | 1 + .github/workflows/triage-issues.yml | 36 +++++++++---------- 5 files changed, 69 insertions(+), 18 deletions(-) create mode 100755 .github/scripts/issue-fix-intent.sh create mode 100755 .github/scripts/issue-fix-intent.test.sh diff --git a/.github/ISSUE_TEMPLATE/regression-report.yaml b/.github/ISSUE_TEMPLATE/regression-report.yaml index ccabf27e32..123c884af5 100644 --- a/.github/ISSUE_TEMPLATE/regression-report.yaml +++ b/.github/ISSUE_TEMPLATE/regression-report.yaml @@ -60,3 +60,10 @@ body: - Linux validations: required: true + - type: checkboxes + id: working-on-fix + attributes: + label: Contributing a fix + description: Tick this if you plan to open a pull request. The issue will be assigned to you, so nobody else starts on the same fix. + options: + - label: I am working on a fix diff --git a/.github/scripts/issue-fix-intent.sh b/.github/scripts/issue-fix-intent.sh new file mode 100755 index 0000000000..db92c5199e --- /dev/null +++ b/.github/scripts/issue-fix-intent.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +# Reads an issue body on stdin and prints whether the author ticked the issue +# form's "I am working on a fix" checkbox: "checked", "unchecked", or +# "missing" when the body has no such checkbox, e.g. an issue filed with +# `gh issue create --body`. Only the checkbox under the form's own +# "Contributing a fix" heading counts, not the same text in another section. + +set -euo pipefail + +awk ' + { sub(/\r$/, "") } + /^### / { in_fix = ($0 ~ /^### Contributing a fix[[:space:]]*$/); next } + in_fix && /^- \[[ xX]\] I am working on a fix[[:space:]]*$/ { + seen = 1 + if ($0 !~ /^- \[ \]/) checked = 1 + } + END { print checked ? "checked" : seen ? "unchecked" : "missing" } +' diff --git a/.github/scripts/issue-fix-intent.test.sh b/.github/scripts/issue-fix-intent.test.sh new file mode 100755 index 0000000000..4ed347a648 --- /dev/null +++ b/.github/scripts/issue-fix-intent.test.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -euo pipefail + +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) + +assert_intent() { + local expected=$1 + local body=$2 + local actual + actual=$("$script_dir/issue-fix-intent.sh" <<< "$body") + if [ "$actual" != "$expected" ]; then + printf 'expected %s, got %s for body:\n%s\n' "$expected" "$actual" "$body" >&2 + exit 1 + fi +} + +assert_intent checked $'### Describe the Bug\n\nIt breaks.\n\n### Contributing a fix\n\n- [x] I am working on a fix' +assert_intent checked $'### Contributing a fix\r\n\r\n- [X] I am working on a fix\r' +assert_intent unchecked $'### Describe the Bug\n\nIt breaks.\n\n### Contributing a fix\n\n- [ ] I am working on a fix' +assert_intent missing $'### Describe the Bug\n\nIt breaks.\n\nA fix is prepared and will be submitted as a PR shortly.' +assert_intent missing $'### Describe the Bug\n\n- [x] I am working on a fix' +assert_intent missing $'### Contributing a fix\n\nI will send a PR.' +assert_intent missing '' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c7dcfefed4..d7811e278b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,6 +106,7 @@ jobs: run: | .github/scripts/npm-package-publication-state.test.sh .github/scripts/npm-staged-publication.test.sh + .github/scripts/issue-fix-intent.test.sh .agents/skills/pull-requests/scripts/resolve-pr-conflicts.test.sh node --test .github/scripts/ts-test-scope.test.mjs .github/scripts/ts-test-chunks.test.mjs .github/scripts/assert-windows-crt-static.test.mjs - name: Compile and lint TypeScript diff --git a/.github/workflows/triage-issues.yml b/.github/workflows/triage-issues.yml index b49fef79e0..c588ada463 100644 --- a/.github/workflows/triage-issues.yml +++ b/.github/workflows/triage-issues.yml @@ -32,7 +32,12 @@ jobs: contents: read # let the agent inspect the checked-out codebase issues: write # let the agent apply labels and comment steps: - - name: Assign the author if they are working on a fix + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Assign the author or ask whether they are working on a fix env: GH_TOKEN: ${{ github.token }} # Passed as env, never inlined into the script, so the free-form body @@ -41,23 +46,18 @@ jobs: ISSUE_URL: ${{ github.event.issue.html_url }} AUTHOR: ${{ github.event.issue.user.login }} run: | - # Only the form's own "Contributing a fix" section counts, not the - # same text typed into a free-form field. - if awk ' - { sub(/\r$/, "") } - /^### / { in_fix = ($0 ~ /^### Contributing a fix[[:space:]]*$/); next } - in_fix && /^- \[[xX]\] I am working on a fix[[:space:]]*$/ { found = 1 } - END { exit !found } - ' <<<"$ISSUE_BODY"; then - # GitHub refuses some authors as assignees. Triage must still run. - gh issue edit "$ISSUE_URL" --add-assignee "$AUTHOR" || - echo "::warning::Could not assign the issue to $AUTHOR" - fi - - - name: Checkout repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false + fix_state=$(.github/scripts/issue-fix-intent.sh <<<"$ISSUE_BODY") + case "$fix_state" in + checked) + # GitHub refuses some authors as assignees. Triage must still run. + gh issue edit "$ISSUE_URL" --add-assignee "$AUTHOR" || + echo "::warning::Could not assign the issue to $AUTHOR" + ;; + missing) + gh issue comment "$ISSUE_URL" --body "@$AUTHOR, are you planning to open a pull request for this? If so, reply here and a maintainer will assign the issue to you, so nobody else starts on the same fix." || + echo "::warning::Could not ask $AUTHOR about a fix" + ;; + esac - name: Triage with Oz agent uses: warpdotdev/oz-agent-action@261367f00a9899a054aac2661b39e6783f5e7c25 # v1.0.35