Skip to content

feat: add discussion command set#13541

Merged
babakks merged 47 commits into
trunkfrom
feature/discussion
Jun 10, 2026
Merged

feat: add discussion command set#13541
babakks merged 47 commits into
trunkfrom
feature/discussion

Conversation

@babakks

@babakks babakks commented May 28, 2026

Copy link
Copy Markdown
Member

This PR adds the gh discussion command group (list, view, create, edit) as a preview feature.

Huge thanks to @maxbeizer for doing the heavy lifting on this. :copilot: was also instrumental in implementation, review, and polish throughout.

I rewrote the commit history (81 commits squashed into 6) for easier review and a cleaner git log. Note that the commits are structured to split the work logically; intermediate commits may not compile independently.

Commands

discussion list

gh discussion list [--category <name>] [--state <open|closed|all>] [--author <handle>] [--label <name>] [--search <query>] [--limit <n>] [--json <fields>] [--web]

List discussions in a repository with optional filters. (8b73951)

discussion view

gh discussion view {<number> | <url>} [--comments [--limit <n>]] [--replies <comment-id> [--limit <n>]] [--json <fields>] [--web]

View a discussion's details, comments, or replies to a specific comment. (57008e7)

discussion create

gh discussion create --title <text> --body <text> --category <name> [--label <name>,...] [--body-file <path>]

Create a new discussion, interactively or via flags. (7bd67a8)

discussion edit

gh discussion edit {<number> | <url>} [--title <text>] [--body <text>] [--body-file <path>] [--category <name>] [--add-label <name>,...] [--remove-label <name>,...]

Edit a discussion's title, body, category, or labels, interactively or via flags. (797effe)

Reusable components

  • pkg/cmd/discussion/client: GraphQL client for Discussions covering list, search, get, create, update, and label mutations with full pagination support. (51b7653)
  • pkg/cmd/discussion/shared: Shared utilities including argument parsing, category matching, label resolution, and client factory helpers. (d3a1538)

Screenshots

gh discussion list

Terminal output showing a table of discussions with columns for number, state, title, category, author, and date

gh discussion view 9094

Terminal output showing discussion details including title, metadata, labels, and body text

gh discussion view 9094 --comments --limit 1

Terminal output showing a discussion with its threaded comments displayed below the body

gh discussion view 9094 --replies DC_kwDODKw3uc4AkHLS --limit 1

Terminal output showing paginated replies to a specific discussion comment

gh discussion create (non-interactive)

Terminal showing discussion creation via flags with title, body, category, and label options

gh discussion create (interactive, category selection)

Terminal showing an interactive prompt listing available discussion categories to choose from

gh discussion create (interactive)

Terminal showing interactive prompts for title and body input during discussion creation

gh discussion edit (interactive)

  1. Select fields to update
    Terminal showing a multi-select prompt asking which fields to edit: title, body, category

  2. Populate new values
    Terminal showing input prompts pre-filled with current values for the selected fields

  3. Submit
    Terminal showing the discussion URL printed after a successful edit

gh discussion edit (non-interactive)

Terminal showing discussion edit via flags updating title, body, and labels in one command

Comment thread pkg/cmd/discussion/client/client_impl.go Fixed
Comment thread pkg/cmd/discussion/client/client_impl.go Fixed
Comment thread pkg/cmd/discussion/client/client_impl.go Fixed
babakks and others added 6 commits June 1, 2026 13:32
Implement a GraphQL client for GitHub Discussions supporting:
- List and search discussions with pagination
- Get discussion by number with comments
- Get paginated comment replies
- List repository categories and labels
- Create discussions with optional labels
- Update discussion title, body, category, and labels
- Add/remove labels via separate mutations

Includes comprehensive table-driven tests with HTTP mocking.

Co-authored-by: Max Beizer <[email protected]>
Co-authored-by: Copilot <[email protected]>
Add shared package with:
- ParseDiscussionArg: parses discussion number or URL from CLI args
- MatchCategory: case-insensitive category matching by name or slug
- ResolveLabels: case-insensitive label name to ID resolution
- DiscussionClientFunc: factory helper for lazy client initialization

Includes tests for all utilities.

Co-authored-by: Max Beizer <[email protected]>
Co-authored-by: Copilot <[email protected]>
Add `gh discussion list` with support for:
- Filtering by category, state, author, and labels
- Search keyword matching
- Table and JSON output formats
- Web mode (opens browser with filters)
- Pagination via --limit flag

Also adds the discussion command group scaffolding and root wiring.

Co-authored-by: Max Beizer <[email protected]>
Co-authored-by: Copilot <[email protected]>
Add `gh discussion view` with support for:
- Viewing discussion details with metadata and body
- Threaded comment display with --comments flag
- Paginated reply fetching with --replies flag
- JSON output with --json/--jq/--template flags
- Web mode (opens browser)
- Accepts discussion number or URL as argument

