11 Commits

Author SHA1 Message Date
Copilot 6dcf9f050a Respect repository default branch in gh stack link (#265)
* Initial plan

* Respect repository default branch in gh stack link

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-24 06:54:23 -04:00
Sameen Karim 9dfef64ffb Append to an existing stack by stack number with link (#181)
* link append to stack by number

* updated link docs

* address review comment
2026-07-15 12:07:46 -04:00
Sameen Karim a82dc3ef1d Migrate to new Stacks REST API (#177)
* Add stack Number field to local model and schema

The new Stacks REST API exposes a human-facing stack number (shown in the
github.com UI) alongside the internal stack id. Add a Number field to the
stack.Stack model and document it in schema.json so it can be persisted in
the .git/gh-stack file. Purely additive; behavior is unchanged until callers
populate it.

Copilot-Session: 03673c26-a245-42da-93ed-dfcebc92a740

* Cut over stack operations to the public Stacks REST API

Replace the private cli_internal stack endpoints with the new public
Stacks REST API (/repos/{owner}/{repo}/stacks):
- ListStacks / FindStackForPR (?pull_request= filter) / GetStack for reads
- CreateStack, which now returns the created stack including its number
- AddToStack for delta-only appends (there is no full-replace endpoint)
- Unstack for server-driven removal (204 dissolved / 200 partial / 422)

Migrate all callers (checkout, submit, link, sync, unstack, utils) and
drop the client-side unstack eligibility pre-check — the server now
decides which PRs can be unstacked. checkout discovers stacks via the
pull_request filter; submit/link express updates as append-only deltas;
unstack adopts partial-unstack semantics, keeping local tracking when
PRs remain stacked on GitHub.

RemoteStack now carries the stack number, and stack updates resolve a
stack's number from its internal id for stack files that predate the
Number field.

Copilot-Session: 03673c26-a245-42da-93ed-dfcebc92a740

* Remove the personal access token (PAT) limitation

The new Stacks REST API is public, so any user authenticated with the
GitHub CLI (including via a PAT with repo scope) can perform stack
operations once the feature is enabled for their repository. Remove the
PAT detection and the private-preview gating:

- Delete Config.WarnIfPAT / IsPersonalAccessToken and the TokenForHostFn
  test hook (internal/config/auth.go is no longer needed).
- Drop the submit pre-flight that aborted on a PAT.
- Rename warnStacksUnavailableOrPAT to warnStacksUnavailable and simplify
  it to the "stacked PRs not enabled" message.

Copilot-Session: 03673c26-a245-42da-93ed-dfcebc92a740

* address review comments
2026-07-15 12:07:44 -04:00
Sameen Karim 46b5dc4f78 Fix link failing when an existing stack PR is queued for merge (#171)
gh stack link validated PR eligibility before it fetched the repository's
stacks, so validatePREligibility rejected any queued PR unconditionally —
including one already a member of the stack being updated. Because link is
additive (every existing stack PR must be re-listed or the update is refused
for dropping them), a stack whose bottom PR was in the merge queue could never
take new PRs on top: re-listing the queued PR failed eligibility, and omitting
it failed the drop check.

Fetch the stacks and resolve the target stack before validating eligibility,
then skip the eligibility checks (queued, auto-merge, merged, closed) for any
PR that is already a member of that stack — those PRs are not being added, so
the checks don't apply. PRs not already in the stack, and brand-new stacks,
keep the previous strict behavior. prevalidateStack now takes the resolved
stack instead of looking it up a second time.

Add coverage for linking new PRs onto a stack whose existing PR is queued,
merged, or has auto-merge enabled, and for still rejecting a queued PR that is
not yet part of the target stack.
2026-07-15 12:07:43 -04:00
Sameen Karim 5975945dfd Ignore symlinked pull request templates (#164)
Template discovery in internal/pr read candidate template paths with
os.ReadFile, which follows symlinks. A pull request template that is a
symlink (for example .github/pull_request_template.md pointing to a file
outside the repository) would therefore be read through to its target, and
that target's contents would be used as the PR body by `gh stack submit`
and `gh stack link`.

Reuse cli/cli's githubtemplate package (already a dependency) for template
discovery instead of the hand-rolled path list. It is the same code
`gh pr create` uses, and it ignores symlinked templates, so only regular
template files inside the repository are read. FindTemplate keeps the same
signature, so the submit and link callers are unchanged.

Two behavior changes come with the switch:
- YAML front-matter is stripped from the template, matching `gh pr create`.
- Template filename matching is slightly broader; hyphenated and non-.md
  variants are now recognized.

Add tests for FindTemplate and for the `gh stack submit --auto` and
`gh stack link` PR-creation flows to confirm symlinked templates are not
followed.
2026-07-15 12:07:42 -04:00
Sameen Karim 499985210a parse PR URLs in args (#122)
* Accept PR URLs in link and checkout commands

Add support for GitHub PR URLs (e.g. https://github.com/owner/repo/pull/42)
as arguments to `gh stack link` and `gh stack checkout`, in addition to
the existing PR number and branch name support.

For `link`: PR URLs are parsed in findExistingPR before the numeric check.
Unlike numeric args, if a URL-extracted PR number doesn't exist, the command
errors immediately rather than falling through to branch name lookup (since
a URL can never be a valid branch name).

For `checkout`: PR URLs are parsed in runCheckout before the numeric check,
routing to resolveNumericTarget which supports both local and remote API
fallback — same behavior as passing a PR number directly.

Closes #115

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* update docs

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-15 13:54:18 -04:00
Sameen Karim d235a21a9c alert for unsupported auth tokens (#113)
When users authenticate the GitHub CLI with a personal access token
(PAT) instead of OAuth (`gh auth login`), the `cli_internal` stacks
API endpoints return 404. The CLI previously interpreted this as
"Stacked PRs are not enabled for this repository," which is misleading
— the feature may be enabled, but the token type simply cannot access
the internal endpoints.

This is a recurring source of user confusion. The docs already note
that PATs are not supported, but users don't always read them before
hitting the error.

This change adds token-type detection by inspecting the `gh` auth
token prefix:

  - `gho_`        → OAuth (supported)
  - `ghs_`        → GitHub App installation token (supported)
  - `ghp_`        → Classic PAT (NOT supported)
  - `github_pat_` → Fine-grained PAT (NOT supported)

When a PAT is detected, the CLI now shows:

  ⚠ Personal access tokens are not supported by gh stack
    Run `gh auth login` to authenticate with OAuth instead.

Instead of the misleading:

  ⚠ Stacked PRs are not enabled for this repository

Changes:

- Add `internal/config/auth.go` with auth detection methods on Config:
  `IsPersonalAccessToken()`, `WarnIfPAT()`, and `RepoHost()`. Uses a
  `TokenForHostFn` field on Config for test overrides, following the
  same pattern as `GitHubClientOverride`.

- Add a pre-flight PAT check in `cmd/submit.go` before the
  `ListStacks` call. If a PAT is detected, the command aborts early
  with a clear error instead of making a doomed API call.

- Update all 404 handlers for `cli_internal` endpoints to check the
  token type and show the appropriate message:
  - `cmd/submit.go` (createNewStack)
  - `cmd/link.go` (listStacksSafe, createLink)
  - `cmd/checkout.go` (checkoutRemoteStack)

- Add `warnStacksUnavailableOrPAT()` helper in `cmd/utils.go` that
  shows the PAT-specific warning when applicable, falling back to the
  generic "not enabled" message for non-PAT tokens.

- Add unit tests in `internal/config/auth_test.go` for token prefix
  detection and warning output.

- Add integration tests in `cmd/submit_test.go` verifying that both
  classic PATs (`ghp_`) and fine-grained PATs (`github_pat_`) trigger
  the pre-flight check and abort before any API calls.

- Add `warnStacksUnavailableOrPAT` tests in `cmd/utils_test.go`
  verifying correct message selection based on token type.

- Update existing 404 tests to explicitly set an OAuth token so they
  continue exercising the ListStacks 404 path.
2026-06-15 13:54:17 -04:00
Sameen Karim d2a390f2ff link: block merged, closed, queued, and auto-merge-enabled PRs (#112)
The `link` command previously allowed PRs in any state to be added to a
stack, including PRs that had already been merged, were closed, were
sitting in a merge queue, or had auto-merge enabled. Adding such PRs to
a stack is invalid because they have already been or will soon be merged,
which breaks the stacked PR workflow.

Add a new validation phase (Phase 2b) to `runLink` that checks the
eligibility of every existing PR found during lookup, before any new PRs
are created or stack operations are performed. Only open/draft PRs
without auto-merge enabled are eligible. All ineligible PRs are reported
at once with a clear per-PR error message indicating the specific reason
(merged, closed, in merge queue, or auto-merge enabled).

Changes:

  internal/github/github.go:
  - Add AutoMergeRequest struct and field on PullRequest
  - Add IsAutoMergeEnabled() method on *PullRequest
  - Update FindPRByNumber and FindPRForBranch GraphQL queries to fetch
    the autoMergeRequest field

  internal/github/github_test.go:
  - Add TestPullRequest_IsAutoMergeEnabled (nil, non-nil, nil receiver)

  cmd/link.go:
  - Add pr field to resolvedArg to retain full PR data from lookup
  - Add validatePREligibility() that rejects merged/closed/queued/
    auto-merge-enabled PRs with descriptive error messages
  - Wire validation into runLink between PR lookup and stack operations

  cmd/link_test.go:
  - Add 7 tests covering each disallowed state by PR number and branch
    name, plus a multi-invalid-PR reporting test
2026-06-01 15:54:30 -07:00
Sameen Karim b71b10c268 use PR template when opening PRs (#77)
* use pr template when opening prs

* add a helper to clearly distinguish between filesystem errors and actual test failures
2026-05-11 11:09:31 -04:00
Sameen Karim 13330406ef open PRs as draft by default (#76)
* open prs as draft by default

* apply suggested docs updates from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-11 11:09:30 -04:00
Sameen Karim a00ff54996 link command for api-only operations (#50)
* link cmd for api-only stack upserts

* accept branch names too

* push branches first

* update docs with link cmd details

* adding more logging
2026-04-20 11:19:01 -04:00