From 1d7ca96a09b142925e1e4d9e5688b1037ac86da0 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Tue, 3 Nov 2026 21:34:04 +0800 Subject: [PATCH] chore(github): add PR template, contributing guide and PR description check - PR template: linked issue, what and why, how it was verified, review focus. - Bug form gains an optional minimal reproduction; feature form requires acceptance criteria. - CONTRIBUTING.md states the issue and PR rules for people and coding agents. - PR check labels `needs-info` and leaves one comment when the issue link or the verification section is missing, and clears both once the description is fixed. It reads only the title and description and never runs PR code. --- .github/ISSUE_TEMPLATE/bug_report.yml | 6 ++ .github/ISSUE_TEMPLATE/feature_request.yml | 10 ++++ .github/pull_request_template.md | 17 ++++++ .github/workflows/pr-check.yml | 69 ++++++++++++++++++++++ CONTRIBUTING.md | 34 +++++++++++ 5 files changed, 136 insertions(+) create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/pr-check.yml create mode 100644 CONTRIBUTING.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index b7008354c..35e26f55f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -42,6 +42,12 @@ body: 3. ... validations: required: true + - type: textarea + id: reproduction + attributes: + label: Minimal reproduction + description: A link to a small public repository, or the smallest files/snippet that trigger the problem. Optional, but it's the fastest way to get a fix. + placeholder: https://github.com/you/repro-project - type: textarea id: expected attributes: diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index bc9ad7844..ac1c90377 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -27,6 +27,16 @@ body: description: How you'd like it to work. Mockups or examples from other tools are welcome. validations: required: true + - type: textarea + id: acceptance + attributes: + label: Acceptance criteria + description: How we'll know it's done. One observable behavior per line. + placeholder: | + - [ ] Right-clicking a test class shows "Run with Coverage" + - [ ] Coverage results open in the Coverage tool window + validations: + required: true - type: textarea id: alternatives attributes: diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..836b8710b --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,17 @@ +Closes # + +## What and why + + + +## How it was verified + + + +## Review focus + + diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml new file mode 100644 index 000000000..d1a74b7ee --- /dev/null +++ b/.github/workflows/pr-check.yml @@ -0,0 +1,69 @@ +name: PR check +on: + # pull_request_target so the check can label PRs from forks. It never checks out + # or runs PR code: it only reads the PR title and description. + pull_request_target: + types: [opened, edited, reopened, ready_for_review] + +permissions: + issues: write + pull-requests: write + +concurrency: + group: pr-check-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + check: + if: github.event.pull_request.user.type != 'Bot' && !github.event.pull_request.draft + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v7 + with: + script: | + const pr = context.payload.pull_request; + const LABEL = 'needs-info'; + const MARKER = ''; + // Docs, CI and pure refactors may skip the linked issue. + const NO_ISSUE_TYPES = /^(docs|ci|build|chore|refactor|style|test)(\(.+\))?!?:/; + + const body = (pr.body || '').replace(//g, ''); + const problems = []; + + const linksIssue = + /\b(close[sd]?|fix(e[sd])?|resolve[sd]?)\s*:?\s+(#\d+|https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/issues\/\d+)/i.test(body); + if (!linksIssue && !NO_ISSUE_TYPES.test(pr.title)) { + problems.push('Link the issue this PR resolves, e.g. `Closes #123`.'); + } + + const verified = body.match(/^##+\s*How it was verified\s*$([\s\S]*?)(?=^##+\s|(?![\s\S]))/im); + if (!verified || !verified[1].trim()) { + problems.push('Fill in **How it was verified**: the commands you ran and their results. UI changes need before/after screenshots.'); + } + + const { owner, repo } = context.repo; + const issue_number = pr.number; + const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number }); + const existing = comments.find(c => c.user.type === 'Bot' && c.body.includes(MARKER)); + const labeled = pr.labels.some(l => l.name === LABEL); + + if (problems.length) { + const text = `${MARKER}\nThanks for the PR. Before review, please update the description (see [CONTRIBUTING.md](https://github.com/${owner}/${repo}/blob/main/CONTRIBUTING.md)):\n\n${problems.map(p => `- ${p}`).join('\n')}\n\nThis check reruns when you edit the description.`; + if (existing) { + await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body: text }); + } else { + await github.rest.issues.createComment({ owner, repo, issue_number, body: text }); + } + if (!labeled) { + await github.rest.issues.addLabels({ owner, repo, issue_number, labels: [LABEL] }); + } + return; + } + + // Only undo what this check did: the label is cleared only when our comment exists. + if (existing) { + await github.rest.issues.deleteComment({ owner, repo, comment_id: existing.id }); + if (labeled) { + await github.rest.issues.removeLabel({ owner, repo, issue_number, name: LABEL }).catch(() => {}); + } + } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..547527892 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,34 @@ +# Contributing to OpenIDEA + +These rules apply to everyone, and to any coding agent working on their behalf. + +## Issues + +- One problem or request per issue. Use the issue forms. +- Bugs: steps that reproduce the problem from a fresh start. A minimal sample + project is the fastest way to get a fix. +- Features: state the problem and the acceptance criteria. A feature is ready to + build once a maintainer labels it `planned`. +- Labels track status: `needs-info` waits on the reporter, `needs-decision` waits + on a maintainer, `planned` is accepted, `needs-acceptance` has a fix waiting to be + checked. + +## Pull requests + +- One issue per PR, linked with `Closes #123`. Feature PRs need a `planned` issue. + Docs, CI and pure refactors may skip the issue. +- Reproduce the problem first, or write a test that fails before the fix. +- Fix the cause, and check whether the same cause breaks anything nearby. +- Keep the diff focused. Unrelated refactors go in their own PR. +- Title: [Conventional Commits](https://www.conventionalcommits.org/), e.g. + `fix(editor): keep the caret visible after folding`. +- Fill in the template. Keep the description short and in plain words. If it + doesn't fit in a few sentences, the PR is probably too big. +- **How it was verified** is required: the commands you ran and their results, + and what else the change could affect. UI changes need before/after screenshots; + multi-step interactions need a recording. +- If a change needs a product decision you can't make, ask in the issue and stop + rather than guessing. + +A check on each PR adds `needs-info` when the issue link or the verification +section is missing, and removes it once they're filled in.