Co-authored-by: Max Beizer <[email protected]>
Co-authored-by: Copilot <[email protected]>
Add `gh discussion create` with support for:
- Non-interactive creation with --title, --body, --category, --label flags
- Interactive mode with prompts for title, body, and category
- Body input from file via --body-file (including stdin)
- Label resolution (name to ID) before creation
- Category validation by name or slug

Co-authored-by: Max Beizer <[email protected]>
Co-authored-by: Copilot <[email protected]>
Add `gh discussion edit` with support for:
- Non-interactive editing with --title, --body, --body-file, --category flags
- Label management with --add-label and --remove-label flags
- Interactive mode with multi-select prompts for fields to edit
- Flag presence detection (allows setting body to empty string)
- Label name to ID resolution via shared.ResolveLabels
- Body input from stdin via --body-file -

Co-authored-by: Max Beizer <[email protected]>
Co-authored-by: Copilot <[email protected]>
@babakks babakks force-pushed the feature/discussion branch from b6d5f84 to 797effe Compare June 1, 2026 12:35
@babakks babakks marked this pull request as ready for review June 1, 2026 12:49
@babakks babakks requested a review from a team as a code owner June 1, 2026 12:49
@babakks babakks requested review from BagToad and Copilot June 1, 2026 12:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new preview gh discussion command group to the GitHub CLI, backed by a dedicated Discussions GraphQL client and shared helpers, with support for human-readable and JSON output modes.

Changes:

  • Adds the gh discussion command group and wires it into the CLI root command.
  • Implements discussion list, discussion view, discussion create, and discussion edit commands (including interactive flows and JSON output).
  • Adds a Discussions GraphQL client, shared argument/category/label utilities, and accompanying unit tests.
Show a summary per file
File Description
pkg/cmd/root/root.go Registers the new discussion command group at the root level.
pkg/cmd/discussion/discussion.go Defines the top-level gh discussion command and groups subcommands.
pkg/cmd/discussion/list/list.go Implements listing discussions with filters, web mode, and JSON output.
pkg/cmd/discussion/list/list_test.go Tests list behavior across tty/non-tty/json/web and filters.
pkg/cmd/discussion/view/view.go Implements viewing discussions, including comments and comment-reply pagination.
pkg/cmd/discussion/view/view_test.go Tests view output (tty/raw/json) and pagination for comments/replies.
pkg/cmd/discussion/create/create.go Implements discussion creation (interactive or via flags) with label resolution.
pkg/cmd/discussion/create/create_test.go Tests create flows, validation, prompting, and error handling.
pkg/cmd/discussion/edit/edit.go Implements discussion editing (interactive or via flags), including label add/remove.
pkg/cmd/discussion/edit/edit_test.go Tests edit flows, validation, prompting, and mutation inputs.
pkg/cmd/discussion/shared/client.go Adds a factory helper for creating a Discussions client from Factory.
pkg/cmd/discussion/shared/lookup.go Parses discussion arguments (number / URL) into number + repo override.
pkg/cmd/discussion/shared/lookup_test.go Tests discussion argument parsing.
pkg/cmd/discussion/shared/categories.go Adds category name/slug matching helper.
pkg/cmd/discussion/shared/labels.go Adds label-name-to-ID resolution helper.
pkg/cmd/discussion/shared/labels_test.go Tests label resolution behavior.
pkg/cmd/discussion/client/client.go Defines the Discussions client interface.
pkg/cmd/discussion/client/client_impl.go Implements Discussions GraphQL operations (list/search/get/create/update, pagination).
pkg/cmd/discussion/client/types.go Defines domain types + ExportData mappings for --json output.
pkg/cmd/discussion/client/client_mock.go Adds generated mock for testing (moq).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Files not reviewed (1)
  • pkg/cmd/discussion/client/client_mock.go: Language not supported
  • Files reviewed: 19/21 changed files
  • Comments generated: 10

Comment thread pkg/cmd/discussion/view/view.go Outdated
Comment thread pkg/cmd/discussion/client/client_impl.go Outdated
Comment thread pkg/cmd/discussion/shared/lookup.go
Comment thread pkg/cmd/discussion/shared/lookup.go Outdated
Comment thread pkg/cmd/discussion/shared/labels.go
Comment thread pkg/cmd/discussion/view/view.go Outdated
Comment thread pkg/cmd/discussion/client/client_impl.go Outdated
Comment thread pkg/cmd/discussion/shared/lookup.go
Comment thread pkg/cmd/discussion/shared/lookup.go Outdated
Comment thread pkg/cmd/discussion/shared/labels.go

@BagToad BagToad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass 🙂

