mirror of
https://github.com/glittercowboy/get-shit-done
synced 2026-04-25 17:25:23 +02:00
docs: add typed contribution templates and tighten contributor guidelines (#1673)
Overhaul CONTRIBUTING.md and all GitHub issue/PR templates to enforce a structured, approval-gated contribution process that cuts down on drive-by feature submissions. Changes: - CONTRIBUTING.md: add Types of Contributions section defining Fix, Enhancement, and Feature with escalating requirements and explicit rejection criteria; add Issue-First Rule section making clear that enhancements require approved-enhancement and features require approved-feature label before any code is written; backport gsd-2 testing standards (t.after() per-test cleanup, array join() fixture pattern, Node 24 as primary CI target, test requirements by change type, reviewer standards) - .github/ISSUE_TEMPLATE/enhancement.yml: new template requiring current vs. proposed behavior, reason/benefit narrative, full scope of changes, and breaking changes assessment; cannot be clicked through - .github/ISSUE_TEMPLATE/feature_request.yml: full rewrite requiring solo- developer problem statement, what is being added, full file-level scope, user stories, acceptance criteria, maintenance burden assessment, and alternatives considered; incomplete specs are closed, not revised - .github/pull_request_template.md: converted from general template to a routing page directing contributors to the correct typed template; using the default template for a feature or enhancement is a rejection reason - .github/PULL_REQUEST_TEMPLATE/fix.md: new typed template requiring confirmed-bug label on linked issue and regression test confirmation - .github/PULL_REQUEST_TEMPLATE/enhancement.md: new typed template with hard gate on approved-enhancement label and scope confirmation section - .github/PULL_REQUEST_TEMPLATE/feature.md: new typed template requiring file inventory, spec compliance checklist from the issue, and scope confirmation that nothing beyond the approved spec was added Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
160
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
Normal file
160
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
---
|
||||||
|
name: Enhancement Proposal
|
||||||
|
description: Propose an improvement to an existing feature. Read the full instructions before opening this issue.
|
||||||
|
labels: ["enhancement", "needs-review"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
## ⚠️ Read this before you fill anything out
|
||||||
|
|
||||||
|
An enhancement improves something that already exists — better output, expanded edge-case handling, improved performance, cleaner UX. It does **not** add new commands, new workflows, or new concepts. If you are proposing something new, use the [Feature Request](./feature_request.yml) template instead.
|
||||||
|
|
||||||
|
**Before opening this issue:**
|
||||||
|
- Confirm the thing you want to improve actually exists and works today.
|
||||||
|
- Read [CONTRIBUTING.md](../../CONTRIBUTING.md#-enhancement) — understand what `approved-enhancement` means and why you must wait for it before writing any code.
|
||||||
|
|
||||||
|
**What happens after you submit:**
|
||||||
|
A maintainer will review this proposal. If it is incomplete or out of scope, it will be **closed**. If approved, it will be labeled `approved-enhancement` and you may begin coding.
|
||||||
|
|
||||||
|
**Do not open a PR until this issue is labeled `approved-enhancement`.**
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
id: preflight
|
||||||
|
attributes:
|
||||||
|
label: Pre-submission checklist
|
||||||
|
description: You must check every box. Unchecked boxes are an immediate close.
|
||||||
|
options:
|
||||||
|
- label: I have confirmed this improves existing behavior — it does not add a new command, workflow, or concept
|
||||||
|
required: true
|
||||||
|
- label: I have searched existing issues and this enhancement has not already been proposed
|
||||||
|
required: true
|
||||||
|
- label: I have read CONTRIBUTING.md and understand I must wait for `approved-enhancement` before writing any code
|
||||||
|
required: true
|
||||||
|
- label: I can clearly describe the concrete benefit — not just "it would be nicer"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: what_is_being_improved
|
||||||
|
attributes:
|
||||||
|
label: What existing feature or behavior does this improve?
|
||||||
|
description: Name the specific command, workflow, output, or behavior you are enhancing.
|
||||||
|
placeholder: "e.g., `/gsd:plan` output, phase status display in statusline, context summary format"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: current_behavior
|
||||||
|
attributes:
|
||||||
|
label: Current behavior
|
||||||
|
description: |
|
||||||
|
Describe exactly how the thing works today. Be specific. Include example output or commands if helpful.
|
||||||
|
placeholder: |
|
||||||
|
Currently, `/gsd:status` shows:
|
||||||
|
```
|
||||||
|
Phase 2/5 — In Progress
|
||||||
|
```
|
||||||
|
It does not show the phase name, making it hard to know what phase you are actually in without
|
||||||
|
opening STATE.md.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: proposed_behavior
|
||||||
|
attributes:
|
||||||
|
label: Proposed behavior
|
||||||
|
description: |
|
||||||
|
Describe exactly how it should work after the enhancement. Be specific. Include example output or commands.
|
||||||
|
placeholder: |
|
||||||
|
After the enhancement, `/gsd:status` would show:
|
||||||
|
```
|
||||||
|
Phase 2/5 — In Progress — "Implement core auth module"
|
||||||
|
```
|
||||||
|
The phase name is pulled from STATE.md and appended to the existing output.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: reason_and_benefit
|
||||||
|
attributes:
|
||||||
|
label: Reason and benefit
|
||||||
|
description: |
|
||||||
|
Answer both of these clearly:
|
||||||
|
|
||||||
|
1. **Why is the current behavior a problem?** (Not just inconvenient — what goes wrong, what is harder than it should be, or what is confusing?)
|
||||||
|
2. **What is the concrete benefit of the proposed behavior?** (What becomes easier, faster, less error-prone, or clearer?)
|
||||||
|
|
||||||
|
Vague answers like "it would be better" or "it's more user-friendly" are not sufficient.
|
||||||
|
placeholder: |
|
||||||
|
**Why the current behavior is a problem:**
|
||||||
|
When working in a long session, the AI agent frequently loses track of which phase is active
|
||||||
|
and must re-read STATE.md. The numeric-only status gives no semantic context.
|
||||||
|
|
||||||
|
**Concrete benefit:**
|
||||||
|
Showing the phase name means the agent can confirm the active phase from the status output
|
||||||
|
alone, without an extra file read. This reduces context consumption in long sessions.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: scope
|
||||||
|
attributes:
|
||||||
|
label: Scope of changes
|
||||||
|
description: |
|
||||||
|
List the files and systems this enhancement would touch. Be complete.
|
||||||
|
An enhancement should have a narrow, well-defined scope. If your list is long, this might be a feature, not an enhancement.
|
||||||
|
placeholder: |
|
||||||
|
Files modified:
|
||||||
|
- `get-shit-done/commands/gsd/status.md` — update output format description
|
||||||
|
- `get-shit-done/bin/lib/state.cjs` — expose phase name in status() return value
|
||||||
|
- `tests/status.test.cjs` — update snapshot and add test for phase name in output
|
||||||
|
- `CHANGELOG.md` — user-facing change entry
|
||||||
|
|
||||||
|
No new files created. No new dependencies.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: breaking_changes
|
||||||
|
attributes:
|
||||||
|
label: Breaking changes
|
||||||
|
description: |
|
||||||
|
Does this change existing command output, file formats, or behavior that users or AI agents might depend on?
|
||||||
|
If yes, describe exactly what changes and how it stays backward compatible (or why it cannot).
|
||||||
|
Write "None" only if you are certain.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: alternatives
|
||||||
|
attributes:
|
||||||
|
label: Alternatives considered
|
||||||
|
description: |
|
||||||
|
What other ways could this be improved? Why is your proposed approach the right one?
|
||||||
|
If you haven't considered alternatives, take a moment before submitting.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: area
|
||||||
|
attributes:
|
||||||
|
label: Area affected
|
||||||
|
options:
|
||||||
|
- Core workflow (init, plan, build, verify)
|
||||||
|
- Planning system (phases, roadmap, state)
|
||||||
|
- Context management (context engineering, summaries)
|
||||||
|
- Runtime integration (hooks, statusline, settings)
|
||||||
|
- Installation / setup
|
||||||
|
- Output / formatting
|
||||||
|
- Documentation
|
||||||
|
- Other
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: additional_context
|
||||||
|
attributes:
|
||||||
|
label: Additional context
|
||||||
|
description: Screenshots, related issues, or anything else that helps explain the proposal.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
213
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
213
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,44 +1,165 @@
|
|||||||
---
|
---
|
||||||
name: Feature Request
|
name: Feature Request
|
||||||
description: Suggest a new feature or improvement
|
description: Propose a new feature. Read the full instructions before opening this issue.
|
||||||
labels: ["enhancement"]
|
labels: ["feature-request", "needs-review"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thanks for suggesting a feature! Please describe what you'd like to see.
|
## ⚠️ Read this before you fill anything out
|
||||||
|
|
||||||
- type: textarea
|
A feature adds something new to GSD — a new command, workflow, concept, or integration. Features have the **highest bar** for acceptance because every feature adds permanent maintenance burden to a project built for solo developers.
|
||||||
id: problem
|
|
||||||
|
**Before opening this issue:**
|
||||||
|
- Check [Discussions](https://github.com/gsd-build/get-shit-done/discussions) — has this been proposed and declined before?
|
||||||
|
- Read [CONTRIBUTING.md](../../CONTRIBUTING.md#-feature) — understand what "approved-feature" means and why you must wait for it before writing code.
|
||||||
|
- Ask yourself: *does this solve a real problem for a solo developer working with an AI coding tool, or is it a feature I personally want?*
|
||||||
|
|
||||||
|
**What happens after you submit:**
|
||||||
|
A maintainer will review this spec. If it is incomplete, it will be **closed**, not revised. If it conflicts with GSD's design philosophy, it will be declined. If it is approved, it will be labeled `approved-feature` and you may begin coding.
|
||||||
|
|
||||||
|
**Do not open a PR until this issue is labeled `approved-feature`.**
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
id: preflight
|
||||||
attributes:
|
attributes:
|
||||||
label: Problem or motivation
|
label: Pre-submission checklist
|
||||||
description: What problem does this solve? Why do you want this?
|
description: You must check every box. Unchecked boxes are an immediate close.
|
||||||
placeholder: "I'm frustrated when..."
|
options:
|
||||||
|
- label: I have searched existing issues and discussions — this has not been proposed and declined before
|
||||||
|
required: true
|
||||||
|
- label: I have read CONTRIBUTING.md and understand that I must wait for `approved-feature` before writing any code
|
||||||
|
required: true
|
||||||
|
- label: I have read the existing GSD commands and workflows and confirmed this feature does not duplicate existing behavior
|
||||||
|
required: true
|
||||||
|
- label: This feature solves a problem for solo developers using AI coding tools, not a personal preference or workflow I happen to like
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: feature_name
|
||||||
|
attributes:
|
||||||
|
label: Feature name
|
||||||
|
description: A short, concrete name for this feature (not a sales pitch — just what it is).
|
||||||
|
placeholder: "e.g., Phase rollback command, Auto-archive completed phases, Cross-project state sync"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: feature_type
|
||||||
|
attributes:
|
||||||
|
label: Type of addition
|
||||||
|
description: What kind of thing is this feature adding?
|
||||||
|
options:
|
||||||
|
- New command (slash command or CLI flag)
|
||||||
|
- New workflow (multi-step process)
|
||||||
|
- New runtime integration
|
||||||
|
- New planning concept (phase type, state, etc.)
|
||||||
|
- New installation/setup behavior
|
||||||
|
- New output or reporting format
|
||||||
|
- Other (describe in spec)
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: solution
|
id: problem_statement
|
||||||
attributes:
|
attributes:
|
||||||
label: Proposed solution
|
label: The solo developer problem
|
||||||
description: How do you think this should work? Include example commands or workflows if possible.
|
description: |
|
||||||
|
Describe the concrete problem this solves for a solo developer using an AI coding tool. Be specific.
|
||||||
|
|
||||||
|
Good: "When a phase fails mid-way, there is no way to roll back state without manually editing STATE.md. This causes the AI agent to continue from a corrupted state, producing wrong plans."
|
||||||
|
|
||||||
|
Bad: "It would be nice to have a rollback feature." / "Other tools have this." / "I need this for my workflow."
|
||||||
placeholder: |
|
placeholder: |
|
||||||
A new command `/gsd:example` that...
|
When [specific situation], the developer cannot [specific thing], which causes [specific negative outcome].
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: what_is_added
|
||||||
|
attributes:
|
||||||
|
label: What this feature adds
|
||||||
|
description: |
|
||||||
|
Describe exactly what is being added. Be specific about commands, output, behavior, and user interaction.
|
||||||
|
Include example commands or example output where possible.
|
||||||
|
placeholder: |
|
||||||
|
A new command `/gsd:rollback` that:
|
||||||
|
1. Reads the current phase from STATE.md
|
||||||
|
2. Reverts STATE.md to the previous phase's snapshot
|
||||||
|
3. Outputs a confirmation with the rolled-back state
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
```
|
||||||
|
/gsd:rollback
|
||||||
|
> Rolled back from Phase 3 (failed) to Phase 2 (completed)
|
||||||
|
```
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: full_scope
|
||||||
|
attributes:
|
||||||
|
label: Full scope of changes
|
||||||
|
description: |
|
||||||
|
List every file, system, and area of the codebase this feature would touch. Be exhaustive.
|
||||||
|
If you cannot fill this out, you do not understand the codebase well enough to propose this feature yet.
|
||||||
|
placeholder: |
|
||||||
|
Files that would be created:
|
||||||
|
- `get-shit-done/commands/gsd/rollback.md` — new slash command definition
|
||||||
|
|
||||||
|
Files that would be modified:
|
||||||
|
- `get-shit-done/bin/lib/state.cjs` — add rollback() function
|
||||||
|
- `get-shit-done/bin/lib/phases.cjs` — expose phase snapshot API
|
||||||
|
- `tests/rollback.test.cjs` — new test file
|
||||||
|
- `docs/COMMANDS.md` — document new command
|
||||||
|
- `CHANGELOG.md` — entry for this feature
|
||||||
|
|
||||||
|
Systems affected:
|
||||||
|
- STATE.md schema (must remain backward compatible)
|
||||||
|
- Phase lifecycle state machine
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: user_stories
|
||||||
|
attributes:
|
||||||
|
label: User stories
|
||||||
|
description: Write at least two user stories in the format "As a [user], I want [thing] so that [outcome]."
|
||||||
|
placeholder: |
|
||||||
|
1. As a solo developer, I want to roll back a failed phase so that I can re-attempt it without corrupting my project state.
|
||||||
|
2. As a solo developer, I want rollback to be undoable so that I don't accidentally lose completed work.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: acceptance_criteria
|
||||||
|
attributes:
|
||||||
|
label: Acceptance criteria
|
||||||
|
description: |
|
||||||
|
List the specific, testable conditions that must be true for this feature to be considered complete.
|
||||||
|
These become the basis for reviewer sign-off. Vague criteria ("it works") are not acceptable.
|
||||||
|
placeholder: |
|
||||||
|
- [ ] `/gsd:rollback` reverts STATE.md to the previous phase when current phase status is `failed`
|
||||||
|
- [ ] `/gsd:rollback` exits with an error if there is no previous phase to roll back to
|
||||||
|
- [ ] `/gsd:rollback` outputs the before/after phase names in its confirmation message
|
||||||
|
- [ ] Rollback is logged in the phase history so the AI agent can see it happened
|
||||||
|
- [ ] All existing tests still pass
|
||||||
|
- [ ] New tests cover the happy path, no-previous-phase case, and STATE.md corruption case
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
id: scope
|
id: scope
|
||||||
attributes:
|
attributes:
|
||||||
label: Which area does this affect?
|
label: Which area does this primarily affect?
|
||||||
options:
|
options:
|
||||||
- Core workflow (init, plan, build, verify)
|
- Core workflow (init, plan, build, verify)
|
||||||
- Planning system (phases, roadmap, state)
|
- Planning system (phases, roadmap, state)
|
||||||
- Context management (context engineering, summaries)
|
- Context management (context engineering, summaries)
|
||||||
- Runtime integration (hooks, statusline, settings)
|
- Runtime integration (hooks, statusline, settings)
|
||||||
- Installation / setup
|
- Installation / setup
|
||||||
- Documentation
|
- Documentation only
|
||||||
- Other
|
- Multiple areas (describe in scope section above)
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
@@ -46,7 +167,7 @@ body:
|
|||||||
id: runtimes
|
id: runtimes
|
||||||
attributes:
|
attributes:
|
||||||
label: Applicable runtimes
|
label: Applicable runtimes
|
||||||
description: Which runtimes should this work with?
|
description: Which runtimes must this work with? Check all that apply.
|
||||||
options:
|
options:
|
||||||
- label: Claude Code
|
- label: Claude Code
|
||||||
- label: Gemini CLI
|
- label: Gemini CLI
|
||||||
@@ -58,18 +179,72 @@ body:
|
|||||||
- label: Windsurf
|
- label: Windsurf
|
||||||
- label: All runtimes
|
- label: All runtimes
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: breaking_changes
|
||||||
|
attributes:
|
||||||
|
label: Breaking changes assessment
|
||||||
|
description: |
|
||||||
|
Does this feature change existing behavior, command output, file formats, or APIs?
|
||||||
|
If yes, describe exactly what breaks and how existing users would migrate.
|
||||||
|
Write "None" only if you are certain.
|
||||||
|
placeholder: |
|
||||||
|
None — this adds a new command and does not modify any existing command behavior or file schemas.
|
||||||
|
|
||||||
|
OR:
|
||||||
|
|
||||||
|
STATE.md will gain a new `phase_history` array field. Existing STATE.md files without this field
|
||||||
|
will be treated as having an empty history (backward compatible). The rollback command will
|
||||||
|
decline gracefully if history is empty.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: maintenance_burden
|
||||||
|
attributes:
|
||||||
|
label: Maintenance burden
|
||||||
|
description: |
|
||||||
|
Every feature is code that must be maintained forever. Describe the ongoing cost:
|
||||||
|
- How does this interact with future changes to phases, state, or commands?
|
||||||
|
- Does this add external dependencies?
|
||||||
|
- Does this require documentation updates across multiple files?
|
||||||
|
- Will this create edge cases or interactions with other features?
|
||||||
|
placeholder: |
|
||||||
|
- No new dependencies
|
||||||
|
- The rollback function must be updated if the STATE.md schema ever changes
|
||||||
|
- Will need to be tested on each new Node.js LTS release
|
||||||
|
- The command definition must be kept in sync with any future command format changes
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: alternatives
|
id: alternatives
|
||||||
attributes:
|
attributes:
|
||||||
label: Alternatives considered
|
label: Alternatives considered
|
||||||
description: Have you considered other approaches?
|
description: |
|
||||||
|
What other approaches did you consider? Why did you reject them?
|
||||||
|
If the answer is "I didn't consider any alternatives", this issue will be closed.
|
||||||
|
placeholder: |
|
||||||
|
1. Manual STATE.md editing — rejected because it requires the developer to understand the schema
|
||||||
|
and is error-prone. The AI agent cannot reliably guide this.
|
||||||
|
2. A `/gsd:reset` command that wipes all state — rejected because it is too destructive and
|
||||||
|
loses all completed phase history.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: prior_art
|
||||||
|
attributes:
|
||||||
|
label: Prior art and references
|
||||||
|
description: |
|
||||||
|
Does any other tool, project, or GSD discussion address this? Link to anything relevant.
|
||||||
|
If you are aware of a prior declined proposal for this feature, explain why this proposal is different.
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: context
|
id: additional_context
|
||||||
attributes:
|
attributes:
|
||||||
label: Additional context
|
label: Additional context
|
||||||
description: Any other information, screenshots, or examples.
|
description: Anything else — screenshots, recordings, related issues, or links.
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|||||||
86
.github/PULL_REQUEST_TEMPLATE/enhancement.md
vendored
Normal file
86
.github/PULL_REQUEST_TEMPLATE/enhancement.md
vendored
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
## Enhancement PR
|
||||||
|
|
||||||
|
> **Using the wrong template?**
|
||||||
|
> — Bug fix: use [fix.md](?template=fix.md)
|
||||||
|
> — New feature: use [feature.md](?template=feature.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Linked Issue
|
||||||
|
|
||||||
|
> **Required.** This PR will be auto-closed if no valid issue link is found.
|
||||||
|
> The linked issue **must** have the `approved-enhancement` label. If it does not, this PR will be closed without review.
|
||||||
|
|
||||||
|
Closes #
|
||||||
|
|
||||||
|
> ⛔ **No `approved-enhancement` label on the issue = immediate close.**
|
||||||
|
> Do not open this PR if a maintainer has not yet approved the enhancement proposal.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What this enhancement improves
|
||||||
|
|
||||||
|
<!-- Name the specific command, workflow, or behavior being improved. -->
|
||||||
|
|
||||||
|
## Before / After
|
||||||
|
|
||||||
|
**Before:**
|
||||||
|
<!-- Describe or show the current behavior. Include example output if applicable. -->
|
||||||
|
|
||||||
|
**After:**
|
||||||
|
<!-- Describe or show the behavior after this enhancement. Include example output if applicable. -->
|
||||||
|
|
||||||
|
## How it was implemented
|
||||||
|
|
||||||
|
<!-- Brief description of the approach. Point to the key files changed. -->
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
### How I verified the enhancement works
|
||||||
|
|
||||||
|
<!-- Manual steps or automated tests. -->
|
||||||
|
|
||||||
|
### Platforms tested
|
||||||
|
|
||||||
|
- [ ] macOS
|
||||||
|
- [ ] Windows (including backslash path handling)
|
||||||
|
- [ ] Linux
|
||||||
|
- [ ] N/A (not platform-specific)
|
||||||
|
|
||||||
|
### Runtimes tested
|
||||||
|
|
||||||
|
- [ ] Claude Code
|
||||||
|
- [ ] Gemini CLI
|
||||||
|
- [ ] OpenCode
|
||||||
|
- [ ] Other: ___
|
||||||
|
- [ ] N/A (not runtime-specific)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Scope confirmation
|
||||||
|
|
||||||
|
<!-- Confirm the implementation matches the approved proposal. -->
|
||||||
|
|
||||||
|
- [ ] The implementation matches the scope approved in the linked issue — no additions or removals
|
||||||
|
- [ ] If scope changed during implementation, I updated the issue and got re-approval before continuing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] Issue linked above with `Closes #NNN` — **PR will be auto-closed if missing**
|
||||||
|
- [ ] Linked issue has the `approved-enhancement` label — **PR will be closed if missing**
|
||||||
|
- [ ] Changes are scoped to the approved enhancement — nothing extra included
|
||||||
|
- [ ] All existing tests pass (`npm test`)
|
||||||
|
- [ ] New or updated tests cover the enhanced behavior
|
||||||
|
- [ ] CHANGELOG.md updated
|
||||||
|
- [ ] Documentation updated if behavior or output changed
|
||||||
|
- [ ] No unnecessary dependencies added
|
||||||
|
|
||||||
|
## Breaking changes
|
||||||
|
|
||||||
|
<!-- Does this enhancement change any existing behavior, output format, or API?
|
||||||
|
If yes, describe exactly what changes and confirm backward compatibility.
|
||||||
|
Write "None" if not applicable. -->
|
||||||
|
|
||||||
|
None
|
||||||
113
.github/PULL_REQUEST_TEMPLATE/feature.md
vendored
Normal file
113
.github/PULL_REQUEST_TEMPLATE/feature.md
vendored
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
## Feature PR
|
||||||
|
|
||||||
|
> **Using the wrong template?**
|
||||||
|
> — Bug fix: use [fix.md](?template=fix.md)
|
||||||
|
> — Enhancement to existing behavior: use [enhancement.md](?template=enhancement.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Linked Issue
|
||||||
|
|
||||||
|
> **Required.** This PR will be auto-closed if no valid issue link is found.
|
||||||
|
> The linked issue **must** have the `approved-feature` label. If it does not, this PR will be closed without review — no exceptions.
|
||||||
|
|
||||||
|
Closes #
|
||||||
|
|
||||||
|
> ⛔ **No `approved-feature` label on the issue = immediate close.**
|
||||||
|
> Do not open this PR if a maintainer has not yet approved the feature spec.
|
||||||
|
> Do not open this PR if you wrote code before the issue was approved.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Feature summary
|
||||||
|
|
||||||
|
<!-- One paragraph. What does this feature add? Assume the reviewer has read the issue spec. -->
|
||||||
|
|
||||||
|
## What changed
|
||||||
|
|
||||||
|
### New files
|
||||||
|
|
||||||
|
<!-- List every new file added and its purpose. -->
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| | |
|
||||||
|
|
||||||
|
### Modified files
|
||||||
|
|
||||||
|
<!-- List every existing file modified and what changed in it. -->
|
||||||
|
|
||||||
|
| File | What changed |
|
||||||
|
|------|-------------|
|
||||||
|
| | |
|
||||||
|
|
||||||
|
## Implementation notes
|
||||||
|
|
||||||
|
<!-- Describe any decisions made during implementation that were not specified in the issue.
|
||||||
|
If any part of the implementation differs from the approved spec, explain why. -->
|
||||||
|
|
||||||
|
## Spec compliance
|
||||||
|
|
||||||
|
<!-- For each acceptance criterion in the linked issue, confirm it is met. Copy them here and check them off. -->
|
||||||
|
|
||||||
|
- [ ] <!-- Acceptance criterion 1 from issue -->
|
||||||
|
- [ ] <!-- Acceptance criterion 2 from issue -->
|
||||||
|
- [ ] <!-- Add all criteria from the issue -->
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
### Test coverage
|
||||||
|
|
||||||
|
<!-- Describe what is tested and where. New features require new tests — no exceptions. -->
|
||||||
|
|
||||||
|
### Platforms tested
|
||||||
|
|
||||||
|
- [ ] macOS
|
||||||
|
- [ ] Windows (including backslash path handling)
|
||||||
|
- [ ] Linux
|
||||||
|
|
||||||
|
### Runtimes tested
|
||||||
|
|
||||||
|
- [ ] Claude Code
|
||||||
|
- [ ] Gemini CLI
|
||||||
|
- [ ] OpenCode
|
||||||
|
- [ ] Codex
|
||||||
|
- [ ] Copilot
|
||||||
|
- [ ] Other: ___
|
||||||
|
- [ ] N/A — specify which runtimes are supported and why others are excluded
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Scope confirmation
|
||||||
|
|
||||||
|
- [ ] The implementation matches the scope approved in the linked issue exactly
|
||||||
|
- [ ] No additional features, commands, or behaviors were added beyond what was approved
|
||||||
|
- [ ] If scope changed during implementation, I updated the issue spec and received re-approval
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] Issue linked above with `Closes #NNN` — **PR will be auto-closed if missing**
|
||||||
|
- [ ] Linked issue has the `approved-feature` label — **PR will be closed if missing**
|
||||||
|
- [ ] All acceptance criteria from the issue are met (listed above)
|
||||||
|
- [ ] Implementation scope matches the approved spec exactly
|
||||||
|
- [ ] All existing tests pass (`npm test`)
|
||||||
|
- [ ] New tests cover the happy path, error cases, and edge cases
|
||||||
|
- [ ] CHANGELOG.md updated with a user-facing description of the feature
|
||||||
|
- [ ] Documentation updated — commands, workflows, references, README if applicable
|
||||||
|
- [ ] No unnecessary external dependencies added
|
||||||
|
- [ ] Works on Windows (backslash paths handled)
|
||||||
|
|
||||||
|
## Breaking changes
|
||||||
|
|
||||||
|
<!-- Describe any behavior, output format, file schema, or API changes that affect existing users.
|
||||||
|
For each breaking change, describe the migration path.
|
||||||
|
Write "None" only if you are certain. -->
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
## Screenshots / recordings
|
||||||
|
|
||||||
|
<!-- If this feature has any visual output or changes the user experience, include before/after screenshots
|
||||||
|
or a short recording. Delete this section if not applicable. -->
|
||||||
74
.github/PULL_REQUEST_TEMPLATE/fix.md
vendored
Normal file
74
.github/PULL_REQUEST_TEMPLATE/fix.md
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
## Fix PR
|
||||||
|
|
||||||
|
> **Using the wrong template?**
|
||||||
|
> — Enhancement: use [enhancement.md](?template=enhancement.md)
|
||||||
|
> — Feature: use [feature.md](?template=feature.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Linked Issue
|
||||||
|
|
||||||
|
> **Required.** This PR will be auto-closed if no valid issue link is found.
|
||||||
|
|
||||||
|
Fixes #
|
||||||
|
|
||||||
|
> The linked issue must have the `confirmed-bug` label. If it doesn't, ask a maintainer to confirm the bug before continuing.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What was broken
|
||||||
|
|
||||||
|
<!-- One or two sentences. What was the incorrect behavior? -->
|
||||||
|
|
||||||
|
## What this fix does
|
||||||
|
|
||||||
|
<!-- One or two sentences. How does this fix the broken behavior? -->
|
||||||
|
|
||||||
|
## Root cause
|
||||||
|
|
||||||
|
<!-- Brief explanation of why the bug existed. Skip for trivial typo/doc fixes. -->
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
### How I verified the fix
|
||||||
|
|
||||||
|
<!-- Describe manual steps or point to the automated test that proves this is fixed. -->
|
||||||
|
|
||||||
|
### Regression test added?
|
||||||
|
|
||||||
|
- [ ] Yes — added a test that would have caught this bug
|
||||||
|
- [ ] No — explain why: <!-- e.g., environment-specific, non-deterministic -->
|
||||||
|
|
||||||
|
### Platforms tested
|
||||||
|
|
||||||
|
- [ ] macOS
|
||||||
|
- [ ] Windows (including backslash path handling)
|
||||||
|
- [ ] Linux
|
||||||
|
- [ ] N/A (not platform-specific)
|
||||||
|
|
||||||
|
### Runtimes tested
|
||||||
|
|
||||||
|
- [ ] Claude Code
|
||||||
|
- [ ] Gemini CLI
|
||||||
|
- [ ] OpenCode
|
||||||
|
- [ ] Other: ___
|
||||||
|
- [ ] N/A (not runtime-specific)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] Issue linked above with `Fixes #NNN` — **PR will be auto-closed if missing**
|
||||||
|
- [ ] Linked issue has the `confirmed-bug` label
|
||||||
|
- [ ] Fix is scoped to the reported bug — no unrelated changes included
|
||||||
|
- [ ] Regression test added (or explained why not)
|
||||||
|
- [ ] All existing tests pass (`npm test`)
|
||||||
|
- [ ] CHANGELOG.md updated if this is a user-facing fix
|
||||||
|
- [ ] No unnecessary dependencies added
|
||||||
|
|
||||||
|
## Breaking changes
|
||||||
|
|
||||||
|
<!-- Does this fix change any existing behavior, output format, or API that users might depend on?
|
||||||
|
If yes, describe. Write "None" if not applicable. -->
|
||||||
|
|
||||||
|
None
|
||||||
69
.github/pull_request_template.md
vendored
69
.github/pull_request_template.md
vendored
@@ -1,59 +1,38 @@
|
|||||||
## Linked Issue
|
## ⚠️ Wrong template — please use the correct one for your PR type
|
||||||
|
|
||||||
> **Required.** PRs without a linked issue are closed without review.
|
Every PR must use a typed template. Using this default template is a reason for rejection.
|
||||||
> Open an issue first if one doesn't exist: https://github.com/gsd-build/get-shit-done/issues/new/choose
|
|
||||||
|
|
||||||
Closes #
|
Select the template that matches your PR:
|
||||||
|
|
||||||
## What
|
| PR Type | When to use | Template link |
|
||||||
|
|---------|-------------|---------------|
|
||||||
|
| **Fix** | Correcting a bug, crash, or behavior that doesn't match documentation | [Use fix template](?template=PULL_REQUEST_TEMPLATE/fix.md) |
|
||||||
|
| **Enhancement** | Improving an existing feature — better output, expanded edge cases, performance | [Use enhancement template](?template=PULL_REQUEST_TEMPLATE/enhancement.md) |
|
||||||
|
| **Feature** | Adding something new — new command, workflow, concept, or integration | [Use feature template](?template=PULL_REQUEST_TEMPLATE/feature.md) |
|
||||||
|
|
||||||
<!-- One sentence: what does this PR do? -->
|
---
|
||||||
|
|
||||||
## Why
|
### Not sure which type applies?
|
||||||
|
|
||||||
<!-- One sentence: why is this change needed? -->
|
- If it **corrects broken behavior** → Fix
|
||||||
|
- If it **improves existing behavior** without adding new commands or concepts → Enhancement
|
||||||
|
- If it **adds something that doesn't exist today** → Feature
|
||||||
|
- If you are not sure → open a [Discussion](https://github.com/gsd-build/get-shit-done/discussions) first
|
||||||
|
|
||||||
## How
|
---
|
||||||
|
|
||||||
<!-- Brief description of the approach taken. Skip for trivial changes. -->
|
### Reminder: Issues must be approved before PRs
|
||||||
|
|
||||||
## Testing
|
For **enhancements**: the linked issue must have the `approved-enhancement` label before you open this PR.
|
||||||
|
|
||||||
### Platforms tested
|
For **features**: the linked issue must have the `approved-feature` label before you open this PR.
|
||||||
|
|
||||||
- [ ] macOS
|
PRs that arrive without a labeled, approved issue are closed without review.
|
||||||
- [ ] Windows (including backslash path handling)
|
|
||||||
- [ ] Linux
|
|
||||||
|
|
||||||
### Runtimes tested
|
See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full process.
|
||||||
|
|
||||||
- [ ] Claude Code
|
---
|
||||||
- [ ] Gemini CLI
|
|
||||||
- [ ] OpenCode
|
|
||||||
- [ ] Codex
|
|
||||||
- [ ] Copilot
|
|
||||||
- [ ] N/A (not runtime-specific)
|
|
||||||
|
|
||||||
### Test details
|
<!-- If you believe your PR genuinely does not fit any of the above categories (e.g., CI/tooling changes,
|
||||||
|
dependency updates, or doc-only fixes with no linked issue), delete this file and describe your PR below.
|
||||||
<!-- How did you verify this works? Manual steps, automated tests, etc. -->
|
Add a note explaining why none of the typed templates apply. -->
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
- [ ] Issue linked above (`Closes #NNN`) — **PR will be auto-closed if missing**
|
|
||||||
- [ ] Follows GSD style (no enterprise patterns, no filler)
|
|
||||||
- [ ] Updates CHANGELOG.md for user-facing changes
|
|
||||||
- [ ] No unnecessary dependencies added
|
|
||||||
- [ ] Works on Windows (backslash paths tested)
|
|
||||||
- [ ] Templates/references updated if behavior changed
|
|
||||||
- [ ] Existing tests pass (`npm test`)
|
|
||||||
|
|
||||||
## Breaking Changes
|
|
||||||
|
|
||||||
<!-- List any breaking changes, or write "None" -->
|
|
||||||
|
|
||||||
None
|
|
||||||
|
|
||||||
## Screenshots / recordings
|
|
||||||
|
|
||||||
<!-- If this is a visual change, add before/after screenshots. Delete this section if not applicable. -->
|
|
||||||
|
|||||||
158
CONTRIBUTING.md
158
CONTRIBUTING.md
@@ -14,15 +14,81 @@ npm install
|
|||||||
npm test
|
npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Types of Contributions
|
||||||
|
|
||||||
|
GSD accepts three types of contributions. Each type has a different process and a different bar for acceptance. **Read this section before opening anything.**
|
||||||
|
|
||||||
|
### 🐛 Fix (Bug Report)
|
||||||
|
|
||||||
|
A fix corrects something that is broken, crashes, produces wrong output, or behaves contrary to documented behavior.
|
||||||
|
|
||||||
|
**Process:**
|
||||||
|
1. Open a [Bug Report issue](https://github.com/gsd-build/get-shit-done/issues/new?template=bug_report.yml) — fill it out completely.
|
||||||
|
2. Wait for a maintainer to confirm it is a bug (label: `confirmed-bug`). For obvious, reproducible bugs this is typically fast.
|
||||||
|
3. Fix it. Write a test that would have caught the bug.
|
||||||
|
4. Open a PR using the [Fix PR template](.github/PULL_REQUEST_TEMPLATE/fix.md) — link the confirmed issue.
|
||||||
|
|
||||||
|
**Rejection reasons:** Not reproducible, works-as-designed, duplicate of an existing issue.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ⚡ Enhancement
|
||||||
|
|
||||||
|
An enhancement improves an existing feature — better output, faster execution, cleaner UX, expanded edge-case handling. It does **not** add new commands, new workflows, or new concepts.
|
||||||
|
|
||||||
|
**The bar:** Enhancements must have a scoped written proposal approved by a maintainer before any code is written. A PR for an enhancement will be closed without review if the linked issue does not carry the `approved-enhancement` label.
|
||||||
|
|
||||||
|
**Process:**
|
||||||
|
1. Open an [Enhancement issue](https://github.com/gsd-build/get-shit-done/issues/new?template=enhancement.yml) with the full proposal. The issue template requires: the problem being solved, the concrete benefit, the scope of changes, and alternatives considered.
|
||||||
|
2. **Wait for maintainer approval.** A maintainer must label the issue `approved-enhancement` before you write a single line of code. Do not open a PR against an unapproved enhancement issue — it will be closed.
|
||||||
|
3. Write the code. Keep the scope exactly as approved. If scope creep occurs, comment on the issue and get re-approval before continuing.
|
||||||
|
4. Open a PR using the [Enhancement PR template](.github/PULL_REQUEST_TEMPLATE/enhancement.md) — link the approved issue.
|
||||||
|
|
||||||
|
**Rejection reasons:** Issue not labeled `approved-enhancement`, scope exceeds what was approved, no written proposal, duplicate of existing behavior.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ✨ Feature
|
||||||
|
|
||||||
|
A feature adds something new — a new command, a new workflow, a new concept, a new integration. Features have the highest bar because they add permanent maintenance burden to a solo-developer tool maintained by a small team.
|
||||||
|
|
||||||
|
**The bar:** Features require a complete written specification approved by a maintainer before any code is written. A PR for a feature will be closed without review if the linked issue does not carry the `approved-feature` label. Incomplete specs are closed, not revised by maintainers.
|
||||||
|
|
||||||
|
**Process:**
|
||||||
|
1. **Discuss first** — check [Discussions](https://github.com/gsd-build/get-shit-done/discussions) to see if the idea has been raised. If it has and was declined, don't open a new issue.
|
||||||
|
2. Open a [Feature Request issue](https://github.com/gsd-build/get-shit-done/issues/new?template=feature_request.yml) with the complete spec. The template requires: the solo-developer problem being solved, what is being added, full scope of affected files and systems, user stories, acceptance criteria, and assessment of maintenance burden.
|
||||||
|
3. **Wait for maintainer approval.** A maintainer must label the issue `approved-feature` before you write a single line of code. Approval is not guaranteed — GSD is intentionally lean and many valid ideas are declined because they conflict with the project's design philosophy.
|
||||||
|
4. Write the code. Implement exactly the approved spec. Changes to scope require re-approval.
|
||||||
|
5. Open a PR using the [Feature PR template](.github/PULL_REQUEST_TEMPLATE/feature.md) — link the approved issue.
|
||||||
|
|
||||||
|
**Rejection reasons:** Issue not labeled `approved-feature`, spec is incomplete, scope exceeds what was approved, feature conflicts with GSD's solo-developer focus, maintenance burden too high.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The Issue-First Rule — No Exceptions
|
||||||
|
|
||||||
|
> **No code before approval.**
|
||||||
|
|
||||||
|
For **fixes**: open the issue, confirm it's a bug, then fix it.
|
||||||
|
For **enhancements**: open the issue, get `approved-enhancement`, then code.
|
||||||
|
For **features**: open the issue, get `approved-feature`, then code.
|
||||||
|
|
||||||
|
PRs that arrive without a properly-labeled linked issue are closed automatically. This is not a bureaucratic hurdle — it protects you from spending time on work that will be rejected, and it protects maintainers from reviewing code for changes that were never agreed to.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Pull Request Guidelines
|
## Pull Request Guidelines
|
||||||
|
|
||||||
**Every PR must link to an open issue.** PRs without a linked issue are closed without review, no exceptions. If no issue exists for your change, open one first.
|
**Every PR must link to an approved issue.** PRs without a linked issue are closed without review, no exceptions.
|
||||||
|
|
||||||
- **Open an issue first** — describe the bug or feature before writing code. This lets maintainers confirm the direction before you invest time.
|
- **Use the correct PR template** — there are separate templates for [Fix](.github/PULL_REQUEST_TEMPLATE/fix.md), [Enhancement](.github/PULL_REQUEST_TEMPLATE/enhancement.md), and [Feature](.github/PULL_REQUEST_TEMPLATE/feature.md). Using the wrong template or using the default template for a feature is a rejection reason.
|
||||||
- **Link with a closing keyword** — use `Closes #123`, `Fixes #123`, or `Resolves #123` in the PR body. The CI check will fail and the PR will be auto-closed if no valid issue reference is found.
|
- **Link with a closing keyword** — use `Closes #123`, `Fixes #123`, or `Resolves #123` in the PR body. The CI check will fail and the PR will be auto-closed if no valid issue reference is found.
|
||||||
- **One concern per PR** — bug fixes, features, and refactors should be separate PRs
|
- **One concern per PR** — bug fixes, enhancements, and features must be separate PRs
|
||||||
- **No drive-by formatting** — don't reformat code unrelated to your change
|
- **No drive-by formatting** — don't reformat code unrelated to your change
|
||||||
- **CI must pass** — all matrix jobs (Ubuntu, macOS, Windows × Node 22, 24) must be green
|
- **CI must pass** — all matrix jobs (Ubuntu, macOS, Windows × Node 22, 24) must be green
|
||||||
|
- **Scope matches the approved issue** — if your PR does more than what the issue describes, the extra changes will be asked to be removed or moved to a new issue
|
||||||
|
|
||||||
## Testing Standards
|
## Testing Standards
|
||||||
|
|
||||||
@@ -35,12 +101,14 @@ const { describe, it, test, beforeEach, afterEach, before, after } = require('no
|
|||||||
const assert = require('node:assert/strict');
|
const assert = require('node:assert/strict');
|
||||||
```
|
```
|
||||||
|
|
||||||
### Setup and Cleanup: Use Hooks, Not try/finally
|
### Setup and Cleanup
|
||||||
|
|
||||||
**Always use `beforeEach`/`afterEach` for setup and cleanup.** Do not use `try/finally` blocks for test cleanup — they are verbose, error-prone, and can mask test failures.
|
There are two approved cleanup patterns. Choose the one that fits the situation.
|
||||||
|
|
||||||
|
**Pattern 1 — Shared fixtures (`beforeEach`/`afterEach`):** Use when all tests in a `describe` block share identical setup and teardown. This is the most common case.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// GOOD — hooks handle setup/cleanup
|
// GOOD — shared setup/teardown with hooks
|
||||||
describe('my feature', () => {
|
describe('my feature', () => {
|
||||||
let tmpDir;
|
let tmpDir;
|
||||||
|
|
||||||
@@ -53,25 +121,39 @@ describe('my feature', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('does the thing', () => {
|
test('does the thing', () => {
|
||||||
// test body focuses only on the assertion
|
|
||||||
assert.strictEqual(result, expected);
|
assert.strictEqual(result, expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Pattern 2 — Per-test cleanup (`t.after()`):** Use when individual tests require unique teardown that differs from other tests in the same block.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// BAD — try/finally is verbose and masks failures
|
// GOOD — per-test cleanup when each test needs different teardown
|
||||||
|
test('does the thing with a custom setup', (t) => {
|
||||||
|
const tmpDir = createTempProject('custom-prefix');
|
||||||
|
t.after(() => cleanup(tmpDir));
|
||||||
|
|
||||||
|
assert.strictEqual(result, expected);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Never use `try/finally` inside test bodies.** It is verbose, masks test failures, and is not an approved pattern in this project.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// BAD — try/finally inside a test body
|
||||||
test('does the thing', () => {
|
test('does the thing', () => {
|
||||||
const tmpDir = createTempProject();
|
const tmpDir = createTempProject();
|
||||||
try {
|
try {
|
||||||
// test body
|
|
||||||
assert.strictEqual(result, expected);
|
assert.strictEqual(result, expected);
|
||||||
} finally {
|
} finally {
|
||||||
cleanup(tmpDir);
|
cleanup(tmpDir); // masks failures — don't do this
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> `try/finally` is only permitted inside standalone utility or helper functions that have no access to test context.
|
||||||
|
|
||||||
### Use Centralized Test Helpers
|
### Use Centralized Test Helpers
|
||||||
|
|
||||||
Import helpers from `tests/helpers.cjs` instead of inlining temp directory creation:
|
Import helpers from `tests/helpers.cjs` instead of inlining temp directory creation:
|
||||||
@@ -126,13 +208,37 @@ describe('featureName', () => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Fixture Data Formatting
|
||||||
|
|
||||||
|
Template literals inside test blocks inherit indentation from the surrounding code. This can introduce unexpected leading whitespace that breaks regex anchors and string matching. Construct multi-line fixture strings using array `join()` instead:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// GOOD — no indentation bleed
|
||||||
|
const content = [
|
||||||
|
'line one',
|
||||||
|
'line two',
|
||||||
|
'line three',
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
// BAD — template literal inherits surrounding indentation
|
||||||
|
const content = `
|
||||||
|
line one
|
||||||
|
line two
|
||||||
|
line three
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
|
||||||
### Node.js Version Compatibility
|
### Node.js Version Compatibility
|
||||||
|
|
||||||
Tests must pass on:
|
**Node 24 is the primary CI target.** All tests must pass on Node 24. Node 22 (LTS) must remain backward-compatible — do not use APIs that are not available in Node 22.
|
||||||
- **Node 22** (LTS)
|
|
||||||
- **Node 24** (Current)
|
|
||||||
|
|
||||||
Forward-compatible with Node 26. Do not use:
|
| Version | Status |
|
||||||
|
|---------|--------|
|
||||||
|
| **Node 24** | Primary CI target — all tests must pass |
|
||||||
|
| **Node 22** | Backward compatibility required |
|
||||||
|
| Node 26 | Forward-compatible target — avoid deprecated APIs |
|
||||||
|
|
||||||
|
Do not use:
|
||||||
- Deprecated APIs
|
- Deprecated APIs
|
||||||
- Version-specific features not available in Node 22
|
- Version-specific features not available in Node 22
|
||||||
|
|
||||||
@@ -140,6 +246,7 @@ Safe to use:
|
|||||||
- `node:test` — stable since Node 18, fully featured in 22+
|
- `node:test` — stable since Node 18, fully featured in 22+
|
||||||
- `describe`/`it`/`test` — all supported
|
- `describe`/`it`/`test` — all supported
|
||||||
- `beforeEach`/`afterEach`/`before`/`after` — all supported
|
- `beforeEach`/`afterEach`/`before`/`after` — all supported
|
||||||
|
- `t.after()` — per-test cleanup, available in Node 22+
|
||||||
- `t.plan()` — available since Node 22.2
|
- `t.plan()` — available since Node 22.2
|
||||||
- Snapshot testing — available since Node 22.3
|
- Snapshot testing — available since Node 22.3
|
||||||
|
|
||||||
@@ -170,6 +277,29 @@ node --test tests/core.test.cjs
|
|||||||
npm run test:coverage
|
npm run test:coverage
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Test Requirements by Contribution Type
|
||||||
|
|
||||||
|
The required tests differ depending on what you are contributing:
|
||||||
|
|
||||||
|
**Bug Fix:** A regression test is required. Write the test first — it must demonstrate the original failure before your fix is applied, then pass after the fix. A PR that fixes a bug without a regression test will be asked to add one. "Tests pass" does not prove correctness; it proves the bug isn't present in the tests that exist.
|
||||||
|
|
||||||
|
**Enhancement:** Tests covering the enhanced behavior are required. Update any existing tests that test the area you changed. Do not leave tests that pass but no longer accurately describe the behavior.
|
||||||
|
|
||||||
|
**Feature:** Tests are required for the primary success path and at minimum one failure scenario. Leaving gaps in test coverage for a new feature is a rejection reason.
|
||||||
|
|
||||||
|
**Behavior Change:** If your change modifies existing behavior, the existing tests covering that behavior must be updated or replaced. Leaving passing-but-incorrect tests in the suite is not acceptable — a test that passes but asserts the old (now wrong) behavior makes the suite less useful than no test at all.
|
||||||
|
|
||||||
|
### Reviewer Standards
|
||||||
|
|
||||||
|
Reviewers do not rely solely on CI to verify correctness. Before approving a PR, reviewers:
|
||||||
|
|
||||||
|
- Build locally (`npm run build` if applicable)
|
||||||
|
- Run the full test suite locally (`npm test`)
|
||||||
|
- Confirm regression tests exist for bug fixes and that they would fail without the fix
|
||||||
|
- Validate that the implementation matches what the linked issue described — green CI on the wrong implementation is not an approval signal
|
||||||
|
|
||||||
|
**"Tests pass in CI" is not sufficient for merge.** The implementation must correctly solve the problem described in the linked issue.
|
||||||
|
|
||||||
## Code Style
|
## Code Style
|
||||||
|
|
||||||
- **CommonJS** (`.cjs`) — the project uses `require()`, not ESM `import`
|
- **CommonJS** (`.cjs`) — the project uses `require()`, not ESM `import`
|
||||||
|
|||||||
Reference in New Issue
Block a user