diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f5ce9c1..bf2e712d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,8 @@ jobs: sudo apt-get install -y --no-install-recommends zsh - name: Run Bats tests - run: uv run bats --print-output-on-failure tests/esa/zsh.bats tests/moshi/update_moshi_hook.bats tests/codex/update_codex.bats + # Discovery keeps new files in CI; files tagged macos need a macOS host and are excluded. + run: uv run bats --recursive --filter-tags '!macos' --print-output-on-failure tests - name: Run Python integration tests # The installed macOS popup profile is checked locally; static TOML checks run on Linux. diff --git a/README.md b/README.md index 8390d011..411ce4f7 100644 --- a/README.md +++ b/README.md @@ -351,6 +351,13 @@ uv run --frozen pytest nix flake check ``` +Bats files that need a macOS host or builder, such as ones that build the +aarch64-darwin Home Manager configuration, carry `# bats file_tags=macos` and a +comment stating why. Put such tests in their own file (for example +`_macos.bats`) so the tag applies to the whole file. CI runs +`bats --recursive --filter-tags '!macos' tests`, so an untagged file must pass on +Linux, while `bats --recursive tests` on a Mac runs everything. + CI checks shell integration with Bats and checks Python automation with Ruff, ty, and pytest. Tests marked `integration` run in the Bats job; other pytest tests run separately without duplicating those cases. diff --git a/flake.nix b/flake.nix index 64fe8743..7f4c482e 100644 --- a/flake.nix +++ b/flake.nix @@ -196,6 +196,8 @@ shellPkgs.actionlint shellPkgs.bats shellPkgs.commitlint + # Headless Neovim runs the esa and LSP Bats specs on Linux. + shellPkgs.neovim # lefthook before 2.1.6 runs hooks under a pty, which agent sandboxes deny. shellUnstable.lefthook # Same uv and Python as the Home Manager profile; Nix owns the interpreter, uv owns dependencies. diff --git a/tests/esa/format.bats b/tests/esa/format.bats index 4c5eba3f..6227f120 100644 --- a/tests/esa/format.bats +++ b/tests/esa/format.bats @@ -1,6 +1,8 @@ #!/usr/bin/env bats # Tests Markdown formatting used for esa posts. +bats_require_minimum_version 1.5.0 + setup() { load test-helper/setup } @@ -10,14 +12,14 @@ format_markdown() { } @test "Markdown formatting preserves line breaks in esa prose" { - run format_markdown < <(printf 'こんにちは.\nこんばんは.\n') + run --separate-stderr format_markdown < <(printf 'こんにちは.\nこんばんは.\n') [ "$status" -eq 0 ] [ "$output" = $'こんにちは.\nこんばんは.' ] } @test "Markdown formatting indents nested lists by four spaces" { - run format_markdown < <(printf -- '- parent\n - child\n') + run --separate-stderr format_markdown < <(printf -- '- parent\n - child\n') [ "$status" -eq 0 ] [ "$output" = $'- parent\n - child' ] @@ -27,7 +29,7 @@ format_markdown() { local _outside="$BATS_TEST_TMPDIR/outside/post.md" mkdir -p "${_outside%/*}" - run dprint fmt --config "$REPO_ROOT/dprint/dprint.json" --stdin "$_outside" < <(printf -- '- parent\n - child\n') + run --separate-stderr dprint fmt --config "$REPO_ROOT/dprint/dprint.json" --stdin "$_outside" < <(printf -- '- parent\n - child\n') [ "$status" -eq 0 ] [ "$output" = $'- parent\n - child' ] diff --git a/tests/esa/nvim.bats b/tests/esa/nvim.bats index 95728c76..a726fa6b 100644 --- a/tests/esa/nvim.bats +++ b/tests/esa/nvim.bats @@ -14,7 +14,7 @@ setup() { ESA_EDIT_POST_NUMBER=1515 \ ESA_EDIT_FILE="$ARTICLE_FILE" \ XDG_DATA_HOME="$NVIM_DATA_HOME" \ - nvim --headless -u "$REPO_ROOT/nvim/init.lua" \ + nvim --headless --cmd "set runtimepath^=$REPO_ROOT/nvim,$NVIM_DATA_HOME/nvim/lazy/lazy.nvim" -u "$REPO_ROOT/nvim/init.lua" \ "$ARTICLE_FILE" \ -c "call setline(1, '# After')" \ -c write \ @@ -32,7 +32,7 @@ setup() { ESA_EDIT_POST_NUMBER=1515 \ ESA_EDIT_FILE="$ARTICLE_FILE" \ XDG_DATA_HOME="$NVIM_DATA_HOME" \ - nvim --headless -u "$REPO_ROOT/nvim/init.lua" \ + nvim --headless --cmd "set runtimepath^=$REPO_ROOT/nvim,$NVIM_DATA_HOME/nvim/lazy/lazy.nvim" -u "$REPO_ROOT/nvim/init.lua" \ "$other_file" \ -c "call setline(1, '# Changed')" \ -c write \ diff --git a/tests/herdr/herdr_command.bats b/tests/herdr/herdr_command.bats index 6de03076..a461b629 100755 --- a/tests/herdr/herdr_command.bats +++ b/tests/herdr/herdr_command.bats @@ -1,5 +1,8 @@ #!/usr/bin/env bats # Executable specifications for Nix-managed Herdr command helpers. +# macOS only: builds the aarch64-darwin Home Manager configuration, which needs a macOS host or builder. +# bats file_tags=macos + bats_require_minimum_version 1.5.0 diff --git a/tests/nix/agent_hook.bats b/tests/nix/agent_hook.bats index 9c193d3d..2b8b9105 100644 --- a/tests/nix/agent_hook.bats +++ b/tests/nix/agent_hook.bats @@ -1,5 +1,8 @@ #!/usr/bin/env bats # Executable specifications for external agent hook composition. +# macOS only: builds the aarch64-darwin Home Manager activation package, which needs a macOS host or builder. +# bats file_tags=macos + bats_require_minimum_version 1.5.0 diff --git a/tests/nix/codex_notification.bats b/tests/nix/codex_notification.bats index 893f7b54..5e1cbd93 100644 --- a/tests/nix/codex_notification.bats +++ b/tests/nix/codex_notification.bats @@ -2,6 +2,9 @@ # Codex delegates terminal notifications only when launched inside Herdr. # Bats isolates each test's environment. # shellcheck disable=SC2030,SC2031 +# macOS only: builds the codex package for aarch64-darwin, which needs a macOS host or builder. +# bats file_tags=macos + setup_file() { local _repo_root _derivation _package diff --git a/tests/nix/configuration.bats b/tests/nix/configuration.bats index 92fd456e..c75ba46b 100644 --- a/tests/nix/configuration.bats +++ b/tests/nix/configuration.bats @@ -1,5 +1,8 @@ #!/usr/bin/env bats # The hook's Bats entry point delegates declarative contracts to native flake checks. +# macOS only: builds the aarch64-darwin flake checks, which need a macOS host or builder. +# bats file_tags=macos + bats_require_minimum_version 1.5.0 diff --git a/tests/ssh-agent/load_identity.bats b/tests/ssh-agent/load_identity.bats index df3e1862..9b66c0d4 100644 --- a/tests/ssh-agent/load_identity.bats +++ b/tests/ssh-agent/load_identity.bats @@ -31,10 +31,10 @@ evaluate_ssh_directory_permissions() { [ "$status" -eq 0 ] [ -f "$BATS_TEST_TMPDIR/home/.ssh/existing-file" ] - run /usr/bin/stat -f "%Lp" "$BATS_TEST_TMPDIR/home/.ssh" + run find "$BATS_TEST_TMPDIR/home/.ssh" -maxdepth 0 -perm 0700 [ "$status" -eq 0 ] - [ "$output" = "700" ] + [ "$output" = "$BATS_TEST_TMPDIR/home/.ssh" ] } @test "home activation reports a missing SSH public key" { diff --git a/tests/terminal-browser/terminal_browser.bats b/tests/terminal-browser/terminal_browser.bats index 2fb9d1f5..0fc442b8 100644 --- a/tests/terminal-browser/terminal_browser.bats +++ b/tests/terminal-browser/terminal_browser.bats @@ -1,5 +1,8 @@ #!/usr/bin/env bats # Executable specifications for the terminal-browser package. +# macOS only: runs the darwin-arm64 terminal-browser binary. +# bats file_tags=macos + bats_require_minimum_version 1.5.0 diff --git a/tests/zsh/ssh_agent.bats b/tests/zsh/ssh_agent.bats index df474435..81288415 100644 --- a/tests/zsh/ssh_agent.bats +++ b/tests/zsh/ssh_agent.bats @@ -1,5 +1,8 @@ #!/usr/bin/env bats # Interactive Zsh points SSH_AUTH_SOCK at the user's 1Password agent, never at another local agent. +# macOS only: zsh/.zshrc attaches the 1Password agent and validates its socket only when OSTYPE is darwin, +# so every case here would pass vacuously on Linux. +# bats file_tags=macos setup() { REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/../.." && pwd)" diff --git a/tests/zsh/startup.bats b/tests/zsh/startup.bats index bd0e67b3..41dd2209 100644 --- a/tests/zsh/startup.bats +++ b/tests/zsh/startup.bats @@ -271,20 +271,3 @@ run_startup_path() { print -rl -- "${path[@]}" ' } - -@test "Home Manager activation invokes the packaged Zsh cache builder" { - run --separate-stderr nix build --no-link --print-out-paths \ - "$TEST_FLAKE#homeConfigurations.\"kaito@mbp\".activationPackage" - - if [ "$status" -ne 0 ]; then - printf '%s\n' "$stderr" >&2 - fi - [ "$status" -eq 0 ] - - local _activation_package="$output" - [ -f "$_activation_package/activate" ] - local _builder - _builder="$(grep -Eo '/nix/store/[^"[:space:]]+-build_cache[.]zsh' "$_activation_package/activate" | head -n 1)" - [ -f "$_builder" ] - cmp --silent "$REPO_ROOT/zsh/build_cache.zsh" "$_builder" -} diff --git a/tests/zsh/startup_macos.bats b/tests/zsh/startup_macos.bats new file mode 100644 index 00000000..c4b19a85 --- /dev/null +++ b/tests/zsh/startup_macos.bats @@ -0,0 +1,28 @@ +#!/usr/bin/env bats +# Executable specifications for Zsh startup behavior that needs the darwin Home Manager build. +# macOS only: builds the aarch64-darwin Home Manager activation package, which needs a macOS host or builder. +# bats file_tags=macos + +bats_require_minimum_version 1.5.0 + +setup() { + REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/../.." && pwd)" + TEST_FLAKE="${DOTFILES_TEST_FLAKE:-$REPO_ROOT}" +} + +@test "Home Manager activation invokes the packaged Zsh cache builder" { + run --separate-stderr nix build --no-link --print-out-paths \ + "$TEST_FLAKE#homeConfigurations.\"kaito@mbp\".activationPackage" + + if [ "$status" -ne 0 ]; then + printf '%s\n' "$stderr" >&2 + fi + [ "$status" -eq 0 ] + + local _activation_package="$output" + [ -f "$_activation_package/activate" ] + local _builder + _builder="$(grep -Eo '/nix/store/[^"[:space:]]+-build_cache[.]zsh' "$_activation_package/activate" | head -n 1)" + [ -f "$_builder" ] + cmp --silent "$REPO_ROOT/zsh/build_cache.zsh" "$_builder" +}