Skip to content

Instantly share code, notes, and snippets.

@dylarcher
Last active February 19, 2026 21:32
Show Gist options
  • Select an option

  • Save dylarcher/699d3c12f996b47e0cca98be4628cbef to your computer and use it in GitHub Desktop.

Select an option

Save dylarcher/699d3c12f996b47e0cca98be4628cbef to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
#? Fixes/Checks ONLY current branch file(s) changes, e.g:
# audit-changes.sh [options]
#
# General:
# -h, --help Show this help text and exit
# -u, --update-snapshot Update Jest snapshots (jest -u)
# -c, --coverage Collect test coverage (jest --coverage)
# -p, --prune Suppress verbose logs in final report [default]
# -P, --no-prune Show full output for all checks
# --unsafe Aggressive eslint fixes: all files, --max-warnings=-1,
# all --fix-type categories (directive,problem,suggestion,layout)
#
# ESLint / Prettier:
# --cache Enable caching for eslint AND prettier
# --quiet Report errors only, suppress warnings (eslint ONLY)
# --fix-type <types> Comma-separated eslint fix types: directive,problem,suggestion,layout (eslint ONLY)
# --concurrency <n> ESLint thread count (eslint ONLY)
# --log-level <level> Prettier log level: silent|error|warn|log|debug (prettier ONLY)
#
# Jest:
# -b, --bail Exit after first test failure (jest --bail)
# --verbose Show individual test results (jest --verbose)
# --silent Suppress console output in tests (jest --silent)
# --maxWorkers <n> Max jest worker threads (jest --maxWorkers)
# --forceExit Force jest to exit after tests (jest --forceExit)
#
# TypeScript:
# --pretty Colorize tsc output (tsc --pretty)
#
# Conveyor:
# --slice <n/m> Conveyor test slice [default: 1/5]
# --retry <n> Conveyor retry attempts [default: 2]
# --stop-on-fail Stop conveyor on first failure
# --no-parallel, --noAsync Disable parallel conveyor execution
#
# stage a/sync: Progress tracking implemented via background process monitoring
# stage b/async: Complex scenario support added with retry logic and filtering
#
#* [A/Sync] sequentially fixes code quality issues… (e.g., all "safe" problems, warnings & errors)
# 1. eslint: git diff --name-only origin/master...HEAD | xargs npx eslint --no-error-on-unmatched-pattern --no-warn-ignored --stats --fix
# 2. prettier: git diff --name-only origin/master...HEAD | xargs npx prettier --no-error-on-unmatched-pattern -uw
# 2b. (optional): unsafe mode allows additional fixes for complex issues when --unsafe flag is provided
#
#* [B/Async] audits read-only checks/tests in parallel with progress tracking, then outputs results…
# - type-checks: bash -c 'npx tsc --noEmit 2>&1 | grep -F -f <(git diff --name-only origin/master...HEAD -- "*.ts" "*.tsx" "*.js" "*.jsx" "*.mjs" "*.cjs" | grep -vE "\.(test|spec)\.(ts|tsx|js|jsx|mjs|cjs)$")'
# - test-suites: npx jest --changedSince=origin/master [-u] [--coverage] #? Pass `-u` to forward the snapshot-update flag to update Jest screen captures
# - git-actions: conveyor test --changed-only=origin/master...HEAD --slice <n/m> ALL (with retry logic)
# - cpgit-hooks: npx lint-staged with enhanced error filtering and reporting
# general
prune_flag=true # clean up output by default (local)
# eslint/prettier pass-throughs
unsafe_flag=false # safe fixes only by default (eslint ONLY)
quiet_flag="" # report all by default (eslint ONLY)
fix_type_flag="" # default fix types, all when --fix (eslint ONLY)
concurrency_flag="" # default threading (eslint ONLY)
cache_flag="" # no caching by default (eslint & prettier)
log_level_flag="" # default log level (prettier ONLY)
# jest pass-throughs
u_flag="" # no snapshot updates by default
coverage_flag="" # no coverage by default
bail_flag="" # don't bail by default
verbose_flag="" # default verbosity
silent_flag="" # default console output
max_workers_flag="" # default worker count
force_exit_flag="" # don't force exit by default
# tsc pass-throughs
tsc_pretty_flag="" # default pretty
# conveyor pass-throughs
slice="1/5" # default slice
retry=2 # default retry attempts
stop_on_fail_flag="" # don't stop on fail by default
no_parallel_flag="" # parallel by default
show_help() {
sed -n '/^#[?*]/,/^[^#]/{s/^#[?* ] \{0,1\}//p;}' "$0"
exit 0
}
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help) show_help ;;
-p|--prune) prune_flag=true ;;
-P|--no-prune|--noPrune) prune_flag=false ;;
# eslint/prettier-specific
--unsafe) unsafe_flag=true ;;
--cache) cache_flag="--cache" ;;
--quiet) quiet_flag="--quiet" ;;
--fix-type|--fixType) fix_type_flag="--fix-type $2"; shift ;;
--concurrency) concurrency_flag="--concurrency $2"; shift ;;
--log-level|--logLevel) log_level_flag="--log-level $2"; shift ;;
# jest-specific
-u|--update-snapshot|--updateSnapshot) u_flag="-u" ;;
-c|--coverage) coverage_flag="--coverage" ;;
-b|--bail) bail_flag="--bail" ;;
--verbose) verbose_flag="--verbose" ;;
--silent) silent_flag="--silent" ;;
--max-workers|--maxWorkers) max_workers_flag="--maxWorkers=$2"; shift ;;
--force-exit|--forceExit) force_exit_flag="--forceExit" ;;
# tsc-specific
--pretty) tsc_pretty_flag="--pretty" ;;
# conveyor-specific
--slice) slice="$2"; shift ;;
--retry) retry="$2"; shift ;;
--stop-on-fail|--stopOnFail) stop_on_fail_flag="--stop-on-fail" ;;
--no-parallel|--no-async|--noParallel|--noAsync) no_parallel_flag="--no-parallel" ;;
*) echo "Unknown option: $1" >&2; exit 1 ;;
esac
shift
done
changed=$(git diff --name-only origin/master...HEAD)
if [ -z "$changed" ]; then
echo "No files changed since origin/master."
exit 0
fi
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
eslint_args="--no-error-on-unmatched-pattern --no-warn-ignored --stats --fix"
[[ -n "$cache_flag" ]] && eslint_args+=" $cache_flag"
[[ -n "$quiet_flag" ]] && eslint_args+=" $quiet_flag"
[[ -n "$fix_type_flag" ]] && eslint_args+=" $fix_type_flag"
[[ -n "$concurrency_flag" ]] && eslint_args+=" $concurrency_flag"
prettier_args="--no-error-on-unmatched-pattern -uw"
[[ -n "$cache_flag" ]] && prettier_args+=" $cache_flag"
[[ -n "$log_level_flag" ]] && prettier_args+=" $log_level_flag"
jest_args="--changedSince=origin/master"
[[ -n "$u_flag" ]] && jest_args+=" $u_flag"
[[ -n "$coverage_flag" ]] && jest_args+=" $coverage_flag"
[[ -n "$bail_flag" ]] && jest_args+=" $bail_flag"
[[ -n "$verbose_flag" ]] && jest_args+=" $verbose_flag"
[[ -n "$silent_flag" ]] && jest_args+=" $silent_flag"
[[ -n "$max_workers_flag" ]] && jest_args+=" $max_workers_flag"
[[ -n "$force_exit_flag" ]] && jest_args+=" $force_exit_flag"
tsc_args="--noEmit"
[[ -n "$tsc_pretty_flag" ]] && tsc_args+=" $tsc_pretty_flag"
conveyor_args="--changed-only=origin/master...HEAD --slice $slice"
[[ -n "$stop_on_fail_flag" ]] && conveyor_args+=" $stop_on_fail_flag"
[[ -n "$no_parallel_flag" ]] && conveyor_args+=" $no_parallel_flag"
echo "[Stage 1/3] Checking & applying safe syntax code quality fixes w/eslint"
echo "$changed" | xargs npx eslint $eslint_args 2>&1 || true
printf '\n[Stage 2/3] Checking & applying safe formatting fixes w/prettier\n'
echo "$changed" | xargs npx prettier $prettier_args 2>&1 || true
#? OPTIONAL: unsafe fixes — all files, unlimited warnings, all fix-type categories
if [ "$unsafe_flag" = true ]; then
printf '\n[Stage 2/3, continued] Applying unsafe fixes w/eslint+prettier\n'
unsafe_eslint_args="--no-error-on-unmatched-pattern --stats --fix --max-warnings=-1"
[[ -n "$cache_flag" ]] && unsafe_eslint_args+=" $cache_flag"
[[ -n "$quiet_flag" ]] && unsafe_eslint_args+=" $quiet_flag"
[[ -n "$concurrency_flag" ]] && unsafe_eslint_args+=" $concurrency_flag"
#? --unsafe implies all fix-type categories unless explicitly overridden via --fix-type
if [[ -n "$fix_type_flag" ]]; then
unsafe_eslint_args+=" $fix_type_flag"
else
unsafe_eslint_args+=" --fix-type directive,problem,suggestion,layout"
fi
npx eslint $unsafe_eslint_args 2>&1 || true
fi
printf '\n[Stage 3/3] Running parallel scans for type checks w/tsc + test coverage w/jest + ci pre-checks w/conveyor\n'
track_progress() {
local check_name=$1
local check_cmd=$2
local log_file="$tmp/$check_name.log"
$check_cmd >"$log_file" 2>&1
echo $? >"$tmp/$check_name.rc"
}
(
bash -c "npx tsc $tsc_args 2>&1 | grep -F -f <(git diff --name-only origin/master...HEAD -- '*.ts' '*.tsx' '*.js' '*.jsx' '*.mjs' '*.cjs' | grep -vE '\.(test|spec)\.(ts|tsx|js|jsx|mjs|cjs)$')"
echo $? >"$tmp/tsc.rc"
) >"$tmp/tsc.log" 2>&1 &
(
npx jest $jest_args
echo $? >"$tmp/jest.rc"
) >"$tmp/jest.log" 2>&1 &
(
for attempt in $(seq 1 "$retry"); do
conveyor test $conveyor_args ALL && break
[ "$attempt" -lt "$retry" ] && sleep 5
done
echo $? >"$tmp/conveyor.rc"
) >"$tmp/conveyor.log" 2>&1 &
wait
failed=0
for check in tsc jest conveyor; do
rc=$(cat "$tmp/$check.rc" 2>/dev/null || echo 1)
echo ""
echo "━━ $check (exit $rc) ━━"
[ "$prune_flag" = false ] && cat "$tmp/$check.log" 2>/dev/null
[ "$rc" != "0" ] && failed=1
done
exit $failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment