From 443982d118dd9bc11179d78c7e23cabf706f41da Mon Sep 17 00:00:00 2001 From: olavostauros Date: Tue, 23 Jun 2026 11:52:53 -0300 Subject: [PATCH 1/4] feat: add lint rule for shiv plugin prerequisites Adds mise-shiv-plugin lint rule that flags mise.toml files declaring shiv-managed tools without the required [plugins] shiv entry and [settings] experimental = true. Based on the CI failure observed in KnickKnackLabs/chat#39. Includes 11 BATS tests across 7 fixture scenarios, plus an ignore directive on an existing github-actions fixture that declares shiv tools. Implements #34 (KnickKnackLabs/codebase) --- .mise/tasks/lint/mise-shiv-plugin | 75 ++++++++++++++ .../fixtures/fix-lints-provisioned/mise.toml | 1 + .../fixtures/complete/mise.toml | 10 ++ .../fixtures/ignored/mise.toml | 13 +++ .../fixtures/missing-both/mise.toml | 2 + .../fixtures/missing-experimental/mise.toml | 8 ++ .../fixtures/missing-plugin/mise.toml | 5 + .../fixtures/no-shiv-tools/mise.toml | 7 ++ .../fixtures/no-toml/README.md | 2 + .../mise-shiv-plugin/mise-shiv-plugin.bats | 98 +++++++++++++++++++ 10 files changed, 221 insertions(+) create mode 100755 .mise/tasks/lint/mise-shiv-plugin create mode 100644 test/lint/mise-shiv-plugin/fixtures/complete/mise.toml create mode 100644 test/lint/mise-shiv-plugin/fixtures/ignored/mise.toml create mode 100644 test/lint/mise-shiv-plugin/fixtures/missing-both/mise.toml create mode 100644 test/lint/mise-shiv-plugin/fixtures/missing-experimental/mise.toml create mode 100644 test/lint/mise-shiv-plugin/fixtures/missing-plugin/mise.toml create mode 100644 test/lint/mise-shiv-plugin/fixtures/no-shiv-tools/mise.toml create mode 100644 test/lint/mise-shiv-plugin/fixtures/no-toml/README.md create mode 100644 test/lint/mise-shiv-plugin/mise-shiv-plugin.bats diff --git a/.mise/tasks/lint/mise-shiv-plugin b/.mise/tasks/lint/mise-shiv-plugin new file mode 100755 index 0000000..33b2675 --- /dev/null +++ b/.mise/tasks/lint/mise-shiv-plugin @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +#MISE description="Check that mise.toml has shiv plugin setup when declaring shiv-managed tools" +#USAGE arg "…" help="Paths to codebases to check (one or more)" + +set -euo pipefail + +# shellcheck source=../../../lib/shell-files.sh +source "$MISE_CONFIG_ROOT/lib/shell-files.sh" + +# Required shiv plugin setup +REQUIRED_PLUGIN_LINE='shiv = "https://github.com/KnickKnackLabs/vfox-shiv"' +REQUIRED_SETTING='experimental = true' + +IFS=' ' read -ra TARGETS <<< "${usage_targets}" + +if [[ ${#TARGETS[@]} -eq 0 ]]; then + echo "ERROR: at least one target is required" >&2 + exit 1 +fi + +# Resolve relative paths against CALLER_PWD (see lib/shell-files.sh). +for i in "${!TARGETS[@]}"; do + TARGETS[i]=$(resolve_target "${TARGETS[i]}") +done + +failures=0 + +for target in "${TARGETS[@]}"; do + if [[ ! -e "$target" ]]; then + echo "ERROR: target does not exist: $target" >&2 + exit 1 + fi + + toml="$target/mise.toml" + name=$(basename "$target") + + if [[ ! -f "$toml" ]]; then + echo "INFO $name: no mise.toml found" + continue + fi + + # Check for file-level ignore + if head -20 "$toml" | grep -q 'codebase:ignore mise-shiv-plugin'; then + echo "SKIP $name (codebase:ignore)" + continue + fi + + # Check if any [tools] key starts with shiv: + if ! grep -q '^\s*"shiv:' "$toml" && ! grep -q "^shiv:" "$toml"; then + echo "OK $name (no shiv tools declared)" + continue + fi + + missing=() + + # Check [plugins] for shiv entry + if ! grep -Eq '^\s*shiv\s*=' "$toml"; then + missing+=("$REQUIRED_PLUGIN_LINE") + fi + + # Check [settings] for experimental = true + if ! grep -q "^experimental = true" "$toml"; then + missing+=("$REQUIRED_SETTING") + fi + + if [[ ${#missing[@]} -eq 0 ]]; then + echo "OK $name" + continue + fi + + echo "FAIL $name: missing ${missing[*]}" + failures=$((failures + 1)) +done + +exit "$failures" \ No newline at end of file diff --git a/test/lint/github-actions/fixtures/fix-lints-provisioned/mise.toml b/test/lint/github-actions/fixtures/fix-lints-provisioned/mise.toml index 51af5bb..3765f13 100644 --- a/test/lint/github-actions/fixtures/fix-lints-provisioned/mise.toml +++ b/test/lint/github-actions/fixtures/fix-lints-provisioned/mise.toml @@ -1,3 +1,4 @@ +# codebase:ignore mise-shiv-plugin — fixture for github-actions rule, not a mise-shiv-plugin test case [plugins] shiv = "https://github.com/KnickKnackLabs/vfox-shiv" diff --git a/test/lint/mise-shiv-plugin/fixtures/complete/mise.toml b/test/lint/mise-shiv-plugin/fixtures/complete/mise.toml new file mode 100644 index 0000000..937db0f --- /dev/null +++ b/test/lint/mise-shiv-plugin/fixtures/complete/mise.toml @@ -0,0 +1,10 @@ +[settings] +experimental = true +quiet = true +task_output = "interleave" + +[plugins] +shiv = "https://github.com/KnickKnackLabs/vfox-shiv" + +[tools] +"shiv:codebase" = "latest" \ No newline at end of file diff --git a/test/lint/mise-shiv-plugin/fixtures/ignored/mise.toml b/test/lint/mise-shiv-plugin/fixtures/ignored/mise.toml new file mode 100644 index 0000000..02df3c6 --- /dev/null +++ b/test/lint/mise-shiv-plugin/fixtures/ignored/mise.toml @@ -0,0 +1,13 @@ +[settings] +experimental = true +quiet = true +task_output = "interleave" + +[plugins] +shiv = "https://github.com/KnickKnackLabs/vfox-shiv" + +[tools] +"shiv:codebase" = "latest" + +# This fixture should be ignored by mise-shiv-plugin +# codebase:ignore mise-shiv-plugin \ No newline at end of file diff --git a/test/lint/mise-shiv-plugin/fixtures/missing-both/mise.toml b/test/lint/mise-shiv-plugin/fixtures/missing-both/mise.toml new file mode 100644 index 0000000..3a574f3 --- /dev/null +++ b/test/lint/mise-shiv-plugin/fixtures/missing-both/mise.toml @@ -0,0 +1,2 @@ +[tools] +"shiv:codebase" = "latest" \ No newline at end of file diff --git a/test/lint/mise-shiv-plugin/fixtures/missing-experimental/mise.toml b/test/lint/mise-shiv-plugin/fixtures/missing-experimental/mise.toml new file mode 100644 index 0000000..93ec199 --- /dev/null +++ b/test/lint/mise-shiv-plugin/fixtures/missing-experimental/mise.toml @@ -0,0 +1,8 @@ +[settings] +quiet = true + +[plugins] +shiv = "https://github.com/KnickKnackLabs/vfox-shiv" + +[tools] +"shiv:codebase" = "latest" \ No newline at end of file diff --git a/test/lint/mise-shiv-plugin/fixtures/missing-plugin/mise.toml b/test/lint/mise-shiv-plugin/fixtures/missing-plugin/mise.toml new file mode 100644 index 0000000..1ff0f6a --- /dev/null +++ b/test/lint/mise-shiv-plugin/fixtures/missing-plugin/mise.toml @@ -0,0 +1,5 @@ +[settings] +experimental = true + +[tools] +"shiv:codebase" = "latest" \ No newline at end of file diff --git a/test/lint/mise-shiv-plugin/fixtures/no-shiv-tools/mise.toml b/test/lint/mise-shiv-plugin/fixtures/no-shiv-tools/mise.toml new file mode 100644 index 0000000..d6bddb5 --- /dev/null +++ b/test/lint/mise-shiv-plugin/fixtures/no-shiv-tools/mise.toml @@ -0,0 +1,7 @@ +[settings] +experimental = true +quiet = true +task_output = "interleave" + +[tools] +bats = "1.13.0" \ No newline at end of file diff --git a/test/lint/mise-shiv-plugin/fixtures/no-toml/README.md b/test/lint/mise-shiv-plugin/fixtures/no-toml/README.md new file mode 100644 index 0000000..763da0a --- /dev/null +++ b/test/lint/mise-shiv-plugin/fixtures/no-toml/README.md @@ -0,0 +1,2 @@ +# This directory intentionally has no mise.toml +# Used to test graceful handling when mise.toml is missing \ No newline at end of file diff --git a/test/lint/mise-shiv-plugin/mise-shiv-plugin.bats b/test/lint/mise-shiv-plugin/mise-shiv-plugin.bats new file mode 100644 index 0000000..c6d64f1 --- /dev/null +++ b/test/lint/mise-shiv-plugin/mise-shiv-plugin.bats @@ -0,0 +1,98 @@ +#!/usr/bin/env bats +# Tests for mise-shiv-plugin lint rule + +load ../../test_helper + +setup() { + FIXTURES="$BATS_TEST_DIRNAME/fixtures" +} + +# ============================================================================ +# Detection +# ============================================================================ + +@test "lint: passes when shiv plugin and experimental are present" { + run codebase lint:mise-shiv-plugin "$FIXTURES/complete" + [ "$status" -eq 0 ] + [[ "$output" == *"OK"* ]] +} + +@test "lint: fails when shiv plugin entry is missing" { + run codebase lint:mise-shiv-plugin "$FIXTURES/missing-plugin" + [ "$status" -ne 0 ] + [[ "$output" == *"FAIL"* ]] + [[ "$output" == *"vfox-shiv"* ]] + # Should NOT complain about experimental (which is present) + [[ "$output" != *"experimental"* ]] +} + +@test "lint: fails when experimental setting is missing" { + run codebase lint:mise-shiv-plugin "$FIXTURES/missing-experimental" + [ "$status" -ne 0 ] + [[ "$output" == *"FAIL"* ]] + [[ "$output" == *"experimental"* ]] +} + +@test "lint: fails when both prerequisites are missing" { + run codebase lint:mise-shiv-plugin "$FIXTURES/missing-both" + [ "$status" -ne 0 ] + [[ "$output" == *"FAIL"* ]] + [[ "$output" == *"vfox-shiv"* ]] + [[ "$output" == *"experimental"* ]] +} + +@test "lint: passes when no shiv tools are declared" { + run codebase lint:mise-shiv-plugin "$FIXTURES/no-shiv-tools" + [ "$status" -eq 0 ] + [[ "$output" == *"OK"* ]] + [[ "$output" == *"no shiv tools"* ]] +} + +@test "lint: passes when no mise.toml exists" { + run codebase lint:mise-shiv-plugin "$FIXTURES/no-toml" + [ "$status" -eq 0 ] + [[ "$output" == *"INFO"* ]] + [[ "$output" == *"no mise.toml"* ]] +} + +@test "lint: skips when codebase:ignore mise-shiv-plugin is set" { + run codebase lint:mise-shiv-plugin "$FIXTURES/ignored" + [ "$status" -eq 0 ] + [[ "$output" == *"SKIP"* ]] +} + +@test "lint: checks multiple targets" { + run codebase lint:mise-shiv-plugin "$FIXTURES/complete" "$FIXTURES/missing-both" + [ "$status" -ne 0 ] + [[ "$output" == *"OK"*"complete"* ]] + [[ "$output" == *"FAIL"*"missing-both"* ]] +} + +# ============================================================================ +# Error handling +# ============================================================================ + +@test "lint: fails when target does not exist" { + run codebase lint:mise-shiv-plugin /nonexistent + [ "$status" -ne 0 ] + [[ "$output" == *"ERROR"* ]] +} + +@test "lint: fails when no targets provided" { + run codebase lint:mise-shiv-plugin + [ "$status" -ne 0 ] + [[ "$output" == *"ERROR"* ]] +} + +@test "lint: supports multiple targets with mixed results" { + run codebase lint:mise-shiv-plugin \ + "$FIXTURES/complete" \ + "$FIXTURES/missing-plugin" \ + "$FIXTURES/no-shiv-tools" \ + "$FIXTURES/no-toml" + [ "$status" -ne 0 ] + [[ "$output" == *"OK"*"complete"* ]] + [[ "$output" == *"FAIL"*"missing-plugin"* ]] + [[ "$output" == *"OK"*"no shiv tools"* ]] + [[ "$output" == *"INFO"*"no mise.toml"* ]] +} \ No newline at end of file From b8fa14acbc344849668121ec3f8013fac8f80a4a Mon Sep 17 00:00:00 2001 From: olavostauros Date: Tue, 23 Jun 2026 17:09:22 -0300 Subject: [PATCH 2/4] feat: add bats-setup-suite-path lint rule Adds bats-setup-suite-path lint rule that flags test/setup_suite.bash files calling `mise env` without preserving BATS_LIBEXEC first. BATS 1.13.0 relies on libexec path resolution; mise env can rewrite PATH and drop bats's libexec directory, causing 'bats-exec-file: command not found' before any tests run. Follows established file-discovery + scan pattern. ShellCheck-clean (SC2016 excluded on intentional code-snippet echo lines). Implements #55 (KnickKnackLabs/codebase) --- .mise/tasks/lint/bats-setup-suite-path | 130 ++++++++++++++++++ .../bats-setup-suite-path.bats | 89 ++++++++++++ .../ignored-inline/test/setup_suite.bash | 6 + .../fixtures/ignored-repo/mise.toml | 3 + .../ignored-repo/test/setup_suite.bash | 5 + .../missing-preserve/test/setup_suite.bash | 5 + .../no-mise-env/test/setup_suite.bash | 5 + .../fixtures/no-setup-suite/.gitkeep | 1 + .../fixtures/preserved/test/setup_suite.bash | 10 ++ 9 files changed, 254 insertions(+) create mode 100755 .mise/tasks/lint/bats-setup-suite-path create mode 100644 test/lint/bats-setup-suite-path/bats-setup-suite-path.bats create mode 100644 test/lint/bats-setup-suite-path/fixtures/ignored-inline/test/setup_suite.bash create mode 100644 test/lint/bats-setup-suite-path/fixtures/ignored-repo/mise.toml create mode 100644 test/lint/bats-setup-suite-path/fixtures/ignored-repo/test/setup_suite.bash create mode 100644 test/lint/bats-setup-suite-path/fixtures/missing-preserve/test/setup_suite.bash create mode 100644 test/lint/bats-setup-suite-path/fixtures/no-mise-env/test/setup_suite.bash create mode 100644 test/lint/bats-setup-suite-path/fixtures/no-setup-suite/.gitkeep create mode 100644 test/lint/bats-setup-suite-path/fixtures/preserved/test/setup_suite.bash diff --git a/.mise/tasks/lint/bats-setup-suite-path b/.mise/tasks/lint/bats-setup-suite-path new file mode 100755 index 0000000..771288c --- /dev/null +++ b/.mise/tasks/lint/bats-setup-suite-path @@ -0,0 +1,130 @@ +#!/usr/bin/env bash +#MISE description="Flag setup_suite.bash that calls mise env without preserving BATS_LIBEXEC" +#USAGE arg "…" help="Paths to codebases to check (one or more)" +#USAGE example "codebase lint:bats-setup-suite-path ." header="Flag repos with unprotected mise env in setup_suite" + +set -euo pipefail + +# shellcheck source=../../../lib/shell-files.sh +source "$MISE_CONFIG_ROOT/lib/shell-files.sh" + +# Rationale: BATS 1.13.0 looks up bats-exec-file, bats-format-*, +# etc. by bare name from files under its libexec dir. If +# test/setup_suite.bash calls `mise env` (which rewrites PATH to +# include tool-manager shims), Bats' libexec directory can fall +# off PATH, and the suite fails before running any tests: +# +# bats-exec-suite: line 323: bats-exec-file: command not found +# # bats warning: Executed 0 instead of expected N tests +# +# The safe shape saves BATS_LIBEXEC before mise env and prepends +# it afterward: +# +# setup_suite() { +# REPO_DIR="$(cd "$BATS_TEST_DIRNAME/.." && pwd)" +# export REPO_DIR +# bats_libexec="${BATS_LIBEXEC:-}" +# eval "$(cd "$REPO_DIR" && mise env)" +# if [ -n "$bats_libexec" ]; then +# export PATH="$bats_libexec:$PATH" +# fi +# } +# +# When upstream Bats releases a fix (bats-core/bats-core#1209) +# and KKL repos move past Bats 1.13.0, this rule may become less +# necessary. + +SETUP_SUITE="test/setup_suite.bash" + +IFS=' ' read -ra TARGETS <<< "${usage_targets}" + +if [[ ${#TARGETS[@]} -eq 0 ]]; then + echo "ERROR: at least one target is required" >&2 + exit 1 +fi + +# Resolve relative paths against CALLER_PWD (see lib/shell-files.sh). +for i in "${!TARGETS[@]}"; do + TARGETS[i]=$(resolve_target "${TARGETS[i]}") +done + +failures=0 + +for target in "${TARGETS[@]}"; do + if [[ ! -e "$target" ]]; then + echo "ERROR: target does not exist: $target" >&2 + exit 1 + fi + + name=$(basename "$target") + + # Repo-level ignore via mise.toml + toml="$target/mise.toml" + if [[ -f "$toml" ]] && rg -q 'codebase:ignore bats-setup-suite-path' "$toml"; then + echo "SKIP $name (codebase:ignore)" + continue + fi + + suite="$target/$SETUP_SUITE" + if [[ ! -f "$suite" ]]; then + echo "OK $name (no $SETUP_SUITE -- nothing to check)" + continue + fi + + # Inline ignore + if rg -q 'codebase:ignore bats-setup-suite-path' "$suite"; then + echo "SKIP $name (inline codebase:ignore)" + continue + fi + + # Check: does the file call `mise env`? + if ! rg -q 'mise env' "$suite"; then + echo "OK $name ($SETUP_SUITE doesn't call mise env -- nothing to check)" + continue + fi + + # Check: is BATS_LIBEXEC preserved before the mise env call? + # Walk through the file top-to-bottom. If any `mise env` line appears + # without a preceding BATS_LIBEXEC capture, flag it. + bats_preserved=false + found_offense=false + + while IFS= read -r line; do + # Skip comments + [[ "$line" =~ ^[[:space:]]*# ]] && continue + + # Detect BATS_LIBEXEC capture (any assignment reading BATS_LIBEXEC) + if grep -q 'BATS_LIBEXEC' <<< "$line"; then + bats_preserved=true + fi + + # Detect `mise env` invocation + if grep -q 'mise env' <<< "$line"; then + if [[ "$bats_preserved" == false ]]; then + echo "FAIL $name (mise env without BATS_LIBEXEC preservation in $SETUP_SUITE)" + echo " hint: save BATS_LIBEXEC before mise env and prepend it afterward:" + # shellcheck disable=SC2016 + echo ' bats_libexec="${BATS_LIBEXEC:-}"' + # shellcheck disable=SC2016 + echo ' eval "$(cd "$REPO_DIR" && mise env)"' + # shellcheck disable=SC2016 + echo ' if [ -n "$bats_libexec" ]; then' + # shellcheck disable=SC2016 + echo ' export PATH="$bats_libexec:$PATH"' + echo ' fi' + echo " see: https://github.com/bats-core/bats-core/pull/1209" + failures=$((failures + 1)) + found_offense=true + break + fi + # Reset for potential subsequent mise env calls (defensive) + bats_preserved=false + fi + done < "$suite" + + if [[ "$found_offense" == false ]]; then + echo "OK $name ($SETUP_SUITE preserves BATS_LIBEXEC correctly)" + fi +done + +exit "$failures" \ No newline at end of file diff --git a/test/lint/bats-setup-suite-path/bats-setup-suite-path.bats b/test/lint/bats-setup-suite-path/bats-setup-suite-path.bats new file mode 100644 index 0000000..c32faf4 --- /dev/null +++ b/test/lint/bats-setup-suite-path/bats-setup-suite-path.bats @@ -0,0 +1,89 @@ +#!/usr/bin/env bats +# Tests for bats-setup-suite-path lint rule + +load ../../test_helper + +setup() { + FIXTURES="$BATS_TEST_DIRNAME/fixtures" +} + +# ============================================================================ +# Detection +# ============================================================================ + +@test "lint: passes when no test/setup_suite.bash exists" { + run codebase lint:bats-setup-suite-path "$FIXTURES/no-setup-suite" + [ "$status" -eq 0 ] + [[ "$output" == *"OK"* ]] + [[ "$output" == *"no test/setup_suite.bash"* ]] +} + +@test "lint: passes when BATS_LIBEXEC is preserved correctly" { + run codebase lint:bats-setup-suite-path "$FIXTURES/preserved" + [ "$status" -eq 0 ] + [[ "$output" == *"OK"* ]] + [[ "$output" == *"preserves BATS_LIBEXEC correctly"* ]] +} + +@test "lint: fails when mise env is called without BATS_LIBEXEC preservation" { + run codebase lint:bats-setup-suite-path "$FIXTURES/missing-preserve" + [ "$status" -ne 0 ] + [[ "$output" == *"FAIL"* ]] + [[ "$output" == *"mise env without BATS_LIBEXEC preservation"* ]] + # Should mention the fix + [[ "$output" == *"bats_libexec"* ]] + [[ "$output" == *"BATS_LIBEXEC:-"* ]] +} + +@test "lint: passes when setup_suite.bash doesn't call mise env" { + run codebase lint:bats-setup-suite-path "$FIXTURES/no-mise-env" + [ "$status" -eq 0 ] + [[ "$output" == *"OK"* ]] + [[ "$output" == *"doesn't call mise env"* ]] +} + +@test "lint: skips when inline codebase:ignore is present" { + run codebase lint:bats-setup-suite-path "$FIXTURES/ignored-inline" + [ "$status" -eq 0 ] + [[ "$output" == *"SKIP"* ]] +} + +@test "lint: skips when repo-level codebase:ignore is present in mise.toml" { + run codebase lint:bats-setup-suite-path "$FIXTURES/ignored-repo" + [ "$status" -eq 0 ] + [[ "$output" == *"SKIP"* ]] +} + +@test "lint: passes when no test/ directory exists" { + run codebase lint:bats-setup-suite-path "$FIXTURES/no-test-dir" + [ "$status" -eq 0 ] + [[ "$output" == *"OK"* ]] + [[ "$output" == *"no test/setup_suite.bash"* ]] +} + +@test "lint: handles multiple targets with mixed results" { + run codebase lint:bats-setup-suite-path \ + "$FIXTURES/preserved" \ + "$FIXTURES/missing-preserve" \ + "$FIXTURES/no-mise-env" + [ "$status" -ne 0 ] + [[ "$output" == *"OK"*"preserved"* ]] + [[ "$output" == *"FAIL"*"missing-preserve"* ]] + [[ "$output" == *"OK"*"no-mise-env"* ]] +} + +# ============================================================================ +# Error handling +# ============================================================================ + +@test "lint: fails when target does not exist" { + run codebase lint:bats-setup-suite-path /nonexistent + [ "$status" -ne 0 ] + [[ "$output" == *"ERROR"* ]] +} + +@test "lint: fails when no targets provided" { + run codebase lint:bats-setup-suite-path + [ "$status" -ne 0 ] + [[ "$output" == *"ERROR"* ]] +} \ No newline at end of file diff --git a/test/lint/bats-setup-suite-path/fixtures/ignored-inline/test/setup_suite.bash b/test/lint/bats-setup-suite-path/fixtures/ignored-inline/test/setup_suite.bash new file mode 100644 index 0000000..ef491e7 --- /dev/null +++ b/test/lint/bats-setup-suite-path/fixtures/ignored-inline/test/setup_suite.bash @@ -0,0 +1,6 @@ +setup_suite() { + REPO_DIR="$(cd "$BATS_TEST_DIRNAME/.." && pwd)" + export REPO_DIR + # codebase:ignore bats-setup-suite-path -- intentionally bypassing for test setup reasons + eval "$(cd "$REPO_DIR" && mise env)" +} \ No newline at end of file diff --git a/test/lint/bats-setup-suite-path/fixtures/ignored-repo/mise.toml b/test/lint/bats-setup-suite-path/fixtures/ignored-repo/mise.toml new file mode 100644 index 0000000..5b3247b --- /dev/null +++ b/test/lint/bats-setup-suite-path/fixtures/ignored-repo/mise.toml @@ -0,0 +1,3 @@ +[_.codebase] +lint = ["mise-settings"] +codebase:ignore bats-setup-suite-path \ No newline at end of file diff --git a/test/lint/bats-setup-suite-path/fixtures/ignored-repo/test/setup_suite.bash b/test/lint/bats-setup-suite-path/fixtures/ignored-repo/test/setup_suite.bash new file mode 100644 index 0000000..e7945ce --- /dev/null +++ b/test/lint/bats-setup-suite-path/fixtures/ignored-repo/test/setup_suite.bash @@ -0,0 +1,5 @@ +setup_suite() { + REPO_DIR="$(cd "$BATS_TEST_DIRNAME/.." && pwd)" + export REPO_DIR + eval "$(cd "$REPO_DIR" && mise env)" +} \ No newline at end of file diff --git a/test/lint/bats-setup-suite-path/fixtures/missing-preserve/test/setup_suite.bash b/test/lint/bats-setup-suite-path/fixtures/missing-preserve/test/setup_suite.bash new file mode 100644 index 0000000..e7945ce --- /dev/null +++ b/test/lint/bats-setup-suite-path/fixtures/missing-preserve/test/setup_suite.bash @@ -0,0 +1,5 @@ +setup_suite() { + REPO_DIR="$(cd "$BATS_TEST_DIRNAME/.." && pwd)" + export REPO_DIR + eval "$(cd "$REPO_DIR" && mise env)" +} \ No newline at end of file diff --git a/test/lint/bats-setup-suite-path/fixtures/no-mise-env/test/setup_suite.bash b/test/lint/bats-setup-suite-path/fixtures/no-mise-env/test/setup_suite.bash new file mode 100644 index 0000000..f976535 --- /dev/null +++ b/test/lint/bats-setup-suite-path/fixtures/no-mise-env/test/setup_suite.bash @@ -0,0 +1,5 @@ +setup_suite() { + REPO_DIR="$(cd "$BATS_TEST_DIRNAME/.." && pwd)" + export REPO_DIR + echo "setup complete" +} \ No newline at end of file diff --git a/test/lint/bats-setup-suite-path/fixtures/no-setup-suite/.gitkeep b/test/lint/bats-setup-suite-path/fixtures/no-setup-suite/.gitkeep new file mode 100644 index 0000000..2979cca --- /dev/null +++ b/test/lint/bats-setup-suite-path/fixtures/no-setup-suite/.gitkeep @@ -0,0 +1 @@ +# Minimal repo fixture — no test/setup_suite.bash to check \ No newline at end of file diff --git a/test/lint/bats-setup-suite-path/fixtures/preserved/test/setup_suite.bash b/test/lint/bats-setup-suite-path/fixtures/preserved/test/setup_suite.bash new file mode 100644 index 0000000..59b69ff --- /dev/null +++ b/test/lint/bats-setup-suite-path/fixtures/preserved/test/setup_suite.bash @@ -0,0 +1,10 @@ +setup_suite() { + REPO_DIR="$(cd "$BATS_TEST_DIRNAME/.." && pwd)" + export REPO_DIR + + bats_libexec="${BATS_LIBEXEC:-}" + eval "$(cd "$REPO_DIR" && mise env)" + if [ -n "$bats_libexec" ]; then + export PATH="$bats_libexec:$PATH" + fi +} \ No newline at end of file From cac1e002718976f17b459635f5529a41a0426424 Mon Sep 17 00:00:00 2001 From: olavostauros Date: Wed, 24 Jun 2026 10:31:17 -0300 Subject: [PATCH 3/4] style: collapse 3-line section comment blocks to single line --- .mise/tasks/lint/bats-setup-suite-path | 2 +- .mise/tasks/lint/mise-shiv-plugin | 2 +- test/lib/shell-files.bats | 2 -- .../bats-setup-suite-path.bats | 6 +----- .../ignored-inline/test/setup_suite.bash | 2 +- .../fixtures/ignored-repo/mise.toml | 2 +- .../ignored-repo/test/setup_suite.bash | 2 +- .../missing-preserve/test/setup_suite.bash | 2 +- .../fixtures/no-mise-env/test/setup_suite.bash | 2 +- .../fixtures/no-setup-suite/.gitkeep | 2 +- .../fixtures/preserved/test/setup_suite.bash | 2 +- .../bats-test-helper/bats-test-helper.bats | 14 -------------- test/lint/bats-test-task/bats-test-task.bats | 12 ------------ test/lint/gum-table/gum-table.bats | 16 ---------------- test/lint/mcr-scope/mcr-scope.bats | 10 ---------- test/lint/mise-settings/mise-settings.bats | 6 ------ .../fixtures/complete/mise.toml | 2 +- .../fixtures/ignored/mise.toml | 2 +- .../fixtures/missing-both/mise.toml | 2 +- .../fixtures/missing-experimental/mise.toml | 2 +- .../fixtures/missing-plugin/mise.toml | 2 +- .../fixtures/no-shiv-tools/mise.toml | 2 +- .../fixtures/no-toml/README.md | 2 +- .../mise-shiv-plugin/mise-shiv-plugin.bats | 6 +----- test/lint/or-true/or-true.bats | 18 ------------------ test/lint/shellcheck/shellcheck.bats | 10 ---------- test/migrations/task-pattern/task-pattern.bats | 10 ---------- test/pre-commit/pre-commit.bats | 16 ---------------- test/scan/scan.bats | 10 ---------- 29 files changed, 18 insertions(+), 150 deletions(-) mode change 100755 => 100644 .mise/tasks/lint/bats-setup-suite-path mode change 100755 => 100644 .mise/tasks/lint/mise-shiv-plugin diff --git a/.mise/tasks/lint/bats-setup-suite-path b/.mise/tasks/lint/bats-setup-suite-path old mode 100755 new mode 100644 index 771288c..b8dcc3f --- a/.mise/tasks/lint/bats-setup-suite-path +++ b/.mise/tasks/lint/bats-setup-suite-path @@ -127,4 +127,4 @@ for target in "${TARGETS[@]}"; do fi done -exit "$failures" \ No newline at end of file +exit "$failures" diff --git a/.mise/tasks/lint/mise-shiv-plugin b/.mise/tasks/lint/mise-shiv-plugin old mode 100755 new mode 100644 index 33b2675..4c54582 --- a/.mise/tasks/lint/mise-shiv-plugin +++ b/.mise/tasks/lint/mise-shiv-plugin @@ -72,4 +72,4 @@ for target in "${TARGETS[@]}"; do failures=$((failures + 1)) done -exit "$failures" \ No newline at end of file +exit "$failures" diff --git a/test/lib/shell-files.bats b/test/lib/shell-files.bats index a462482..5d6ed6e 100644 --- a/test/lib/shell-files.bats +++ b/test/lib/shell-files.bats @@ -7,9 +7,7 @@ setup() { source "$REPO_DIR/lib/shell-files.sh" } -# ============================================================================ # resolve_target -# ============================================================================ @test "resolve_target: absolute path passes through unchanged" { result=$(resolve_target "/some/absolute/path") diff --git a/test/lint/bats-setup-suite-path/bats-setup-suite-path.bats b/test/lint/bats-setup-suite-path/bats-setup-suite-path.bats index c32faf4..0f25179 100644 --- a/test/lint/bats-setup-suite-path/bats-setup-suite-path.bats +++ b/test/lint/bats-setup-suite-path/bats-setup-suite-path.bats @@ -7,9 +7,7 @@ setup() { FIXTURES="$BATS_TEST_DIRNAME/fixtures" } -# ============================================================================ # Detection -# ============================================================================ @test "lint: passes when no test/setup_suite.bash exists" { run codebase lint:bats-setup-suite-path "$FIXTURES/no-setup-suite" @@ -72,9 +70,7 @@ setup() { [[ "$output" == *"OK"*"no-mise-env"* ]] } -# ============================================================================ # Error handling -# ============================================================================ @test "lint: fails when target does not exist" { run codebase lint:bats-setup-suite-path /nonexistent @@ -86,4 +82,4 @@ setup() { run codebase lint:bats-setup-suite-path [ "$status" -ne 0 ] [[ "$output" == *"ERROR"* ]] -} \ No newline at end of file +} diff --git a/test/lint/bats-setup-suite-path/fixtures/ignored-inline/test/setup_suite.bash b/test/lint/bats-setup-suite-path/fixtures/ignored-inline/test/setup_suite.bash index ef491e7..ac3e730 100644 --- a/test/lint/bats-setup-suite-path/fixtures/ignored-inline/test/setup_suite.bash +++ b/test/lint/bats-setup-suite-path/fixtures/ignored-inline/test/setup_suite.bash @@ -3,4 +3,4 @@ setup_suite() { export REPO_DIR # codebase:ignore bats-setup-suite-path -- intentionally bypassing for test setup reasons eval "$(cd "$REPO_DIR" && mise env)" -} \ No newline at end of file +} diff --git a/test/lint/bats-setup-suite-path/fixtures/ignored-repo/mise.toml b/test/lint/bats-setup-suite-path/fixtures/ignored-repo/mise.toml index 5b3247b..af145ea 100644 --- a/test/lint/bats-setup-suite-path/fixtures/ignored-repo/mise.toml +++ b/test/lint/bats-setup-suite-path/fixtures/ignored-repo/mise.toml @@ -1,3 +1,3 @@ [_.codebase] lint = ["mise-settings"] -codebase:ignore bats-setup-suite-path \ No newline at end of file +codebase:ignore bats-setup-suite-path diff --git a/test/lint/bats-setup-suite-path/fixtures/ignored-repo/test/setup_suite.bash b/test/lint/bats-setup-suite-path/fixtures/ignored-repo/test/setup_suite.bash index e7945ce..db7a68d 100644 --- a/test/lint/bats-setup-suite-path/fixtures/ignored-repo/test/setup_suite.bash +++ b/test/lint/bats-setup-suite-path/fixtures/ignored-repo/test/setup_suite.bash @@ -2,4 +2,4 @@ setup_suite() { REPO_DIR="$(cd "$BATS_TEST_DIRNAME/.." && pwd)" export REPO_DIR eval "$(cd "$REPO_DIR" && mise env)" -} \ No newline at end of file +} diff --git a/test/lint/bats-setup-suite-path/fixtures/missing-preserve/test/setup_suite.bash b/test/lint/bats-setup-suite-path/fixtures/missing-preserve/test/setup_suite.bash index e7945ce..db7a68d 100644 --- a/test/lint/bats-setup-suite-path/fixtures/missing-preserve/test/setup_suite.bash +++ b/test/lint/bats-setup-suite-path/fixtures/missing-preserve/test/setup_suite.bash @@ -2,4 +2,4 @@ setup_suite() { REPO_DIR="$(cd "$BATS_TEST_DIRNAME/.." && pwd)" export REPO_DIR eval "$(cd "$REPO_DIR" && mise env)" -} \ No newline at end of file +} diff --git a/test/lint/bats-setup-suite-path/fixtures/no-mise-env/test/setup_suite.bash b/test/lint/bats-setup-suite-path/fixtures/no-mise-env/test/setup_suite.bash index f976535..b88e10e 100644 --- a/test/lint/bats-setup-suite-path/fixtures/no-mise-env/test/setup_suite.bash +++ b/test/lint/bats-setup-suite-path/fixtures/no-mise-env/test/setup_suite.bash @@ -2,4 +2,4 @@ setup_suite() { REPO_DIR="$(cd "$BATS_TEST_DIRNAME/.." && pwd)" export REPO_DIR echo "setup complete" -} \ No newline at end of file +} diff --git a/test/lint/bats-setup-suite-path/fixtures/no-setup-suite/.gitkeep b/test/lint/bats-setup-suite-path/fixtures/no-setup-suite/.gitkeep index 2979cca..54064e7 100644 --- a/test/lint/bats-setup-suite-path/fixtures/no-setup-suite/.gitkeep +++ b/test/lint/bats-setup-suite-path/fixtures/no-setup-suite/.gitkeep @@ -1 +1 @@ -# Minimal repo fixture — no test/setup_suite.bash to check \ No newline at end of file +# Minimal repo fixture — no test/setup_suite.bash to check diff --git a/test/lint/bats-setup-suite-path/fixtures/preserved/test/setup_suite.bash b/test/lint/bats-setup-suite-path/fixtures/preserved/test/setup_suite.bash index 59b69ff..0d00894 100644 --- a/test/lint/bats-setup-suite-path/fixtures/preserved/test/setup_suite.bash +++ b/test/lint/bats-setup-suite-path/fixtures/preserved/test/setup_suite.bash @@ -7,4 +7,4 @@ setup_suite() { if [ -n "$bats_libexec" ]; then export PATH="$bats_libexec:$PATH" fi -} \ No newline at end of file +} diff --git a/test/lint/bats-test-helper/bats-test-helper.bats b/test/lint/bats-test-helper/bats-test-helper.bats index 27ebba4..f4b0e76 100644 --- a/test/lint/bats-test-helper/bats-test-helper.bats +++ b/test/lint/bats-test-helper/bats-test-helper.bats @@ -7,9 +7,7 @@ setup() { FIXTURES="$BATS_TEST_DIRNAME/fixtures" } -# ============================================================================ # Pass paths -# ============================================================================ @test "bats-test-helper: passes on clean wrapper-based tests" { run codebase lint:bats-test-helper "$FIXTURES/clean" @@ -24,9 +22,7 @@ setup() { [[ "$output" == *"no test/ files found"* ]] } -# ============================================================================ # Invocation signatures — each form fails -# ============================================================================ @test "bats-test-helper: flags 'bash \$TASK' (var whose name contains TASK)" { run codebase lint:bats-test-helper "$FIXTURES/dirty-task-var" @@ -84,9 +80,7 @@ setup() { [[ "$output" == *"bash \$REPO_DIR/.mise/tasks/lint/check"* ]] } -# ============================================================================ # False positives — none of these are actual invocations -# ============================================================================ @test "bats-test-helper: does NOT flag reading a task file as data (grep/cat)" { # Regression guard: 'grep "$MCR/.mise/tasks/foo"' reads the script, doesn't @@ -97,9 +91,7 @@ setup() { [[ "$output" == *"OK"* ]] } -# ============================================================================ # Ignore directives -# ============================================================================ @test "bats-test-helper: inline '# codebase:ignore' suppresses a single line" { run codebase lint:bats-test-helper "$FIXTURES/ignored-inline" @@ -113,9 +105,7 @@ setup() { [[ "$output" == *"SKIP"*"ignored-file"* ]] } -# ============================================================================ # Output details -# ============================================================================ @test "bats-test-helper: fail output includes file:line citations" { run codebase lint:bats-test-helper "$FIXTURES/dirty-task-var" @@ -130,9 +120,7 @@ setup() { [[ "$output" == *"Call the Tool"* ]] } -# ============================================================================ # Error handling -# ============================================================================ @test "bats-test-helper: fails when no targets given" { run codebase lint:bats-test-helper @@ -146,9 +134,7 @@ setup() { [[ "$output" == *"does not exist"* ]] } -# ============================================================================ # Multi-target -# ============================================================================ @test "bats-test-helper: accepts multiple targets and reports each" { run codebase lint:bats-test-helper "$FIXTURES/clean" "$FIXTURES/dirty-task-var" diff --git a/test/lint/bats-test-task/bats-test-task.bats b/test/lint/bats-test-task/bats-test-task.bats index 295d92f..f761f2b 100644 --- a/test/lint/bats-test-task/bats-test-task.bats +++ b/test/lint/bats-test-task/bats-test-task.bats @@ -7,9 +7,7 @@ setup() { FIXTURES="$BATS_TEST_DIRNAME/fixtures" } -# ============================================================================ # Pass paths -# ============================================================================ @test "bats-test-task: passes on the canonical pattern" { run codebase lint:bats-test-task "$FIXTURES/clean" @@ -33,9 +31,7 @@ setup() { [[ "$output" == *"OK"*"shimmer-variant"* ]] } -# ============================================================================ # Failure modes -# ============================================================================ @test "bats-test-task: flags missing USAGE arg spec" { run codebase lint:bats-test-task "$FIXTURES/missing-usage-arg" @@ -80,9 +76,7 @@ setup() { [[ "$output" != *"invocations found"* ]] } -# ============================================================================ # Ignore directive -# ============================================================================ @test "bats-test-task: 'codebase:ignore bats-test-task' in mise.toml skips the target" { run codebase lint:bats-test-task "$FIXTURES/ignored-file" @@ -90,9 +84,7 @@ setup() { [[ "$output" == *"SKIP"*"ignored-file"* ]] } -# ============================================================================ # Output details -# ============================================================================ @test "bats-test-task: fail output includes the remediation hint" { run codebase lint:bats-test-task "$FIXTURES/missing-usage-arg" @@ -109,9 +101,7 @@ setup() { [[ "$output" == *"invocations"* ]] } -# ============================================================================ # Error handling -# ============================================================================ @test "bats-test-task: fails when no targets given" { run codebase lint:bats-test-task @@ -125,9 +115,7 @@ setup() { [[ "$output" == *"does not exist"* ]] } -# ============================================================================ # Multi-target -# ============================================================================ @test "bats-test-task: accepts multiple targets and reports each" { run codebase lint:bats-test-task "$FIXTURES/clean" "$FIXTURES/missing-examples" diff --git a/test/lint/gum-table/gum-table.bats b/test/lint/gum-table/gum-table.bats index 2dfddaa..809b670 100644 --- a/test/lint/gum-table/gum-table.bats +++ b/test/lint/gum-table/gum-table.bats @@ -7,9 +7,7 @@ setup() { FIXTURES="$BATS_TEST_DIRNAME/fixtures" } -# ============================================================================ # High confidence: column -t (always a true positive) -# ============================================================================ @test "column-t: detects piping to column -t" { run codebase lint:gum-table "$FIXTURES/manual-padding/task-c" @@ -18,9 +16,7 @@ setup() { [[ "$output" == *"WARN"* ]] } -# ============================================================================ # High confidence: printf padding inside a loop -# ============================================================================ @test "loop-table: detects printf %-Ns inside while-read" { run codebase lint:gum-table "$FIXTURES/manual-padding/task-b" @@ -45,9 +41,7 @@ setup() { echo "$output" | grep "padding" | grep -q "INFO" } -# ============================================================================ # Low confidence: printf padding outside loops (INFO only, not a failure) -# ============================================================================ @test "padding: printf %-Ns outside loop is INFO, not a failure" { run codebase lint:gum-table "$FIXTURES/manual-padding/task-a" @@ -69,9 +63,7 @@ setup() { [[ "$output" == *"INFO"* ]] } -# ============================================================================ # True negatives — no output at all -# ============================================================================ @test "clean: already using gum table" { run codebase lint:gum-table "$FIXTURES/clean/task-gum" @@ -103,9 +95,7 @@ setup() { [[ "$output" == *"OK"* ]] } -# ============================================================================ # Multi-file scanning -# ============================================================================ @test "directory scan finds high-confidence hits" { run codebase lint:gum-table "$FIXTURES/manual-padding" @@ -121,9 +111,7 @@ setup() { [ "$status" -eq 0 ] } -# ============================================================================ # Output format -# ============================================================================ @test "WARN output includes file path, category, and line number" { run codebase lint:gum-table "$FIXTURES/manual-padding/task-b" @@ -136,9 +124,7 @@ setup() { [[ "$output" =~ INFO.*task-a:\[padding\].*[0-9]+: ]] } -# ============================================================================ # Error handling -# ============================================================================ @test "fails when target does not exist" { run codebase lint:gum-table /nonexistent @@ -146,9 +132,7 @@ setup() { [[ "$output" == *"ERROR"* ]] } -# ============================================================================ # Relative path resolution (regression: codebase#24) -# ============================================================================ @test "relative path resolves against CODEBASE_CALLER_PWD (dirty fixture)" { # Regression: relative targets resolved against codebase's install diff --git a/test/lint/mcr-scope/mcr-scope.bats b/test/lint/mcr-scope/mcr-scope.bats index 3ae6215..49869b4 100644 --- a/test/lint/mcr-scope/mcr-scope.bats +++ b/test/lint/mcr-scope/mcr-scope.bats @@ -7,9 +7,7 @@ setup() { FIXTURES="$BATS_TEST_DIRNAME/fixtures" } -# ============================================================================ # Detection -# ============================================================================ @test "mcr-scope: passes on a clean codebase" { run codebase lint:mcr-scope "$FIXTURES/clean" @@ -102,9 +100,7 @@ setup() { [[ "$output" == *"no test/ or lib/ files found"* ]] } -# ============================================================================ # Ignore directives -# ============================================================================ @test "mcr-scope: inline '# codebase:ignore' suppresses a single line" { run codebase lint:mcr-scope "$FIXTURES/ignored-inline" @@ -118,9 +114,7 @@ setup() { [[ "$output" == *"SKIP"*"ignored-file"* ]] } -# ============================================================================ # Output details -# ============================================================================ @test "mcr-scope: fail output includes file:line citations" { run codebase lint:mcr-scope "$FIXTURES/dirty-lib" @@ -136,9 +130,7 @@ setup() { [[ "$output" == *"BASH_SOURCE"* ]] } -# ============================================================================ # Error handling -# ============================================================================ @test "mcr-scope: fails when no targets given" { run codebase lint:mcr-scope @@ -153,9 +145,7 @@ setup() { [[ "$output" == *"does not exist"* ]] } -# ============================================================================ # Multi-target -# ============================================================================ @test "mcr-scope: accepts multiple targets and reports each" { run codebase lint:mcr-scope "$FIXTURES/clean" "$FIXTURES/dirty-test" diff --git a/test/lint/mise-settings/mise-settings.bats b/test/lint/mise-settings/mise-settings.bats index 565be0a..d925495 100644 --- a/test/lint/mise-settings/mise-settings.bats +++ b/test/lint/mise-settings/mise-settings.bats @@ -7,9 +7,7 @@ setup() { FIXTURES="$BATS_TEST_DIRNAME/fixtures" } -# ============================================================================ # Detection -# ============================================================================ @test "lint: passes when all settings present" { run codebase lint:mise-settings "$FIXTURES/complete" @@ -54,9 +52,7 @@ setup() { [[ "$output" == *"FAIL"*"missing-both"* ]] } -# ============================================================================ # Fix mode -# ============================================================================ @test "fix: adds missing settings" { WORK_DIR="$BATS_TEST_TMPDIR/fix-test" @@ -96,9 +92,7 @@ setup() { [[ "$output" == *"OK"* ]] } -# ============================================================================ # Error handling -# ============================================================================ @test "lint: fails when target does not exist" { run codebase lint:mise-settings /nonexistent diff --git a/test/lint/mise-shiv-plugin/fixtures/complete/mise.toml b/test/lint/mise-shiv-plugin/fixtures/complete/mise.toml index 937db0f..02466e9 100644 --- a/test/lint/mise-shiv-plugin/fixtures/complete/mise.toml +++ b/test/lint/mise-shiv-plugin/fixtures/complete/mise.toml @@ -7,4 +7,4 @@ task_output = "interleave" shiv = "https://github.com/KnickKnackLabs/vfox-shiv" [tools] -"shiv:codebase" = "latest" \ No newline at end of file +"shiv:codebase" = "latest" diff --git a/test/lint/mise-shiv-plugin/fixtures/ignored/mise.toml b/test/lint/mise-shiv-plugin/fixtures/ignored/mise.toml index 02df3c6..fa470fa 100644 --- a/test/lint/mise-shiv-plugin/fixtures/ignored/mise.toml +++ b/test/lint/mise-shiv-plugin/fixtures/ignored/mise.toml @@ -10,4 +10,4 @@ shiv = "https://github.com/KnickKnackLabs/vfox-shiv" "shiv:codebase" = "latest" # This fixture should be ignored by mise-shiv-plugin -# codebase:ignore mise-shiv-plugin \ No newline at end of file +# codebase:ignore mise-shiv-plugin diff --git a/test/lint/mise-shiv-plugin/fixtures/missing-both/mise.toml b/test/lint/mise-shiv-plugin/fixtures/missing-both/mise.toml index 3a574f3..f8d317b 100644 --- a/test/lint/mise-shiv-plugin/fixtures/missing-both/mise.toml +++ b/test/lint/mise-shiv-plugin/fixtures/missing-both/mise.toml @@ -1,2 +1,2 @@ [tools] -"shiv:codebase" = "latest" \ No newline at end of file +"shiv:codebase" = "latest" diff --git a/test/lint/mise-shiv-plugin/fixtures/missing-experimental/mise.toml b/test/lint/mise-shiv-plugin/fixtures/missing-experimental/mise.toml index 93ec199..bf0ff29 100644 --- a/test/lint/mise-shiv-plugin/fixtures/missing-experimental/mise.toml +++ b/test/lint/mise-shiv-plugin/fixtures/missing-experimental/mise.toml @@ -5,4 +5,4 @@ quiet = true shiv = "https://github.com/KnickKnackLabs/vfox-shiv" [tools] -"shiv:codebase" = "latest" \ No newline at end of file +"shiv:codebase" = "latest" diff --git a/test/lint/mise-shiv-plugin/fixtures/missing-plugin/mise.toml b/test/lint/mise-shiv-plugin/fixtures/missing-plugin/mise.toml index 1ff0f6a..c58bdf8 100644 --- a/test/lint/mise-shiv-plugin/fixtures/missing-plugin/mise.toml +++ b/test/lint/mise-shiv-plugin/fixtures/missing-plugin/mise.toml @@ -2,4 +2,4 @@ experimental = true [tools] -"shiv:codebase" = "latest" \ No newline at end of file +"shiv:codebase" = "latest" diff --git a/test/lint/mise-shiv-plugin/fixtures/no-shiv-tools/mise.toml b/test/lint/mise-shiv-plugin/fixtures/no-shiv-tools/mise.toml index d6bddb5..d2230f5 100644 --- a/test/lint/mise-shiv-plugin/fixtures/no-shiv-tools/mise.toml +++ b/test/lint/mise-shiv-plugin/fixtures/no-shiv-tools/mise.toml @@ -4,4 +4,4 @@ quiet = true task_output = "interleave" [tools] -bats = "1.13.0" \ No newline at end of file +bats = "1.13.0" diff --git a/test/lint/mise-shiv-plugin/fixtures/no-toml/README.md b/test/lint/mise-shiv-plugin/fixtures/no-toml/README.md index 763da0a..96bae94 100644 --- a/test/lint/mise-shiv-plugin/fixtures/no-toml/README.md +++ b/test/lint/mise-shiv-plugin/fixtures/no-toml/README.md @@ -1,2 +1,2 @@ # This directory intentionally has no mise.toml -# Used to test graceful handling when mise.toml is missing \ No newline at end of file +# Used to test graceful handling when mise.toml is missing diff --git a/test/lint/mise-shiv-plugin/mise-shiv-plugin.bats b/test/lint/mise-shiv-plugin/mise-shiv-plugin.bats index c6d64f1..233e841 100644 --- a/test/lint/mise-shiv-plugin/mise-shiv-plugin.bats +++ b/test/lint/mise-shiv-plugin/mise-shiv-plugin.bats @@ -7,9 +7,7 @@ setup() { FIXTURES="$BATS_TEST_DIRNAME/fixtures" } -# ============================================================================ # Detection -# ============================================================================ @test "lint: passes when shiv plugin and experimental are present" { run codebase lint:mise-shiv-plugin "$FIXTURES/complete" @@ -68,9 +66,7 @@ setup() { [[ "$output" == *"FAIL"*"missing-both"* ]] } -# ============================================================================ # Error handling -# ============================================================================ @test "lint: fails when target does not exist" { run codebase lint:mise-shiv-plugin /nonexistent @@ -95,4 +91,4 @@ setup() { [[ "$output" == *"FAIL"*"missing-plugin"* ]] [[ "$output" == *"OK"*"no shiv tools"* ]] [[ "$output" == *"INFO"*"no mise.toml"* ]] -} \ No newline at end of file +} diff --git a/test/lint/or-true/or-true.bats b/test/lint/or-true/or-true.bats index 31d7776..68cfaca 100644 --- a/test/lint/or-true/or-true.bats +++ b/test/lint/or-true/or-true.bats @@ -7,9 +7,7 @@ setup() { FIXTURES="$BATS_TEST_DIRNAME/fixtures" } -# ============================================================================ # Detection -# ============================================================================ @test "or-true: passes on a clean codebase" { run codebase lint:or-true "$FIXTURES/clean" @@ -76,9 +74,7 @@ setup() { [[ "$output" == *"if !"* ]] } -# ============================================================================ # Corpus-calibrated diagnostics -# ============================================================================ @test "or-true: arithmetic increments get a safer arithmetic suggestion" { local tmp @@ -173,9 +169,7 @@ EOF [[ "$output" == *"Intentional cases need a rule-specific reason"* ]] } -# ============================================================================ # Ignore directives -# ============================================================================ @test "or-true: inline '# codebase:ignore or-true — reason' skips the line" { run codebase lint:or-true "$FIXTURES/ignored-inline" @@ -189,9 +183,7 @@ EOF [[ "$output" == *"SKIP"*"ignored-file"* ]] } -# ============================================================================ # Scope / discovery -# ============================================================================ @test "or-true: walks the whole target — finds hits outside .mise/tasks and lib/" { run codebase lint:or-true "$FIXTURES/broad-walk" @@ -213,9 +205,7 @@ EOF [[ "$output" == *"no shell files"* ]] } -# ============================================================================ # Discovery correctness -# ============================================================================ @test "or-true: discovery skips non-bash/sh shebangs (fish, zsh, …)" { # Regression: the shebang regex '^#!.*(bash|sh)\b' matched 'sh' as @@ -255,9 +245,7 @@ EOF rm -rf "$tmp" } -# ============================================================================ # Comment handling -# ============================================================================ @test "or-true: does not flag '|| true' inside a single-quoted string" { # Accidental protection: the closing quote ''' is not in the @@ -293,9 +281,7 @@ EOF rm -rf "$tmp" } -# ============================================================================ # Multi-target -# ============================================================================ @test "or-true: checks multiple targets and reports each" { run codebase lint:or-true "$FIXTURES/clean" "$FIXTURES/dirty" @@ -309,9 +295,7 @@ EOF [ "$status" -eq 2 ] } -# ============================================================================ # Error paths -# ============================================================================ @test "or-true: fails when target does not exist" { run codebase lint:or-true "$FIXTURES/does-not-exist" @@ -328,9 +312,7 @@ EOF [[ "$output" == *""* ]] } -# ============================================================================ # Relative path resolution (regression: codebase#24) -# ============================================================================ @test "or-true: relative path resolves against CODEBASE_CALLER_PWD, not codebase install dir" { # Regression: when invoked via the shiv shim, relative paths resolved diff --git a/test/lint/shellcheck/shellcheck.bats b/test/lint/shellcheck/shellcheck.bats index 370c7d6..f0ac032 100644 --- a/test/lint/shellcheck/shellcheck.bats +++ b/test/lint/shellcheck/shellcheck.bats @@ -7,9 +7,7 @@ setup() { FIXTURES="$BATS_TEST_DIRNAME/fixtures" } -# ============================================================================ # Detection -# ============================================================================ @test "lint: passes on a clean codebase" { run codebase lint:shellcheck "$FIXTURES/clean" @@ -37,9 +35,7 @@ setup() { [[ "$output" == *"SC"* ]] } -# ============================================================================ # Ignore directive -# ============================================================================ @test "lint: skips when codebase:ignore shellcheck is set in mise.toml" { run codebase lint:shellcheck "$FIXTURES/ignored" @@ -76,9 +72,7 @@ setup() { [[ "$output" == *"SC2154"* ]] } -# ============================================================================ # Scope -# ============================================================================ @test "lint: works on a codebase with no mise.toml" { run codebase lint:shellcheck "$FIXTURES/no-toml" @@ -100,9 +94,7 @@ setup() { [[ "$output" == *"bad.sh"* ]] } -# ============================================================================ # Multi-target -# ============================================================================ @test "lint: checks multiple targets and reports each" { run codebase lint:shellcheck "$FIXTURES/clean" "$FIXTURES/dirty" @@ -116,9 +108,7 @@ setup() { [ "$status" -eq 2 ] } -# ============================================================================ # Error paths -# ============================================================================ @test "lint: fails when target does not exist" { run codebase lint:shellcheck "$FIXTURES/does-not-exist" diff --git a/test/migrations/task-pattern/task-pattern.bats b/test/migrations/task-pattern/task-pattern.bats index d86c33e..5f8a90d 100644 --- a/test/migrations/task-pattern/task-pattern.bats +++ b/test/migrations/task-pattern/task-pattern.bats @@ -23,9 +23,7 @@ assert_matches_before() { diff -u "$FIXTURES/before/$file" "$WORK_DIR/$file" } -# ============================================================================ # Individual variant tests -# ============================================================================ @test "migrate: simple mise run → _task" { codebase migrate:task-pattern "$WORK_DIR" @@ -57,9 +55,7 @@ assert_matches_before() { assert_matches_after ".mise/tasks/error-strings" } -# ============================================================================ # Full migration test -# ============================================================================ @test "migrate: all files match expected after state" { codebase migrate:task-pattern "$WORK_DIR" @@ -68,9 +64,7 @@ assert_matches_before() { [ "$status" -eq 0 ] } -# ============================================================================ # Reverse migration tests -# ============================================================================ @test "reverse: _task → mise run" { # Start from the after state @@ -101,9 +95,7 @@ assert_matches_before() { ! grep -q '_task' "$WORK_DIR/.mise/tasks/in-subshell" } -# ============================================================================ # Round-trip tests -# ============================================================================ @test "round-trip: forward then reverse restores lossless fixtures" { # Only test fixtures where forward is lossless (no -q flag) @@ -114,9 +106,7 @@ assert_matches_before() { assert_matches_before ".mise/tasks/error-strings" } -# ============================================================================ # Error handling -# ============================================================================ @test "migrate: fails when target does not exist" { run codebase migrate:task-pattern /nonexistent diff --git a/test/pre-commit/pre-commit.bats b/test/pre-commit/pre-commit.bats index 96bd4f2..c0fbddc 100644 --- a/test/pre-commit/pre-commit.bats +++ b/test/pre-commit/pre-commit.bats @@ -24,9 +24,7 @@ EOF export CODEBASE_CALLER_PWD="$REPO" } -# ============================================================================ # Install — fresh repo -# ============================================================================ @test "install: creates dispatcher" { codebase pre-commit @@ -97,9 +95,7 @@ EOF [ -x "$REPO/.git/hooks/pre-commit" ] } -# ============================================================================ # Install — existing dispatcher -# ============================================================================ @test "install: preserves existing dispatcher and other hooks" { mkdir -p "$REPO/.git/hooks/pre-commit.d" @@ -121,9 +117,7 @@ EOF [ -f "$REPO/.git/hooks/pre-commit.d/codebase" ] } -# ============================================================================ # Install — existing plain hook (not a dispatcher) -# ============================================================================ @test "install: errors when existing plain hook is not a dispatcher" { cat > "$REPO/.git/hooks/pre-commit" <<'EOF' @@ -137,9 +131,7 @@ EOF [[ "$output" == *"not a dispatcher"* ]] } -# ============================================================================ # Idempotent -# ============================================================================ @test "install: running twice is safe" { codebase pre-commit @@ -149,9 +141,7 @@ EOF [ -f "$REPO/.git/hooks/pre-commit.d/codebase" ] } -# ============================================================================ # --check -# ============================================================================ @test "check: exits 0 when hook is current" { codebase pre-commit @@ -189,9 +179,7 @@ EOF [ "$status" -ne 0 ] } -# ============================================================================ # --revert -# ============================================================================ @test "revert: removes codebase hook" { codebase pre-commit @@ -225,9 +213,7 @@ EOF [[ "$output" == *"No codebase hook"* ]] } -# ============================================================================ # Scope -# ============================================================================ @test "scope: default scopes are delegated to aggregate lint" { cat > "$REPO/mise.toml" <<'EOF' @@ -258,9 +244,7 @@ EOF ! grep -q 'src/scripts' "$REPO/.git/hooks/pre-commit.d/codebase" } -# ============================================================================ # Error handling -# ============================================================================ @test "error: fails outside git repo" { export CODEBASE_CALLER_PWD="$BATS_TEST_TMPDIR" diff --git a/test/scan/scan.bats b/test/scan/scan.bats index 9552433..e52a500 100644 --- a/test/scan/scan.bats +++ b/test/scan/scan.bats @@ -8,9 +8,7 @@ setup() { FIXTURES_B="$BATS_TEST_DIRNAME/fixtures-b" } -# ============================================================================ # Single target (basic matching) -# ============================================================================ @test "scan: finds mise run calls in extension-less task files" { run codebase scan -p 'mise run $$$ARGS' "$FIXTURES_A" @@ -39,9 +37,7 @@ setup() { [[ -z "$output" ]] } -# ============================================================================ # Different patterns -# ============================================================================ @test "scan: finds _task calls with custom pattern" { run codebase scan -p '_task $$$ARGS' "$FIXTURES_A" @@ -56,9 +52,7 @@ setup() { [ "$count" -eq 4 ] } -# ============================================================================ # Multiple targets -# ============================================================================ @test "multi: finds matches across multiple codebases" { run codebase scan -p 'mise run $$$ARGS' "$FIXTURES_A" "$FIXTURES_B" @@ -84,9 +78,7 @@ setup() { [[ "$output" != *"fixtures-b:"* ]] } -# ============================================================================ # Exclude filter -# ============================================================================ @test "exclude: filters out files matching glob" { run codebase scan -p 'mise run $$$ARGS' -e '.mise/tasks/ci/*' "$FIXTURES_A" @@ -110,9 +102,7 @@ setup() { [[ "$output" != *"ci/deploy"* ]] } -# ============================================================================ # Error handling -# ============================================================================ @test "error: fails when no pattern provided" { run codebase scan "$FIXTURES_A" From b5079545c82f1ef35be3b9c63fed0c5ea356d50e Mon Sep 17 00:00:00 2001 From: olavostauros Date: Thu, 25 Jun 2026 16:27:09 -0300 Subject: [PATCH 4/4] fix: make new lint task files executable (644 -> 755) mise requires task files under .mise/tasks/ to be executable (mode 755) to discover them. Both bats-setup-suite-path and mise-shiv-plugin were committed as 644 (non-executable), causing mise run to report "no task found" and all functional BATS tests to fail. --- .mise/tasks/lint/bats-setup-suite-path | 0 .mise/tasks/lint/mise-shiv-plugin | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .mise/tasks/lint/bats-setup-suite-path mode change 100644 => 100755 .mise/tasks/lint/mise-shiv-plugin diff --git a/.mise/tasks/lint/bats-setup-suite-path b/.mise/tasks/lint/bats-setup-suite-path old mode 100644 new mode 100755 diff --git a/.mise/tasks/lint/mise-shiv-plugin b/.mise/tasks/lint/mise-shiv-plugin old mode 100644 new mode 100755