Skip to content

Issues 2.0: review feedback round - #13411

Merged
BagToad merged 17 commits into
kw/issues-2.0from
kw/issues-2.0-feedback
Jun 4, 2026
Merged

Issues 2.0: review feedback round#13411
BagToad merged 17 commits into
kw/issues-2.0from
kw/issues-2.0-feedback

Conversation

@BagToad

@BagToad BagToad commented May 13, 2026

Copy link
Copy Markdown
Member

Issues 2.0: review feedback round

This PR addresses review feedback on #13057

Fixes

Show Issues 2.0 fields in non-tty gh issue view

Thread: #13057 (comment)
Commit: 1a2293b

Add issue-type, parent, sub-issues, sub-issues-completed, blocked-by, and blocking lines to the raw issue preview, and dedupe the issue-ref formatting helpers along the way.

Reject --add-sub-issue when editing multiple issues

Thread: #13057 (comment)
Commit: ed355a4

A sub-issue can have only one parent, so applying --add-sub-issue across 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 IssueRelationships check.

Apply deferred update mutations in parallel for gh issue edit

Thread: #13057 (comment)
Commit: 0245748

Introduce api.DeferredUpdateIssue to fan out the Issues 2.0 mutations (issue type, parent set/remove, sub-issues, blocked-by, blocking) in parallel and errors.Join their failures so a single error no longer aborts the rest.

Drop the interactive Parent prompt and move Parent off Editable

Commit: 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 Editable as bare flag fields; bring Parent into line so editRun reads Parent / RemoveParent directly when building DeferredUpdateIssueOptions.

Rename --set-parent to --parent

Thread: #13057 (comment)
Commit: 5c783a2

Match the long-standing --milestone / --remove-milestone pattern with --parent / --remove-parent.

Apply deferred update mutations in parallel for gh issue create

Thread: #13057 (comment)
Commit: eb73976

Replace the three sequential applyIssueType / applyParent / applyRelationships helpers in createRun with a single api.DeferredUpdateIssue call so create runs the post-creation Issues 2.0 mutations in parallel like edit does.

Add --remove-type flag to gh issue edit

Thread: #13057 (comment)
Commit: 6bbe6e5

Pair --type with --remove-type (mirroring the --milestone / --remove-milestone and --parent / --remove-parent patterns) so callers can clear an issue's type non-interactively; UpdateIssueIssueType now sends issueTypeId: null when given an empty ID.

Move --type into the search Qualifiers

Threads: #13057 (comment) + #13057 (comment)
Commit: 7285923

SearchQueryBuild was concatenating --type directly into ImmutableKeywords, bypassing pkg/search's quoting. Add an IssueType field on search.Qualifiers tagged qualifier:"type", teach Qualifiers.Map to honour the tag and accumulate values when multiple fields share a key, and drop the bespoke formatting in SearchQueryBuild.

BagToad and others added 10 commits May 12, 2026 14:06
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>
@BagToad
BagToad requested a review from a team as a code owner May 13, 2026 02:53
@BagToad
BagToad requested review from babakks and removed request for a team May 13, 2026 02:53
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.
}
} 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 {

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.

Suggested change
if err = api.DeferredUpdateIssue(apiClient, updateOpts); err != nil {
if err := api.DeferredUpdateIssue(apiClient, updateOpts); err != nil {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressing in #13584

var err error
typeID, err = issueShared.ResolveIssueTypeName(client, baseRepo, opts.IssueType)
if err != nil {
return updateOpts, err

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.

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yeah good idea we can just return nil

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressing in #13584

// 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 ||

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.

Why --type is not among these?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressing in #13584

Signed-off-by: Babak K. Shandiz <babakks@github.com>

@babakks babakks 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, thanks for the changes! 🍻

BagToad added 3 commits June 3, 2026 18:17
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
@BagToad
BagToad merged commit 9511bb9 into kw/issues-2.0 Jun 4, 2026
7 of 8 checks passed
@BagToad
BagToad deleted the kw/issues-2.0-feedback branch June 4, 2026 00: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.

2 participants