Skip to content

Development

Rui edited this page Nov 3, 2026 · 1 revision

Development

How the repo is laid out, tested and changed.

Layout

Path Installed to
.config/ ~/.config/ tool configs; folders with more than one file have a README
git_hooks/ ~/git_hooks/ the global git hooks
claude/ ~/.claude/ Claude Code
.zshrc, .p10k.zsh, .gitconfig* ~ the files .config/dotfiles/home-files lists
tests/ — pytest
.github/workflows/lint.yml — CI

The playbook (devops-daily-driver) and dotfiles-sync install the same way: both read home-files and run install.sh.

Languages: which one where

  • bash 3.2 for scripts (#!/bin/bash): it is what macOS ships, so they run from SketchyBar, launchd, tmux and git without Homebrew on the PATH. shellcheck checks them all, unquoted variables included; CI checks the syntax with /bin/bash 3.2.
  • zsh for the shell functions in .config/zsh/: they need the shell's own state (hooks, variables of the shell).
  • Go where there is real logic of our own and it pays to test it: kube-guard, sops-guard, commit-msg, local-files, the SketchyBar checks, the Claude Code hook. Each is a module with its own go.mod, built by install.sh when a .go file or go.mod is newer than the binary.
    • Go tools that talk to a person use fatih/color and go-isatty: colors and emojis when stderr is a terminal, plain text otherwise and with NO_COLOR. Messages go to stderr.
  • Python only for tests and rex/settings.py.

Tests

python3 -m venv .venv && .venv/bin/pip install -r tests/requirements.txt
.venv/bin/pytest tests/                       # ~1 min
for d in git_hooks/go/commit-msg git_hooks/go/sops-guard .config/kube-guard \
  .config/dotfiles/local-files .config/sketchybar/plugins/check claude/hooks/deny-sensitive-reads; do
  (cd "$d" && go vet ./... && go test ./...)
done
node --test .config/vscode/extensions/hue/colors.test.js
  • tests/test_install.py runs dotfiles-sync into an empty fake HOME, from a clone of the working tree: a first run installs everything, a second changes nothing, the warnings, the links, a single rebuild, the built tools working, dotfiles-diff, a broken build failing. The apps a sync touches (defaults for Rex, tmux, AeroSpace, SketchyBar, brew, VS Code) are fakes, so it is safe on your Mac. It downloads the SketchyBar icon map (network).
  • Fake commands for tests: the stubs fixture in tests/conftest.py puts them first on PATH. Terminal prompts are answered with pexpect.
  • Reference: tests README.

CI

lint.yml runs on macOS: bash -n with bash 3.2, shellcheck, zsh -n, jq on every JSON file, nvim started headless, pytest, Hue's tests, go vet + go test on every Go tool (modules and builds cached), and gitleaks over the whole history. Renovate keeps the Actions (pinned by SHA) and the Go modules up to date.

Recipes

  • A file copied to ~: add it to the repo root and to .config/dotfiles/home-files. Nothing else: the sync, the diff, the playbook and the tests read that list.
  • A new install step: in .config/dotfiles/install.sh, printing one line when it changes something and nothing otherwise (the playbook's changed_when matches those lines).
  • A new Go tool: its folder with a go.mod, a line in install.sh's tools=(...), its binary in .gitignore, a go vet / go test step in CI, and its path in tests/test_install.py's TOOLS.
  • A file that leaves the repo: add its path (relative to $HOME) to .config/dotfiles/obsolete; rsync never deletes, so the sync removes it there.
  • A LaunchAgent: a plist in .config/dotfiles/launchd/; install.sh copies it and it runs from the next login.
  • A per-machine file: never committed; add it to .gitignore when it lives under a synced folder, and to local-files' list to have it backed up.
  • Commits: Conventional Commits, signed, no co-author trailer.

Clone this wiki locally