homelab: add work verbs (start/land/clean) with a land verification gate
Completes the infra-loop verb surface. work start creates .worktrees/<topic> on <user>/<topic> off <remote>/master (git-crypt-aware, ensures .worktrees is ignored) and prints the path for native EnterWorktree entry. work land fetches, merges master in, verifies, pushes HEAD:master with non-fast-forward retry, and falls back to pushing the feature branch for a PR when the direct push is rejected (branch protection). work clean removes the worktree + branch. Safety: work land REFUSES to push when it cannot verify (no --verify-cmd and no auto-detected suite) unless --no-verify is passed. This was added after an accidental smoke-test invocation pushed unverified WIP to master (benign — the infra CI applied 0 stacks since the diff was cli/-only — but the gate makes an unverified land a deliberate choice, not the default). Known v0.1 limitation: land does not yet block on CI to green; that arrives with the ci/deploy watch verbs. It prints a reminder to follow the pipeline manually. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
36d562c15c
commit
087b415f73
4 changed files with 276 additions and 0 deletions
32
cli/cmd_work_test.go
Normal file
32
cli/cmd_work_test.go
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestRunVerifyRefusesWhenNothingToVerify(t *testing.T) {
|
||||
dir := t.TempDir() // no go.mod, no verify cmd
|
||||
if err := runVerify(dir, "", false); err == nil {
|
||||
t.Fatal("runVerify must refuse (error) when nothing to verify and --no-verify absent")
|
||||
}
|
||||
if err := runVerify(dir, "", true); err != nil {
|
||||
t.Fatalf("runVerify must skip when --no-verify set, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlagValue(t *testing.T) {
|
||||
cases := []struct {
|
||||
args []string
|
||||
name string
|
||||
want string
|
||||
}{
|
||||
{[]string{"--verify-cmd", "go test ./..."}, "--verify-cmd", "go test ./..."},
|
||||
{[]string{"--verify-cmd=make test"}, "--verify-cmd", "make test"},
|
||||
{[]string{"topic", "--verify-cmd", "x"}, "--verify-cmd", "x"},
|
||||
{[]string{"topic"}, "--verify-cmd", ""},
|
||||
{[]string{"--verify-cmd"}, "--verify-cmd", ""}, // no value
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := flagValue(c.args, c.name); got != c.want {
|
||||
t.Errorf("flagValue(%v, %q) = %q, want %q", c.args, c.name, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue