test(ci): add fish config test suite and gate docs build on it #109
@@ -13,10 +13,33 @@ on:
|
|||||||
- "functions/**"
|
- "functions/**"
|
||||||
- "conf.d/**"
|
- "conf.d/**"
|
||||||
- "config.fish"
|
- "config.fish"
|
||||||
|
- "completions/**"
|
||||||
|
- "integrations/**"
|
||||||
|
- "tests/**"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: racknerd-mini
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
|
- name: Install fish
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y software-properties-common
|
||||||
|
sudo add-apt-repository -y ppa:fish-shell/release-4
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y fish
|
||||||
|
|
||||||
|
- name: Run fish config tests
|
||||||
|
run: fish tests/run-tests.fish
|
||||||
|
|
||||||
build-docs:
|
build-docs:
|
||||||
|
needs: test
|
||||||
runs-on: racknerd-mini
|
runs-on: racknerd-mini
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ abbreviation system for keyboard-driven workflows.
|
|||||||
- [Installation](#installation)
|
- [Installation](#installation)
|
||||||
- [Personalization](#personalization)
|
- [Personalization](#personalization)
|
||||||
- [Minimal Mode](#minimal-mode)
|
- [Minimal Mode](#minimal-mode)
|
||||||
|
- [Testing](#testing)
|
||||||
- [Attribution](#attribution)
|
- [Attribution](#attribution)
|
||||||
- [License](#license)
|
- [License](#license)
|
||||||
|
|
||||||
@@ -330,6 +331,16 @@ for the full sub-category list per category.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
```fish
|
||||||
|
fish tests/run-tests.fish
|
||||||
|
```
|
||||||
|
|
||||||
|
Runs before every push (and gates the [documentation build](.github/workflows/build-docs.yml) in CI, so a broken config can't get published): syntax-lints every `.fish` file, then loads the config in an isolated `HOME`/XDG sandbox — never this checkout itself, since it doubles as a real `~/.config/fish` — and runs functional checks against foundational behavior (XDG/PATH/CDPATH setup, key bindings, abbreviations, core functions, the opinionated-component registry, and more).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Attribution
|
## Attribution
|
||||||
|
|
||||||
The core of the [Zoxide integration](https://fish.rootiest.fyi/02-path-setup/) in this repository was originally adapted from the [icezyclon/zoxide.fish](https://github.com/icezyclon/zoxide.fish) plugin (MIT Licensed) and has since been heavily customized for performance and Fish 4.x compatibility.
|
The core of the [Zoxide integration](https://fish.rootiest.fyi/02-path-setup/) in this repository was originally adapted from the [icezyclon/zoxide.fish](https://github.com/icezyclon/zoxide.fish) plugin (MIT Licensed) and has since been heavily customized for performance and Fish 4.x compatibility.
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# Copyright (C) 2026 Rootiest
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# Functional checks for foundational config behavior. Sourced inside a
|
||||||
|
# fully-loaded, sandboxed interactive fish session by tests/run-tests.fish
|
||||||
|
# -- see that file for the sandbox setup. Each test_* function returns 0
|
||||||
|
# on pass, non-zero on fail; functional_test_main collects and runs them.
|
||||||
|
|
||||||
|
function test_xdg_defaults
|
||||||
|
test -n "$XDG_CONFIG_HOME" -a -n "$XDG_CACHE_HOME" \
|
||||||
|
-a -n "$XDG_DATA_HOME" -a -n "$XDG_STATE_HOME"
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_path_additions
|
||||||
|
contains -- "$HOME/.local/bin" $PATH
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_cdpath
|
||||||
|
contains -- "$HOME/projects" $CDPATH
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_vi_key_bindings
|
||||||
|
test "$fish_key_bindings" = fish_vi_key_bindings
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_abbreviations_loaded
|
||||||
|
abbr -q n
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_core_functions_defined
|
||||||
|
for f in cat logs config-help fish-deps check_fish_deps config-settings
|
||||||
|
if not functions -q $f
|
||||||
|
echo " missing function: $f"
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_exit_rewired
|
||||||
|
functions -q exit
|
||||||
|
and functions exit | string match -q '*smart_exit*'
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_op_registry_lookup
|
||||||
|
functions -q __fish_config_op_registry_lookup
|
||||||
|
or return 1
|
||||||
|
set -l tags (__fish_config_op_registry_lookup config cdpath)
|
||||||
|
test $status -eq 0 -a (count $tags) -gt 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_op_enabled_fail_open
|
||||||
|
# An identity/site pair with no registry entry must resolve to
|
||||||
|
# enabled -- the documented fail-open default.
|
||||||
|
__fish_config_op_enabled __fish_config_test_never_registered somesite
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_greeting_function_defined
|
||||||
|
functions -q fish_greeting
|
||||||
|
end
|
||||||
|
|
||||||
|
function functional_test_main
|
||||||
|
set -l names (functions -a | string match 'test_*' | sort)
|
||||||
|
set -l failed 0
|
||||||
|
for name in $names
|
||||||
|
if $name
|
||||||
|
echo " PASS $name"
|
||||||
|
else
|
||||||
|
echo " FAIL $name"
|
||||||
|
set failed (math $failed + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
echo ""
|
||||||
|
echo (math (count $names) - $failed)"/"(count $names)" passed"
|
||||||
|
return $failed
|
||||||
|
end
|
||||||
Executable
+89
@@ -0,0 +1,89 @@
|
|||||||
|
#!/usr/bin/env fish
|
||||||
|
# Copyright (C) 2026 Rootiest
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# CI test runner for this fish configuration.
|
||||||
|
# 1. Syntax-lints every tracked .fish file (fish -n).
|
||||||
|
# 2. Copies the config-relevant files into a throwaway sandbox (never
|
||||||
|
# the live checkout -- this repo doubles as a real ~/.config/fish,
|
||||||
|
# so a symlinked sandbox would let universal-variable writes like
|
||||||
|
# first-run's escape into the real, gitignored fish_variables file)
|
||||||
|
# and loads it as an isolated interactive session.
|
||||||
|
# 3. Runs the functional checks in tests/functional.fish inside that
|
||||||
|
# loaded session.
|
||||||
|
#
|
||||||
|
# Usage: fish tests/run-tests.fish
|
||||||
|
|
||||||
|
set -l script_dir (realpath (dirname (status filename)))
|
||||||
|
set -l repo_root (realpath $script_dir/..)
|
||||||
|
set -l overall_failed 0
|
||||||
|
|
||||||
|
# ---- Phase 1: syntax lint ------------------------------------------------
|
||||||
|
echo "== Syntax lint =="
|
||||||
|
set -l lint_files $repo_root/config.fish
|
||||||
|
for dir in functions conf.d completions integrations
|
||||||
|
set -a lint_files (find $repo_root/$dir -name '*.fish' | sort)
|
||||||
|
end
|
||||||
|
|
||||||
|
set -l lint_failed 0
|
||||||
|
for f in $lint_files
|
||||||
|
set -l out (fish -n $f 2>&1)
|
||||||
|
if test $status -ne 0
|
||||||
|
echo " FAIL "(string replace $repo_root/ '' $f)
|
||||||
|
printf '%s\n' $out
|
||||||
|
set lint_failed (math $lint_failed + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
set -l lint_total (count $lint_files)
|
||||||
|
echo (math $lint_total - $lint_failed)"/$lint_total files passed lint"
|
||||||
|
if test $lint_failed -ne 0
|
||||||
|
set overall_failed 1
|
||||||
|
end
|
||||||
|
|
||||||
|
# ---- Phase 2: isolated load + functional checks --------------------------
|
||||||
|
echo ""
|
||||||
|
echo "== Sandboxed load + functional checks =="
|
||||||
|
|
||||||
|
set -l sandbox (mktemp -d)
|
||||||
|
set -l sandbox_cfg $sandbox/xdgcfg/fish
|
||||||
|
mkdir -p $sandbox_cfg
|
||||||
|
# path-setup only adds directories that already exist (fish_add_path is a
|
||||||
|
# no-op on missing paths), so give it $HOME/.local/bin to find.
|
||||||
|
mkdir -p $sandbox/home/.local/bin
|
||||||
|
|
||||||
|
cp $repo_root/config.fish $sandbox_cfg/
|
||||||
|
test -f $repo_root/fish_plugins
|
||||||
|
and cp $repo_root/fish_plugins $sandbox_cfg/
|
||||||
|
for d in functions conf.d completions integrations themes data
|
||||||
|
test -d $repo_root/$d
|
||||||
|
and cp -r $repo_root/$d $sandbox_cfg/
|
||||||
|
end
|
||||||
|
|
||||||
|
set -l err_file (mktemp)
|
||||||
|
env -i \
|
||||||
|
HOME=$sandbox/home \
|
||||||
|
XDG_CONFIG_HOME=$sandbox/xdgcfg \
|
||||||
|
PATH="$PATH" \
|
||||||
|
TERM=xterm \
|
||||||
|
__fish_config_op_autoexec=off \
|
||||||
|
fish -i -c "source $repo_root/tests/functional.fish; functional_test_main" \
|
||||||
|
2>$err_file
|
||||||
|
set -l functional_status $status
|
||||||
|
|
||||||
|
set -l stderr_out (cat $err_file)
|
||||||
|
rm -rf $sandbox $err_file
|
||||||
|
|
||||||
|
if test -n "$stderr_out"
|
||||||
|
# Diagnostic only, not a gate: on machines with vendor fish configs
|
||||||
|
# (e.g. CachyOS's cachyos-fish-config, which this repo's config.fish
|
||||||
|
# sources when present) unrelated vendor warnings can land here. Real
|
||||||
|
# breakage in this repo's own code is caught by the assertions below.
|
||||||
|
echo " Session stderr output (informational):"
|
||||||
|
printf '%s\n' $stderr_out
|
||||||
|
end
|
||||||
|
|
||||||
|
if test $functional_status -ne 0
|
||||||
|
set overall_failed 1
|
||||||
|
end
|
||||||
|
|
||||||
|
exit $overall_failed
|
||||||
Reference in New Issue
Block a user