mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 18:07:06 +01:00
The last unit over the cap is now github.com/kuhyx/digital-wellbeing, cloned at ~/digital-wellbeing, and `--warn` is gone from the directory-depth-cap hook. `check_directory_depth.sh --all` exits 0 with zero violations, down from 46 at the start of the session. That was the point of the campaign. History was filtered across all three paths the unit has lived at (63 commits); the current path alone holds 2. The six suites that test this code lived in linux_configuration/tests/ rather than beside it, so they were filtered separately (24 commits) and merged in as a second root. A path filter of the unit alone would have left them here, testing code that had left the repo -- and their names would still have been in shell-tests.yml's hardcoded arrays, failing CI on missing files. linux_configuration/lib/common.sh is vendored into vendor/ rather than trimmed to the four functions actually used: set_actual_user_vars calls two of the others, so a trim breaks silently. It is in vendor/ and not lib/ because test_music_parallelism.sh copies the unit's own lib/ into a scratch worktree while stubbing the shared lib; in one directory the real common.sh overwrote the stub, and the suite silently measured the wrong library. Running the callers caught what shellcheck and grep both missed: check_and_enable_services.sh died with "DW_REPO: unbound variable" because the definition sat below its first use. It now runs clean and reports ok for every extracted-unit check. Two long-standing live defects fixed as a consequence. The pacman-wrapper drift manifest embeds ABSOLUTE paths and had named deleted scripts/ paths since the flatten, so the check reported a permanent false "stale or tampered"; it now verifies, with unchanged hashes proving the extracted bytes are identical. And the last two stale live references are gone: 8 -> 0. The two pre-commit excludes for setup_midnight_shutdown.sh are dropped rather than moved. lsattr shows nothing in the unit is chattr +i any more, and the fixer hooks leave the file alone when allowed to run. Removing 80 shell files also shrank the jscpd denominator enough that the virtualenv/tqdm clones inside the GENERATED .ci-mirror-venv/ tipped the repo to 2.09% and blocked this commit, which adds no duplication. That directory is the same vendored third-party shell the ignore list already excludes as .venv/, just under another name; jscpd walks the working tree rather than the index, so being untracked did not spare it. Excluded by name: 1.74%. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
128 lines
4.9 KiB
Bash
Executable File
128 lines
4.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
repo_root=$(git rev-parse --show-toplevel)
|
|
cd "$repo_root"
|
|
|
|
# shellcheck source=linux_configuration/.githooks/lib/common.sh
|
|
source "${repo_root}/linux_configuration/.githooks/lib/common.sh"
|
|
|
|
printf 'Verifying hook wiring and toolchain before committing...\n'
|
|
ensure_hooks_path
|
|
verify_toolchain
|
|
printf ' ✓ toolchain complete\n'
|
|
|
|
printf 'Running auto-fixers and shell_check before committing...\n'
|
|
|
|
# Get list of staged shell files
|
|
mapfile -t staged_files < <(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(sh|bash|zsh)$' || true)
|
|
|
|
if [[ ${#staged_files[@]} -gt 0 ]]; then
|
|
printf 'Auto-fixing %d shell file(s)...\n' "${#staged_files[@]}"
|
|
|
|
# Auto-fix with shfmt (guaranteed present by verify_toolchain)
|
|
printf ' → Running shfmt...\n'
|
|
for file in "${staged_files[@]}"; do
|
|
if [[ -f $file ]]; then
|
|
shfmt -w "$file" 2> /dev/null || true
|
|
fi
|
|
done
|
|
|
|
# Re-stage the auto-fixed files
|
|
for file in "${staged_files[@]}"; do
|
|
if [[ -f $file ]]; then
|
|
git add "$file"
|
|
fi
|
|
done
|
|
|
|
printf ' ✓ Auto-fixes applied and staged\n'
|
|
fi
|
|
|
|
printf 'Running shell_check validation...\n'
|
|
|
|
# Run shell_check to validate all checks
|
|
# Note: We only validate the staged files since we just auto-formatted them
|
|
# Validate only shellcheck, not shfmt (we already applied formatting)
|
|
mapfile -d '' -t staged_shell_files < <(git diff --cached --name-only --diff-filter=ACM -z | grep -zE '\.(sh|bash|zsh)$' || true)
|
|
|
|
if [[ ${#staged_shell_files[@]} -gt 0 ]]; then
|
|
# Run shellcheck on staged files (guaranteed present by verify_toolchain)
|
|
# -x: follow source directives
|
|
# -S warning: only fail on warning or higher (not info-level SC1091)
|
|
if ! shellcheck -x -S warning "${staged_shell_files[@]}" 2>&1; then
|
|
printf '\nCommit aborted: shellcheck found issues.\n' >&2
|
|
printf 'Fix the remaining problems and retry the commit.\n' >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
printf 'shell_check passed.\n'
|
|
|
|
# Run duplicate code detection
|
|
printf 'Running duplicate code detection...\n'
|
|
|
|
JSCPD_BIN="${HOME}/.local/node_modules/.bin/jscpd"
|
|
|
|
# Install jscpd if not present
|
|
if [[ ! -x $JSCPD_BIN ]]; then
|
|
printf ' → jscpd not found, installing...\n'
|
|
if ! npm install --prefix ~/.local jscpd 2>&1; then
|
|
printf '\nCommit aborted: failed to install jscpd.\n' >&2
|
|
printf 'Please install manually: npm install --prefix ~/.local jscpd\n' >&2
|
|
exit 1
|
|
fi
|
|
printf ' ✓ jscpd installed\n'
|
|
fi
|
|
|
|
# Run jscpd and capture output
|
|
# --min-lines 14: minimum 14 lines to consider a clone (ignores small boilerplate)
|
|
# --min-tokens 25: minimum 25 tokens to consider a clone
|
|
# --threshold 2: fail if more than 2% duplication
|
|
# Excluded from the scan, and why:
|
|
# .venv/ vendored third-party shell (virtualenv, tqdm completions).
|
|
# .ci-mirror-venv/
|
|
# Not ours, and it alone pushed the repo over the bar: the
|
|
# same scan reads 2.50% with it and 1.67% without.
|
|
# .ci-mirror-venv/ is the SAME third-party shell under a
|
|
# different name -- the clean-venv the ci-mirror pre-push gate
|
|
# builds. It is untracked and generated, but jscpd walks the
|
|
# working tree, not the index, so it was still being scanned.
|
|
# Extracting digital_wellbeing shrank the denominator enough
|
|
# for those virtualenv/tqdm clones to push the total to 2.09%
|
|
# and block a commit that added no duplication at all.
|
|
# lib/tests/ a fixture IS repetitive by design; the 2% rule exists to
|
|
# stop duplicated production logic, not shared test setup.
|
|
# Needed headroom for the Phase 3 coverage campaign.
|
|
jscpd_output=$("$JSCPD_BIN" \
|
|
--pattern "**/*.sh" \
|
|
--min-lines 14 \
|
|
--min-tokens 25 \
|
|
--threshold 2 \
|
|
--reporters "console" \
|
|
--ignore "**/node_modules/**,**/.git/**,**/misc/**,**/*.txt,**/.venv/**,**/.ci-mirror-venv/**,**/lib/tests/**,**/tests/**" \
|
|
. 2>&1) || jscpd_exit=$?
|
|
|
|
if [[ ${jscpd_exit:-0} -ne 0 ]]; then
|
|
printf '\n%s\n' "$jscpd_output"
|
|
printf '\nCommit aborted: duplicate code exceeds 2%% threshold.\n' >&2
|
|
printf 'Consider extracting common code to scripts/lib/common.sh\n' >&2
|
|
printf 'To see all duplicates: %s --pattern "**/*.sh" --min-lines 5 .\n' "$JSCPD_BIN" >&2
|
|
exit 1
|
|
fi
|
|
printf ' ✓ Duplication check passed (under 2%% threshold)\n'
|
|
|
|
# Run pre-commit framework hooks (.pre-commit-config.yaml)
|
|
# This covers: Python (ruff, mypy, pylint, bandit, flake8, autoflake),
|
|
# C/C++ (clang-format, cppcheck, flawfinder), TypeScript (eslint),
|
|
# shell (shellcheck), and general checks (trailing-whitespace, etc.)
|
|
printf '\nRunning pre-commit framework hooks...\n'
|
|
if ! pre-commit run --hook-stage pre-commit; then
|
|
printf '\nCommit aborted: pre-commit hooks failed.\n' >&2
|
|
printf 'Fix the issues above and retry the commit.\n' >&2
|
|
exit 1
|
|
fi
|
|
printf ' ✓ pre-commit framework hooks passed\n'
|
|
|
|
printf 'All checks passed. Proceeding with commit.\n'
|