251 lines
9.0 KiB
Bash
Executable File
251 lines
9.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
resolve_repo_root() {
|
|
local candidate
|
|
for candidate in "${SCRIPT_DIR}/.." "${SCRIPT_DIR}/../.." "${PWD}"; do
|
|
if [[ -f "${candidate}/credentials/.env" ]]; then
|
|
(cd "${candidate}" && pwd)
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
if ! REPO_ROOT="$(resolve_repo_root)"; then
|
|
echo "Error: could not locate repository root containing credentials/.env" >&2
|
|
exit 1
|
|
fi
|
|
|
|
ENV_FILE="${REPO_ROOT}/credentials/.env"
|
|
if [[ ! -f "${ENV_FILE}" ]]; then
|
|
echo "Error: credentials file not found: ${ENV_FILE}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
load_env_value() {
|
|
local key="$1"
|
|
local line
|
|
line="$(grep -E "^${key}=" "${ENV_FILE}" | tail -n 1 || true)"
|
|
line="${line#*=}"
|
|
line="${line%\"}"
|
|
line="${line#\"}"
|
|
line="${line%\'}"
|
|
line="${line#\'}"
|
|
printf '%s' "${line}"
|
|
}
|
|
|
|
DB_NAME="$(load_env_value MAILSHOTS_REMOTE_MYSQL_DB)"
|
|
MYSQL_USER="$(load_env_value REMOTE_MYSQL_USER)"
|
|
MYSQL_PASSWORD="$(load_env_value REMOTE_MYSQL_PASSWORD)"
|
|
REMOTE_MYSQL_HOST="$(load_env_value REMOTE_MYSQL_HOST)"
|
|
REMOTE_MYSQL_PORT="$(load_env_value REMOTE_MYSQL_PORT)"
|
|
LOCAL_TUNNEL_PORT="${LOCAL_PORT:-13306}"
|
|
|
|
# Match scripts/mysql_tunnel.sh defaults unless explicitly overridden.
|
|
MYSQL_HOST="${MYSQL_HOST:-127.0.0.1}"
|
|
MYSQL_PORT="${MYSQL_PORT:-${LOCAL_TUNNEL_PORT}}"
|
|
|
|
if [[ -z "${DB_NAME}" ]]; then
|
|
echo "Error: MAILSHOTS_REMOTE_MYSQL_DB is missing in ${ENV_FILE}" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -z "${MYSQL_USER}" || -z "${MYSQL_PASSWORD}" ]]; then
|
|
echo "Error: REMOTE_MYSQL_USER/REMOTE_MYSQL_PASSWORD missing in ${ENV_FILE}" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -z "${MYSQL_HOST}" || -z "${MYSQL_PORT}" ]]; then
|
|
echo "Error: MYSQL host/port is empty. Set REMOTE_MYSQL_HOST/REMOTE_MYSQL_PORT or MYSQL_HOST/MYSQL_PORT." >&2
|
|
exit 1
|
|
fi
|
|
|
|
DRY_RUN=0
|
|
AUTO_YES=0
|
|
INCLUDE_CREDENTIALS=0
|
|
USE_REMOTE=0
|
|
INCLUDE_MAILSHOT_TEST=0
|
|
|
|
# Strict, test-suite-specific markers only.
|
|
ARTEFACT_REGEX='^(e2e_|phase2_db_access_|phase3_|phase4_)'
|
|
MAILSHOT_PURPOSE_REGEX='^(e2e_|Phase3 Mailshot |Phase4 )'
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage: cleanup_testing_artefacts.sh [options]
|
|
|
|
Options:
|
|
--dry-run Show row counts only; make no changes.
|
|
--yes Skip confirmation prompt.
|
|
--include-credentials Also delete test-marked rows in mailshot_credentials.
|
|
--include-mailshot-test Also delete test-marked rows in mailshot_test.
|
|
--remote Connect directly to REMOTE_MYSQL_HOST:REMOTE_MYSQL_PORT.
|
|
-h, --help Show this help text.
|
|
|
|
Environment overrides:
|
|
LOCAL_PORT, MYSQL_HOST, MYSQL_PORT
|
|
USAGE
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--dry-run) DRY_RUN=1 ;;
|
|
--yes) AUTO_YES=1 ;;
|
|
--include-credentials) INCLUDE_CREDENTIALS=1 ;;
|
|
--include-mailshot-test) INCLUDE_MAILSHOT_TEST=1 ;;
|
|
--remote) USE_REMOTE=1 ;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Error: unknown option: $1" >&2
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [[ "${USE_REMOTE}" -eq 1 ]]; then
|
|
MYSQL_HOST="${REMOTE_MYSQL_HOST}"
|
|
MYSQL_PORT="${REMOTE_MYSQL_PORT}"
|
|
fi
|
|
|
|
MYSQL_CMD=(mysql --protocol=TCP "-h${MYSQL_HOST}" "-P${MYSQL_PORT}" "-u${MYSQL_USER}" "-p${MYSQL_PASSWORD}" -N -B)
|
|
|
|
echo "Target database: ${DB_NAME}"
|
|
echo "MySQL endpoint: ${MYSQL_HOST}:${MYSQL_PORT}"
|
|
echo "Cleanup mode: selective delete only (no TRUNCATE)."
|
|
echo "Artefact regex: ${ARTEFACT_REGEX}"
|
|
echo "Mailshot purpose regex: ${MAILSHOT_PURPOSE_REGEX}"
|
|
|
|
for t in mailshot_last_run mailshot_queries mailshot_attachments mailshot_pdf_assets mailshots mailshot_credentials mailshot_test; do
|
|
exists="$("${MYSQL_CMD[@]}" -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='${DB_NAME}' AND table_name='${t}';")"
|
|
if [[ "${exists}" != "1" ]]; then
|
|
echo "Error: required table ${DB_NAME}.${t} does not exist." >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
candidate_counts_sql="
|
|
SELECT 'mailshot_queries' AS t, COUNT(*) AS c
|
|
FROM \`${DB_NAME}\`.\`mailshot_queries\`
|
|
WHERE \`name\` REGEXP '${ARTEFACT_REGEX}'
|
|
UNION ALL
|
|
SELECT 'mailshot_attachments' AS t, COUNT(*) AS c
|
|
FROM \`${DB_NAME}\`.\`mailshot_attachments\`
|
|
WHERE \`name\` REGEXP '${ARTEFACT_REGEX}'
|
|
OR COALESCE(\`file_name\`, '') REGEXP '${ARTEFACT_REGEX}'
|
|
UNION ALL
|
|
SELECT 'mailshot_pdf_assets' AS t, COUNT(*) AS c
|
|
FROM \`${DB_NAME}\`.\`mailshot_pdf_assets\`
|
|
WHERE \`name\` REGEXP '${ARTEFACT_REGEX}'
|
|
OR COALESCE(\`file_name\`, '') REGEXP '${ARTEFACT_REGEX}'
|
|
UNION ALL
|
|
SELECT 'mailshots' AS t, COUNT(*) AS c
|
|
FROM \`${DB_NAME}\`.\`mailshots\`
|
|
WHERE COALESCE(\`Purpose\`, '') REGEXP '${MAILSHOT_PURPOSE_REGEX}'
|
|
OR COALESCE(\`DataSource\`, '') REGEXP '${ARTEFACT_REGEX}'
|
|
UNION ALL
|
|
SELECT 'mailshot_last_run' AS t, COUNT(*) AS c
|
|
FROM \`${DB_NAME}\`.\`mailshot_last_run\` lr
|
|
WHERE COALESCE(lr.\`data_source\`, '') REGEXP '${ARTEFACT_REGEX}'
|
|
OR COALESCE(lr.\`recipient_key\`, '') REGEXP '^phase[0-9]'
|
|
OR lr.\`mailshot_id\` IN (
|
|
SELECT m.\`id\` FROM \`${DB_NAME}\`.\`mailshots\` m
|
|
WHERE COALESCE(m.\`Purpose\`, '') REGEXP '${MAILSHOT_PURPOSE_REGEX}'
|
|
OR COALESCE(m.\`DataSource\`, '') REGEXP '${ARTEFACT_REGEX}'
|
|
);"
|
|
|
|
echo
|
|
echo "Candidate rows to delete:"
|
|
"${MYSQL_CMD[@]}" -e "${candidate_counts_sql}" | while IFS=$'\t' read -r t c; do
|
|
printf ' %-26s %s\n' "${t}" "${c}"
|
|
done
|
|
|
|
if [[ "${INCLUDE_MAILSHOT_TEST}" -eq 1 ]]; then
|
|
c="$("${MYSQL_CMD[@]}" -e "SELECT COUNT(*) FROM \`${DB_NAME}\`.\`mailshot_test\` WHERE COALESCE(\`Name\`, '') REGEXP '${ARTEFACT_REGEX}' OR COALESCE(\`Email\`, '') REGEXP '${ARTEFACT_REGEX}' OR COALESCE(\`Email\`, '') LIKE '%@example.test';")"
|
|
printf ' %-26s %s\n' "mailshot_test (optional)" "${c}"
|
|
else
|
|
echo " mailshot_test skipped (use --include-mailshot-test)"
|
|
fi
|
|
|
|
if [[ "${INCLUDE_CREDENTIALS}" -eq 1 ]]; then
|
|
c="$("${MYSQL_CMD[@]}" -e "SELECT COUNT(*) FROM \`${DB_NAME}\`.\`mailshot_credentials\` WHERE COALESCE(\`smtp_host\`, '') LIKE 'smtp.test.%' OR COALESCE(\`imap_host\`, '') LIKE 'imap.test.%' OR COALESCE(\`smtp_user\`, '') REGEXP '${ARTEFACT_REGEX}' OR COALESCE(\`imap_user\`, '') REGEXP '${ARTEFACT_REGEX}';")"
|
|
printf ' %-26s %s\n' "mailshot_credentials (optional)" "${c}"
|
|
else
|
|
echo " mailshot_credentials skipped (use --include-credentials)"
|
|
fi
|
|
|
|
if [[ "${DRY_RUN}" -eq 1 ]]; then
|
|
echo
|
|
echo "Dry run complete. No changes made."
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "${AUTO_YES}" -ne 1 ]]; then
|
|
echo
|
|
read -r -p "Proceed to delete only the candidate test artefact rows above? [y/N] " reply
|
|
if [[ ! "${reply}" =~ ^[Yy]$ ]]; then
|
|
echo "Aborted. No changes made."
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
delete_sql="
|
|
DELETE FROM \`${DB_NAME}\`.\`mailshot_last_run\`
|
|
WHERE COALESCE(\`data_source\`, '') REGEXP '${ARTEFACT_REGEX}'
|
|
OR COALESCE(\`recipient_key\`, '') REGEXP '^phase[0-9]'
|
|
OR \`mailshot_id\` IN (
|
|
SELECT \`id\` FROM (
|
|
SELECT m.\`id\`
|
|
FROM \`${DB_NAME}\`.\`mailshots\` m
|
|
WHERE COALESCE(m.\`Purpose\`, '') REGEXP '${MAILSHOT_PURPOSE_REGEX}'
|
|
OR COALESCE(m.\`DataSource\`, '') REGEXP '${ARTEFACT_REGEX}'
|
|
) x
|
|
);
|
|
|
|
DELETE FROM \`${DB_NAME}\`.\`mailshots\`
|
|
WHERE COALESCE(\`Purpose\`, '') REGEXP '${MAILSHOT_PURPOSE_REGEX}'
|
|
OR COALESCE(\`DataSource\`, '') REGEXP '${ARTEFACT_REGEX}';
|
|
|
|
DELETE FROM \`${DB_NAME}\`.\`mailshot_queries\`
|
|
WHERE \`name\` REGEXP '${ARTEFACT_REGEX}';
|
|
|
|
DELETE FROM \`${DB_NAME}\`.\`mailshot_attachments\`
|
|
WHERE \`name\` REGEXP '${ARTEFACT_REGEX}'
|
|
OR COALESCE(\`file_name\`, '') REGEXP '${ARTEFACT_REGEX}';
|
|
|
|
DELETE FROM \`${DB_NAME}\`.\`mailshot_pdf_assets\`
|
|
WHERE \`name\` REGEXP '${ARTEFACT_REGEX}'
|
|
OR COALESCE(\`file_name\`, '') REGEXP '${ARTEFACT_REGEX}';
|
|
"
|
|
|
|
"${MYSQL_CMD[@]}" -e "${delete_sql}"
|
|
|
|
if [[ "${INCLUDE_MAILSHOT_TEST}" -eq 1 ]]; then
|
|
"${MYSQL_CMD[@]}" -e "DELETE FROM \`${DB_NAME}\`.\`mailshot_test\` WHERE COALESCE(\`Name\`, '') REGEXP '${ARTEFACT_REGEX}' OR COALESCE(\`Email\`, '') REGEXP '${ARTEFACT_REGEX}' OR COALESCE(\`Email\`, '') LIKE '%@example.test';"
|
|
fi
|
|
|
|
if [[ "${INCLUDE_CREDENTIALS}" -eq 1 ]]; then
|
|
"${MYSQL_CMD[@]}" -e "DELETE FROM \`${DB_NAME}\`.\`mailshot_credentials\` WHERE COALESCE(\`smtp_host\`, '') LIKE 'smtp.test.%' OR COALESCE(\`imap_host\`, '') LIKE 'imap.test.%' OR COALESCE(\`smtp_user\`, '') REGEXP '${ARTEFACT_REGEX}' OR COALESCE(\`imap_user\`, '') REGEXP '${ARTEFACT_REGEX}';"
|
|
fi
|
|
|
|
echo
|
|
echo "Cleanup complete. Remaining candidate row counts:"
|
|
"${MYSQL_CMD[@]}" -e "${candidate_counts_sql}" | while IFS=$'\t' read -r t c; do
|
|
printf ' %-26s %s\n' "${t}" "${c}"
|
|
done
|
|
|
|
if [[ "${INCLUDE_MAILSHOT_TEST}" -eq 1 ]]; then
|
|
c="$("${MYSQL_CMD[@]}" -e "SELECT COUNT(*) FROM \`${DB_NAME}\`.\`mailshot_test\` WHERE COALESCE(\`Name\`, '') REGEXP '${ARTEFACT_REGEX}' OR COALESCE(\`Email\`, '') REGEXP '${ARTEFACT_REGEX}' OR COALESCE(\`Email\`, '') LIKE '%@example.test';")"
|
|
printf ' %-26s %s\n' "mailshot_test (optional)" "${c}"
|
|
fi
|
|
|
|
if [[ "${INCLUDE_CREDENTIALS}" -eq 1 ]]; then
|
|
c="$("${MYSQL_CMD[@]}" -e "SELECT COUNT(*) FROM \`${DB_NAME}\`.\`mailshot_credentials\` WHERE COALESCE(\`smtp_host\`, '') LIKE 'smtp.test.%' OR COALESCE(\`imap_host\`, '') LIKE 'imap.test.%' OR COALESCE(\`smtp_user\`, '') REGEXP '${ARTEFACT_REGEX}' OR COALESCE(\`imap_user\`, '') REGEXP '${ARTEFACT_REGEX}';")"
|
|
printf ' %-26s %s\n' "mailshot_credentials (optional)" "${c}"
|
|
fi
|