From b7965a64c482c7f2e6fa7999b0c810c38bf77763 Mon Sep 17 00:00:00 2001 From: arteeh Date: Fri, 25 Sep 2026 13:51:44 +0000 Subject: [PATCH 1/7] ci: run all maintained unit suites in CI Register all current suites, install missing dependencies, and widen the workflow triggers while preserving the Bazaar coverage gate. Hive-Run: projectbluefin/common#1167 Hive-Plan: issue-1167-recommendation Hive-Spec: issue-1167#recommendation-1-7 Assisted-by: GPT-6 Astra via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: arteeh --- .github/workflows/unit-tests.yml | 80 ++++++++++++++++++++++++++++++-- docs/TESTING.md | 2 +- docs/skills/workflow-map.md | 12 ++++- 3 files changed, 89 insertions(+), 5 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index d63b464a5..f1d7ebd94 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -7,16 +7,18 @@ on: paths: - "system_files/**" - "tests/**" - - "scripts/validate-brewfiles.sh" + - "scripts/**" - "Justfile" + - ".github/workflows/unit-tests.yml" push: branches: - main paths: - "system_files/**" - "tests/**" - - "scripts/validate-brewfiles.sh" + - "scripts/**" - "Justfile" + - ".github/workflows/unit-tests.yml" merge_group: workflow_dispatch: @@ -38,7 +40,26 @@ jobs: - name: Install test deps run: | sudo apt-get install -y bats fish zsh - pip install pytest pytest-cov pyyaml + pip install pytest pytest-cov pyyaml jsonschema + + - name: Install just + shell: bash + run: | + set -euo pipefail + + if command -v just >/dev/null 2>&1; then + echo "just is already installed" + just --version + exit 0 + fi + + if ! command -v cargo >/dev/null 2>&1; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal + fi + + source "$HOME/.cargo/env" + cargo install --locked just + echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Run shellcheck — extensionless scripts run: | @@ -62,6 +83,14 @@ jobs: - name: Run pytest (hooks.py) run: python3 -m pytest tests/test_hooks.py tests/test_chairlift_config.py -v --cov=system_files/bluefin/etc/bazaar --cov-report=term-missing --cov-report=xml:coverage.xml --cov-report=html:coverage-html --cov-fail-under=80 + - name: Run pytest (scripts and config validators) + run: | + python3 -m pytest \ + tests/test_curated_config.py \ + tests/test_check_oci_refs.py \ + tests/test_skill_docs.py \ + -v + - name: Upload coverage report uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: always() @@ -140,6 +169,51 @@ jobs: - name: Run bats (apps.just — install-opentabletdriver, cncf) run: bats tests/test_apps_just.bats + - name: Run bats (bling preexec re-arm) + run: bats tests/test_bling_preexec_rearm.bats + + - name: Run bats (bluefin-countme) + run: bats tests/test_bluefin_countme.bats + + - name: Run bats (brew tap trust) + run: bats tests/test_brew_tap_trust.bats + + - name: Run bats (clean-system podman path) + run: bats tests/test_clean_system_podman_path.bats + + - name: Run bats (default.just) + run: bats tests/test_default_just.bats + + - name: Run bats (dynamic wallpaper hook) + run: bats tests/test_dynamic_wallpaper_hook.bats + + - name: Run bats (hardware hooks) + run: bats tests/test_hardware_hooks.bats + + - name: Run bats (ublue-image-repo) + run: bats tests/test_image_repo.bats + + - name: Run bats (libvirt helper) + run: bats tests/test_libvirt_helper.bats + + - name: Run bats (nvidia flatpak sync) + run: bats tests/test_nvidia_flatpak_sync.bats + + - name: Run bats (shared.just) + run: bats tests/test_shared_just.bats + + - name: Run bats (system.just) + run: bats tests/test_system_just.bats + + - name: Run bats (theming hook) + run: bats tests/test_theming_hook.bats + + - name: Run bats (ujust) + run: bats tests/test_ujust.bats + + - name: Run bats (uwelcome profile) + run: bats tests/test_uwelcome_profile.bats + - name: Smoke-test brew bundle accepts preinstall Brewfile (real Homebrew) run: | eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" diff --git a/docs/TESTING.md b/docs/TESTING.md index e55de7b8f..f6fd3e0c7 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -50,7 +50,7 @@ whoever remembers to add it. which runs in [`.github/workflows/unit-tests.yml`](../.github/workflows/unit-tests.yml) on pull requests that touch `tests/`, `system_files/`, - `scripts/validate-brewfiles.sh`, or the `Justfile` (that workflow's `paths` + `scripts/`, the `Justfile`, or the workflow itself (that workflow's `paths` filter). Adding or renaming a suite means editing the runner and the gate together — the gate failing is the signal that you forgot one of them. - **Never reference a suite that does not exist.** A dangling runner line makes diff --git a/docs/skills/workflow-map.md b/docs/skills/workflow-map.md index bb67aea8c..0125b44f4 100644 --- a/docs/skills/workflow-map.md +++ b/docs/skills/workflow-map.md @@ -31,7 +31,7 @@ Load this when you need to understand **what each GitHub workflow in `projectblu | `validate.yml` | Main PR gate: submodule drift, `just check`, shellcheck, image-registry guard, dconf parity, pre-commit | Tightening repo-local validation or policy guards | | `validate-brewfiles.yaml` | Validates Brewfile correctness | Changing Brewfile structure or Brewfile validation rules | | `validate-chairlift-config.yaml` | Checks `/usr/share/chairlift/config.yml` against the schema of the pinned ChairLift release (`CHAIRLIFT_SCHEMA_REF`, currently `v0.12.2`); path-filtered plus a weekly cron | Changing the ChairLift maintainer config, cask pin, or upstream schema assumptions | -| `unit-tests.yml` | Runs `pytest` + `bats` on `system_files/**`, `tests/**`, and the `Justfile`. Triggers on PR, push to `main`, and `merge_group`. | Adding or changing unit tests, or changing the paths they cover | +| `unit-tests.yml` | Runs `pytest` + `bats` on `system_files/**`, `tests/**`, `scripts/**`, the `Justfile`, and the workflow itself. Triggers on PR, push to `main`, and `merge_group`. | Adding or changing unit tests, or changing the paths they cover | | `build.yml` | Builds and publishes the `common` OCI layer on merge. Runs parallel per-arch jobs (x86_64 on `ubuntu-24.04`, aarch64 on `ubuntu-24.04-arm`). Build uses rootless `buildah-build`; after build, `sudo skopeo copy` promotes the image into root storage so `push-image` (which uses `sudo podman push`) can find it. Then a `manifest` job assembles the multi-arch manifest, logs into GHCR, signs with keyless OIDC, generates SBOM, and attests SLSA L2. Downstream propagation is handled by Renovate (bluefin/bluefin-lts, ~3h) and dakota's daily cron — there is no direct dispatch from this workflow. | Changing how the shared layer is built or pushed | | `pr-e2e.yml` | Pre-merge composed-image gate for the PR's common layer (composes + runs common suite via `run-testsuite.yml`) | Changing how PR-time downstream composition is tested | | `e2e.yml` | Post-merge, **advisory** common-suite validation. Tests the downstream `*-testing` images (`bluefin:testing`, `dakota:testing`) — not the layer just built. Triggers on `push: main` in parallel with `build.yml`, is **not** a required check, and does **not** gate publication: `common:latest` is pushed regardless of the result. On failure it opens or updates a single tracking issue. **Bluefin LTS is deliberately excluded** while [bluefin-lts#492](https://github.com/projectbluefin/bluefin-lts/issues/492) is open — it failed every run, and GitHub does not allow `continue-on-error` on a reusable-workflow call, so it could not be soft-failed in place. LTS is still covered weekly by `promotion-candidate-e2e.yml`. | Changing shipped-layer validation after merge | @@ -50,6 +50,16 @@ Load this when you need to understand **what each GitHub workflow in `projectblu ## Mental model +### Unit suite registration + +Register maintained suites in both the `Justfile` test recipe and +`unit-tests.yml`; the registration drift gate currently checks only the +Justfile. Install suite dependencies in CI (`jsonschema` for skill docs and +`just` for recipe execution). Keep script/config pytest suites in a separate +step from the Bazaar coverage command so unrelated imports do not change its +coverage denominator. When adding covered source paths, update both PR and +push filters. + ### Validation and policy `validate.yml` and `validate-brewfiles.yaml` are about catching repo-local mistakes **before merge**. From 53f2e4220ad250668671194813ef4d475efd43c6 Mon Sep 17 00:00:00 2001 From: castrojo Date: Fri, 25 Sep 2026 19:15:04 -0400 Subject: [PATCH 2/7] ci: install just via apt instead of building from source via cargo --- .github/workflows/unit-tests.yml | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index f1d7ebd94..6d3f57546 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -39,28 +39,9 @@ jobs: - name: Install test deps run: | - sudo apt-get install -y bats fish zsh + sudo apt-get install -y bats fish zsh just pip install pytest pytest-cov pyyaml jsonschema - - name: Install just - shell: bash - run: | - set -euo pipefail - - if command -v just >/dev/null 2>&1; then - echo "just is already installed" - just --version - exit 0 - fi - - if ! command -v cargo >/dev/null 2>&1; then - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal - fi - - source "$HOME/.cargo/env" - cargo install --locked just - echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - - name: Run shellcheck — extensionless scripts run: | shellcheck \ From d0ba3e5e862671375915010e7fc72c256a732c22 Mon Sep 17 00:00:00 2001 From: castrojo Date: Fri, 25 Sep 2026 19:28:19 -0400 Subject: [PATCH 3/7] ci: use taiki-e/install-action for just instead of apt package --- .github/workflows/unit-tests.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 6d3f57546..bc203c192 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -39,9 +39,14 @@ jobs: - name: Install test deps run: | - sudo apt-get install -y bats fish zsh just + sudo apt-get install -y bats fish zsh pip install pytest pytest-cov pyyaml jsonschema + - name: Install just + uses: taiki-e/install-action@1a85bbbe6e8628d43d225ac830981df21a8567d2 # just + with: + tool: just + - name: Run shellcheck — extensionless scripts run: | shellcheck \ From 93680a0eb3069f64a6a5a3d75a9322ca6f955867 Mon Sep 17 00:00:00 2001 From: castrojo Date: Fri, 25 Sep 2026 19:29:59 -0400 Subject: [PATCH 4/7] ci: use ubuntu-26.04 runner and homebrew for test dependencies --- .github/workflows/unit-tests.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index bc203c192..147da11a2 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -31,15 +31,17 @@ concurrency: jobs: test: - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 timeout-minutes: 10 steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - name: Install test deps + - name: Set up Homebrew environment and test dependencies run: | - sudo apt-get install -y bats fish zsh + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + echo "$(/home/linuxbrew/.linuxbrew/bin/brew --prefix)/bin" >> "$GITHUB_PATH" + brew install bats-core fish zsh pip install pytest pytest-cov pyyaml jsonschema - name: Install just From 86ce0dfc643fcea3043126eca60e58cf3a3bdfd7 Mon Sep 17 00:00:00 2001 From: castrojo Date: Fri, 25 Sep 2026 19:38:57 -0400 Subject: [PATCH 5/7] test(ujust): discover shell bin directories dynamically in hermetic test subshells --- tests/test_ujust_completion.bats | 41 +++++++++++++++++++------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/tests/test_ujust_completion.bats b/tests/test_ujust_completion.bats index 724a0b38d..0e78b7af6 100644 --- a/tests/test_ujust_completion.bats +++ b/tests/test_ujust_completion.bats @@ -17,6 +17,13 @@ WORKDIR="" setup() { WORKDIR="$(mktemp -d)" + SHELL_BIN_DIRS="" + for sh_bin in bash zsh fish; do + if p="$(command -v "$sh_bin" 2>/dev/null)"; then + d="$(dirname "$p")" + [[ ":$SHELL_BIN_DIRS:" != *":$d:"* ]] && SHELL_BIN_DIRS="${SHELL_BIN_DIRS:+${SHELL_BIN_DIRS}:}$d" + fi + done mkdir -p "${WORKDIR}/bin" : > "${WORKDIR}/calls.log" # Sandbox justfile and flags file: functional tests point the @@ -140,7 +147,7 @@ teardown() { # --------------------------------------------------------------------------- @test "bash completion offers matching recipes for a prefix" { - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ bash -c ' source "${BASH_COMPLETION}" COMP_WORDS=(ujust up) @@ -159,7 +166,7 @@ teardown() { } @test "bash completion lists all recipes on an empty word" { - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ bash -c ' source "${BASH_COMPLETION}" COMP_WORDS=(ujust "") @@ -178,7 +185,7 @@ teardown() { } @test "bash completion offers flags for a dash-prefixed word" { - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ bash -c ' source "${BASH_COMPLETION}" COMP_WORDS=(ujust --l) @@ -195,7 +202,7 @@ teardown() { } @test "bash completion finds flags next to the entry justfile by default" { - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" BASH_COMPLETION="${BASH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" BASH_COMPLETION="${BASH_COMPLETION}" \ bash -c ' source "${BASH_COMPLETION}" COMP_WORDS=(ujust --l) @@ -212,7 +219,7 @@ teardown() { } @test "bash completion offers -V (version), distinct from -v (verbose)" { - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ bash -c ' source "${BASH_COMPLETION}" COMP_WORDS=(ujust -V) @@ -229,7 +236,7 @@ teardown() { } @test "bash completion queries recipes from the entry justfile" { - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" CALLS="${WORKDIR}/calls.log" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" CALLS="${WORKDIR}/calls.log" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ bash -c ' source "${BASH_COMPLETION}" COMP_WORDS=(ujust "") @@ -245,7 +252,7 @@ teardown() { } @test "bash completion offers nothing when the justfile is missing" { - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/no-such.just" BASH_COMPLETION="${BASH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/no-such.just" BASH_COMPLETION="${BASH_COMPLETION}" \ bash -c ' source "${BASH_COMPLETION}" COMP_WORDS=(ujust "") @@ -262,7 +269,7 @@ teardown() { } @test "bash completion offers no flags when the flags file is missing" { - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/no-such-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/no-such-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ bash -c ' source "${BASH_COMPLETION}" COMP_WORDS=(ujust --l) @@ -282,7 +289,7 @@ teardown() { [ -n "$(command -v zsh)" ] || skip "zsh not installed" local out="${WORKDIR}/zsh-recipes.txt" - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" OUT="${out}" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" ZSH_COMPLETION="${ZSH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" OUT="${out}" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" ZSH_COMPLETION="${ZSH_COMPLETION}" \ zsh -c ' _call_program() { local _tag=$1; shift; "$@" } _describe() { print -r -- "${(P)${@[-1]}}" > "$OUT" } @@ -301,7 +308,7 @@ teardown() { [ -n "$(command -v zsh)" ] || skip "zsh not installed" local out="${WORKDIR}/zsh-flags.txt" - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" OUT="${out}" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" ZSH_COMPLETION="${ZSH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" OUT="${out}" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" ZSH_COMPLETION="${ZSH_COMPLETION}" \ zsh -c ' _call_program() { local _tag=$1; shift; "$@" } _describe() { print -r -- "${(P)${@[-1]}}" > "$OUT" } @@ -320,7 +327,7 @@ teardown() { [ -n "$(command -v zsh)" ] || skip "zsh not installed" local out="${WORKDIR}/zsh-flags-default.txt" - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" OUT="${out}" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" ZSH_COMPLETION="${ZSH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" OUT="${out}" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" ZSH_COMPLETION="${ZSH_COMPLETION}" \ zsh -c ' _call_program() { local _tag=$1; shift; "$@" } _describe() { print -r -- "${(P)${@[-1]}}" > "$OUT" } @@ -337,7 +344,7 @@ teardown() { [ -n "$(command -v zsh)" ] || skip "zsh not installed" local out="${WORKDIR}/zsh-flags-missing.txt" - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" OUT="${out}" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/no-such-flags" ZSH_COMPLETION="${ZSH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" OUT="${out}" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/no-such-flags" ZSH_COMPLETION="${ZSH_COMPLETION}" \ zsh -c ' _call_program() { local _tag=$1; shift; "$@" } _describe() { print -r -- "${(P)${@[-1]}}" > "$OUT" } @@ -353,7 +360,7 @@ teardown() { @test "fish completion offers matching recipes for a prefix" { [ -n "$(command -v fish)" ] || skip "fish not installed" - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" FISH_COMPLETION="${FISH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" FISH_COMPLETION="${FISH_COMPLETION}" \ fish --private -c 'set -g fish_complete_path; source "$FISH_COMPLETION"; complete -C"ujust up"' [ "${status}" -eq 0 ] @@ -365,7 +372,7 @@ teardown() { @test "fish completion lists all recipes on an empty word" { [ -n "$(command -v fish)" ] || skip "fish not installed" - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" FISH_COMPLETION="${FISH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" FISH_COMPLETION="${FISH_COMPLETION}" \ fish --private -c 'set -g fish_complete_path; source "$FISH_COMPLETION"; complete -C"ujust "' [ "${status}" -eq 0 ] @@ -377,7 +384,7 @@ teardown() { @test "fish completion offers flags for a dash-prefixed word" { [ -n "$(command -v fish)" ] || skip "fish not installed" - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" FISH_COMPLETION="${FISH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" FISH_COMPLETION="${FISH_COMPLETION}" \ fish --private -c 'set -g fish_complete_path; source "$FISH_COMPLETION"; complete -C"ujust --l"' [ "${status}" -eq 0 ] @@ -387,7 +394,7 @@ teardown() { @test "fish completion finds flags next to the entry justfile by default" { [ -n "$(command -v fish)" ] || skip "fish not installed" - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" FISH_COMPLETION="${FISH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" FISH_COMPLETION="${FISH_COMPLETION}" \ fish --private -c 'set -g fish_complete_path; source "$FISH_COMPLETION"; complete -C"ujust --l"' [ "${status}" -eq 0 ] @@ -397,7 +404,7 @@ teardown() { @test "fish completion offers -V (version)" { [ -n "$(command -v fish)" ] || skip "fish not installed" - run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" FISH_COMPLETION="${FISH_COMPLETION}" \ + run env PATH="${WORKDIR}/bin:${SHELL_BIN_DIRS}:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" FISH_COMPLETION="${FISH_COMPLETION}" \ fish --private -c 'set -g fish_complete_path; source "$FISH_COMPLETION"; complete -C"ujust -V"' [ "${status}" -eq 0 ] From 3cee84779ed8e6cf5a4f15336cc9599e83f6cbd6 Mon Sep 17 00:00:00 2001 From: castrojo Date: Fri, 25 Sep 2026 19:42:54 -0400 Subject: [PATCH 6/7] test(rechunker): stage temporary root with executables for systemd-analyze verify --- tests/test_rechunker_group_fix.bats | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/test_rechunker_group_fix.bats b/tests/test_rechunker_group_fix.bats index 1abd6194e..209d9dd15 100644 --- a/tests/test_rechunker_group_fix.bats +++ b/tests/test_rechunker_group_fix.bats @@ -155,7 +155,15 @@ UNIT="$BATS_TEST_DIRNAME/../system_files/shared/usr/lib/systemd/system/rechunker # boot-time ordering graph offline, so this does not by itself prove the # cycle is gone. See tests/README or the PR discussion for VM evidence. command -v systemd-analyze >/dev/null 2>&1 || skip "systemd-analyze not available" - run systemd-analyze verify --recursive-errors=no "${UNIT}" + local root_dir="${BATS_TEST_TMPDIR}/systemd-root" + mkdir -p "${root_dir}/usr/bin" "${root_dir}/usr/lib/systemd/system" "${root_dir}/etc" + cp "$BATS_TEST_DIRNAME/../system_files/shared/usr/bin/rechunker-group-fix" "${root_dir}/usr/bin/" + for cmd in bash systemd-sysusers systemd-tmpfiles; do + touch "${root_dir}/usr/bin/${cmd}" + chmod +x "${root_dir}/usr/bin/${cmd}" + done + cp "${UNIT}" "${root_dir}/usr/lib/systemd/system/" + run systemd-analyze verify --root="${root_dir}" --recursive-errors=no "${root_dir}/usr/lib/systemd/system/rechunker-group-fix.service" [ "${status}" -eq 0 ] } From 4bacedb221deda4304c560b000b786b984ede5a2 Mon Sep 17 00:00:00 2001 From: castrojo Date: Fri, 25 Sep 2026 19:48:40 -0400 Subject: [PATCH 7/7] test(ujust): isolate tests from runner inherited XDG_CONFIG_HOME --- tests/test_ujust.bats | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_ujust.bats b/tests/test_ujust.bats index 46d87c816..5a924e367 100644 --- a/tests/test_ujust.bats +++ b/tests/test_ujust.bats @@ -160,6 +160,7 @@ _extract_apps_recipe() { PATH="${WORKDIR}/bin:${PATH}" \ CALLS="${WORKDIR}/calls.log" \ HOME="${test_home}" \ + XDG_CONFIG_HOME="" \ GOOSE_TEMPLATE="${mock_template}" \ bash "${script}" @@ -210,6 +211,7 @@ _extract_apps_recipe() { PATH="${WORKDIR}/bin:${PATH}" \ CALLS="${WORKDIR}/calls.log" \ HOME="${test_home}" \ + XDG_CONFIG_HOME="" \ GOOSE_TEMPLATE="${mock_template}" \ bash "${script}"