feat(discussion): add support for Discussion Templates - #14017
feat(discussion): add support for Discussion Templates#14017jamietanna wants to merge 2 commits into
Conversation
Per cli#14015, it would be useful to present the user with an interactive prompt when authoring a Discussion on a repository that has Discussion Template(s) in place. This builds on top of code from https://github.com/jamietanna/gh-discussion (Apache-2.0) and rewritten in the style of the project by Claude Sonnet 5. Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
5d75422 to
c513704
Compare
|
Thanks for your pull request! Unfortunately, it doesn't meet the requirements for review:
Please update your PR to address the above. This PR will be automatically closed in 4 days if these requirements are not met. Full contribution requirements
|
There was a problem hiding this comment.
Pull request overview
This PR adds support for GitHub Discussion Category Forms (“discussion templates”) to gh discussion create, enabling an interactive, field-by-field prompt when a repository defines a .github/DISCUSSION_TEMPLATE/<category-slug>.yml file for the selected discussion category.
Changes:
- Introduces YAML parsing + prompting logic for Discussion Category Forms (markdown blocks, input, textarea, dropdown, checkboxes).
- Fetches the category form via the REST “contents” endpoint and uses it to generate a web-UI-like markdown body when creating discussions interactively.
- Adds unit tests covering template parsing, fetching, and the updated create flow.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| pkg/cmd/discussion/shared/template.go | Adds form schema parsing, remote fetching, and interactive prompting to assemble a discussion body from a category form. |
| pkg/cmd/discussion/shared/template_test.go | Adds tests for YAML unmarshalling, REST fetch behavior, and prompt-to-body rendering. |
| pkg/cmd/discussion/create/create.go | Wires template prompting into gh discussion create when --body/--body-file isn’t provided. |
| pkg/cmd/discussion/create/create_test.go | Extends create tests with HTTP stubs and a template-present scenario. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| func (e *TemplateElement) UnmarshalYAML(value *yaml.Node) error { | ||
| var shape struct { | ||
| Type string `yaml:"type"` | ||
| Attributes yaml.Node `yaml:"attributes"` | ||
| Validations struct { | ||
| Required bool `yaml:"required"` | ||
| } `yaml:"validations"` | ||
| } |
| If the selected category defines a Discussion Category Form (a | ||
| %[1]s.github/DISCUSSION_TEMPLATE/<category>.yml%[1]s file), and %[1]s--body%[1]s/%[1]s--body-file%[1]s | ||
| was not given, the form's fields are prompted for individually instead of a single free-text body. |
| func promptBody(opts *CreateOptions, repo ghrepo.Interface, categorySlug string) (string, error) { | ||
| httpClient, err := opts.HttpClient() | ||
| if err != nil { | ||
| return "", err | ||
| } |
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
pkg/cmd/discussion/shared/template.go:277
- For optional dropdowns, the skip check compares the selected label to the literal string "Skip". If a repository template legitimately includes an option labeled "Skip", selecting it would be treated as “leave blank” and silently discarded. Safer to detect skip by index (only when the extra option was appended) rather than by string value.
if err != nil {
return "", err
}
if options[idx] == skipOption {
return "", nil
|
@jamietanna, I mentioned I'm going to close the PR for now, but I'm also happy to keep it open if you're okay with turning it into a draft. |
Checking the pull request head out means this job executes that PR's code — install lifecycle scripts included — while holding a subscription token, `pull-requests: write` and `actions: write`. The owner gate does not cover that. It decides who may TRIGGER a review, not whose code then runs, and the ordinary sequence is the dangerous one: a stranger opens a pull request, the owner reads it and comments `@claude review`. `ci.yml` builds fork pull requests safely because `pull_request` hands it a read-only token and no secrets. This job has both, and `actions: write` widens it further, since a poisoned cache entry outlives the run and is restored by a later job on `main`. So the head must be a branch of this repository. The `issue_comment` payload cannot answer that — `issue.pull_request` carries only URLs — so it is resolved through the API in a step that runs before anything is checked out, and the job stops with a readable error otherwise. Reviewing a fork stays possible by hand, which is what it was before this branch. Resolving the SHA rather than trusting `refs/pull/N/head` also closes the window between the check and the checkout, since that ref moves when the contributor pushes. Verified both directions against live pull requests: this one resolves to saeedkolivand/crosskit and passes, and cli/cli#14017 resolves to jamietanna/cli and takes the exit path. Install scripts stay enabled rather than `--ignore-scripts`, now that the code is this repository's: an install that differs from the one `ci.yml` performs would have the review measuring something other than the gate, which is the failure this branch exists to fix. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* ci: let the PR review run the code instead of only reading it Every review this cycle closed with the same line: "I could not run the gate: this checkout has no node_modules and pnpm install isn't in this job's allowed tools." So every finding was reasoned from the diff — and in this repo the questions that matter most are the ones reading cannot settle. Does the assertion still fail when the fix is reverted? Does a green jsdom test survive a real browser? Both have hidden a real bug behind a passing suite here. Dependencies are installed and packages built in the workflow rather than by the agent: the lockfile stays frozen, the pnpm store cache applies, and the allowed-tools list never needs a command that mutates dependencies. Building also matters because the playgrounds import dist rather than src, so without it a suite the review runs would measure whatever was last built. Chromium is installed because the browser suite is the one that catches what jsdom structurally cannot — inert blocking focus, and which of two overlapping fixed elements a press reaches. The system prompt now asks it to reproduce before reporting, to revert a fix and confirm the test actually fails before calling coverage adequate, and to mark anything it could not reproduce as unconfirmed. Allowed tools are read-and-run only: no install, no write, no push. * ci: check out the pull request, not the default branch Round 1 review, four findings, each confirmed against evidence rather than taken on the reviewer's word. The one that mattered: an `issue_comment` event points GITHUB_REF at the default branch, so the checkout landed on `main` and every step this branch adds — install, build, browser download — would have run against main's tree. Confirmed in the log of the review that raised it, which shows `git checkout --force -B main refs/remotes/origin/main` before the action does its own checkout of the PR branch. The build writes `packages/*/dist`, which is gitignored and therefore survives that switch, and the playgrounds import it — trap 2, automated. That is strictly worse than what it replaces: today a review says it could not run the gate; with the wrong ref it reports a confident green measured against main. Pinned to `refs/pull/N/head`. Reviews have opened by saying they cannot post inline comments, and the pin explains why: the inline-comment MCP server starts only when `--allowedTools` names one of its tools, and tag mode's own list does not (install-mcp-server.ts:80,138-142; modes/tag/index.ts:123-133). The comment claiming tag mode grants them was wrong; naming the tool is what starts it. Tag mode runs `--permission-mode acceptEdits` and already allows `git add` and `git commit`, so telling the reviewer to delete code and confirm a test fails handed it a way to mutate the tree and no way to put it back. Added the restore verbs and an instruction to leave the tree clean and never commit. `test:browser` did not exist on the branch this was cut from, only on the one that has since merged. Rebased, both suite names are real, and the prompt now says they are disjoint rather than implying one covers the other. Also: the action's post step was failing with "cache write denied: token has no writable scopes". An explicit permissions block makes every omitted scope `none`, so `cache: pnpm` was inert in both directions and every review cold-installed. Timeout raised to 45 for the work the job has gained, since a killed job posts nothing at all. Corrected two comments that claimed more than the file delivers: installing in the workflow does not stop the agent mutating dependencies, because `Bash(pnpm --filter:*)` is a prefix rule that also matches `pnpm --filter x add`. The owner gate is what bounds this job, and it now says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * ci: run the review only on branches of this repository Checking the pull request head out means this job executes that PR's code — install lifecycle scripts included — while holding a subscription token, `pull-requests: write` and `actions: write`. The owner gate does not cover that. It decides who may TRIGGER a review, not whose code then runs, and the ordinary sequence is the dangerous one: a stranger opens a pull request, the owner reads it and comments `@claude review`. `ci.yml` builds fork pull requests safely because `pull_request` hands it a read-only token and no secrets. This job has both, and `actions: write` widens it further, since a poisoned cache entry outlives the run and is restored by a later job on `main`. So the head must be a branch of this repository. The `issue_comment` payload cannot answer that — `issue.pull_request` carries only URLs — so it is resolved through the API in a step that runs before anything is checked out, and the job stops with a readable error otherwise. Reviewing a fork stays possible by hand, which is what it was before this branch. Resolving the SHA rather than trusting `refs/pull/N/head` also closes the window between the check and the checkout, since that ref moves when the contributor pushes. Verified both directions against live pull requests: this one resolves to saeedkolivand/crosskit and passes, and cli/cli#14017 resolves to jamietanna/cli and takes the exit path. Install scripts stay enabled rather than `--ignore-scripts`, now that the code is this repository's: an install that differs from the one `ci.yml` performs would have the review measuring something other than the gate, which is the failure this branch exists to fix. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Description
Per #14015, it would be useful to present the user with an interactive
prompt when authoring a Discussion on a repository that has Discussion
Template(s) in place.
This builds on top of code from
https://github.com/jamietanna/gh-discussion (Apache-2.0) and rewritten
in the style of the project by Claude Sonnet 5.
Closes #14015.
How did you test this change?
Key points
Notes for reviewers
Authorship and follow-up
Who wrote this:
Who answers review comments: