Skip to content
74 changes: 68 additions & 6 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -29,16 +31,23 @@ 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
pip install pytest pytest-cov pyyaml
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
uses: taiki-e/install-action@1a85bbbe6e8628d43d225ac830981df21a8567d2 # just
with:
tool: just

- name: Run shellcheck — extensionless scripts
run: |
Expand All @@ -62,6 +71,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()
Expand Down Expand Up @@ -140,6 +157,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)"
Expand Down
2 changes: 1 addition & 1 deletion docs/TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 11 additions & 1 deletion docs/skills/workflow-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand All @@ -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**.
Expand Down
10 changes: 9 additions & 1 deletion tests/test_rechunker_group_fix.bats
Original file line number Diff line number Diff line change
Expand Up @@ -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 ]
}

Expand Down
2 changes: 2 additions & 0 deletions tests/test_ujust.bats
Original file line number Diff line number Diff line change
Expand Up @@ -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}"

Expand Down Expand Up @@ -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}"

Expand Down
41 changes: 24 additions & 17 deletions tests/test_ujust_completion.bats
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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 "")
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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 "")
Expand All @@ -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 "")
Expand All @@ -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)
Expand All @@ -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" }
Expand All @@ -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" }
Expand All @@ -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" }
Expand All @@ -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" }
Expand All @@ -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 ]
Expand All @@ -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 ]
Expand All @@ -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 ]
Expand All @@ -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 ]
Expand All @@ -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 ]
Expand Down
Loading