Commit graph

11267 commits

Author SHA1 Message Date
Kynan Ware
dbe8e34121 Overwrite existing parent on --add-sub-issue
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.
2026-05-12 21:35:50 -06:00
Kynan Ware
6106bd3076 Rename Editable.Allowed to Selectable
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>
2026-05-12 21:18:18 -06:00
Kynan Ware
72859237e2 Move --type into the search Qualifiers
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>
2026-05-12 20:40:02 -06:00
Kynan Ware
6bbe6e5bac Add --remove-type flag to gh issue edit
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>
2026-05-12 20:28:56 -06:00
Kynan Ware
eb7397695f Apply deferred update mutations in parallel for gh issue create
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>
2026-05-12 20:18:53 -06:00
Kynan Ware
5c783a229b Rename --set-parent to --parent for milestone-style symmetry
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>
2026-05-12 20:06:34 -06:00
Kynan Ware
e87ccc5fca Drop interactive Parent prompt and move Parent off Editable
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>
2026-05-12 19:56:45 -06:00
Kynan Ware
02457482a5 Apply deferred update mutations in parallel for gh issue edit
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>
2026-05-12 19:38:55 -06:00
Kynan Ware
315dafbf74 Drop client-side feature detection for issue relationships
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>
2026-05-12 14:58:54 -06:00
Kynan Ware
8f9069b275 Hoist issue-type ID lookup out of the per-issue edit loop
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>
2026-05-12 14:36:20 -06:00
Kynan Ware
ed355a474f Reject --add-sub-issue when editing multiple issues
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>
2026-05-12 14:16:06 -06:00
Kynan Ware
1a2293b6e0 Show Issues 2.0 fields in non-tty view output
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>
2026-05-12 14:06:23 -06:00
Kynan Ware
d1363a9e5b Use strongly-typed githubv4 form for new issue mutations
The pinned githubv4 version pre-dates these Issues 2.0 input types, so
the input structs are defined locally to match the pattern in
ReplaceActorsForAssignableByLogin.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-07 11:52:57 -06:00
Kynan Ware
628325920d Reject cross-host issue refs in ResolveIssueRef
Relationship mutations (parent, sub-issue, blocked-by, blocking) run
against baseRepo's host with node IDs that must come from that same
host. Catch a different-host ref up front with a clear error instead
of letting the mutation fail with a confusing node-ID error.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 18:04:48 -06:00
Kynan Ware
eff9d48f6e Replace em-dashes with hyphens in code comments
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:33:29 -06:00
Kynan Ware
0c48bd0981 Cache issue-type name->ID map and use it in issue edit
prShared.FetchOptions already fetches RepoIssueTypes when IssueType is
edited, but only kept the names. editRun then called RepoIssueTypes a
second time via ResolveIssueTypeName.

Have FetchOptions store the name->ID map on Editable, and look the ID
up directly in editRun. The lookup now also lives inside the per-issue
loop, which fixes a bug where the interactive type prompt's chosen
value was set after the upfront resolve, sending an empty issueTypeId
on the mutation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 17:12:29 -06:00
Kynan Ware
e9f102e8be Test interactive issue-type prompt in createRun
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 16:42:36 -06:00
Kynan Ware
85ee04d0fd Exercise loop in blocked-by/blocking createRun test
Two values per relationship verifies each ref is resolved and applied
independently rather than masking a single-iteration bug.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 16:31:02 -06:00
Kynan Ware
a04438c22c Merge createRun_issuesV2 cases into Test_createRun
Same code path, same scope. Test_createRun's httpStubs signature picks
up *testing.T to match the V2 cases that need it for input assertions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 16:27:22 -06:00
Kynan Ware
201eb7ec5e Merge issuesV2Flags cases into TestNewCmdCreate
The five Issues 2.0 cases (type, parent by number, parent by URL,
blocked-by, blocking) live as a separate parallel test today. They
exercise the same NewCmdCreate code path as the existing cases, so
fold them into TestNewCmdCreate and extend the assertions to cover
IssueType, Parent, BlockedBy, and Blocking.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 16:22:45 -06:00
Kynan Ware
5987cb3be4 Add Issue.ExportData tests for Issues 2.0 fields
Cover the JSON shape of issueType, parent, subIssues, subIssuesSummary,
blockedBy, and blocking, including the null cases for issueType and
parent.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 16:18:01 -06:00
Kynan Ware
a78bedb772 Wrap relationship JSON output in {nodes, totalCount}, fetch full pages
The subIssues, blockedBy, and blocking JSON output is currently shaped
as a flat array, which silently truncates when there are more entries
than the GraphQL fragment fetches. That's misleading once a user
crosses the page size, so this switches each connection to a
{nodes, totalCount} object so consumers can see when there's more.

While confirming page sizes, the GitHub limits turn out to be:

- sub-issues: up to 100 per parent
  https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/adding-sub-issues
- blocked-by / blocking: up to 50 per relationship type
  https://github.blog/changelog/2025-08-21-dependencies-on-issues/

So subIssues moves to first:100 to fetch the full set; blockedBy and
blocking stay at first:50, which already covers their cap.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 16:05:07 -06:00
Kynan Ware
20105edbcb Include id in linked-issue JSON exports
Add id to the GraphQL fragment for subIssues, blockedBy, and blocking
nodes so the canonical node identifier is fetched, and surface it in
the JSON output alongside number/title/url/state for parent, subIssues,
blockedBy, and blocking.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 15:54:39 -06:00
Kynan Ware
469438ebc5 Remove redundant nil check in IssueNodeID
GraphQL already returns an error when the repository or issue does not
exist, making the empty-ID check unreachable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 15:52:21 -06:00
Kynan Ware
e3ce7e5225 Add json tags to SubIssues and LinkedIssueConnection
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 15:45:13 -06:00
Kynan Ware
6e76f11dec fix: correct GraphQL field name in AddBlockedBy/RemoveBlockedBy mutations
The AddBlockedByPayload and RemoveBlockedByPayload types expose
the result as 'issue', not 'blockedIssue'. Found during live spec
testing against github.com — the mutations returned empty responses.

Updated mutation queries and corresponding test fixtures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
Kynan Ware
e3b0d9dec3 fix: restore displaced TODO comment, add GHES edit relationship test
- Restore // TODO projectsV1Deprecation comment above
  TestProjectsV1Deprecation (was displaced when new tests were
  inserted at that location)
- Add 'relationships unsupported on GHES' test case to edit command
  using DisabledDetectorMock (parity with create's GHES tests)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
Kynan Ware
4a196ddf1d test: add regression test for issue-only fields in FieldsToEditSurvey
Verifies Type and Parent only appear in the interactive picker when
Allowed is explicitly set. Prevents regression where issue-only
fields leak into gh pr edit's interactive mode.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
Kynan Ware
2a72a59f76 fix: address round 2 code review findings
- Fix PR edit regression: gate Type and Parent behind Allowed bool
  in FieldsToEditSurvey, matching the Reviewers.Allowed pattern.
  Only issue edit sets Allowed=true; PR edit won't show these fields.
- Add missing RemoveBlocking assertion in flag parsing tests
- Quote issue type names containing spaces in search queries
  (type:"Bug Report" instead of type:Bug Report)
- Remove duplicate TODO comment in view.go
- Avoid double RepoIssueTypes API call in interactive create:
  cache the resolved ID from the picker, skip re-resolution
- Rename applyIssueTypes → applyIssueType (singular)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
Kynan Ware
b6f29b0376 feat: add --remove-blocking flag to issue edit
Completes the symmetry of relationship flags:
- --add-blocked-by / --remove-blocked-by
- --add-blocking / --remove-blocking

The --remove-blocking flag swaps API args (same as --add-blocking):
calls RemoveBlockedBy(issueId=OTHER, blockingIssueId=THIS).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
Kynan Ware
3f1df513c5 test: add missing --type flag tests for issue list
Add flag parsing and behavior tests for gh issue list --type:
- TestNewCmdList/type_flag: verifies opts.IssueType is set
- Test_issueList/with_issue_type: verifies search path is forced
  and query includes type:Bug qualifier

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
Kynan Ware
c00bc6a9b4 fix: address code review findings from multi-model review
Critical fixes:
- GHES data-flow regression: blockedBy/blocking fields now
  conditionally added to view lookupFields only when
  IssueRelationshipsSupported is true (GHES 3.19+). Previously
  would break gh issue view on GHES 3.17-3.18.
- State line separator: restore original bullet (•) to avoid
  breaking downstream parsers. Issue type prefix uses middle dot (·).

Optimizations:
- Batch edit --type: resolve issueTypeID once before the loop
  instead of per-goroutine (eliminates N-1 redundant API calls)
- Parent removal: include id in parent GraphQL fragment, use
  issue.Parent.ID directly instead of extra IssueNodeID lookup

Nit fixes:
- Fix formatLinkedIssueRef godoc to match actual behavior

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
Kynan Ware
ddb2fce07b refactor: extract shared helpers for issue ref resolution and type lookup
Address code review findings:

- Extract resolveIssueRef into shared.ResolveIssueRef (was duplicated
  between create.go and edit.go)
- Extract issue type name→ID resolution into shared.ResolveIssueTypeName
  (was duplicated between create applyIssueTypes and edit applyEditIssueType)
- Fix double import of issue/shared in view.go

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
Kynan Ware
4c12393b88 test: add comprehensive tests for Issues 2.0 features
Create tests (11 new):
- Flag parsing: --type, --parent (number/URL), --blocked-by, --blocking
- Behavior: type resolution + mutation, type not found error,
  parent resolution + addSubIssue, blocked-by/blocking with
  swapped args verification, GHES unsupported error

Edit tests (18 new):
- Flag parsing: --type, --set-parent, --remove-parent, mutual
  exclusivity, --add-sub-issue, --remove-sub-issue,
  --add-blocked-by, --remove-blocked-by, --add-blocking
- Behavior: type edit, set/remove parent, add/remove sub-issues,
  add/remove blocked-by, add-blocking with swapped args,
  batch edit type across multiple issues
- Bug fix: copy SetParent value into Editable.Parent.Value

View tests (5 new):
- TTY: full view with all Issues 2.0 fields, regression test
  with no new fields
- JSON: issueType export, parent/subIssues/subIssuesSummary
  export, blockedBy/blocking export

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
Kynan Ware
67f63a1096 feat: add --type filter flag to issue list
Filter issues by type using the search API path. The --type flag
appends a type: qualifier to the search query, forcing the search
path (same as --label and --milestone).

Updated FilterOptions with IssueType field, IsDefault(), and
SearchQueryBuild() to include the type qualifier.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
Kynan Ware
b7ee31d791 feat: add Issues 2.0 flags to issue edit
New flags for issue edit:
- --type: set issue type by name
- --set-parent / --remove-parent: set or remove parent issue
  (mutually exclusive via cmdutil.MutuallyExclusive)
- --add-sub-issue / --remove-sub-issue: manage sub-issues
- --add-blocked-by / --remove-blocked-by: manage blocked-by relationships
- --add-blocking: add blocking relationships (swaps API args)

Interactive mode: Type and Parent added to the field picker survey.
FetchOptions loads issue types when Type is selected.

Editable struct: added IssueType and Parent fields with Dirty(),
Clone(), FieldsToEditSurvey, and EditFieldsSurvey support.

GHES: relationships gated behind IssueRelationshipsSupported.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
Kynan Ware
44e9f4bd50 feat: add --type, --parent, --blocked-by, --blocking to issue create
Post-creation mutations for Issues 2.0 fields:
- --type: resolve type name to ID via RepoIssueTypes, then
  updateIssueIssueType mutation
- --parent: resolve issue ref (number or URL), then addSubIssue
  mutation (supports cross-repo URLs)
- --blocked-by: resolve refs, then addBlockedBy mutations
- --blocking: resolve refs, then addBlockedBy with swapped args

Interactive mode: type picker when repo has issue types configured.

GHES: relationships gated behind IssueRelationshipsSupported feature
detection (3.19+). Types and sub-issues need no detection (GA 3.17+).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
Kynan Ware
7dae882c9d feat: add Issues 2.0 fields to issue view
Display new issue metadata in TTY view:
- Issue type on state line (gray, before Open/Closed)
- Type, Parent, Blocked by, Blocking metadata rows
- Sub-issues section with completion progress (X/Y, Z%)
- Cross-repo references show full owner/repo#N format

All new fields included in defaultFields and JSON export.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
Kynan Ware
c00257386e feat: add Issues 2.0 API types, mutations, and feature detection
Add API infrastructure for issue types, sub-issues, and issue
relationships (blocked-by/blocking):

- New types: IssueType, LinkedIssue, SubIssues, SubIssuesSummary,
  LinkedIssueConnection
- New Issue struct fields for all Issues 2.0 data
- GraphQL query builder cases for new fields
- ExportData cases for JSON output
- Mutation functions: UpdateIssueIssueType, AddSubIssue,
  RemoveSubIssue, AddBlockedBy, RemoveBlockedBy
- Helper functions: RepoIssueTypes, IssueNodeID
- Feature detection: IssueRelationshipsSupported for GHES 3.19+
  (issue types and sub-issues are GA on GHES 3.17+, no detection needed)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 08:49:43 -06:00
tidy-dev
611b01f6c8
Merge pull request #13312 from cli/enable-pr-screening
Enable extended PR screening for external PRs
2026-04-30 07:59:51 -04:00
tidy-dev
8b89c8b2b2 Enable extended PR screening for external PRs
Opts in to the new PR screening features in the shared triage workflow:
- Instantly closes PRs with zero file changes
- Detects same-author resubmissions of recently closed PRs
- Fast-tracks small, well-described fixes to ready-for-review
- Accelerates closure of large unsolicited PRs (3 days vs 7)

Depends on desktop/gh-cli-and-desktop-shared-workflows#17

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-29 09:43:23 -04:00
William Martin
d762f9e232
Merge pull request #13304 from pdostal/fix/accessible-prompter-password-test-timeout
Fix flaky accessible prompter Password test timeout
2026-04-28 18:47:53 +02:00
William Martin
fae293f8e8
Merge pull request #13303 from pdostal/fix/add-integration-build-tag
Add missing //go:build integration tag to verify_integration_test.go
2026-04-28 18:34:25 +02:00
Pavel Dostál
6d6ea5f371 Fix flaky Password test by increasing echo mode setup timeout
The beforePasswordSendTimeout was set to 100 microseconds, which is
insufficient for huh to disable echo mode on the PTY in slow or
constrained environments (e.g. network-isolated build containers).
Increase to 100 milliseconds to avoid the race condition.
2026-04-28 18:25:51 +02:00
Pavel Dostál
20e4d25147 Add missing //go:build integration tag to verify_integration_test.go
The four tests in this file (TestVerifyIntegration,
TestVerifyIntegrationCustomIssuer, TestVerifyIntegrationReusableWorkflow,
TestVerifyIntegrationReusableWorkflowSignerWorkflow) call
NewLiveSigstoreVerifier which requires network access to Sigstore and
GitHub TUF servers. Unlike the other integration test files in this
package (attestation_integration_test.go, sigstore_integration_test.go,
inspect_integration_test.go), this file was missing the //go:build
integration tag, causing these tests to run during a regular
'go test ./...' and fail in network-isolated build environments.
2026-04-28 18:20:23 +02:00
William Martin
bd4a06aab7
Merge pull request #13297 from cli/dependabot/github_actions/goreleaser/goreleaser-action-7.2.1
chore(deps): bump goreleaser/goreleaser-action from 7.0.0 to 7.2.1
2026-04-28 16:32:29 +02:00
William Martin
6c470f6080
Merge pull request #13281 from maxbeizer/fix/projects-v2-ignorable-error
Add "Resource not accessible" to ProjectsV2IgnorableError
2026-04-28 12:16:54 +02:00
William Martin
697f7f64ee
Merge pull request #13301 from cli/bump-go-1.26.2
Bump Go to 1.26.2
2026-04-28 11:32:21 +02:00
cli automation
06ac7b6e0a Bump Go to 1.26.2 2026-04-28 11:22:34 +02:00
Babak K. Shandiz
e41ec700c1
Merge pull request #13298 from cli/dependabot/go_modules/github.com/mattn/go-isatty-0.0.22
chore(deps): bump github.com/mattn/go-isatty from 0.0.21 to 0.0.22
2026-04-28 08:31:39 +01:00