Commit Graph

3 Commits

Author SHA1 Message Date
Aiden Bai 13138a4af5 refactor: simplify internals across the workspace (#1590) 2026-08-08 00:20:14 -07:00
devin-ai-integration[bot] d241e5105e FABLE_CLEANUP: fix(cli): 20-day audit fixes for the CLI (#1014)
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
Co-authored-by: Rayhan Noufal Arayilakath <me@rayhanadev.com>
2026-07-02 01:31:13 -07:00
Ray Arayilakath 8b91ac8206 fix: make GitHub Actions setup flow idempotent and stop bundling local changes (#906)
* fix(cli): make GitHub Actions setup flow idempotent and stop bundling local changes (#904)

The setup flow opened duplicate PRs and swept unrelated local changes into
the generated branch. Two root causes in `openWorkflowPullRequest`:

1. Non-idempotent: `findUniqueBranchName` only avoided a *local* branch
   collision by appending a timestamp, and nothing checked for an
   already-open setup PR. A re-run (the workflow file lives only on the prior
   PR's branch, so it's re-written each run) minted `…-<timestamp>` branches
   and opened a second PR. Now we `gh pr list` for an open PR whose head is
   under the setup prefix and surface it (`pr-exists`) instead of opening a
   duplicate.

2. Dirty-tree bundling: `git checkout -b <new> origin/<default>` carries the
   index across and the whole-index `git commit` then committed whatever the
   user had staged (modified app files, a deleted/rewritten lockfile). Now we
   bail (`working-tree-dirty`) when the tree has tracked changes other than
   the workflow file itself, falling back to staging the workflow file. The
   workflow path is excluded from the check so the v1→v2 upgrade flow (which
   modifies the tracked workflow in place) still works.

Both callers handle the new `pr-exists` status; the runner / gh-availability
probe are now injectable for hermetic tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(cli): harden setup-flow fix from adversarial review

Findings from an adversarial review+deslop pass over the #904 fix:

- fix(correctness): normalize `workflowRelative` with `toForwardSlashes` so the
  `:!` exclude pathspec matches git's forward-slash repo paths on Windows.
  Without it, `path.relative` yields backslashes there, git's magic pathspec
  doesn't treat them as separators, and the upgrade flow (tracked workflow
  modified in place) would always report `working-tree-dirty` and never open
  the PR. Applied in `openWorkflowPullRequest` and `stageWorkflowFile`.
- fix(correctness): on the upgrade flow's `pr-exists` path, restore the
  original @v1 workflow content. `pr-exists` returns without touching git
  state, so the @v2 edit written before the call would otherwise linger
  uncommitted — matching the pr-opened path's "bump lives only on the PR
  branch" contract.
- chore: extract the `gh pr list` cap to `GH_PR_LIST_MAX` in constants.ts
  (AGENTS.md: no inline magic numbers).
- test: assert the dirty-tree guard skips add/commit/push (not just checkout),
  the happy path stages ONLY the workflow file (no `git add -A`/`.`), and
  branch-pushed keeps the branch (no `git branch -D`) and restores HEAD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(cli): trigger duplicate-PR guard on match presence, not URL truthiness

Bot review (Cursor) flagged that the idempotency short-circuit keyed on a
truthy URL: if `gh pr list` returned a matching setup head branch with a
missing/empty `url`, `findExistingSetupPullRequest` returned null and the
flow could still mint a branch and open a duplicate PR — the exact failure
the guard exists to prevent. `gh` always populates `url` for `--json url`, so
this is defensive, but the headline #904 guarantee shouldn't hinge on it.

Return the matched PR object and short-circuit on its existence; use its url
only for the `pr-exists` message (empty when absent). Adds a regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 18:15:40 -04:00