- Read changed paths NUL-delimited so non-ASCII paths are no longer silently skipped. - Fail closed when only local main resolves and the pushed commit is the merge-base, instead of passing on an empty diff. - Accept ASCII-only versions with at most nine digits per part. - Check for python3/PyYAML up front, and report read failures as such rather than as a missing version; name a missing SKILL.md. - Document that pre-commit gates only the first ref of a multi-ref push. Tests grow to 29 cases covering each fix plus annotated tags, CRLF frontmatter, unrelated histories and pushing main. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
411 lines
16 KiB
Bash
Executable File
411 lines
16 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
SCRIPT="$REPO_ROOT/scripts/check-skill-version-bump.sh"
|
||
PASS=0
|
||
FAIL=0
|
||
|
||
pass() { echo " PASS: $1"; PASS=$((PASS + 1)); }
|
||
fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
|
||
|
||
# The gate reads versions with python3 + PyYAML, the same hard requirement
|
||
# skill-size-check carries. Without them this suite cannot run: exit 77 so
|
||
# run-tests reports SKIPPED (and --strict fails the push).
|
||
if ! python3 -c 'import yaml' 2>/dev/null; then
|
||
echo "SKIP: python3 with PyYAML is required" >&2
|
||
exit 77
|
||
fi
|
||
|
||
# Output assertions use here-strings, never `echo | grep -q` (pipefail race;
|
||
# see tests/test-check-release-needed.sh).
|
||
|
||
CLEANUP_DIRS=()
|
||
trap 'rm -rf ${CLEANUP_DIRS[@]+"${CLEANUP_DIRS[@]}"}' EXIT
|
||
|
||
# write_skill <repo> <plugin> <skill> <version-line|""> [body]
|
||
# An empty version line writes a SKILL.md with no metadata block at all.
|
||
write_skill() {
|
||
local repo="$1" plugin="$2" skill="$3" vline="$4" body="${5:-body}"
|
||
local d="$repo/plugins/$plugin/.apm/skills/$skill"
|
||
mkdir -p "$d"
|
||
{
|
||
echo "---"
|
||
echo "name: $skill"
|
||
echo "description: Use when testing."
|
||
if [[ -n "$vline" ]]; then
|
||
echo "metadata:"
|
||
echo " $vline"
|
||
fi
|
||
echo "---"
|
||
echo "$body"
|
||
} > "$d/SKILL.md"
|
||
}
|
||
|
||
commit() { (cd "$1" && git add -A && git commit -q -m "${2:-change}"); }
|
||
|
||
# A fixture with skills alpha (1.0.0) and beta (1.0.9) on main, then checked out
|
||
# onto a feature branch.
|
||
make_fixture() {
|
||
local dir
|
||
dir="$(mktemp -d)"
|
||
CLEANUP_DIRS+=("$dir")
|
||
(cd "$dir" && git init -q -b main && git config user.email t@t.t && git config user.name t)
|
||
write_skill "$dir" demo alpha 'version: "1.0.0"'
|
||
write_skill "$dir" demo beta "version: 1.0.9"
|
||
commit "$dir" initial
|
||
(cd "$dir" && git checkout -q -b feature)
|
||
echo "$dir"
|
||
}
|
||
|
||
# Every PRE_COMMIT_* input comes from here: a value inherited from the pre-push
|
||
# hook running this suite names a sha of the real repo, not the fixture.
|
||
run_check() {
|
||
local dir="$1"
|
||
if [[ $# -ge 2 ]]; then
|
||
(cd "$dir" && unset PRE_COMMIT_FROM_REF PRE_COMMIT_REMOTE_BRANCH \
|
||
&& PRE_COMMIT_TO_REF="$2" bash "$SCRIPT" 2>&1)
|
||
else
|
||
(cd "$dir" && unset PRE_COMMIT_FROM_REF PRE_COMMIT_TO_REF PRE_COMMIT_REMOTE_BRANCH \
|
||
&& bash "$SCRIPT" 2>&1)
|
||
fi
|
||
}
|
||
|
||
# expect_pass <desc> <dir> [to-ref]
|
||
expect_pass() {
|
||
local desc="$1"; shift
|
||
local out
|
||
if out="$(run_check "$@")" && [[ -z "$out" ]]; then
|
||
pass "$desc"
|
||
else
|
||
fail "$desc — expected silent exit 0, got: $out"
|
||
fi
|
||
}
|
||
|
||
# expect_fail <desc> <pattern> <dir> [to-ref]
|
||
expect_fail() {
|
||
local desc="$1" pattern="$2"; shift 2
|
||
local out
|
||
if out="$(run_check "$@")"; then
|
||
fail "$desc — expected non-zero exit, got 0"
|
||
elif grep -qE "$pattern" <<< "$out"; then
|
||
pass "$desc"
|
||
else
|
||
fail "$desc — output did not match /$pattern/: $out"
|
||
fi
|
||
}
|
||
|
||
echo ""
|
||
echo "--- 1. unchanged skill passes ---"
|
||
F="$(make_fixture)"
|
||
echo "unrelated" > "$F/README.md"; commit "$F"
|
||
expect_pass "no skill change passes silently" "$F"
|
||
|
||
echo ""
|
||
echo "--- 2. changed without bump fails ---"
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo alpha 'version: "1.0.0"' "new body"; commit "$F"
|
||
expect_fail "unbumped change fails and names baseline and current" "alpha: 1\.0\.0 -> 1\.0\.0" "$F"
|
||
|
||
echo ""
|
||
echo "--- 3. changed with patch / minor / major bump passes ---"
|
||
for v in 1.0.1 1.1.0 2.0.0; do
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo alpha "version: \"$v\"" "new body"; commit "$F"
|
||
expect_pass "bump to $v passes" "$F"
|
||
done
|
||
|
||
echo ""
|
||
echo "--- 4. version decreased fails ---"
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo beta "version: 1.0.8" "new body"; commit "$F"
|
||
expect_fail "decrease fails" "beta: 1\.0\.9 -> 1\.0\.8" "$F"
|
||
|
||
echo ""
|
||
echo "--- 5. change to a non-SKILL.md file still counts ---"
|
||
F="$(make_fixture)"
|
||
mkdir -p "$F/plugins/demo/.apm/skills/alpha/references"
|
||
echo "ref" > "$F/plugins/demo/.apm/skills/alpha/references/x.md"; commit "$F"
|
||
expect_fail "references/ change without bump fails" "alpha: 1\.0\.0 -> 1\.0\.0" "$F"
|
||
|
||
echo ""
|
||
echo "--- 6. tests/-only change passes without bump ---"
|
||
F="$(make_fixture)"
|
||
mkdir -p "$F/plugins/demo/.apm/skills/alpha/tests"
|
||
echo "t" > "$F/plugins/demo/.apm/skills/alpha/tests/test-x.sh"; commit "$F"
|
||
expect_pass "tests/-only change is exempt" "$F"
|
||
|
||
echo ""
|
||
echo "--- 7. new skill exempt ---"
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo gamma 'version: "0.1.0"'; commit "$F"
|
||
expect_pass "new skill passes" "$F"
|
||
|
||
echo ""
|
||
echo "--- 8. deleted skill exempt ---"
|
||
F="$(make_fixture)"
|
||
rm -rf "$F/plugins/demo/.apm/skills/alpha"; commit "$F"
|
||
expect_pass "deleted skill passes" "$F"
|
||
|
||
echo ""
|
||
echo "--- 9. renamed skill exempt ---"
|
||
F="$(make_fixture)"
|
||
(cd "$F" && git mv plugins/demo/.apm/skills/alpha plugins/demo/.apm/skills/alpha2)
|
||
commit "$F"
|
||
expect_pass "renamed skill passes (old absent at pushed, new absent at baseline)" "$F"
|
||
|
||
echo ""
|
||
echo "--- 10. missing version on changed skill fails ---"
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo alpha "" "new body"; commit "$F"
|
||
expect_fail "missing version fails" "alpha: metadata\.version missing" "$F"
|
||
|
||
echo ""
|
||
echo "--- 11. malformed / prerelease version fails ---"
|
||
for v in 'version: 1.1' 'version: "1.0.1-rc1"'; do
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo alpha "$v" "new body"; commit "$F"
|
||
expect_fail "'$v' is rejected like skill-size-check rejects it" "alpha: metadata\.version missing or not" "$F"
|
||
done
|
||
|
||
echo ""
|
||
echo "--- 12. multiple offenders all reported ---"
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo alpha 'version: "1.0.0"' "x"
|
||
write_skill "$F" demo beta "version: 1.0.9" "x"
|
||
commit "$F"
|
||
OUT="$(run_check "$F" || true)"
|
||
if grep -q "alpha: 1.0.0 -> 1.0.0" <<< "$OUT" && grep -q "beta: 1.0.9 -> 1.0.9" <<< "$OUT" \
|
||
&& grep -q "bump PATCH at minimum" <<< "$OUT"; then
|
||
pass "both offenders and the fix are reported"
|
||
else
|
||
fail "not every offender reported: $OUT"
|
||
fi
|
||
|
||
echo ""
|
||
echo "--- 13. PRE_COMMIT_TO_REF respected over HEAD ---"
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo alpha 'version: "1.0.0"' "unbumped"; commit "$F"
|
||
BAD="$(cd "$F" && git rev-parse HEAD)"
|
||
(cd "$F" && git checkout -q -b clean main)
|
||
echo "unrelated" > "$F/README.md"; commit "$F"
|
||
CLEAN="$(cd "$F" && git rev-parse HEAD)"
|
||
expect_fail "unbumped TO_REF fails while HEAD is clean" "alpha: 1\.0\.0 -> 1\.0\.0" "$F" "$BAD"
|
||
(cd "$F" && git checkout -q "$BAD")
|
||
expect_pass "clean TO_REF passes while HEAD is unbumped" "$F" "$CLEAN"
|
||
|
||
echo ""
|
||
echo "--- 14. all-zeros delete sha no-ops ---"
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo alpha 'version: "1.0.0"' "unbumped"; commit "$F"
|
||
expect_pass "40-zero sha exits 0" "$F" "0000000000000000000000000000000000000000"
|
||
expect_pass "64-zero sha exits 0" "$F" "$(printf '0%.0s' {1..64})"
|
||
|
||
echo ""
|
||
echo "--- 15. bin plugin covered ---"
|
||
F="$(make_fixture)"
|
||
write_skill "$F" bin tool 'version: "1.0.0"'
|
||
(cd "$F" && git checkout -q main); commit "$F" "add bin skill"
|
||
(cd "$F" && git checkout -q feature && git merge -q main)
|
||
write_skill "$F" bin tool 'version: "1.0.0"' "changed"; commit "$F"
|
||
expect_fail "bin skill change without bump fails" "plugins/bin/\.apm/skills/tool: 1\.0\.0 -> 1\.0\.0" "$F"
|
||
|
||
echo ""
|
||
echo "--- 16. multi-digit semver compare ---"
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo beta "version: 1.0.10" "x"; commit "$F"
|
||
expect_pass "1.0.10 > 1.0.9 passes" "$F"
|
||
|
||
echo ""
|
||
echo "--- 17. baseline is the merge-base, not main's tip ---"
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo alpha 'version: "1.0.1"' "branch change"; commit "$F"
|
||
(cd "$F" && git checkout -q main)
|
||
write_skill "$F" demo alpha 'version: "1.0.5"' "main moved on"; commit "$F"
|
||
(cd "$F" && git checkout -q feature)
|
||
expect_pass "bump over the merge-base passes even though main is ahead" "$F"
|
||
|
||
echo ""
|
||
echo "--- 18. origin/main preferred over local main ---"
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo alpha 'version: "1.0.1"' "x"; commit "$F"
|
||
# A stale local main pointing at the feature tip would make the diff empty;
|
||
# origin/main at the original commit must win and still see the change.
|
||
(cd "$F" && git update-ref refs/remotes/origin/main main && git branch -f main feature)
|
||
write_skill "$F" demo alpha 'version: "1.0.1"' "y"; commit "$F"
|
||
if OUT="$(run_check "$F")" && [[ -z "$OUT" ]]; then
|
||
pass "origin/main used as baseline (1.0.0 -> 1.0.1 counted as a bump)"
|
||
else
|
||
fail "unexpected output: $OUT"
|
||
fi
|
||
(cd "$F" && git update-ref refs/remotes/origin/main feature~1)
|
||
expect_fail "origin/main at the bumped commit flags the further unbumped change" \
|
||
"merge-base with origin/main" "$F"
|
||
|
||
echo ""
|
||
echo "--- 19. no main ref fails closed ---"
|
||
F="$(mktemp -d)"; CLEANUP_DIRS+=("$F")
|
||
(cd "$F" && git init -q -b trunk && git config user.email t@t.t && git config user.name t)
|
||
write_skill "$F" demo alpha 'version: "1.0.0"'; commit "$F"
|
||
expect_fail "missing main fails with a clear message" "neither origin/main nor main resolves" "$F"
|
||
|
||
echo ""
|
||
echo "--- 20. non-ASCII paths are not hidden by core.quotePath ---"
|
||
F="$(make_fixture)"
|
||
mkdir -p "$F/plugins/demo/.apm/skills/alpha/references"
|
||
echo "ref" > "$F/plugins/demo/.apm/skills/alpha/references/résumé.md"; commit "$F"
|
||
expect_fail "non-ASCII file under references/ without bump fails" "alpha: 1\.0\.0 -> 1\.0\.0" "$F"
|
||
F="$(make_fixture)"
|
||
(cd "$F" && git checkout -q main)
|
||
write_skill "$F" demo "café" 'version: "2.0.0"'; commit "$F" "add café"
|
||
(cd "$F" && git checkout -q feature && git merge -q main)
|
||
write_skill "$F" demo "café" 'version: "2.0.0"' "changed"; commit "$F"
|
||
expect_fail "non-ASCII skill dir without bump fails" "skills/café: 2\.0\.0 -> 2\.0\.0" "$F"
|
||
write_skill "$F" demo "café" 'version: "2.0.1"' "changed again"; commit "$F"
|
||
expect_pass "non-ASCII skill dir with bump passes" "$F"
|
||
|
||
echo ""
|
||
echo "--- 21. local main fallback: pushed commit already in main fails closed ---"
|
||
F="$(make_fixture)"
|
||
MAIN_SHA="$(cd "$F" && git rev-parse main)"
|
||
expect_fail "pushing main's sha without origin/main fails" \
|
||
"origin/main does not resolve.*already contained in local main" "$F" "$MAIN_SHA"
|
||
(cd "$F" && git checkout -q main)
|
||
expect_fail "HEAD on main without origin/main fails" "Fix: git fetch origin main" "$F"
|
||
|
||
echo ""
|
||
echo "--- 22. pushing main itself with origin/main present ---"
|
||
F="$(make_fixture)"
|
||
(cd "$F" && git checkout -q main && git update-ref refs/remotes/origin/main main)
|
||
expect_pass "main equal to origin/main passes (nothing changed vs main)" "$F"
|
||
write_skill "$F" demo alpha 'version: "1.0.1"' "x"; commit "$F"
|
||
expect_pass "main ahead of origin/main with a bump passes" "$F"
|
||
write_skill "$F" demo beta "version: 1.0.9" "x"; commit "$F"
|
||
expect_fail "main ahead of origin/main without a bump fails" "beta: 1\.0\.9 -> 1\.0\.9" "$F"
|
||
(cd "$F" && git update-ref refs/remotes/origin/main main)
|
||
expect_pass "already-merged content (merge-base == pushed) passes against origin/main" "$F" \
|
||
"$(cd "$F" && git rev-parse main~1)"
|
||
|
||
echo ""
|
||
echo "--- 23. version shape is ASCII-only and bounded ---"
|
||
for v in 'version: "1.0.1"' 'version: "1.0.1"' 'version: "1.0.9999999999"' \
|
||
'version: "99999999999999999999.0.0"'; do
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo alpha "$v" "new body"; commit "$F"
|
||
OUT="$(run_check "$F" || true)"
|
||
if grep -q "alpha: metadata\.version missing or not" <<< "$OUT" \
|
||
&& ! grep -qiE "integer|syntax error|value too great" <<< "$OUT"; then
|
||
pass "'$v' is rejected as invalid without a bash arithmetic error"
|
||
else
|
||
fail "'$v' not cleanly rejected: $OUT"
|
||
fi
|
||
done
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo alpha 'version: "1.0.999999999"' "new body"; commit "$F"
|
||
expect_pass "nine-digit part is accepted and compared" "$F"
|
||
|
||
echo ""
|
||
echo "--- 24. python3 / PyYAML failures are never reported as a missing version ---"
|
||
REAL_PYTHON="$(command -v python3)"
|
||
SHIM_ROOT="$(mktemp -d)"; CLEANUP_DIRS+=("$SHIM_ROOT")
|
||
mkdir -p "$SHIM_ROOT/shadow" "$SHIM_ROOT/noyaml" "$SHIM_ROOT/crash"
|
||
printf 'raise ImportError("PyYAML deliberately unavailable in this fixture")\n' \
|
||
> "$SHIM_ROOT/shadow/yaml.py"
|
||
cat > "$SHIM_ROOT/noyaml/python3" <<EOF
|
||
#!/bin/sh
|
||
PYTHONPATH="$SHIM_ROOT/shadow\${PYTHONPATH:+:\$PYTHONPATH}" exec "$REAL_PYTHON" "\$@"
|
||
EOF
|
||
# Passes the up-front import probe, crashes on the real read.
|
||
cat > "$SHIM_ROOT/crash/python3" <<EOF
|
||
#!/bin/sh
|
||
[ "\$1" = "-c" ] && [ "\$2" = "import yaml" ] && exec "$REAL_PYTHON" "\$@"
|
||
echo "Traceback: simulated interpreter failure" >&2
|
||
exit 1
|
||
EOF
|
||
chmod +x "$SHIM_ROOT/noyaml/python3" "$SHIM_ROOT/crash/python3"
|
||
if PATH="$SHIM_ROOT/noyaml:$PATH" python3 -c 'import yaml' 2>/dev/null; then
|
||
fail "fixture check: the no-PyYAML shim still imports yaml — the next assertion would be vacuous"
|
||
else
|
||
pass "fixture check: the no-PyYAML shim makes 'import yaml' fail"
|
||
fi
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo alpha 'version: "1.0.1"' "new body"; commit "$F"
|
||
OUT="$(cd "$F" && unset PRE_COMMIT_FROM_REF PRE_COMMIT_TO_REF PRE_COMMIT_REMOTE_BRANCH \
|
||
&& PATH="$SHIM_ROOT/noyaml:$PATH" bash "$SCRIPT" 2>&1)" && RC=0 || RC=$?
|
||
if [[ $RC -ne 0 ]] && grep -q "PyYAML is required" <<< "$OUT" && grep -q "Fix: python3 -m pip install PyYAML" <<< "$OUT" \
|
||
&& ! grep -q "Traceback" <<< "$OUT"; then
|
||
pass "missing PyYAML fails with FAIL + Fix, no traceback"
|
||
else
|
||
fail "missing PyYAML not reported cleanly (rc=$RC): $OUT"
|
||
fi
|
||
OUT="$(cd "$F" && unset PRE_COMMIT_FROM_REF PRE_COMMIT_TO_REF PRE_COMMIT_REMOTE_BRANCH \
|
||
&& PATH="$SHIM_ROOT/crash:$PATH" bash "$SCRIPT" 2>&1)" && RC=0 || RC=$?
|
||
if [[ $RC -ne 0 ]] && grep -q "could not read metadata.version" <<< "$OUT" \
|
||
&& ! grep -q "missing or not" <<< "$OUT"; then
|
||
pass "python3 crash during the read is a read failure, not a missing version"
|
||
else
|
||
fail "python3 crash misreported (rc=$RC): $OUT"
|
||
fi
|
||
|
||
echo ""
|
||
echo "--- 25. SKILL.md deleted but skill dir kept ---"
|
||
F="$(make_fixture)"
|
||
mkdir -p "$F/plugins/demo/.apm/skills/alpha/references"
|
||
echo "ref" > "$F/plugins/demo/.apm/skills/alpha/references/x.md"
|
||
rm "$F/plugins/demo/.apm/skills/alpha/SKILL.md"; commit "$F"
|
||
expect_fail "missing SKILL.md is reported as such" "alpha: SKILL\.md missing at HEAD \(baseline: 1\.0\.0\)" "$F"
|
||
|
||
echo ""
|
||
echo "--- 26. baseline without a valid version accepts any valid version ---"
|
||
F="$(make_fixture)"
|
||
(cd "$F" && git checkout -q main)
|
||
write_skill "$F" demo legacy ""; commit "$F" "add legacy skill"
|
||
(cd "$F" && git checkout -q feature && git merge -q main)
|
||
write_skill "$F" demo legacy 'version: "0.0.1"' "changed"; commit "$F"
|
||
expect_pass "invalid baseline + valid current passes" "$F"
|
||
|
||
echo ""
|
||
echo "--- 27. no merge-base (unrelated histories) fails closed ---"
|
||
F="$(make_fixture)"
|
||
(cd "$F" && git checkout -q --orphan unrelated && git rm -rq --cached . && rm -rf plugins)
|
||
write_skill "$F" demo alpha 'version: "1.0.0"' "orphan"; commit "$F" "orphan root"
|
||
expect_fail "unrelated history fails at the merge-base check" "no merge-base between main and HEAD" "$F"
|
||
|
||
echo ""
|
||
echo "--- 28. annotated tag push is peeled to its commit ---"
|
||
F="$(make_fixture)"
|
||
write_skill "$F" demo alpha 'version: "1.0.0"' "unbumped"; commit "$F"
|
||
(cd "$F" && git tag -a v9 -m "tag" && git checkout -q main)
|
||
TAG_OBJ="$(cd "$F" && git rev-parse v9)"
|
||
if [[ "$(cd "$F" && git cat-file -t "$TAG_OBJ")" == "tag" ]]; then
|
||
pass "fixture check: TO_REF is a tag object, not a commit"
|
||
else
|
||
fail "fixture check: v9 is not an annotated tag object"
|
||
fi
|
||
expect_fail "unbumped change behind an annotated tag fails" "alpha: 1\.0\.0 -> 1\.0\.0" "$F" "$TAG_OBJ"
|
||
|
||
echo ""
|
||
echo "--- 29. CRLF frontmatter is parsed ---"
|
||
# crlf <repo> <skill>: rewrite that skill's SKILL.md with CRLF line endings.
|
||
crlf() {
|
||
local f="$1/plugins/demo/.apm/skills/$2/SKILL.md"
|
||
sed 's/$/\r/' "$f" > "$f.tmp" && mv "$f.tmp" "$f"
|
||
}
|
||
F="$(make_fixture)"
|
||
(cd "$F" && git config core.autocrlf false && git checkout -q main)
|
||
crlf "$F" alpha; commit "$F" "alpha to CRLF"
|
||
(cd "$F" && git checkout -q feature && git merge -q main)
|
||
write_skill "$F" demo alpha 'version: "1.0.0"' "crlf body"; crlf "$F" alpha; commit "$F"
|
||
if grep -q $'\r' "$F/plugins/demo/.apm/skills/alpha/SKILL.md"; then
|
||
pass "fixture check: SKILL.md carries CRLF"
|
||
else
|
||
fail "fixture check: SKILL.md has no CRLF"
|
||
fi
|
||
expect_fail "unbumped CRLF skill reports both parsed versions" "alpha: 1\.0\.0 -> 1\.0\.0" "$F"
|
||
write_skill "$F" demo alpha 'version: "1.0.1"' "crlf body 2"; crlf "$F" alpha; commit "$F"
|
||
expect_pass "bumped CRLF skill passes" "$F"
|
||
|
||
echo ""
|
||
echo "Results: $PASS passed, $FAIL failed"
|
||
[[ $FAIL -eq 0 ]]
|