Add issue field support to gh CLI by ayy-bc · Pull Request #13948 · cli/cli · GitHub
Skip to content

Add issue field support to gh CLI - #13948

Draft
ayy-bc wants to merge 2 commits into
cli:trunkfrom
ayy-bc:issue-fields
Draft

ayy-bc wants to merge 2 commits into
cli:trunkfrom
ayy-bc:issue-fields

Conversation

@ayy-bc

@ayy-bc ayy-bc commented Jul 23, 2026

Copy link
Copy Markdown

Adds support for Projects v2 issue fields.

Issue field values live on the issue itself, like labels and assignees. So the split is:

  • Reading works from the project. Values show up in gh project item-list --format json.
  • Writing has its own issue scoped command: gh issue edit-field <issue> --field-id <id> with one of --text, --number, --date, --single-select-option-id, --multi-select-option-ids, or --clear.
  • gh project field-create --issue-field-id <id> attaches an existing org or repo issue field to a project as a column.

gh project item-edit is unchanged, since issue field values are not set on the project item.

The GraphQL input structs are defined locally because the vendored githubv4 does not have the issue field types yet.

Draft for now. Holding until issue fields are GA in the public schema.

…field

Issue field values live on the issue itself (like labels and assignees), so:
- Read: ProjectV2ItemIssueFieldValue is surfaced through the project item field
  values and exported by gh project item-list --format json.
- Write: new issue-scoped command 'gh issue edit-field <issue> --field-id ...'
  sets/clears a typed value via updateIssueFieldValue, keeping gh project
  item-edit for project-item field writes.
- Attach: gh project field-create --issue-field-id surfaces an existing org/repo
  issue field on a project as a column (createProjectV2IssueField).

Local input structs supply the issue-field GraphQL types the vendored githubv4
lacks.
@github-actions github-actions Bot added external pull request originating outside of the CLI core team needs-triage needs to be reviewed labels Jul 23, 2026

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.

Same comment as I left on your other PR. We should consider opening a PR against the package we are vendoring to support these field types so we don't have mis-alignment between field types supported in different tooling and to avoid creating a maintenance layer here

$ gh issue create --parent 100
$ gh issue create --parent https://github.com/cli/go-gh/issues/42
$ gh issue create --blocked-by 200,201 --blocking 300
$ gh issue create --field "Team" --value "Platform"

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.

Can I create an issue with multiple Issue Field Values? Or can I only create it with a single Field populated then I need to update the Issue after creation?

@BagToad BagToad Jul 23, 2026 •

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.

These flags could be registered as stringarrayvar types, allowing the flags to be repeated:

gh issue create --field "Team" --value "Platform" --field "Priority" --value "High"

We'd loop through the arrays and pair up fields with values, in order.

The problem with this design is that ordering matters, but it might be ok.

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.

The other alternative is something like --field="name-goes-here=value-goes-here"

Comment on lines +78 to +85

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.

nit: I commented on this PR as well - the ergonomics of this CLI contract feels a bit clunky to me. Needing to know the data type of the Field I am passing and specifying different flags for multi-select vs single-select is a bit awkward as a user

ieuanign added a commit to ieuanign/skills that referenced this pull request Aug 9, 2026
…te their intent

Step 3's table gains a `#` key and a Reason column, and stays one line per
comment: what runs past a clause goes to a keyed expansion beneath it. A
`disagreed with` row is marked `(!)` — plain ASCII, so it reads the same in a
terminal as in GitHub's renderer — and its expansion is mandatory. A fix row's
one-clause statement of intent is written once and is the string Step 5 hands
the writer. Steps 4, 5 and 10 now render that one definition rather than
restating it, and the ledger comment carries it as the copy that outlives the
run.

AC 8 — live, read-only verification of the classification as written
====================================================================
Comments read through skills/dev-loop-pr-comments/read-comments.mjs. No `gh`
write of any kind, no worktree provisioned, no gate answered: this exercised
Step 3 only.

cli/cli#14007 — "Guard `pr merge --delete-branch` against worktree conflicts",
7 unresolved comments, all 7 classified. Supplied three of the four reasons:

