Files
agent-tools/cmd/agentws/main_test.go
T
unkin-agent 6a82b88947
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline failed
ci/woodpecker/pr/pre-commit Pipeline was successful
Add agentws worktree-management binary
agentws manages per-branch git worktrees for the unkin-agent user: it clones
repos into the source root (~/src/prodenv/<repo>) so branches are visible in
Ben's main checkout, and creates isolated worktrees under the worktree root
(~/.cache/agentws/<repo>__<branch>).

- New internal/agent/git.go: small, testable git helpers shelling out to the
  git binary (clone/fetch/worktree add/remove/list/prune, branch + config ops,
  porcelain parsing, path sanitizing). No go-git dependency.
- New cmd/agentws: new / list / rm / clean / token / credential subcommands.
  Auth uses an ephemeral git credential helper (agentws credential get) so the
  ~1h Gitea token is never persisted in a remote URL or config; per-worktree
  config keeps the shared checkout's identity untouched.
- Wire agentws into Makefile, scripts/build-rpm.sh, packaging/nfpm.yaml (binary
  + bash/zsh/fish completions), .woodpecker/release.yaml (cross-compile + assets)
  and .gitignore.
- Tests: table tests for parsing/sanitizing/dir-naming, a real temp-git repo for
  the worktree lifecycle, and hermetic cmd tests (bad input + credential-helper
  host guard) that never touch the network.
- Document agentws in README.md and AGENTS.md.
2026-08-15 12:21:08 +10:00

64 lines
1.8 KiB
Go

package main
import (
"bytes"
"io"
"strings"
"testing"
)
// `new` with a bad repo name (contains a slash) must fail before any network
// call, keeping the test hermetic.
func TestNewRejectsOwnerQualifiedRepo(t *testing.T) {
cmd := newRootCmd()
cmd.SetArgs([]string{"new", "unkin/argocd-apps", "--branch", "benvin/x"})
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
if err := cmd.Execute(); err == nil {
t.Fatal("Execute() = nil, want error for owner-qualified repo name")
}
}
// `new` without --branch must fail (cobra required-flag check) before any
// network call.
func TestNewRequiresBranch(t *testing.T) {
cmd := newRootCmd()
cmd.SetArgs([]string{"new", "argocd-apps"})
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
if err := cmd.Execute(); err == nil {
t.Fatal("Execute() = nil, want error when --branch is missing")
}
}
// An unknown credential action must fail.
func TestCredentialUnknownAction(t *testing.T) {
cmd := newRootCmd()
cmd.SetArgs([]string{"credential", "bogus"})
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
if err := cmd.Execute(); err == nil {
t.Fatal("Execute() = nil, want error for unknown credential action")
}
}
// credentialGet must stay silent (and never mint a token) when git asks about a
// host other than the configured Gitea host. This exercises the stdin parser
// without any network access.
func TestCredentialGetIgnoresOtherHost(t *testing.T) {
in := strings.NewReader("protocol=https\nhost=github.com\n\n")
var out bytes.Buffer
if err := credentialGet(in, &out); err != nil {
t.Fatalf("credentialGet: %v", err)
}
if out.Len() != 0 {
t.Errorf("expected no output for non-Gitea host, got %q", out.String())
}
}
func TestGiteaHost(t *testing.T) {
if h := giteaHost(); h != "git.unkin.net" {
t.Errorf("giteaHost() = %q, want git.unkin.net", h)
}
}