Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions cli/internal/deploy/manifest_requires_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import (
"path"
"path/filepath"
"slices"
"strings"
"testing"

"github.com/mlorentedev/dotfiles/cli/internal/tools"
)

// requiresExempt lists the entries allowed to omit the `requires` every
Expand Down Expand Up @@ -125,3 +128,95 @@ func TestMissingSiblingRequires(t *testing.T) {
}
}
}

// requiredButNotCataloged lists the commands an entry may require on an OS
// where packages.json installs nothing, each with the reason. A key is
// "<command>" for every OS or "<command>/<goos>" for one.
var requiredButNotCataloged = map[string]string{
"git": "install.sh's prerequisite: the checkout step needs it before the catalog runs",
"claude": "the setup twins install it until #2013 PR-B moves it to the catalog",
"pi": "the setup twins install it until #2278 moves it to the catalog",
"zsh/darwin": "macOS ships zsh as its login shell",
"zsh/windows": "the zsh configs are for POSIX shells; Windows runs pwsh",
"tmux/windows": "the tmux config is for POSIX terminals; Windows has no tmux",
"colima/linux": "colima is the macOS container runtime; Linux runs the docker engine",
"colima/windows": "colima is the macOS container runtime; Windows runs Docker Desktop",
}

// An entry gated on `requires: X` is deployed only where X is on PATH. On an
// OS where nothing installs X the entry never deploys, and nothing reports it:
// the gate reads as "not this machine's tool". #2013 X1 found the zsh configs
// that way on ubuntu-latest, where packages.json had no zsh. So every command
// an entry requires is installed by the catalog on each OS the entry targets,
// or named in requiredButNotCataloged with the reason.
func TestManifest_EveryRequiredCommandIsInstalledWhereTheEntryDeploys(t *testing.T) {
raw, err := os.ReadFile(filepath.Join("../../..", ManifestRel))
if err != nil {
t.Fatal(err)
}
m, err := ParseManifest(raw)
if err != nil {
t.Fatal(err)
}
cat, err := tools.Load(filepath.Join("../../..", "packages.json"))
if err != nil {
t.Fatal(err)
}
missing := uncatalogedRequires(m.Configs, cat)
// The positive half: zsh is the case this guard was written for.
if slices.Contains(missing, "zsh/linux") {
t.Error("nothing installs zsh on linux, so the zsh configs never deploy there")
}
used := map[string]bool{}
for _, key := range missing {
cmd, _, _ := strings.Cut(key, "/")
switch {
case requiredButNotCataloged[key] != "":
used[key] = true
case requiredButNotCataloged[cmd] != "":
used[cmd] = true
default:
t.Errorf("%s: an entry requires %s, and packages.json installs nothing there; add a catalog entry, or exempt it in requiredButNotCataloged with the reason", key, cmd)
}
}
for key := range requiredButNotCataloged {
if !used[key] {
t.Errorf("requiredButNotCataloged exempts %s, which is no longer needed; drop the exemption", key)
}
}
}

// uncatalogedRequires names, as "<command>/<goos>", each command an entry
// requires on an OS it deploys to where no catalog tool installs that command.
// Sorted and without duplicates.
func uncatalogedRequires(configs []Config, cat tools.Catalog) []string {
var out []string
for _, c := range configs {
if c.Requires == "" {
continue
}
for _, goos := range []string{"linux", "darwin", "windows"} {
if c.AppliesOn(goos) && !catalogInstalls(cat, c.Requires, goos) {
out = append(out, c.Requires+"/"+goos)
}
}
}
slices.Sort(out)
return slices.Compact(out)
}

// catalogInstalls reports whether a catalog tool puts cmd on PATH on goos. A
// system entry names its command when it has one; every other source puts the
// tool's name on PATH.
func catalogInstalls(cat tools.Catalog, cmd, goos string) bool {
for _, t := range cat.Tools {
bin := t.Name
if t.Source.Command != "" {
bin = t.Source.Command
}
if bin == cmd && t.SupportsOS(goos) {
return true
}
}
return false
}
9 changes: 9 additions & 0 deletions packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@
"command": "git-lfs"
}
},
{
"name": "zsh",
"profile": "full",
"source": {
"type": "system",
"apt": "zsh",
"command": "zsh"
}
},
{
"name": "tmux",
"profile": "full",
Expand Down
Loading