diff --git a/.github/ISSUE_TEMPLATE/01-bug-report.yml b/.github/ISSUE_TEMPLATE/01-bug-report.yml index e78c7f921..17ce6199b 100644 --- a/.github/ISSUE_TEMPLATE/01-bug-report.yml +++ b/.github/ISSUE_TEMPLATE/01-bug-report.yml @@ -18,6 +18,35 @@ body: placeholder: When I tried to export a PDF, the app got stuck on loading and never finished. validations: required: true + - type: dropdown + id: area + attributes: + label: Which area seems affected? + description: Pick the closest area. Maintainers can relabel it later. + options: + - Not sure + - App flow or product behavior + - Desktop shell, packaging, updater, signing, paths, or permissions + - UI or design system + - Model harness, prompts, tools, or session mechanics + - CI, release, or developer tooling + - Documentation + validations: + required: false + - type: dropdown + id: impact + attributes: + label: How much does this affect you? + description: Pick the closest impact. Maintainers can relabel it later. + options: + - Not sure + - Blocks me from using PawWork + - Security or data-loss risk + - Breaks an important workflow + - Makes a workflow harder, but there is a workaround + - Minor issue or polish + validations: + required: false - type: textarea id: steps attributes: @@ -64,8 +93,8 @@ body: validations: required: true - type: textarea - id: attachments + id: diagnostics attributes: - label: Screenshots, recordings, or extra context - description: Drag files into the issue, or paste any extra details here. - placeholder: Attach screenshots, recordings, logs, or sample files if helpful. + label: Diagnostics + description: Attach screenshots, recordings, session exports, logs, or sample files if helpful. + placeholder: Paste relevant logs, describe attached files, or add links to screenshots and recordings. diff --git a/.github/ISSUE_TEMPLATE/02-feature-request.yml b/.github/ISSUE_TEMPLATE/02-feature-request.yml index c8d0dbac2..e28bebf38 100644 --- a/.github/ISSUE_TEMPLATE/02-feature-request.yml +++ b/.github/ISSUE_TEMPLATE/02-feature-request.yml @@ -18,6 +18,21 @@ body: placeholder: I want to summarize a spreadsheet and turn it into a shareable report without leaving the app. validations: required: true + - type: dropdown + id: area + attributes: + label: Which area would this change affect? + description: Pick the closest area. Maintainers can relabel it later. + options: + - Not sure + - App flow or product behavior + - Desktop shell, packaging, updater, signing, paths, or permissions + - UI or design system + - Model harness, prompts, tools, or session mechanics + - CI, release, or developer tooling + - Documentation + validations: + required: false - type: textarea id: current attributes: @@ -34,6 +49,23 @@ body: placeholder: I can open a file, ask for a summary, and get a clean report in one place. validations: required: true + - type: textarea + id: acceptance + attributes: + label: What would count as done? + description: List the observable acceptance criteria. Keep this about user-visible behavior and verification, not only implementation details. + placeholder: | + - I can open a spreadsheet and ask PawWork to summarize it. + - The report is created in the same workspace. + - There is a clear way to check that the result works. + validations: + required: true + - type: textarea + id: non_goals + attributes: + label: What should stay out of scope? + description: Optional, but helpful when the request could grow too broad. + placeholder: This does not need to support charts, batch imports, or external publishing in the first version. - type: dropdown id: audience attributes: diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 1019a354a..158ccc105 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -10,13 +10,26 @@ Explain the problem, goal, or context for this pull request. Link the issue if there is one. +## Human Review Status + +Pending. A human should make the final merge decision after reviewing the final diff and verification evidence. + +## Review Focus + +What should reviewers pay the most attention to? + +## Risk Notes + +Call out behavior, data, permissions, dependencies, platform, or migration risks. Write "None" if there are no special risks. + ## How To Verify -List the commands you ran and any manual checks you performed. +List the targeted checks you ran and the key result for each one. Prefer the smallest checks that cover the changed surface. Include the result, not just the command. -```bash -bun turbo typecheck -bun turbo test:ci +```text +YAML parse: ok for both issue forms +Diff check: no whitespace errors +Focused tests: 47 passed ``` ## Screenshots or Recordings @@ -25,10 +38,14 @@ Required for visible UI changes. ## Checklist +- [ ] Human review status is stated above as pending, approved, or not required - [ ] I linked the related issue, or stated why there is no issue - [ ] This PR has type, scope, and priority labels, or I requested maintainer labeling -- [ ] I listed the relevant verification steps, including tests when behavior changed +- [ ] I described the review focus and any meaningful risks +- [ ] I listed the relevant verification steps and the key result for each +- [ ] I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope - [ ] I manually checked visible UI or copy changes when needed, with screenshots or recordings - [ ] I considered macOS and Windows impact for desktop, packaging, updater, signing, paths, shell, or permissions changes -- [ ] I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, or generated/local file changes when relevant +- [ ] I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant +- [ ] I reviewed the final diff for unrelated changes and suspicious dependency changes - [ ] I am targeting `dev`, and my PR title and commit messages use Conventional Commits in English diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 914fc4401..f608a9e61 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: is_docs_path() { case "$1" in - README.md|README_CN.md|packages/*/README.md|packages/opencode/specs/*|packages/opencode/BUN_SHELL_MIGRATION_PLAN.md|packages/app/create-effect-simplification-spec.md) + README.md|README_CN.md|.github/ISSUE_TEMPLATE/*|.github/pull_request_template.md|packages/*/README.md|packages/opencode/specs/*|packages/opencode/BUN_SHELL_MIGRATION_PLAN.md|packages/app/create-effect-simplification-spec.md) return 0 ;; *) diff --git a/.github/workflows/desktop-smoke.yml b/.github/workflows/desktop-smoke.yml index 2a8469d2c..7d25cfcdd 100644 --- a/.github/workflows/desktop-smoke.yml +++ b/.github/workflows/desktop-smoke.yml @@ -35,7 +35,7 @@ jobs: is_docs_path() { case "$1" in - README.md|README_CN.md|packages/*/README.md|packages/opencode/specs/*|packages/opencode/BUN_SHELL_MIGRATION_PLAN.md|packages/app/create-effect-simplification-spec.md) + README.md|README_CN.md|.github/ISSUE_TEMPLATE/*|.github/pull_request_template.md|packages/*/README.md|packages/opencode/specs/*|packages/opencode/BUN_SHELL_MIGRATION_PLAN.md|packages/app/create-effect-simplification-spec.md) return 0 ;; *) diff --git a/.github/workflows/e2e-artifacts.yml b/.github/workflows/e2e-artifacts.yml index 53a11097a..93193a9bc 100644 --- a/.github/workflows/e2e-artifacts.yml +++ b/.github/workflows/e2e-artifacts.yml @@ -29,7 +29,80 @@ env: PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/.playwright-browsers jobs: + changes: + runs-on: ubuntu-latest + outputs: + docs_only: ${{ steps.filter.outputs.docs_only }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6 + with: + fetch-depth: 0 + persist-credentials: false + + - id: filter + env: + EVENT_NAME: ${{ github.event_name }} + BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }} + HEAD_SHA: ${{ github.sha }} + run: | + set -euo pipefail + + is_docs_path() { + case "$1" in + README.md|README_CN.md|.github/ISSUE_TEMPLATE/*|.github/pull_request_template.md|packages/*/README.md|packages/opencode/specs/*|packages/opencode/BUN_SHELL_MIGRATION_PLAN.md|packages/app/create-effect-simplification-spec.md) + return 0 + ;; + *) + return 1 + ;; + esac + } + + docs_only=false + + if [ "$EVENT_NAME" = "workflow_dispatch" ]; then + echo "docs_only=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then + BASE_SHA="$(git rev-list --max-parents=0 HEAD | tail -n 1)" + fi + + mapfile -t changes < <(git diff --name-status --find-renames --find-copies "$BASE_SHA" "$HEAD_SHA" --) + + if [ "${#changes[@]}" -gt 0 ]; then + docs_only=true + + for change in "${changes[@]}"; do + IFS=$'\t' read -r status path1 path2 <<< "$change" + + case "$status" in + A*|M*|T*|D*) + if ! is_docs_path "$path1"; then + docs_only=false + break + fi + ;; + R*|C*) + if ! is_docs_path "$path1" || ! is_docs_path "$path2"; then + docs_only=false + break + fi + ;; + *) + docs_only=false + break + ;; + esac + done + fi + + echo "docs_only=$docs_only" >> "$GITHUB_OUTPUT" + e2e-artifacts: + needs: changes + if: needs.changes.outputs.docs_only != 'true' runs-on: ubuntu-latest timeout-minutes: 30 steps: diff --git a/packages/opencode/test/config/e2e-artifacts-workflow.test.ts b/packages/opencode/test/config/e2e-artifacts-workflow.test.ts index ee793aa3b..f7137d4a8 100644 --- a/packages/opencode/test/config/e2e-artifacts-workflow.test.ts +++ b/packages/opencode/test/config/e2e-artifacts-workflow.test.ts @@ -9,8 +9,12 @@ describe("e2e artifacts workflow", () => { test("defines a required PR e2e workflow with retained failure artifacts", () => { const workflow = readWorkflow(workflowPath) const parsed = parseWorkflow(workflowPath) + const changes = parsed.jobs?.changes const job = parsed.jobs?.["e2e-artifacts"] + const changesSteps = changes?.steps ?? [] const steps = job?.steps ?? [] + const changesCheckoutStep = changesSteps.find((step) => step.uses?.startsWith("actions/checkout@")) + const filterStep = changesSteps.find((step) => step.id === "filter") const checkoutStep = steps.find((step) => step.uses?.startsWith("actions/checkout@")) const bunStep = steps.find((step) => step.uses?.startsWith("oven-sh/setup-bun@")) const installBrowsersStep = steps.find((step) => step.name === "Install Playwright browsers") @@ -35,6 +39,19 @@ describe("e2e artifacts workflow", () => { "group: e2e-artifacts-${{ github.event.pull_request.number || github.ref }}-${{ inputs.suite || 'pr-smoke' }}", ) expect(parsed.permissions).toEqual({ contents: "read" }) + expect(Object.keys(parsed.jobs ?? {}).sort()).toEqual(["changes", "e2e-artifacts"]) + expect(changes?.outputs).toEqual({ docs_only: "${{ steps.filter.outputs.docs_only }}" }) + expect(changesCheckoutStep?.with).toEqual({ + "fetch-depth": 0, + "persist-credentials": false, + }) + expect(filterStep?.env?.EVENT_NAME).toBe("${{ github.event_name }}") + expect(filterStep?.run).toContain(".github/ISSUE_TEMPLATE/*") + expect(filterStep?.run).toContain(".github/pull_request_template.md") + expect(filterStep?.run).toContain("git diff --name-status --find-renames --find-copies") + expect(filterStep?.run).toContain("R*|C*)") + expect(job?.needs).toBe("changes") + expect(job?.if).toBe("needs.changes.outputs.docs_only != 'true'") expect(job?.["runs-on"]).toBe("ubuntu-latest") expect(job?.["continue-on-error"]).not.toBe(true) expect(checkoutStep?.uses).toBe("actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd") diff --git a/packages/opencode/test/github/ci-workflow.test.ts b/packages/opencode/test/github/ci-workflow.test.ts index d9b4ec371..171c2babe 100644 --- a/packages/opencode/test/github/ci-workflow.test.ts +++ b/packages/opencode/test/github/ci-workflow.test.ts @@ -209,6 +209,8 @@ describe("ci workflow", () => { expect(filter?.env?.HEAD_SHA).toBe("${{ github.sha }}") expect(filter?.run).toContain("workflow_dispatch") expect(filter?.run).toContain("docs_only=false") + expect(filter?.run).toContain(".github/ISSUE_TEMPLATE/*") + expect(filter?.run).toContain(".github/pull_request_template.md") expect(filter?.run).toContain("git diff --name-status --find-renames --find-copies") expect(filter?.run).toContain("R*|C*)") expect(filter?.run).toContain("if ! is_docs_path \"$path1\" || ! is_docs_path \"$path2\"; then") diff --git a/packages/opencode/test/github/desktop-smoke-workflow.test.ts b/packages/opencode/test/github/desktop-smoke-workflow.test.ts index fbcb0da40..28dda3402 100644 --- a/packages/opencode/test/github/desktop-smoke-workflow.test.ts +++ b/packages/opencode/test/github/desktop-smoke-workflow.test.ts @@ -36,6 +36,8 @@ describe("desktop smoke workflow", () => { expect(smokeCheckoutStep?.uses).toBe("actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd") expect(changes?.outputs).toEqual({ docs_only: "${{ steps.filter.outputs.docs_only }}" }) + expect(changesSteps.find((step) => step.id === "filter")?.run).toContain(".github/ISSUE_TEMPLATE/*") + expect(changesSteps.find((step) => step.id === "filter")?.run).toContain(".github/pull_request_template.md") expect(changesCheckoutStep?.with).toEqual({ "fetch-depth": 0, "persist-credentials": false,