- out of scope for this branch — babakks, pkg/cmd/pr/merge/merge.go:410,
  discussion_r3719732624 ("In a follow-up we can extract git commands used in
  `pr checkout --worktree`"). Evidence: the separate work is a follow-up
  extracting the git commands `pr checkout --worktree` runs so they can reuse
  this branch's `ToplevelDir` — the commenter names it a follow-up himself.

- already addressed — babakks, merge.go stale anchor 431 (outdated),
  discussion_r3719948135 ("**nitpick:** `len(worktrees)` is always `> 0`").
  Evidence: ea3d3191f "Simplify main-worktree head check, drop misleading len
  guard" drops the `len(worktrees) > 0 &&` conjunct the comment calls
  misleading; merge.go is its only file.
  Two more rows took the same reason: discussion_r3720203296 (same commit — its
  new `if` is that comment's suggestion block character for character) and
  copilot-pull-request-reviewer's review body pullrequestreview-4810038780,
  whose two stated grounds are both met by d7fe64365 "Handle head branch checked
  out in main worktree during pr merge cleanup" — it handles that case in
  `deleteLocalBranch` and adds `TestParseWorktrees` to git/client_test.go, the
  direct unit tests the review says are missing.

- disagreed with (!) — babakks, review body pullrequestreview-4863309209, the
  proposal to restructure `deleteLocalBranch` around "where is the head branch
  checked out". Evidence, in full, is the expansion; in short: the reviewer
  states in the same comment that the scenarios are already covered, so the
  restructure changes no behaviour, and rewriting the whole cleanup flow inside
  a pull request that exists to guard one command widens the blast radius of a
  bug fix. Declined outright rather than deferred, which is what separates it
  from the `out of scope` row above.

Two rows classified fix: discussion_r3719711480 (rename `Worktree.Branch` to
`Ref` at git/objects.go:82) and discussion_r3720001340 (return the errors from
`Worktrees` and `ToplevelDir` instead of discarding them — still `worktrees, _
:=` at head). More than one fix row, so a real run would stop at Step 4.

No comment on 14007 classified `question`: the one opening "**question:** why
can't we simplify this `if`-statement" carries a ```suggestion``` block, so it
asks for a change, and ea3d3191f made it — `already addressed`, above.

cli/cli#13948 — "Add issue field support to gh CLI" — supplied the fourth:

- question — zwick, pkg/cmd/issue/create/create.go:102,
  discussion_r3639448805. Evidence, verbatim: "Can I create an issue with
  multiple Issue Field Values?"

No comment across either pull request came back `unclassified`: every one fit an
intent, and every skip's evidence was produced.

Deviation: the changeset was hand-written at .changeset/142-skip-reasons.md
rather than generated with `npm run changeset`, which names files with a random
human-id. Every existing changeset here is named `<issue>-<slug>.md`.
martinholovsky added a commit to martinholovsky/SOTA-skills that referenced this pull request Sep 15, 2026
§3a asserted that `gh pr diff` and the "Files changed" tab use merge-base
semantics. That was inference: the discriminating run I had done measured the
compare API only, and the repo's own history cannot test it -- every merged PR
here was cut from the then-current tip, so base == merge-base for all of them
(checked #379-#382).

Measured on a public PR 42 commits behind its base (cli/cli#13948):

    gh pr diff --name-only      -> 11 files
    pulls/:n/files endpoint     -> 11 files
    compare base...head         -> 11 files
    compare head...base         -> 33 files

The claim holds. The rule and the ledger now state the measurement rather than
the documented intent, per principle 0 -- a doc page states intent, only running
it reports behaviour.

check-invariants.sh: PASS, exit 0.
martinholovsky added a commit to martinholovsky/SOTA-skills that referenced this pull request Sep 15, 2026
…rity regressions (#385)

* Intake the 2026-09-15 EDR field report: two adoptions, one correction, one rejection

A session applying the library on a private security product. Every falsifiable
claim was reproduced here before a verdict.

- sota-docs-workflow rules/03 gains §3a: two-dot `git diff main..pr` compares
  tips, so everything main gained after the fork renders as a deletion on the
  branch's side. The error is directional -- it only ever invents regressions, and
  in a lockfile that reads as a supply-chain attack. The reporter concluded a PR
  downgraded a TLS library past the previous day's advisory fix and wrote it into
  a commit message; the PR did not touch that dependency. Measured on a branch
  four commits behind its base: two-dot 15 files / 742 deletions, three-dot and
  the forge compare API zero. The rule adds why the habit survives -- `git log
  main..feature` is correct while `git diff main..feature` is not -- because
  without that the rule contradicts the reader's experience. Ships with its audit
  half.

- sota-secrets-management rules/04: a working-tree scan does not read .gitignore,
  so an untracked artifact invisible to `git status` is in scope for the gate.
  Verified on gitleaks 8.30.1 with a positive control, after a first attempt using
  the canonical AWS documentation key returned "no leaks found" and would have
  refuted a true finding.

- commands/sota-report.md: it told the agent to write the report into the target
  repo's root and justified that with a fact about THIS repo. Followed literally
  during a gate run it dirties the tree and feeds an unreviewed file to a secret
  scanner, which is what happened.

- The proposed sentence for sota/SKILL.md principle 0 is rejected and the
  reasoning recorded. The rule was loaded and broken, which is adherence, not
  coverage; the reporter themselves graded the wording medium-confidence. The
  router is the only file loaded every session and sits at 470/500.

Correction to the report: it says *.local.md is not ignored in the target repo.
It is, via .git/info/exclude:10. The load-bearing half -- that a directory
scanner never consults ignore status -- is untouched, but the framing invites the
wrong fix.

* Measure the gh pr diff claim instead of inferring it

§3a asserted that `gh pr diff` and the "Files changed" tab use merge-base
semantics. That was inference: the discriminating run I had done measured the
compare API only, and the repo's own history cannot test it -- every merged PR
here was cut from the then-current tip, so base == merge-base for all of them
(checked #379-#382).

Measured on a public PR 42 commits behind its base (cli/cli#13948):

    gh pr diff --name-only      -> 11 files
    pulls/:n/files endpoint     -> 11 files
    compare base...head         -> 11 files
    compare head...base         -> 33 files

The claim holds. The rule and the ledger now state the measurement rather than
the documented intent, per principle 0 -- a doc page states intent, only running
it reports behaviour.

check-invariants.sh: PASS, exit 0.

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

external pull request originating outside of the CLI core team needs-triage needs to be reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants