238 lines
6.4 KiB
Bash
238 lines
6.4 KiB
Bash
|
|
#!/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
|