Files
wenzi/scripts/ci/clean-artifacts.sh

238 lines
6.4 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
ARCHIVE_BASE_DEFAULT="/tmp/mosquito-archives"
ARCHIVE_TAG_DEFAULT="$(date +%Y%m%d_%H%M%S)"
MODE="archive" # archive | delete
APPLY="false" # false => dry-run
INCLUDE_TRACKED="false" # true => include git tracked paths
FAIL_ON_FOUND="false" # true => exit non-zero when cleanup candidates exist
INCLUDE_BUILD_OUTPUTS="false" # true => include dist/target build outputs
ARCHIVE_BASE="${ARCHIVE_BASE_DEFAULT}"
ARCHIVE_TAG="${ARCHIVE_TAG_DEFAULT}"
ARTIFACT_PATHS=(
"frontend/admin/test-results"
"frontend/e2e/e2e-results"
"frontend/e2e/e2e-report"
"frontend/e2e/playwright-report"
"frontend/e2e/test-results"
"frontend/e2e-admin/test-results"
"frontend/e2e-results"
)
BUILD_OUTPUT_PATHS=(
"target"
"frontend/dist"
"frontend/admin/dist"
"frontend/h5/dist"
)
ROOT_SPILLOVER_GLOBS=(
"e2e-test-report-*.md"
"E2E_TEST*.md"
"TEST_E2E_*.md"
"COVERAGE_*.md"
)
usage() {
cat <<'EOF'
Usage:
./scripts/ci/clean-artifacts.sh [--apply] [--mode archive|delete] [--archive-base DIR] [--archive-tag TAG] [--include-tracked] [--include-build-outputs] [--fail-on-found]
Options:
--apply Execute cleanup. Without this flag, script runs in dry-run mode.
--mode MODE archive (default) | delete
--archive-base DIR Archive base dir for archive mode. Default: /tmp/mosquito-archives
--archive-tag TAG Archive subdir tag. Default: current timestamp
--include-tracked Include git tracked paths (default: skip tracked)
--include-build-outputs
Include build output paths (target, frontend/*/dist)
--fail-on-found Exit non-zero when cleanup candidates are found (useful for CI dry-run)
-h, --help Show help
Examples:
./scripts/ci/clean-artifacts.sh
./scripts/ci/clean-artifacts.sh --apply
./scripts/ci/clean-artifacts.sh --apply --mode archive --archive-tag manual_cleanup
./scripts/ci/clean-artifacts.sh --include-build-outputs --apply --mode archive --archive-tag weekly_cleanup
./scripts/ci/clean-artifacts.sh --fail-on-found
EOF
}
log() { echo "[clean-artifacts] $*"; }
is_git_tracked() {
local rel="$1"
local out
out="$(git -C "${ROOT_DIR}" ls-files -- "${rel}" 2>/dev/null || true)"
[[ -n "${out}" ]]
}
run_cmd() {
if [[ "${APPLY}" == "true" ]]; then
"$@"
else
log "DRY-RUN: $*"
fi
}
while [[ $# -gt 0 ]]; do
case "$1" in
--apply)
APPLY="true"
shift
;;
--mode)
MODE="${2:-}"
shift 2
;;
--archive-base)
ARCHIVE_BASE="${2:-}"
shift 2
;;
--archive-tag)
ARCHIVE_TAG="${2:-}"
shift 2
;;
--include-tracked)
INCLUDE_TRACKED="true"
shift
;;
--include-build-outputs)
INCLUDE_BUILD_OUTPUTS="true"
shift
;;
--fail-on-found)
FAIL_ON_FOUND="true"
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1" >&2
usage
exit 1
;;
esac
done
if [[ "${MODE}" != "archive" && "${MODE}" != "delete" ]]; then
echo "Invalid --mode: ${MODE}" >&2
exit 1
fi
ARCHIVE_DIR="${ARCHIVE_BASE}/${ARCHIVE_TAG}"
log "root=${ROOT_DIR}"
log "mode=${MODE} apply=${APPLY} include_tracked=${INCLUDE_TRACKED} include_build_outputs=${INCLUDE_BUILD_OUTPUTS} fail_on_found=${FAIL_ON_FOUND}"
if [[ "${INCLUDE_BUILD_OUTPUTS}" == "true" ]] && pgrep -af "spring-boot:run|e2e_continuous_runner.sh|vite" >/dev/null 2>&1; then
log "WARN: detected active dev/e2e processes; build outputs may be recreated immediately."
fi
if [[ "${MODE}" == "archive" ]]; then
log "archive_dir=${ARCHIVE_DIR}"
if [[ "${APPLY}" == "true" ]]; then
mkdir -p "${ARCHIVE_DIR}"
fi
fi
cleaned_count=0
skipped_count=0
found_count=0
CANDIDATE_PATHS=("${ARTIFACT_PATHS[@]}")
if [[ "${INCLUDE_BUILD_OUTPUTS}" == "true" ]]; then
CANDIDATE_PATHS+=("${BUILD_OUTPUT_PATHS[@]}")
fi
for rel in "${CANDIDATE_PATHS[@]}"; do
abs="${ROOT_DIR}/${rel}"
if [[ ! -e "${abs}" ]]; then
continue
fi
if [[ "${INCLUDE_TRACKED}" != "true" ]] && is_git_tracked "${rel}"; then
log "SKIP tracked path: ${rel}"
skipped_count=$((skipped_count + 1))
continue
fi
if [[ "${MODE}" == "archive" ]]; then
dest="${ARCHIVE_DIR}/${rel}"
run_cmd mkdir -p "$(dirname "${dest}")"
run_cmd mv "${abs}" "${dest}"
log "ARCHIVE ${rel} -> ${dest}"
else
run_cmd rm -rf "${abs}"
log "DELETE ${rel}"
fi
found_count=$((found_count + 1))
cleaned_count=$((cleaned_count + 1))
done
# Root report spillover (files in repository root)
shopt -s nullglob
for pattern in "${ROOT_SPILLOVER_GLOBS[@]}"; do
for file in "${ROOT_DIR}"/${pattern}; do
[[ -f "${file}" ]] || continue
rel="$(basename "${file}")"
if [[ "${INCLUDE_TRACKED}" != "true" ]] && is_git_tracked "${rel}"; then
log "SKIP tracked root file: ${rel}"
skipped_count=$((skipped_count + 1))
continue
fi
if [[ "${MODE}" == "archive" ]]; then
dest="${ARCHIVE_DIR}/root-spillover/${rel}"
run_cmd mkdir -p "$(dirname "${dest}")"
run_cmd mv "${file}" "${dest}"
log "ARCHIVE ${rel} -> ${dest}"
else
run_cmd rm -f "${file}"
log "DELETE ${rel}"
fi
found_count=$((found_count + 1))
cleaned_count=$((cleaned_count + 1))
done
done
shopt -u nullglob
# Move root attach_pid files into tmp/pids
pids_dir="${ROOT_DIR}/tmp/pids"
if compgen -G "${ROOT_DIR}/.attach_pid*" > /dev/null; then
run_cmd mkdir -p "${pids_dir}"
while IFS= read -r pid_file; do
rel_pid="$(basename "${pid_file}")"
if [[ "${MODE}" == "archive" ]]; then
if [[ "${APPLY}" == "true" ]]; then
mv "${pid_file}" "${pids_dir}/${rel_pid}"
else
log "DRY-RUN: mv ${pid_file} ${pids_dir}/${rel_pid}"
fi
log "MOVE ${rel_pid} -> tmp/pids/"
else
run_cmd rm -f "${pid_file}"
log "DELETE ${rel_pid}"
fi
found_count=$((found_count + 1))
cleaned_count=$((cleaned_count + 1))
done < <(find "${ROOT_DIR}" -maxdepth 1 -type f -name ".attach_pid*" | sort)
fi
log "done: found=${found_count}, cleaned=${cleaned_count}, skipped=${skipped_count}"
if [[ "${APPLY}" != "true" ]]; then
log "dry-run completed. Use --apply to execute."
fi
if [[ "${FAIL_ON_FOUND}" == "true" && "${found_count}" -gt 0 ]]; then
log "fail-on-found enabled: detected ${found_count} cleanup candidates."
exit 2
fi