Commit graph

877 commits

Author SHA1 Message Date
William Martin
cb2b50576f Ensure huh prompter cleans up 2026-03-26 14:26:57 +01:00
Kynan Ware
84a3ba83e4 fix(huh prompter): remove unused fields and imports
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 14:26:57 +01:00
Kynan Ware
13e47d0078 feat(huh prompter): clear search input after submitting query
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 14:26:17 +01:00
Kynan Ware
cfb2224176 refactor(huh prompter): custom Field for MultiSelectWithSearch
Replace the OptionsFunc-based MultiSelectWithSearch with a custom huh
Field implementation. huh's OptionsFunc runs in a goroutine, causing
data races with selection state and stale cache issues that made
selections disappear on toggle or search changes.

The custom field (multiSelectSearchField) combines a text input and
multi-select list in a single field with full control over the update
loop. Search runs asynchronously via tea.Cmd when the user presses
Enter, with a themed spinner during loading. Selections are stored in
a simple map — no goroutine races, no Eval cache, no syncAccessor.

Also adds defensive validation for mismatched Keys/Labels slices from
searchFunc.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 14:26:17 +01:00
Kynan Ware
f38abbe1ca feat(huh prompter): add placeholder to search input
Add 'Type to search, Ctrl+U to clear' placeholder to the
MultiSelectWithSearch search input. Set WithWidth(80) in the test
harness to prevent textinput placeholder rendering panics when
there is no terminal.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 14:26:17 +01:00
Kynan Ware
38e10d5ebf fix(huh prompter): use synchronized accessors to eliminate data race
Replace Value() pointer bindings with syncAccessor in
MultiSelectWithSearch. huh's OptionsFunc runs in a goroutine while
the main event loop writes field values, causing a data race on
shared variables. syncAccessor implements huh's Accessor interface
with a shared mutex, ensuring all reads and writes are synchronized.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 14:26:17 +01:00
Kynan Ware
95a59f4431 fix(accessible prompter): update test expectations for huh v2
Fix accessible prompter tests that broke with the huh v2 upgrade:
- Replace 'Input a number' with 'Enter a number' (huh v2 changed text)
- Remove trailing CRLF from ExpectString calls that now fail due to
  ANSI color codes wrapping the title text
- Allow ANSI escape codes in password masking regex assertions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 14:26:16 +01:00
Kynan Ware
4d74e057f2 refactor(huh prompter): pipe-based test harness with full coverage
Replace manual model updates with an io.Pipe-based test harness that
drives forms through bubbletea's real event loop. Interaction helpers
(tab(), toggle(), typeKeys(), enter(), etc.) send raw terminal bytes
through io.Pipe to form.Run() in a goroutine.

Add tests for AuthToken, ConfirmDeletion, and InputHostname including
validation rejection paths. Add MultiSelectWithSearch coverage for
persistent options and empty search results.

30 tests, ~1s, all build*Form methods at 94-100% coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 14:26:16 +01:00
Kynan Ware
86d876fd34 test(huh prompter): add table-driven tests for all prompt types
Extract build*Form() methods from each huhPrompter method, separating
form construction from form.Run(). This enables testing the real form
construction code by driving it with direct model updates, adapted
from huh's own test patterns.

Tests cover Input, Select, MultiSelect, Confirm, Password,
MarkdownEditor, and MultiSelectWithSearch including a persistence
test that verifies selections survive across search query changes.

Also fixes a search cache initialization bug where the first
buildOptions("") call would skip the searchFunc due to
cachedSearchQuery defaulting to "".

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 14:26:16 +01:00
Kynan Ware
f294831e7d Upgrade to huh/v2 and fix selection persistence in MultiSelectWithSearch
Migrate from github.com/charmbracelet/huh v1 to charm.land/huh/v2,
updating ThemeBase16 to the new ThemeFunc API.