Comment thread pkg/cmd/discussion/list/list.go Outdated
Comment thread pkg/cmd/discussion/client/client.go Outdated
Comment thread pkg/cmd/discussion/list/list_test.go Outdated
Comment thread pkg/cmd/discussion/create/create.go
Comment thread pkg/cmd/discussion/client/client_impl.go Outdated
Comment thread pkg/cmd/discussion/client/client_impl.go Outdated
Comment thread pkg/cmd/discussion/view/view.go Outdated
Comment thread pkg/cmd/discussion/client/client_impl.go Outdated
Comment thread pkg/cmd/discussion/discussion.go
Comment thread pkg/cmd/discussion/client/client_impl.go Outdated
BagToad
BagToad previously requested changes Jun 3, 2026

@BagToad BagToad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's some code scanning alerts that should be fixed.

Looks like code scanning doesn't block right now, so I want to just formally block on those code scanning alerts just in case.

@BagToad BagToad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another pass

Comment thread pkg/cmd/discussion/edit/edit.go
Comment thread pkg/cmd/discussion/client/types.go
Comment thread pkg/cmd/discussion/list/list.go Outdated
Comment thread pkg/cmd/discussion/list/list.go Outdated

@maxbeizer maxbeizer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I noticed with discussion list --json: I know we previously discussed adding pagination metadata like next (e.g. #13084 (comment)), but the current command advertises discussion fields like number,title,url while returning a top-level envelope:

{ "totalCount": 2, "discussions": [
    { "number": 42, "title": "..." } ], "next": "..."
}

That makes sense for pagination, but it seems a little inconsistent with the usual gh <resource> list --json field1,field2 contract, where selected resource fields are emitted directly as an array. It also means totalCount, discussions, and next are always emitted even though they are not selectable JSON fields.

Should we either align this with issue list / pr list and emit just the discussion array, or explicitly make the envelope fields part of the supported/documented JSON shape?

- Fix double default in list --limit help text
- Wire --body-file flag in create command (symmetric with edit)
- Cap comment/reply pagination to maxPageSize (100)
- Use int32 for discussion number params (fixes CodeQL alerts)
- Use strconv.ParseInt instead of Atoi for int32 targets
- Fix IsStdoutTTY -> IsStderrTTY for web mode message
- Use CancelError instead of error string for no-op edit
- Trim whitespace from label names in resolution
- Fix category error formatting (comma-joined instead of %q slice)
- Fix typo in lookup.go comment
- Remove dead len==0 check in view replies path
- Inline exporterNeedsComments into needsComments
- Validate comment ownership in GetCommentReplies
- Remove unimplemented interface methods and CloseReason type

Co-authored-by: Copilot <[email protected]>
@babakks

babakks commented Jun 4, 2026

Copy link
Copy Markdown
Member Author

Should we either align this with issue list / pr list and emit just the discussion array, or explicitly make the envelope fields part of the supported/documented JSON shape?

@maxbeizer, that's actually intentional because the top-level array JSON in pr list (or other similar commands) is a limiting structure and not really forward-compatible. We may even at some point return to the old commands and refactor them toward this new structure.

@maxbeizer

Copy link
Copy Markdown
Contributor

Should we either align this with issue list / pr list and emit just the discussion array, or explicitly make the envelope fields part of the supported/documented JSON shape?

@maxbeizer, that's actually intentional because the top-level array JSON in pr list (or other similar commands) is a limiting structure and not really forward-compatible. We may even at some point return to the old commands and refactor them toward this new structure.

oh that's right. I remember now. Thank you!

babakks and others added 2 commits June 5, 2026 13:24
Return the discussion alongside the error when the primary mutation
succeeds but a secondary mutation (e.g., labels) fails. Callers print
the URL on stdout and the error on stderr, then exit with code 1.

Co-authored-by: Copilot <[email protected]>
Rewrite the help text to be more conversational and less mechanical.
Clarify that inline reply previews are not affected by --order.

Co-authored-by: Copilot <[email protected]>
…stResult

Track the input pagination cursor on DiscussionListResult and add an
ExportData method that conditionally includes cursor/next fields.
Use ExportData in the list command instead of manually building the
JSON envelope.

Co-authored-by: Copilot <[email protected]>
Comment thread pkg/cmd/discussion/view/view.go Outdated

@BagToad BagToad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - there's some things that we discussed to do but I trust you'll action those before merging :)

babakks and others added 19 commits June 10, 2026 09:32
Add client methods for managing discussion comments and replies:
- AddComment: creates a top-level comment or reply via addDiscussionComment
- UpdateComment: edits a comment body via updateDiscussionComment
- DeleteComment: removes a comment via deleteDiscussionComment
- GetComment: fetches a comment by node ID with typename validation

Co-authored-by: Copilot <[email protected]>
Implement gh discussion comment for adding, editing, and deleting
comments and replies on discussions. Supports --body, --body-file,
--editor for input, --reply-to for threading, --edit and --delete
for modifying existing comments, with confirmation prompts.

Co-authored-by: Copilot <[email protected]>
…PI calls

Replace gh api graphql addDiscussionComment mutations in view and list
acceptance tests with gh discussion comment. Extract comment IDs via
a single view call with jq2env instead of multiple calls.

Co-authored-by: Copilot <[email protected]>
Cover add, reply, edit, delete flows including body-file input,
non-interactive delete requiring --yes, and deletion of both parent
comment and reply to avoid ghost entries.

Co-authored-by: Copilot <[email protected]>
Add test for --delete without --yes in non-TTY mode and fix existing
delete tests to set isTTY: true for prompter-based confirmation.

Co-authored-by: Copilot <[email protected]>
Add ParseDiscussionOrCommentArg to the shared package for parsing
discussion numbers, URLs, comment node IDs, and comment URLs
(with #discussioncomment-NNNNN fragments).

Add ResolveCommentNodeID to the client for constructing node IDs from
repository database ID and comment database ID via msgpack encoding.

Update the comment command to accept comment URLs as positional args
for reply, edit, and delete operations. Update the view command to
accept comment URLs in the --replies flag.

Add DiscussionID field to DiscussionComment for reply flow (fetches
the parent discussion ID from a comment).

Co-authored-by: Copilot <[email protected]>
…ests

Update comment acceptance test to use positional comment IDs instead of
--reply-to, and add URL-based add/edit/delete test cases. Update view
acceptance test to cover --replies with a comment URL.

Co-authored-by: Copilot <[email protected]>
Signed-off-by: Babak K. Shandiz <[email protected]>
…ment argument

Drop the --replies flag from gh discussion view and instead accept a
comment URL or comment node ID (DC_*) as the positional argument. A
discussion number, #number, or discussion URL behaves as before, while a
comment reference shows that comment and its replies.

Rework GetCommentReplies to be node-centric: it resolves the parent
discussion directly from the comment node, so it no longer needs the
discussion number or a repository ownership check. The method now takes a
host string instead of a full repository.

Also add a comment mode for --web that resolves and opens the comment URL,
and add godoc to the DiscussionClient interface methods.

Co-authored-by: Copilot <[email protected]>
GetComment resolves a comment by its node ID, so it only needs the host
to select the GraphQL endpoint. Change its signature from a full
ghrepo.Interface to a host string and update all callers and tests
accordingly, mirroring GetCommentReplies.

Co-authored-by: Copilot <[email protected]>
…test

Replace --replies usage with a positional comment node ID or URL to match
the redesigned gh discussion view command.

Co-authored-by: Copilot <[email protected]>
…gument

In replies mode the --comments flag is meaningless, so reject the
combination with a flag error instead of silently ignoring it.

Co-authored-by: Copilot <[email protected]>
…s icon helper

Collapse the three state-specific no-results messages into a single
"no discussions found in <repo>" message, and render the answered
column with the color scheme SuccessIcon helper for consistency with
the view command.

Co-authored-by: Copilot <[email protected]>
Redesign the human-readable comment and reply output. Comments and
replies are now displayed in chronological order regardless of the
selected sort, reversing newest-first lists for display. Each header
uses a bulleted layout with an abbreviated age, distinguishes between
"commented" and "replied", and tags the newest comment or reply.
Truncation notices now indicate whether older or newer items are
hidden based on the fetch direction.

Co-authored-by: Copilot <[email protected]>
Make the non-interactive output of each mode print only what was asked
for. Without --comments, only the discussion metadata and body are
printed. With --comments, only the comments are printed, each as a
metadata block (author, created, url, and answer when applicable)
followed by its body. In replies mode, only the replies are printed in
the same block format, without the parent comment. Comments and replies
follow the same chronological ordering as the interactive output, and
pagination cursors are no longer emitted in non-tty mode.

Co-authored-by: Copilot <[email protected]>
The discussion URL pattern captures one or more digits, which can exceed
the int32 range. The parse error from strconv.ParseInt was previously
discarded, silently clamping the number. Return an explicit error
instead, and cover it with tests in both URL parsing functions.

Co-authored-by: Copilot <[email protected]>
@babakks babakks requested a review from BagToad June 10, 2026 14:52
Comment thread pkg/cmd/discussion/client/client.go
Comment thread pkg/cmd/discussion/comment/comment.go
@babakks babakks merged commit 52e8e74 into trunk Jun 10, 2026
11 checks passed
@babakks babakks deleted the feature/discussion branch June 10, 2026 20:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants