summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/pr-standards.yml136
-rw-r--r--.github/workflows/pr-title.yml62
-rw-r--r--CONTRIBUTING.md34
3 files changed, 166 insertions, 66 deletions
diff --git a/.github/workflows/pr-standards.yml b/.github/workflows/pr-standards.yml
new file mode 100644
index 000000000..ea5e36574
--- /dev/null
+++ b/.github/workflows/pr-standards.yml
@@ -0,0 +1,136 @@
+name: PR Standards
+
+on:
+ pull_request:
+ types: [opened, edited, synchronize]
+
+jobs:
+ check-standards:
+ if: |
+ github.event.pull_request.user.login != 'actions-user' &&
+ github.event.pull_request.user.login != 'opencode' &&
+ github.event.pull_request.user.login != 'rekram1-node' &&
+ github.event.pull_request.user.login != 'thdxr' &&
+ github.event.pull_request.user.login != 'kommander' &&
+ github.event.pull_request.user.login != 'jayair' &&
+ github.event.pull_request.user.login != 'fwang' &&
+ github.event.pull_request.user.login != 'adamdotdevin' &&
+ github.event.pull_request.user.login != 'iamdavidhill' &&
+ github.event.pull_request.user.login != 'opencode-agent[bot]'
+ runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
+ steps:
+ - name: Check PR standards
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const pr = context.payload.pull_request;
+ const title = pr.title;
+
+ async function addLabel(label) {
+ await github.rest.issues.addLabels({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: pr.number,
+ labels: [label]
+ });
+ }
+
+ async function removeLabel(label) {
+ try {
+ await github.rest.issues.removeLabel({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: pr.number,
+ name: label
+ });
+ } catch (e) {
+ // Label wasn't present, ignore
+ }
+ }
+
+ async function comment(marker, body) {
+ const markerText = `<!-- pr-standards:${marker} -->`;
+ const { data: comments } = await github.rest.issues.listComments({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: pr.number
+ });
+
+ const existing = comments.find(c => c.body.includes(markerText));
+ if (existing) return;
+
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: pr.number,
+ body: markerText + '\n' + body
+ });
+ }
+
+ // Step 1: Check title format
+ const validPrefixes = ['feat:', 'fix:', 'docs:', 'chore:', 'refactor:', 'test:'];
+ const hasValidTitle = validPrefixes.some(prefix => title.startsWith(prefix));
+
+ if (!hasValidTitle) {
+ await addLabel('needs:title');
+ await comment('title', `Hey! Your PR title \`${title}\` doesn't follow conventional commit format.
+
+ Please update it to start with one of:
+ - \`feat:\` new feature
+ - \`fix:\` bug fix
+ - \`docs:\` documentation changes
+ - \`chore:\` maintenance tasks
+ - \`refactor:\` code refactoring
+ - \`test:\` adding or updating tests
+
+ See [CONTRIBUTING.md](../blob/dev/CONTRIBUTING.md#pr-titles) for details.`);
+ return;
+ }
+
+ await removeLabel('needs:title');
+
+ // Step 2: Check for linked issue (skip for docs/refactor PRs)
+ const skipIssueCheck = title.startsWith('docs:') || title.startsWith('refactor:');
+ if (skipIssueCheck) {
+ await removeLabel('needs:issue');
+ console.log('Skipping issue check for docs/refactor PR');
+ return;
+ }
+ const query = `
+ query($owner: String!, $repo: String!, $number: Int!) {
+ repository(owner: $owner, name: $repo) {
+ pullRequest(number: $number) {
+ closingIssuesReferences(first: 1) {
+ totalCount
+ }
+ }
+ }
+ }
+ `;
+
+ const result = await github.graphql(query, {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ number: pr.number
+ });
+
+ const linkedIssues = result.repository.pullRequest.closingIssuesReferences.totalCount;
+
+ if (linkedIssues === 0) {
+ await addLabel('needs:issue');
+ await comment('issue', `Thanks for your contribution!
+
+ This PR doesn't have a linked issue. All PRs must reference an existing issue.
+
+ Please:
+ 1. Open an issue describing the bug/feature (if one doesn't exist)
+ 2. Add \`Fixes #<number>\` or \`Closes #<number>\` to this PR description
+
+ See [CONTRIBUTING.md](../blob/dev/CONTRIBUTING.md#issue-first-policy) for details.`);
+ return;
+ }
+
+ await removeLabel('needs:issue');
+ console.log('PR meets all standards');
diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml
deleted file mode 100644
index 220f34054..000000000
--- a/.github/workflows/pr-title.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-name: PR Title Validation
-
-on:
- pull_request:
- types: [opened, edited, synchronize]
-
-jobs:
- validate-title:
- if: |
- github.event.pull_request.user.login != 'actions-user' &&
- github.event.pull_request.user.login != 'opencode' &&
- github.event.pull_request.user.login != 'rekram1-node' &&
- github.event.pull_request.user.login != 'thdxr' &&
- github.event.pull_request.user.login != 'kommander' &&
- github.event.pull_request.user.login != 'jayair' &&
- github.event.pull_request.user.login != 'fwang' &&
- github.event.pull_request.user.login != 'adamdotdevin' &&
- github.event.pull_request.user.login != 'iamdavidhill' &&
- github.event.pull_request.user.login != 'opencode-agent[bot]'
- runs-on: ubuntu-latest
- permissions:
- pull-requests: write
- steps:
- - name: Validate PR title
- uses: actions/github-script@v7
- with:
- script: |
- const title = context.payload.pull_request.title;
- const validPrefixes = ['feat:', 'fix:', 'docs:', 'chore:', 'refactor:', 'test:'];
- const isValid = validPrefixes.some(prefix => title.startsWith(prefix));
-
- if (!isValid) {
- const body = `👋 Thanks for opening this PR!
-
- Your PR title \`${title}\` doesn't follow our conventional commit format.
-
- Please update it to start with one of these prefixes:
- - \`feat:\` new feature or functionality
- - \`fix:\` bug fix
- - \`docs:\` documentation or README changes
- - \`chore:\` maintenance tasks, dependency updates, etc.
- - \`refactor:\` code refactoring without changing behavior
- - \`test:\` adding or updating tests
-
- **Examples:**
- - \`docs: update contributing guidelines\`
- - \`fix: resolve crash on startup\`
- - \`feat: add dark mode support\`
-
- See [CONTRIBUTING.md](../blob/dev/CONTRIBUTING.md#pr-titles) for more details.`;
-
- await github.rest.issues.createComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.payload.pull_request.number,
- body: body
- });
-
- core.setFailed('PR title does not follow conventional commit format');
- } else {
- console.log('PR title is valid:', title);
- }
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f30d795a6..075d9d351 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -149,11 +149,37 @@ With that said, you may want to try these methods, as they might work for you.
## Pull Request Expectations
-- Try to keep pull requests small and focused.
-- Link relevant issue(s) in the description
+### Issue First Policy
+
+**All PRs must reference an existing issue.** Before opening a PR, open an issue describing the bug or feature. This helps maintainers triage and prevents duplicate work. PRs without a linked issue may be closed without review.
+
+- Use `Fixes #123` or `Closes #123` in your PR description to link the issue
+- For small fixes, a brief issue is fine - just enough context for maintainers to understand the problem
+
+### General Requirements
+
+- Keep pull requests small and focused
- Explain the issue and why your change fixes it
-- Avoid having verbose LLM generated PR descriptions
-- Before adding new functions or functionality, ensure that such behavior doesn't already exist elsewhere in the codebase.
+- Before adding new functionality, ensure it doesn't already exist elsewhere in the codebase
+
+### UI Changes
+
+If your PR includes UI changes, please include screenshots or videos showing the before and after. This helps maintainers review faster and gives you quicker feedback.
+
+### Logic Changes
+
+For non-UI changes (bug fixes, new features, refactors), explain **how you verified it works**:
+
+- What did you test?
+- How can a reviewer reproduce/confirm the fix?
+
+### No AI-Generated Walls of Text
+
+Long, AI-generated PR descriptions and issues are not acceptable and may be ignored. Respect the maintainers' time:
+
+- Write short, focused descriptions
+- Explain what changed and why in your own words
+- If you can't explain it briefly, your PR might be too large
### PR Titles