Repository navigation
chore: sync issue/PR templates from repo-scaffold #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
blairg23
wants to merge
8
commits into
main
Choose a base branch
from
chore/sync-templates
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
50167e6
chore: sync issue/PR templates from repo-scaffold
blairg23 27ef32a
chore: sync issue/PR templates from repo-scaffold
blairg23 fdd9d47
chore: sync issue/PR templates from repo-scaffold
blairg23 8191b78
chore: sync issue/PR templates from repo-scaffold
blairg23 8d15c38
chore: sync issue/PR templates from repo-scaffold
blairg23 4532572
chore: sync issue/PR templates from repo-scaffold
blairg23 62905ca
chore: sync issue/PR templates from repo-scaffold
blairg23 7ab6e85
chore: sync issue/PR templates from repo-scaffold
blairg23 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| * @blairg23 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| blank_issues_enabled: false | ||
| contact_links: | ||
| - name: Security report | ||
| url: https://github.com/blairg23/cuequeue/security/advisories/new | ||
| about: Please privately disclose security issues through GitHub Security Advisories. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| --- | ||
| name: Epic | ||
| about: Track a multi-ticket initiative | ||
| title: "" | ||
| labels: ["epic", "needs-triage"] | ||
| assignees: [] | ||
| --- | ||
|
|
||
| ## 🧾 Title | ||
| <!-- Short, actionable title for this epic. --> | ||
|
|
||
| ## 🧠 Summary | ||
| <!-- Explain what needs to be done and why. Include business and technical context. --> | ||
|
|
||
| ## 📦 Scope | ||
| <!-- What is included in this epic. Be specific about what this initiative will deliver. --> | ||
|
|
||
| ## 🚫 Out of Scope | ||
| <!-- Explicitly list what is NOT included. --> | ||
|
|
||
| ## ✅ Acceptance Criteria | ||
| <!-- Conditions for considering this epic complete. --> | ||
| - [ ] | ||
| - [ ] | ||
| - [ ] | ||
|
|
||
| ## 🗂️ Milestones / Phases | ||
| <!-- Optional sequencing checkpoints for this epic. --> | ||
| - [ ] Phase 1 | ||
| - [ ] Phase 2 | ||
|
|
||
| ## 🧪 Testing / Validation | ||
| <!-- How we validate this epic at a system level. --> | ||
| - [ ] | ||
|
|
||
| ## 🔗 Child Tickets | ||
| <!-- Link the associated implementation tickets here. --> | ||
| - [ ] | ||
|
|
||
| ## 🧰 Notes / Links | ||
| <!-- Any extra notes, docs, links, dependencies, or blockers. --> | ||
|
|
||
| ## ✅ Addendum: Bugs Found/Fixed | ||
| <!-- Post-creation extras that still fit inside scope but were unforeseen. --> | ||
|
|
||
| ## ⏳ Addendum: Pending | ||
| <!-- Remaining items that should become separate tickets if out-of-scope for this epic. --> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| --- | ||
| name: Ticket | ||
| about: Describe one implementation task | ||
| title: "" | ||
| labels: ["needs-triage"] | ||
| assignees: [] | ||
| --- | ||
|
|
||
| ## 🧾 Title | ||
| <!-- Short, actionable title: "Do X" --> | ||
|
|
||
| ## 🧠 Summary | ||
| <!-- Explain what needs to be done and why. Include background/context. --> | ||
|
|
||
| ## 📦 Scope | ||
| <!-- What is included in this work. Be specific about what this issue will deliver. --> | ||
|
|
||
| ## 🚫 Out of Scope | ||
| <!-- Explicitly list what is NOT included, to avoid scope creep. --> | ||
|
|
||
| ## ✅ Acceptance Criteria | ||
| <!-- Checklist of what must be true for this issue to be considered complete. --> | ||
| - [ ] | ||
| - [ ] | ||
| - [ ] | ||
|
|
||
| ## 🧪 Testing / Validation | ||
| <!-- How this should be tested or validated (manual steps, scripts, etc.). --> | ||
| - [ ] | ||
|
|
||
| ## 🧰 Implementation Notes | ||
| <!-- Optional: technical notes, suggested approach, important details for the implementer. --> | ||
|
|
||
| ## 🧰 Notes / Links | ||
| <!-- Any extra notes, docs, links, or blockers. --> | ||
|
|
||
| ## ✅ Addendum: Bugs Found/Fixed | ||
| <!-- Post-ticket creation extras that still fit inside the initial scope but were unforeseen like minor bug fixes during the ticket --> | ||
|
|
||
| ## ⏳ Addendum: Pending | ||
| <!-- Anything still pending that might fit inside this scope, but we're either not doing or needs its own ticket (link it after creation of the ticket) --> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| ## 🧾 Title | ||
| <!-- Example: Improve backlog bootstrap issue creation flow --> | ||
|
|
||
| ## 🧠 Description | ||
| <!-- Briefly explain what this PR accomplishes and why it’s needed. --> | ||
| This pull request [summarize purpose here]. | ||
|
|
||
| ## 🧩 Changes Included | ||
| <!-- List the key modifications made in this PR. --> | ||
| - [ ] Added/updated documentation | ||
| - [ ] Implemented new feature or enhancement | ||
| - [ ] Refactored existing code | ||
| - [ ] Improved error handling or logging | ||
| - [ ] Updated environment configuration | ||
| - [ ] Other (specify) | ||
|
|
||
| ## 🎯 Purpose | ||
| <!-- What problem does this PR solve or what value does it add? --> | ||
| This PR aims to [describe the goal or intended outcome]. | ||
|
|
||
| ## 🔗 Related Issues / Epics | ||
| <!-- Link GitHub issues/epics for traceability. --> | ||
| - **Epic:** #<epic-issue-number> | ||
| - **Issue:** #<issue-number> | ||
| - Closes #<issue-number> | ||
|
|
||
| ## 🧪 Testing | ||
| <!-- Describe how reviewers can verify this PR works as intended. --> | ||
| 1. [Step one of testing] | ||
| 2. [Step two] | ||
| 3. [Expected result] | ||
|
|
||
| ## 🧰 Developer Notes | ||
| <!-- Optional: Add any additional notes, caveats, or follow-ups here. --> | ||
| - [ ] Verify environment variables are configured properly | ||
| - [ ] Ensure code runs under both local and CI/CD environments |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| name: Validate issue body format | ||
|
|
||
| on: | ||
| issues: | ||
| types: [opened, edited] | ||
|
|
||
| jobs: | ||
| validate: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| issues: write | ||
|
|
||
| steps: | ||
| - name: Check body and flag if malformed | ||
| uses: actions/github-script@v9 | ||
| with: | ||
| script: | | ||
| const body = context.payload.issue.body || ""; | ||
| const number = context.payload.issue.number; | ||
|
|
||
| const required = ["## 🧾 Title", "## 🧠 Summary"]; | ||
| const missing = required.filter(h => !body.includes(h)); | ||
|
|
||
| if (missing.length === 0) { | ||
| core.info(`Issue #${number} body looks good.`); | ||
| // Remove needs-format if it was added by a previous failed check | ||
| try { | ||
| await github.rest.issues.removeLabel({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: number, | ||
| name: "needs-format", | ||
| }); | ||
| core.info(`Removed needs-format label from issue #${number}.`); | ||
| } catch (_) {} | ||
| return; | ||
| } | ||
|
|
||
| // Create needs-format label if it does not exist yet (422 = already exists) | ||
| try { | ||
| await github.rest.issues.createLabel({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| name: "needs-format", | ||
| color: "e11d48", | ||
| description: "Issue body does not match the required template format", | ||
| }); | ||
| } catch (_) {} | ||
|
|
||
| await github.rest.issues.addLabels({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: number, | ||
| labels: ["needs-format"], | ||
| }); | ||
|
|
||
| // Relative markdown links in a comment resolve against the comment's | ||
| // own URL (.../issues/<n>), not the repo root, so a plain relative | ||
| // path 404s instead of opening the template. Build an absolute blob | ||
| // URL against the actual default branch instead (see #299). | ||
| const ref = context.payload.repository.default_branch; | ||
| const repoBlobUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/blob/${ref}`; | ||
|
|
||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: number, | ||
| body: [ | ||
| "This issue is missing required template sections:", | ||
| ...missing.map(h => `- \`${h}\``), | ||
| "", | ||
| `Please update the body to match the [epic template](${repoBlobUrl}/.github/ISSUE_TEMPLATE/epic.md) or [ticket template](${repoBlobUrl}/.github/ISSUE_TEMPLATE/ticket.md).`, | ||
| ].join("\n"), | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| name: Validate PR review thread SOP | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, reopened] | ||
| pull_request_review: | ||
| types: [submitted] | ||
| # Replying to a review thread is a new review comment, so this re-triggers | ||
| # the check after the "reply" SOP step. Resolving a thread and reacting | ||
| # +1 have no corresponding Actions trigger event (GitHub does not expose | ||
| # pull_request_review_thread's resolved/unresolved action, or comment | ||
| # reactions, to workflow `on:` triggers) -- `repo-scaffold pr rerun | ||
| # --failed-only` after finishing those steps remains the way to refresh | ||
| # the check without a new commit or review submission. | ||
| pull_request_review_comment: | ||
| types: [created] | ||
| workflow_dispatch: | ||
| inputs: | ||
| pr_number: | ||
| description: PR number to check | ||
| required: true | ||
| type: number | ||
|
|
||
| jobs: | ||
| check-sop: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| pull-requests: read | ||
|
|
||
| steps: | ||
| - name: Check review threads for SOP compliance | ||
| uses: actions/github-script@v9 | ||
| with: | ||
| script: | | ||
| const prNumber = | ||
| context.payload.pull_request?.number || | ||
| parseInt(context.payload.inputs?.pr_number || "0"); | ||
|
|
||
| if (!prNumber) { | ||
| core.setFailed("Could not determine PR number from event payload."); | ||
| return; | ||
| } | ||
|
|
||
| // The SOP's prescribed reply form is "Fixed in <hash>. <sentence>." | ||
| // (see AGENTS.md Review thread SOP step 2) -- anchor to that phrase | ||
| // instead of matching a bare hex-looking token anywhere in the | ||
| // comment, which false-positives on ordinary words built entirely | ||
| // from hex letters (e.g. "defaced"). See #263 (original bug) and | ||
| // the follow-up review on #307 (this anchoring fix). | ||
| const REPLY_RE = /\bfixed in\s+[0-9a-f]{7,40}\b/i; | ||
|
|
||
| // A thread's own comments connection can in principle exceed one | ||
| // page too, same as the outer reviewThreads connection -- fetch | ||
| // whatever's left with a follow-up query scoped to that thread. | ||
| async function fetchRemainingComments(threadId, after) { | ||
| const comments = []; | ||
| while (true) { | ||
| const data = await github.graphql(` | ||
| query($threadId: ID!, $after: String) { | ||
| node(id: $threadId) { | ||
| ... on PullRequestReviewThread { | ||
| comments(first: 50, after: $after) { | ||
| pageInfo { hasNextPage endCursor } | ||
| nodes { | ||
| databaseId | ||
| body | ||
| reactionGroups { | ||
| content | ||
| reactors { totalCount } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| `, { threadId, after }); | ||
| const page = data.node.comments; | ||
| comments.push(...page.nodes); | ||
| if (!page.pageInfo.hasNextPage) break; | ||
| after = page.pageInfo.endCursor; | ||
| } | ||
| return comments; | ||
| } | ||
|
|
||
| const threads = []; | ||
| let after = null; | ||
| while (true) { | ||
| const data = await github.graphql(` | ||
| query($owner: String!, $repo: String!, $number: Int!, $after: String) { | ||
| repository(owner: $owner, name: $repo) { | ||
| pullRequest(number: $number) { | ||
| reviewThreads(first: 50, after: $after) { | ||
| pageInfo { hasNextPage endCursor } | ||
| nodes { | ||
| id | ||
| isResolved | ||
| comments(first: 50) { | ||
| pageInfo { hasNextPage endCursor } | ||
| nodes { | ||
| databaseId | ||
| body | ||
| reactionGroups { | ||
| content | ||
| reactors { totalCount } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| `, { | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| number: prNumber, | ||
| after, | ||
| }); | ||
|
|
||
| const page = data.repository.pullRequest.reviewThreads; | ||
| threads.push(...page.nodes); | ||
| if (!page.pageInfo.hasNextPage) break; | ||
| after = page.pageInfo.endCursor; | ||
| } | ||
|
|
||
| if (threads.length === 0) { | ||
| core.info("No review threads found. SOP check passed."); | ||
| return; | ||
| } | ||
|
|
||
| const failing = []; | ||
| for (const thread of threads) { | ||
| let comments = thread.comments.nodes; | ||
| if (thread.comments.pageInfo.hasNextPage) { | ||
| comments = comments.concat( | ||
| await fetchRemainingComments(thread.id, thread.comments.pageInfo.endCursor) | ||
| ); | ||
| } | ||
|
|
||
| const hasReply = comments.slice(1).some(c => REPLY_RE.test(c.body || "")); | ||
| const isResolved = thread.isResolved; | ||
| const firstComment = comments[0] || {}; | ||
| // reactionGroups gives an aggregate count per reaction type in | ||
| // one shot -- no pagination needed, unlike the raw `reactions` | ||
| // connection this replaced (see #303). | ||
| const reactionGroups = firstComment.reactionGroups || []; | ||
| const hasPlusOne = reactionGroups.some( | ||
| g => g.content === "THUMBS_UP" && g.reactors.totalCount > 0 | ||
| ); | ||
|
|
||
| if (!hasReply || !isResolved || !hasPlusOne) { | ||
| const missing = []; | ||
| if (!hasReply) missing.push("reply"); | ||
| if (!isResolved) missing.push("resolved"); | ||
| if (!hasPlusOne) missing.push("reaction(+1)"); | ||
| failing.push({ | ||
| threadId: thread.id, | ||
| commentId: firstComment.databaseId, | ||
| missing, | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| const total = threads.length; | ||
| const passed = total - failing.length; | ||
| core.info(`${passed}/${total} threads SOP-compliant.`); | ||
|
|
||
| if (failing.length > 0) { | ||
| for (const f of failing) { | ||
| core.error( | ||
| `Thread ${f.threadId} (comment #${f.commentId}) missing: ${f.missing.join(", ")}` | ||
| ); | ||
| } | ||
| core.setFailed( | ||
| `${failing.length} review thread(s) not SOP-compliant. ` + | ||
| "SOP: push fix -> reply with commit hash -> resolve thread -> react +1." | ||
| ); | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.