Fix selected options being lost across searches in the huhPrompter's
MultiSelectWithSearch. The root cause was huh's internal Eval cache:
when the user returned to a previously-seen search query, cached
options with stale .selected state overwrote the current selections
via updateValue(). The fix includes selectedValues in the OptionsFunc
binding hash (via searchOptionsBinding) so the cache key changes
whenever selections change, preventing stale cache hits. A local
searchFunc result cache avoids redundant API calls when only the
selection state (not the query) has changed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 14:26:15 +01:00
Kynan Ware
726714d1a7 Use LayoutStack for huhPrompter MultiSelectWithSearch
Implement a huh-native MultiSelectWithSearch that renders the search
input and multi-select list simultaneously using LayoutStack. The
search input is in Group 0 and the multi-select in Group 1, with
OptionsFunc bound to the search query so results update when the
user presses Enter to advance focus. Users can Shift+Tab back to
refine their search, and selections persist across queries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 14:24:56 +01:00
Kynan Ware
87426ee236 Add experimental huh-only prompter gated by GH_EXPERIMENTAL_PROMPTER
Introduce a new Prompter implementation (huhPrompter) that uses the
charmbracelet/huh library in its standard interactive mode, as an
alternative to the survey-based default prompter. The new implementation
is gated behind the GH_EXPERIMENTAL_PROMPTER environment variable,
following the same truthy/falsey pattern as GH_ACCESSIBLE_PROMPTER.

Key differences from the accessible prompter:
- No WithAccessible(true) flag (full interactive TUI)
- Uses EchoModePassword (masked with *) instead of EchoModeNone
- No default value annotations appended to prompt text

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 14:24:56 +01:00
Kynan Ware
8f7d20855e
Merge pull request #13025 from cli/kw/refactor/reviewer-assignee-actor-symmetry
Consolidate actor-mode signals into ApiActorsSupported
2026-03-25 11:43:18 -06:00
Qingwei Li
e53e360d5b
internal/codespaces/portforwarder: define err in go func instead of use err defined in outer scope
Fixes #13001
2026-03-26 00:31:56 +08:00
Kynan Ware
92f205e54b docs(featuredetection): document GHES removal criteria for ApiActorsSupported
Expand the ApiActorsSupported doc comment to explain the two API
generations (legacy AssignableUser vs actor-based AssignableActor),
what each returns, and the specific GraphQL schema additions to
check for when evaluating GHES support.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 21:15:39 -06:00
Kynan Ware
ae5e857c2e refactor(featuredetection): rename ActorIsAssignable to ApiActorsSupported
Aligns the feature detector field name with the downstream
ApiActorsSupported flag introduced in the previous commit, so the
signal has one consistent name from detection through to consumption.

Also consolidates leftover TODO tags (actorIsAssignableCleanup,
requestReviewsByLoginCleanup) under the single // TODO ApiActorsSupported
tag so there's exactly one thing to grep for.

Pure rename with no logic changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 21:09:04 -06:00
William Martin
c51769c977 Record agentic invocations in User-Agent header
Detect which AI coding agent is invoking gh by checking well-known
environment variables and include the agent name in the User-Agent
header sent to GitHub APIs.

Supported agents: Codex, Gemini CLI, Copilot CLI, OpenCode,
Claude Code, and Amp. Generic AI_AGENT env var is also supported
with validation to prevent header injection.

Fixes github/cli#1111

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 19:58:37 +01:00
Kynan Ware
4f2304d4e5 Remove StateReason feature detection for issue close
The stateReason field was added in GHES ~3.4, which is far older than
the earliest supported GHES version (3.14). The feature detection and
conditional inclusion of stateReason is therefore unnecessary.

This removes:
- StateReason field from IssueFeatures struct
- GHES introspection query in IssueFeatures() (only ActorIsAssignable
  remains, which is always false on GHES)
- Conditional stateReason field inclusion in issue list
- Feature detection guard in issue close
- Feature detection guard in FindIssueOrPR

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-04 13:31:30 -07:00
Kynan Ware
6b56a23970 Remove unnecessary StateReasonDuplicate feature detection
The DUPLICATE enum variant for IssueClosedStateReason was added in
GHES 3.16, which is older than the earliest supported GHES version.
The feature detection check is therefore unnecessary.

Addresses: https://github.com/cli/cli/pull/12811#issuecomment-3997044372

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-04 13:24:05 -07:00
Kynan Ware
38c997567a
Fix incorrect integer conversion from int to uint16 in port forwarder (#12831)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-04 13:01:52 +01:00
Takeshi
b9c8d8e023
Merge branch 'trunk' into issue-close-duplicate-of 2026-03-03 22:03:25 -05:00
Takeshi
2265820853 Combine issue feature detection into a single GraphQL query
Merge the Issue_fields and IssueClosedStateReason_enumValues
introspection queries into one call to avoid an extra API round-trip
on GHES.
2026-03-03 21:51:18 -05:00
Takeshi
01c83acfe8 Add --duplicate-of flag and duplicate reason to gh issue close
Support closing issues as duplicates via --reason duplicate and
--duplicate-of <issue> flags. The --duplicate-of flag accepts an issue
number or URL, validates it references a different issue (not a PR),
and passes the duplicate issue ID to the closeIssue mutation.

Feature detection checks whether the GHES instance supports the
DUPLICATE enum value in IssueClosedStateReason before using it.
2026-02-28 20:10:07 -05:00
Babak K. Shandiz
c9543e7489
fix(licenses): implement VCS-friendly embedding
Signed-off-by: Babak K. Shandiz <babakks@github.com>
2026-02-25 14:59:52 +00:00
William Martin
7ea88b1c4d
Bundle licenses at release time (#12625)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-02-18 17:59:27 +01:00
William Martin
8dcfd330e7
Add --query flag to project item-list (#12696)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Babak K. Shandiz <babakks@github.com>
2026-02-18 16:34:13 +01:00
Babak K. Shandiz
52eca96873
refactor(featuredetection): remove temp in favour of early returns
Signed-off-by: Babak K. Shandiz <babakks@github.com>
2026-02-17 11:46:33 +00:00
Babak K. Shandiz
61ab5e0b5d
docs(featuredetection): fix typo in comment
Signed-off-by: Babak K. Shandiz <babakks@github.com>
2026-02-16 13:07:24 +00:00
Babak K. Shandiz
b64dd58d8b
test(featuredetection): fix test case name
Signed-off-by: Babak K. Shandiz <babakks@github.com>
2026-02-16 13:06:23 +00:00
Babak K. Shandiz
33825477ae
test(featuredetection): add tests for ActionsFeatures
Signed-off-by: Babak K. Shandiz <babakks@github.com>
2026-02-16 11:54:07 +00:00
Babak K. Shandiz
a0dea00fdd
fix(featuredetection): add ActionsFeatures to detect workflow dispatch features
Signed-off-by: Babak K. Shandiz <babakks@github.com>
2026-02-16 11:53:33 +00:00
Kynan Ware
a33d809c88
Apply suggestions from code review
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-26 15:09:16 -07:00
Kynan Ware
af124cd5d2 Add test for MultiSelectWithSearch error propagation
Introduces a test case to verify that errors returned from the MultiSelectWithSearch search function are properly propagated to the caller.
2026-01-26 13:56:47 -07:00
Kynan Ware
38f9d7891b Fix linter and mock prompter signature 2026-01-26 13:29:22 -07:00
Kynan Ware
07dfdf97ae Update edit tests
Updated test mocks and logic to consistently use lowercase 'monalisa' for login names and display names for user assignees. Improved handling of dynamic assignee fetching in interactive flows by relying on searchFunc and metadata population, and clarified logic in FetchOptions to fetch assignees only when necessary. These changes ensure more accurate simulation of interactive assignment and better test coverage for actor assignee features.
2026-01-26 13:29:22 -07:00
Kynan Ware
d46f42a752 Refactor MultiSelectWithSearch to use result struct
Refactored the MultiSelectWithSearch function and related interfaces to use a MultiSelectSearchResult struct instead of multiple return values. This change improves clarity and extensibility of the search function signature, and updates all usages, mocks, and tests accordingly.
2026-01-26 13:29:22 -07:00
Kynan Ware
38578f7991 Add comment describing logger
Added a comment explaining how to enable logging in expect-based tests by using expect.WithLogger. This helps developers debug by printing characters read to stdout.
2026-01-26 13:29:22 -07:00
Kynan Ware
0beb74bf72 MultiSelectWithSearch initial implementation
Initial implementation of MultiSelectWithSearch:

- Implement by survey and accessible prompters. They use the same internal func under the hood.
- Implement in `gh preview prompter` for initial testing and demonstration
- Implement interface changes across the codebase and mocks to satisfy compiler.
- Implement tests for new MultiSelectWithSearch prompter
2026-01-26 13:29:22 -07:00
Babak K. Shandiz
0f32f2ac46
refactor(run download): extract zip extraction func into a separate package
Signed-off-by: Babak K. Shandiz <babakks@github.com>

Co-authored-by: Kynan Ware <bagtoad@github.com>
Co-authored-by: Devraj Mehta <devm33@github.com>
2026-01-19 10:38:21 +00:00
William Martin
d88b4cb8ec Fix accessible prompter tests with huh 0.8.0 upgrade 2025-12-02 14:36:43 +01:00
Kynan Ware
152d328db8
Merge pull request #12084 from cli/babakks/add-basic-linters
chore: add basic linters
2025-11-04 10:46:40 -07:00
Babak K. Shandiz
895c314c5c
Merge pull request #12064 from cli/babakks/add-isimmutable-to-release-list
Add `isImmutable` to `release list` JSON output
2025-11-04 12:43:36 +00:00
Babak K. Shandiz
f498f2e882
fix: resolve copyloopvar issues
Signed-off-by: Babak K. Shandiz <babakks@github.com>
2025-11-03 20:05:26 +00:00
Babak K. Shandiz
26552f3489
fix(featuredetection): add ReleaseFeatures method
Signed-off-by: Babak K. Shandiz <babakks@github.com>
2025-10-31 19:52:09 +00:00
Babak K. Shandiz
139c2c4f9a
refactor: replace backport with strings.CutSuffix
The `cutSuffix` function was added to backport the functionality of
`strings.CutSuffix` from Go 1.20. Now that we're using Go 1.25, we can
safely replace our backport with the standard library function. Our
backport was an intact copy/paste of the stdlib implementation, so this
change does not alter any behavior.

Signed-off-by: Babak K. Shandiz <babakks@github.com>
2025-10-31 12:21:02 +00:00
Babak K. Shandiz
ae9a7ed542
refactor(authflow): receive HTTP client via args
Signed-off-by: Babak K. Shandiz <babakks@github.com>
2025-10-13 16:48:10 +01:00
Babak K. Shandiz
37896d613a
fix(featuredetection): remove redundant AdvancedIssueSearchWebInIssuesTab field
Signed-off-by: Babak K. Shandiz <babakks@github.com>
2025-09-08 18:46:28 +01:00
Babak K. Shandiz
43bedab2dc
docs(featuredetection): remove unknown dates
Signed-off-by: Babak K. Shandiz <babakks@github.com>
2025-09-08 18:39:55 +01:00
Babak K. Shandiz
d56a902a07
docs(featuredetection): add godoc for min GHES version for advanced issue search
Signed-off-by: Babak K. Shandiz <babakks@github.com>
2025-09-02 12:09:38 +01:00
Babak K. Shandiz
87bd76c5aa
docs: add cleanup/future TODO marks for advanced issue search changes
Signed-off-by: Babak K. Shandiz <babakks@github.com>
2025-09-01 13:55:49 +01:00