Skip to content

gh issue artifact stack 3/10: Add the command group and list - #14566

Open
BagToad wants to merge 2 commits into
bagtoad/artifact-attach-documentsfrom
bagtoad/artifact-list
Open

BagToad wants to merge 2 commits into
bagtoad/artifact-attach-documentsfrom
bagtoad/artifact-list

Conversation

@BagToad

@BagToad BagToad commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Part of the pull request stack tracked in #14563.

This adds the gh issue artifact command group from #14529, with its first command, list, from #14523.

Description

Issue artifacts are Markdown documents and links attached to an issue. Each one has a number on its issue, a name and a type. generic and plan artifacts are documents, and link artifacts are links. They aren't GitHub Actions artifacts, which gh run download handles.

This adds gh issue artifact, a new command group under gh issue. Like gh discussion, it's in preview. Its first command lists the artifacts on an issue:

$ gh issue artifact list 142

Showing 3 artifacts on monalisa/monas-cafe#142

NUMBER  NAME                    TYPE     UPDATED
2       OAuth callback plan     generic  about 2 hours ago
3       Staging OAuth runbook   link     about 1 day ago
5       Barista feedback notes  generic  about 3 days ago
  • The issue argument is a number or a URL, like other gh issue commands.
  • list shows every artifact, in number order. --limit stops after that many.
  • --type filters by type. --type generic and --type plan both list every document, since gh treats the two types alike.
  • Piped output has the same columns, tab-separated, with RFC 3339 timestamps and no header. --json exports every field the API returns.
  • In a terminal, list uses the pager, like gh issue list. --json output never pages, like gh discussion list.
  • An issue with no artifacts prints "no artifacts found on monalisa/monas-cafe#161" in a terminal and exits 0, like other gh list commands.
  • Pull requests are refused after one lookup, before any artifact request. GitHub Enterprise Server is refused before any artifact request, with a message like --attach's.

Two packages support this and the commands that follow in the stack:

  • The client package holds the ArtifactClient interface, its REST implementation and a generated moq mock, like the gh discussion client. Commands reach the API only through it.
  • The shared package holds the issue argument, the Enterprise Server check and the pull request check.

How did you test this change?

I recorded the built gh listing artifacts in bagtoad/issue-artifacts-demo: the table, --limit, --type generic with a plan, piped output, --json, an issue with no artifacts and a pull request, with GH_DEBUG=1 showing the requests. It leaves out issue URL arguments, GitHub Enterprise Server and API errors.

recording.mp4

Open chapters and agent notes

Key points

  • The header counts only what's shown. [Design] gh issue artifact list #14523 shows "Showing 3 of 3 artifacts", which needs a total count. The API returns none, so the header says "Showing 3 artifacts on monalisa/monas-cafe#142". With --type, it ends with "that match your search", as in [Design] gh issue artifact list #14523.

  • No url field yet. List responses don't include an artifact URL today, so url isn't among the --json fields. A later pull request in this stack will add it.

  • Both document types are fetched and merged. In [Design] gh issue artifact list #14523, --type generic also lists plans, and --type plan also lists generic artifacts. Each request filters on one type on the server, so either value asks for both types, up to the limit, then merges them in listArtifacts:

    // Either document type asks for both, each up to the limit
    for _, documentType := range []string{client.TypeGeneric, client.TypePlan} {
    	documents, err := c.List(repo, issueNumber, documentType, limit)
    	...
    	artifacts = append(artifacts, documents...)
    }
    
    // Then number order, cut to the limit
    slices.SortStableFunc(artifacts, func(a, b client.Artifact) int {
    	return cmp.Compare(a.Number, b.Number)
    })

    Rows keep their stored type, so a plan still shows plan.

  • Every page has the same size. Each request asks for the smaller of --limit and 100, and pages continue until one comes back short. Pages are numbered, so changing the size partway would shift them. --limit 150 asks for 100 twice and keeps 150, like gh cache list.

  • The pull request check reuses gh issue delete's lookup. The issue lookup runs once, behind the client interface, so command tests use the mock.

  • Placement. artifact sits under "Targeted commands" in gh issue --help, as deploy-key and autolink do under gh repo. It inherits -R from gh issue.

  • Unlimited by default. --limit has no default in the help, and every artifact is listed. --limit 0 is a flag error, "invalid limit: 0", like gh issue list.

Notes for reviewers

Start with the list run function, which shows the order of the checks and the output paths. Then read the client's List, which pages, and the shared checks. TestListRun has a row for each output rule, including a stored type gh doesn't know. TestList covers paging, with each request URL asserted.

Authorship and follow-up

Who wrote this:

  • A human wrote it.
  • An agent wrote it under close human direction.
  • An agent wrote it independently, and no human has guided the implementation beyond the initial prompt.

Who answers review comments:

  • @BagToad will read and reply directly. Name the account.
  • An agent will draft replies and @BagToad will read them before they are posted.
  • Nobody has explicitly committed to replying.

Commands reach the issue artifacts REST API through the ArtifactClient
interface, so their tests can use the generated moq mock, as gh
discussion does.

List asks for pages of up to 100 artifacts until one comes back short.
Every request uses the same page size, so page numbers stay aligned when
the limit is above 100.
gh issue artifact is a new command group, in preview, for the Markdown
documents and links attached to an issue. It starts with list.

gh treats generic and plan artifacts alike as documents, so --type
generic and --type plan list both, merged in number order. Without a
total count from the API, the header counts the artifacts shown.
@BagToad
BagToad requested a review from a team as a code owner October 1, 2026 16:58
@BagToad
BagToad requested review from babakks and removed request for a team October 1, 2026 16:59
@BagToad
BagToad added this pull request to stack #14573 October 1, 2026 16:59

This branch has not been deployed

No deployments
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.

1 participant