Skip to content

feat(git): auto-provision the target repo checkout instead of requiring one - #91

Merged
LukasHirt merged 3 commits into
mainfrom
feat/managed-checkout-clone
Jul 20, 2026
Merged

feat(git): auto-provision the target repo checkout instead of requiring one#91
LukasHirt merged 3 commits into
mainfrom
feat/managed-checkout-clone

Conversation

@LukasHirt

@LukasHirt LukasHirt commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Summary

  • target_repo.checkout used to have to already exist as a manually-cloned repo. git.EnsureCheckout now treats it as a fixed path extctl owns exclusively: clones it via gh repo clone if there's no .git yet, otherwise fetches origin and hard-resets it onto origin/<default_branch>. Since extctl is the only writer to this path, the hard reset is always safe.
  • Stays a real (non-bare) working-tree clone, since the gate's e2e stage runs docker compose directly against files inside it.
  • Wired into cmd/extctl/main.go's PersistentPreRunE, scoped to only the commands that actually touch the target repo (gen, poll, gate, approve-plan, approve-stages, release) — slate/stats/version are unaffected.
  • target_repo.checkout now defaults to ./.extctl-checkout when unset and is resolved to an absolute path at config-load time, same treatment as runs_dir.

Note: independent of #90 (the rebase-before-publish PR) — this branches off main, not off that one.

Test plan

  • go build ./..., go vet ./... clean
  • go test ./... passes, including new TestEnsureCheckout_ClonesWhenMissing / TestEnsureCheckout_FetchesAndResetsWhenPresent in internal/git (the clone path is tested by swapping in a real local git clone in place of gh repo clone, since the latter needs real auth/network)
  • Delete/rename an existing target_repo.checkout locally and confirm extctl poll (or gen) auto-clones it via gh repo clone against the real owncloud/web-extensions remote

🤖 Generated with Claude Code

LukasHirt and others added 2 commits July 20, 2026 16:54
…ng one

target_repo.checkout previously had to already exist — extctl would just
error out (or silently operate on whatever was there) if the path was
missing or stale. That also meant the checkout was implicitly something a
developer might have cloned and be working in themselves, which ruled out
extctl freely keeping it in sync.

git.EnsureCheckout now treats target_repo.checkout as a fixed path extctl
owns exclusively: clones it via `gh repo clone` if there's no .git yet,
otherwise fetches and hard-resets it onto origin/<default_branch>. Because
extctl is the only writer, the hard reset is always safe. It stays a real
working-tree clone (not bare) since the gate's e2e stage runs docker compose
directly inside it.

Wired into cmd/extctl/main.go's PersistentPreRunE, gated to only the
commands that actually touch the target repo (gen, poll, gate, approve-plan,
approve-stages, release) — slate/stats/version are untouched. The checkout
path now defaults to ./.extctl-checkout and is resolved absolute at load
time, same as runs_dir.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Lukas Hirt <info@hirt.cz>
The example still showed checkout: '../web-extensions', directly
contradicting the comment above it that says it defaults to
./.extctl-checkout — a leftover from before target_repo.checkout was
auto-provisioned. Show the actual default explicitly instead, matching how
runs_dir/scaffold_dir/idea_pool are documented elsewhere in the same file.

Also gitignore /.extctl-checkout/ — it's an extctl-managed working directory,
never something to commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Lukas Hirt <info@hirt.cz>
@LukasHirt LukasHirt self-assigned this Jul 20, 2026
@LukasHirt
LukasHirt enabled auto-merge (squash) July 20, 2026 15:03
TestEnsureCheckout_ClonesWhenMissing/_FetchesAndResetsWhenPresent clone into
a fresh directory (seed/otherClone) and then commit into it, but a plain
`git clone` carries no local git config and CI runners have no global one
configured either — commit failed with "Please tell me who you are". Set a
local identity on each clone the same way initRepo already does for its
repos (new configureIdentity helper, shared with internal/git's other tests).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Lukas Hirt <info@hirt.cz>
@LukasHirt
LukasHirt merged commit df8d4e6 into main Jul 20, 2026
3 checks passed
@LukasHirt
LukasHirt deleted the feat/managed-checkout-clone branch July 20, 2026 15:05
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.

1 participant