Issues 2.0: review feedback round - #13411
Merged
Merged
Conversation
Add issue-type, parent, sub-issues, sub-issues-completed, blocked-by, and blocking lines to the raw issue preview. Empty values still print to keep line counts stable for head|grep workflows. Pull the issue-ref formatting into a small set of helpers so the human and machine renderers share a single owner/repo#N source of truth. formatLinkedIssueRef no longer takes baseRepo: callers in this package always have repository.nameWithOwner on the LinkedIssue, so the disambiguation between same-repo and cross-repo references is no longer needed and the resulting refs are unambiguous. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A sub-issue can have only one parent, so applying --add-sub-issue across multiple parent args is ambiguous. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Non-interactive mode resolves the type once before the loop instead of every iteration. Interactive mode still resolves inside the loop after the survey populates IssueType.Value. Both paths share a small lookupIssueTypeID helper. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Let the API return its own "unsupported" error rather than gating the relationship mutations behind a client-side IssueRelationships check. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Issues 2.0 mutations (issue type, parent set/remove, sub-issues, blocked-by, blocking) are deferred until after the main UpdateIssue because they target IDs that the standard mutation does not handle. Move them behind a shared api.DeferredUpdateIssue orchestrator that fans them out in parallel and joins all errors so a single failure does not abort the rest. editRun no longer carries its own applyEditParent / applyEditSubIssues / applyEditRelationships helpers; the per-issue goroutine resolves refs to node IDs via a small deferredUpdateIssueOptions builder, then hands the populated DeferredUpdateIssueOptions to api.DeferredUpdateIssue. Also moves ResolveIssueRef and ResolveIssueTypeName from the deleted resolve.go into lookup.go. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The interactive Parent prompt was a free-text input with no candidate-listing UX, an oversight from the initial Issues 2.0 landing. Sub-issues, blocked-by, and blocking already live as bare flag fields outside of Editable for the same reason; bring Parent into line. editRun now reads opts.SetParent / opts.RemoveParent directly when constructing DeferredUpdateIssueOptions, and the survey machinery no longer sees Parent at all. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The --milestone / --remove-milestone pair has long been the established pattern for value-takes-or-removes flag pairs in gh issue edit. Bring --set-parent into line as --parent / --remove-parent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The post-creation Issues 2.0 mutations (issue type, parent, blocked-by, blocking) ran sequentially in three separate apply* helpers. Replace them with a single call to api.DeferredUpdateIssue, which fans the mutations out in parallel and joins their errors. The new newCreateDeferredOpts helper resolves the user-supplied refs to node IDs (re-using the cached opts.issueTypeID from the interactive prompt) and hands them to the orchestrator. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pair --type with --remove-type so callers can clear an issue's type without going through the interactive editor, mirroring the --milestone / --remove-milestone and --parent / --remove-parent patterns. The two type flags are mutually exclusive. UpdateIssueIssueType now sends a null issueTypeId when the caller passes an empty string, which is what the API requires to clear the field. The orchestrator fires the mutation when either IssueTypeID is non-empty or RemoveIssueType is set. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The --type filter was concatenated into ImmutableKeywords in SearchQueryBuild, which bypassed search.Query's quoting and let values that contained quotes (or extra qualifiers) corrupt the final query. Per babakks's suggestion in the review thread, model it as a regular qualifier instead. Add an IssueType field to Qualifiers tagged `qualifier:"type"` so it shares a key with the existing Type field, and rework Qualifiers.Map to honour the tag and concatenate values when multiple fields share the same key. SearchQueryBuild now drops its bespoke type:X formatting and just sets Qualifiers.IssueType, leaving the keyword/qualifier escaping to pkg/search. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The field gates whether the interactive survey offers the field as a choice; rename so the name reflects intent and add a godoc. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A sub-issue can have only one parent, so when --add-sub-issue is given a candidate that already belongs to another parent the addSubIssue mutation 422s with "Sub issue may only have one parent". Pass replaceParent: true on this path so the take-over is silent.
Cover the new flag surface end to end against a real GitHub repo: issue type set/remove on create and edit, parent set/remove on create and edit, sub-issue add/remove (including the silent take-over of an existing parent), blocked-by/blocking add/remove on create and edit, list filtering by type, and the new non-tty view fields. Live in a dedicated TestIssues2_0 suite so they're easy to run in isolation.
babakks
reviewed
May 13, 2026
| } | ||
| } else if len(opts.BlockedBy) > 0 || len(opts.Blocking) > 0 { | ||
| err = fmt.Errorf("issue relationships are not supported on this GitHub Enterprise Server version") | ||
| if err = api.DeferredUpdateIssue(apiClient, updateOpts); err != nil { |
Member
There was a problem hiding this comment.
Suggested change
| if err = api.DeferredUpdateIssue(apiClient, updateOpts); err != nil { | |
| if err := api.DeferredUpdateIssue(apiClient, updateOpts); err != nil { |
| var err error | ||
| typeID, err = issueShared.ResolveIssueTypeName(client, baseRepo, opts.IssueType) | ||
| if err != nil { | ||
| return updateOpts, err |
Member
There was a problem hiding this comment.
Why still return the half-baked updateOpts while the caller doesn't really need it (it bails out on error)?
This also applies to the rest of this function.
Member
Author
There was a problem hiding this comment.
yeah good idea we can just return nil
| // Sub-issue and relationship flags are outside the Editable pattern | ||
| // but still need to prevent interactive mode. | ||
| hasRelationshipFlags := len(opts.AddSubIssues) > 0 || len(opts.RemoveSubIssues) > 0 || | ||
| hasDeferredFlags := opts.RemoveIssueType || |
Signed-off-by: Babak K. Shandiz <babakks@github.com>
babakks
approved these changes
May 26, 2026
babakks
left a comment
Member
There was a problem hiding this comment.
LGTM, thanks for the changes! 🍻
Add acceptance tests for non-interactive Issues 2.0 flows
…add-sub-issue Overwrite existing parent on `gh issue edit --add-sub-issue`
Rename Editable.Allowed to Selectable
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Issues 2.0: review feedback round
This PR addresses review feedback on #13057
Fixes
Show Issues 2.0 fields in non-tty
gh issue viewThread: #13057 (comment)
Commit: 1a2293b
Add
issue-type,parent,sub-issues,sub-issues-completed,blocked-by, andblockinglines to the raw issue preview, and dedupe the issue-ref formatting helpers along the way.Reject
--add-sub-issuewhen editing multiple issuesThread: #13057 (comment)
Commit: ed355a4
A sub-issue can have only one parent, so applying
--add-sub-issueacross multiple parent args is ambiguous; reject the combination at flag-parse time.Hoist issue-type ID lookup out of the per-issue edit loop
Thread: #13057 (comment)
Commit: 8f9069b
Resolve the type once before the loop in non-interactive mode rather than every iteration; interactive mode still resolves inside the loop after the survey runs.
Drop client-side feature detection for issue relationships
Thread: #13057 (comment)
Commit: 315dafb
Let the API return its own "unsupported" error rather than gating the relationship mutations behind a client-side
IssueRelationshipscheck.Apply deferred update mutations in parallel for
gh issue editThread: #13057 (comment)
Commit: 0245748
Introduce
api.DeferredUpdateIssueto fan out the Issues 2.0 mutations (issue type, parent set/remove, sub-issues, blocked-by, blocking) in parallel anderrors.Jointheir failures so a single error no longer aborts the rest.Drop the interactive Parent prompt and move Parent off
EditableCommit: e87ccc5
The interactive Parent prompt was a free-text input with no candidate listing, an oversight from the initial Issues 2.0 landing. Sub-issues, blocked-by, and blocking already sit outside
Editableas bare flag fields; bring Parent into line so editRun readsParent/RemoveParentdirectly when buildingDeferredUpdateIssueOptions.Rename
--set-parentto--parentThread: #13057 (comment)
Commit: 5c783a2
Match the long-standing
--milestone/--remove-milestonepattern with--parent/--remove-parent.Apply deferred update mutations in parallel for
gh issue createThread: #13057 (comment)
Commit: eb73976
Replace the three sequential
applyIssueType/applyParent/applyRelationshipshelpers increateRunwith a singleapi.DeferredUpdateIssuecall so create runs the post-creation Issues 2.0 mutations in parallel like edit does.Add
--remove-typeflag togh issue editThread: #13057 (comment)
Commit: 6bbe6e5
Pair
--typewith--remove-type(mirroring the--milestone/--remove-milestoneand--parent/--remove-parentpatterns) so callers can clear an issue's type non-interactively;UpdateIssueIssueTypenow sendsissueTypeId: nullwhen given an empty ID.Move
--typeinto the search QualifiersThreads: #13057 (comment) + #13057 (comment)
Commit: 7285923
SearchQueryBuildwas concatenating--typedirectly intoImmutableKeywords, bypassingpkg/search's quoting. Add anIssueTypefield onsearch.Qualifierstaggedqualifier:"type", teachQualifiers.Mapto honour the tag and accumulate values when multiple fields share a key, and drop the bespoke formatting inSearchQueryBuild.