Add PR template, issue templates, and contribution policy (#126)
* chore: add PR template, issue templates, and contribution policy Drive-by feature PRs are becoming a problem. This adds guardrails: - PR template with type selection, checklist, and AI disclosure - Bug report issue template (structured YAML form) - Issue config that redirects features to Discussions and disables blank issues - PR compliance workflow that enforces template completion and requires a Discussion link for feature PRs - Contribution policy in CONTRIBUTING.md (acceptance tiers, AI PR rules) - Agent-facing rules in AGENTS.md (follow the template, no bulk changes) * fornat
This commit is contained in:
51
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
51
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: Report a bug in EmDash
|
||||||
|
labels: ["bug"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for reporting a bug. Please fill out the sections below so we can reproduce and fix it.
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: What happened? What did you expect to happen?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: reproduction
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
description: Minimal steps to trigger the bug. Include code snippets, config, or a link to a reproduction repo if possible.
|
||||||
|
placeholder: |
|
||||||
|
1. Create a collection with ...
|
||||||
|
2. Navigate to ...
|
||||||
|
3. Click ...
|
||||||
|
4. See error
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: environment
|
||||||
|
attributes:
|
||||||
|
label: Environment
|
||||||
|
description: Relevant version info.
|
||||||
|
placeholder: |
|
||||||
|
- emdash version: x.x.x
|
||||||
|
- Node.js version: x.x.x
|
||||||
|
- Runtime: Node / Cloudflare Workers
|
||||||
|
- OS: macOS / Linux / Windows
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Logs / error output
|
||||||
|
description: Paste any relevant error messages or stack traces.
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Feature request
|
||||||
|
url: https://github.com/emdash-cms/emdash/discussions/categories/ideas
|
||||||
|
about: Propose a feature in Discussions. Feature PRs without a prior approved Discussion will be closed.
|
||||||
|
- name: Question
|
||||||
|
url: https://github.com/emdash-cms/emdash/discussions/categories/q-a
|
||||||
|
about: Ask a question in Discussions.
|
||||||
37
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
37
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
## What does this PR do?
|
||||||
|
|
||||||
|
<!-- Describe the change and why it's needed. Link to a related issue or discussion. -->
|
||||||
|
|
||||||
|
Closes #
|
||||||
|
|
||||||
|
## Type of change
|
||||||
|
|
||||||
|
<!-- Check one. If "Feature", a prior Discussion is required — see below. -->
|
||||||
|
|
||||||
|
- [ ] Bug fix
|
||||||
|
- [ ] Feature (requires [approved Discussion](https://github.com/emdash-cms/emdash/discussions/categories/ideas))
|
||||||
|
- [ ] Refactor (no behavior change)
|
||||||
|
- [ ] Documentation
|
||||||
|
- [ ] Performance improvement
|
||||||
|
- [ ] Tests
|
||||||
|
- [ ] Chore (dependencies, CI, tooling)
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] I have read [CONTRIBUTING.md](https://github.com/emdash-cms/emdash/blob/main/CONTRIBUTING.md)
|
||||||
|
- [ ] `pnpm typecheck` passes
|
||||||
|
- [ ] `pnpm --silent lint:json | jq '.diagnostics | length'` returns 0
|
||||||
|
- [ ] `pnpm test` passes (or targeted tests for my change)
|
||||||
|
- [ ] `pnpm format` has been run
|
||||||
|
- [ ] I have added/updated tests for my changes (if applicable)
|
||||||
|
- [ ] New features link to an approved Discussion: https://github.com/emdash-cms/emdash/discussions/...
|
||||||
|
|
||||||
|
## AI-generated code disclosure
|
||||||
|
|
||||||
|
<!-- If any part of this PR was generated by AI tools (Copilot, Claude, GPT, Cursor, etc.), check the box. This is fine — we just need to know so reviewers can pay extra attention to edge cases. -->
|
||||||
|
|
||||||
|
- [ ] This PR includes AI-generated code
|
||||||
|
|
||||||
|
## Screenshots / test output
|
||||||
|
|
||||||
|
<!-- Optional. Include if the change is visual or if you want to show test results. -->
|
||||||
74
.github/workflows/pr-compliance.yml
vendored
Normal file
74
.github/workflows/pr-compliance.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
name: PR Compliance
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
types: [opened, edited, synchronize]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-pr:
|
||||||
|
name: Validate PR
|
||||||
|
if: github.actor != 'dependabot[bot]' && github.actor != 'renovate[bot]'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check PR template
|
||||||
|
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const body = context.payload.pull_request.body || '';
|
||||||
|
|
||||||
|
const errors = [];
|
||||||
|
|
||||||
|
// Must have a description (not just the raw template placeholder)
|
||||||
|
const descriptionSection = body.match(/## What does this PR do\?\s*\n([\s\S]*?)(?=\n## )/);
|
||||||
|
const description = descriptionSection?.[1]?.replace(/<!--[\s\S]*?-->/g, '').trim() || '';
|
||||||
|
if (!description || description === 'Closes #') {
|
||||||
|
errors.push('Fill out the "What does this PR do?" section with a description of your change.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must check at least one type
|
||||||
|
const typeChecks = [
|
||||||
|
/- \[x\] Bug fix/i,
|
||||||
|
/- \[x\] Feature/i,
|
||||||
|
/- \[x\] Refactor/i,
|
||||||
|
/- \[x\] Documentation/i,
|
||||||
|
/- \[x\] Performance/i,
|
||||||
|
/- \[x\] Tests/i,
|
||||||
|
/- \[x\] Chore/i,
|
||||||
|
];
|
||||||
|
const hasType = typeChecks.some(re => re.test(body));
|
||||||
|
if (!hasType) {
|
||||||
|
errors.push('Check at least one "Type of change" checkbox.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// If Feature is checked, require a discussion link
|
||||||
|
const isFeature = /- \[x\] Feature/i.test(body);
|
||||||
|
if (isFeature) {
|
||||||
|
const hasDiscussionLink = /github\.com\/emdash-cms\/emdash\/discussions\/\d+/.test(body);
|
||||||
|
if (!hasDiscussionLink) {
|
||||||
|
errors.push('Feature PRs require a link to an approved Discussion (https://github.com/emdash-cms/emdash/discussions/categories/ideas). Open a Discussion first, get approval, then link it in the PR.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must check the "I have read CONTRIBUTING.md" box
|
||||||
|
const hasReadContributing = /- \[x\] I have read \[CONTRIBUTING\.md\]/i.test(body);
|
||||||
|
if (!hasReadContributing) {
|
||||||
|
errors.push('Check the "I have read CONTRIBUTING.md" checkbox.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.length > 0) {
|
||||||
|
const message = [
|
||||||
|
'## PR template validation failed',
|
||||||
|
'',
|
||||||
|
'Please fix the following issues by editing your PR description:',
|
||||||
|
'',
|
||||||
|
...errors.map(e => `- ${e}`),
|
||||||
|
'',
|
||||||
|
'See [CONTRIBUTING.md](https://github.com/emdash-cms/emdash/blob/main/CONTRIBUTING.md) for the full contribution policy.',
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
core.setFailed(message);
|
||||||
|
}
|
||||||
14
AGENTS.md
14
AGENTS.md
@@ -24,6 +24,18 @@ This is a pre-release project. Do not add backwards compatibility or legacy patt
|
|||||||
|
|
||||||
**TDD for bugs.** Write a failing test -> fix the bug -> verify the test passes. A bug without a reproducing test is not fixed.
|
**TDD for bugs.** Write a failing test -> fix the bug -> verify the test passes. A bug without a reproducing test is not fixed.
|
||||||
|
|
||||||
|
## Contribution Rules (for AI agents and human contributors)
|
||||||
|
|
||||||
|
Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a PR. Key rules:
|
||||||
|
|
||||||
|
- **Features require a prior approved Discussion.** Do not open a feature PR without one. It will be closed. Open a [Discussion](https://github.com/emdash-cms/emdash/discussions/categories/ideas) in the Ideas category first.
|
||||||
|
- **Bug fixes and docs** can be PRed directly.
|
||||||
|
- **Fill out the PR template completely.** Every section. Check every applicable checkbox. PRs with empty or skipped templates will be closed.
|
||||||
|
- **Check the AI disclosure box** in the PR template if any part of the code was AI-generated.
|
||||||
|
- **Do not make bulk/spray changes** (e.g., "fix all lint warnings", "add types everywhere", "improve error handling across codebase"). If you see a systemic issue, open a Discussion.
|
||||||
|
- **Do not touch code outside the scope of your change.** No drive-by refactors, no "while I'm here" improvements, no added comments or logging in unrelated files.
|
||||||
|
- **All CI checks must pass.** Typecheck, lint, format, and tests. No exceptions.
|
||||||
|
|
||||||
## Workflow
|
## Workflow
|
||||||
|
|
||||||
### Before Starting
|
### Before Starting
|
||||||
@@ -47,7 +59,7 @@ You verified linting and types were clean before starting. If they're failing no
|
|||||||
1. All tests pass: `pnpm test`
|
1. All tests pass: `pnpm test`
|
||||||
2. Full lint suite clean: `pnpm --silent lint:json | jq '.diagnostics | length'`. Returns JSON with stderr piped to /dev/null, so it won't break parsers. Fix any issues.
|
2. Full lint suite clean: `pnpm --silent lint:json | jq '.diagnostics | length'`. Returns JSON with stderr piped to /dev/null, so it won't break parsers. Fix any issues.
|
||||||
3. Format with `pnpm format` (oxfmt with tabs for indentation, configured in `.prettierrc`).
|
3. Format with `pnpm format` (oxfmt with tabs for indentation, configured in `.prettierrc`).
|
||||||
4. Open the PR with the `pr` skill
|
4. Open the PR with the `pr` skill. Fill out every section of the PR template. Check the AI disclosure box.
|
||||||
|
|
||||||
### Dev Servers
|
### Dev Servers
|
||||||
|
|
||||||
|
|||||||
@@ -185,10 +185,41 @@ Your site will use `workspace:*` links to the local packages, so any changes you
|
|||||||
4. Check authorization with `requirePerm()` on all state-changing routes.
|
4. Check authorization with `requirePerm()` on all state-changing routes.
|
||||||
5. Register the route in `packages/core/src/astro/integration/routes.ts`.
|
5. Register the route in `packages/core/src/astro/integration/routes.ts`.
|
||||||
|
|
||||||
|
## Contribution Policy
|
||||||
|
|
||||||
|
### What we accept
|
||||||
|
|
||||||
|
| Type | Process |
|
||||||
|
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
|
| **Bug fixes** | Open a PR directly. Include a failing test that reproduces the bug. |
|
||||||
|
| **Docs / typos** | Open a PR directly. |
|
||||||
|
| **Features** | Open a [Discussion](https://github.com/emdash-cms/emdash/discussions/categories/ideas) first. Wait for approval before writing code. |
|
||||||
|
| **Refactors** | Open a Discussion first. Refactors are opinionated and need alignment. |
|
||||||
|
| **Performance** | Open a Discussion first with benchmarks showing the improvement. |
|
||||||
|
|
||||||
|
**PRs that add features without a prior approved Discussion will be closed.** This isn't about gatekeeping — it's about not wasting your time on work that might not align with the project's direction. Talk to us first and we'll figure out the right approach together.
|
||||||
|
|
||||||
|
### AI-generated PRs
|
||||||
|
|
||||||
|
We welcome AI-assisted contributions. They are held to the same quality bar as any other PR:
|
||||||
|
|
||||||
|
- The submitter is responsible for the code's correctness, not the AI tool.
|
||||||
|
- AI-generated PRs must pass all CI checks, follow the project's code patterns, and include tests.
|
||||||
|
- The PR template has an AI disclosure checkbox — please check it. This isn't punitive; it helps reviewers know to pay extra attention to edge cases that AI tools commonly miss.
|
||||||
|
- Bulk/spray PRs across the repo (e.g., "fix all lint warnings", "add types everywhere") will be closed. If you see a pattern worth fixing, open a Discussion first.
|
||||||
|
|
||||||
|
### What we don't accept
|
||||||
|
|
||||||
|
- **Drive-by feature additions.** If there's no Discussion, there's no PR.
|
||||||
|
- **Speculative refactors** that don't solve a concrete problem.
|
||||||
|
- **Dependency upgrades** outside of Renovate/Dependabot. We manage these centrally.
|
||||||
|
- **"Improvements"** to code you haven't been asked to change (added logging, extra error handling, style changes in unrelated files).
|
||||||
|
|
||||||
## Commits and PRs
|
## Commits and PRs
|
||||||
|
|
||||||
- Branch from `main`.
|
- Branch from `main`.
|
||||||
- Commit messages: describe _why_, not just _what_.
|
- Commit messages: describe _why_, not just _what_.
|
||||||
|
- Fill out the PR template completely. PRs with an empty template will be closed.
|
||||||
- Ensure `pnpm typecheck` and `pnpm --silent lint:json` pass before pushing.
|
- Ensure `pnpm typecheck` and `pnpm --silent lint:json` pass before pushing.
|
||||||
- Run relevant tests.
|
- Run relevant tests.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user