163 lines
4.6 KiB
Bash
Executable File
163 lines
4.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
KEEP_COUNT="${GITEA_PACKAGE_KEEP_COUNT:-3}"
|
|
API_BASE_URL="${GITEA_API_BASE_URL:-https://gitea.banlv-ai.com/api/v1}"
|
|
TOKEN="${GITEA_PACKAGE_TOKEN:-}"
|
|
REGISTRY_IMAGE="${REGISTRY_IMAGE:-${IMAGE:-}}"
|
|
DEPLOY_ENV="${DEPLOY_ENV:-}"
|
|
CURRENT_IMAGE_TAG="${IMAGE_VERSION_TAG:-}"
|
|
|
|
if [ -z "$TOKEN" ] && [ -z "${GITEA_PACKAGE_VERSIONS_FILE:-}" ]; then
|
|
echo "Missing GITEA_PACKAGE_TOKEN" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "$REGISTRY_IMAGE" ] || [ -z "$DEPLOY_ENV" ]; then
|
|
echo "Missing REGISTRY_IMAGE/IMAGE or DEPLOY_ENV" >&2
|
|
exit 1
|
|
fi
|
|
|
|
case "$DEPLOY_ENV" in
|
|
test|prod) ;;
|
|
*)
|
|
echo "Unsupported DEPLOY_ENV for package pruning: $DEPLOY_ENV" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
if ! command -v node >/dev/null 2>&1; then
|
|
echo "node is required for package pruning" >&2
|
|
exit 127
|
|
fi
|
|
|
|
if ! command -v curl >/dev/null 2>&1; then
|
|
echo "curl is required for package pruning" >&2
|
|
exit 127
|
|
fi
|
|
|
|
image_without_tag="${REGISTRY_IMAGE%%:*}"
|
|
path_without_registry="${image_without_tag#*/}"
|
|
owner="${path_without_registry%%/*}"
|
|
package="${path_without_registry#*/}"
|
|
|
|
if [ "$owner" = "$path_without_registry" ] || [ -z "$owner" ] || [ -z "$package" ]; then
|
|
echo "Could not parse owner/package from REGISTRY_IMAGE: $REGISTRY_IMAGE" >&2
|
|
exit 1
|
|
fi
|
|
|
|
current_version="${CURRENT_IMAGE_TAG##*:}"
|
|
version_prefix="${DEPLOY_ENV}-"
|
|
latest_version="${DEPLOY_ENV}-latest"
|
|
api_base="${API_BASE_URL%/}"
|
|
|
|
echo "=== prune Gitea container package versions ==="
|
|
echo "owner: $owner"
|
|
echo "package: $package"
|
|
echo "environment: $DEPLOY_ENV"
|
|
echo "keep count: $KEEP_COUNT"
|
|
|
|
versions_json="$(mktemp)"
|
|
delete_list="$(mktemp)"
|
|
cleanup() {
|
|
rm -f "$versions_json" "$delete_list"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
if [ -n "${GITEA_PACKAGE_VERSIONS_FILE:-}" ]; then
|
|
cp "$GITEA_PACKAGE_VERSIONS_FILE" "$versions_json"
|
|
else
|
|
curl -fsS \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Accept: application/json" \
|
|
"$api_base/packages/$owner/container/$package" \
|
|
-o "$versions_json"
|
|
fi
|
|
|
|
KEEP_COUNT="$KEEP_COUNT" \
|
|
VERSION_PREFIX="$version_prefix" \
|
|
LATEST_VERSION="$latest_version" \
|
|
CURRENT_VERSION="$current_version" \
|
|
VERSIONS_JSON_FILE="$versions_json" \
|
|
node <<'NODE' > "$delete_list"
|
|
const fs = require("node:fs");
|
|
|
|
const file = process.env.VERSIONS_JSON_FILE;
|
|
const keepCount = Number.parseInt(process.env.KEEP_COUNT || "3", 10);
|
|
const prefix = process.env.VERSION_PREFIX || "";
|
|
const latest = process.env.LATEST_VERSION || "";
|
|
const current = process.env.CURRENT_VERSION || "";
|
|
const raw = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
const list = Array.isArray(raw) ? raw : Array.isArray(raw.versions) ? raw.versions : [];
|
|
|
|
function versionOf(item) {
|
|
return String(item.version || item.name || item.tag_name || "").trim();
|
|
}
|
|
|
|
function createdAtOf(item) {
|
|
return String(
|
|
item.created_at ||
|
|
item.created ||
|
|
item.createdAt ||
|
|
item.published_at ||
|
|
item.updated_at ||
|
|
"",
|
|
);
|
|
}
|
|
|
|
const candidates = list
|
|
.map((item) => ({
|
|
version: versionOf(item),
|
|
createdAt: createdAtOf(item),
|
|
}))
|
|
.filter(({ version }) => {
|
|
if (!version.startsWith(prefix)) return false;
|
|
if (version === latest) return false;
|
|
return true;
|
|
})
|
|
.sort((a, b) => {
|
|
const bTime = Date.parse(b.createdAt);
|
|
const aTime = Date.parse(a.createdAt);
|
|
if (Number.isFinite(bTime) && Number.isFinite(aTime) && bTime !== aTime) {
|
|
return bTime - aTime;
|
|
}
|
|
return b.version.localeCompare(a.version);
|
|
});
|
|
|
|
const kept = new Set(candidates.slice(0, Math.max(0, keepCount)).map((item) => item.version));
|
|
const toDelete = candidates
|
|
.slice(Math.max(0, keepCount))
|
|
.map((item) => item.version)
|
|
.filter((version) => version !== current && !kept.has(version));
|
|
process.stdout.write(toDelete.join("\n"));
|
|
if (toDelete.length > 0) process.stdout.write("\n");
|
|
NODE
|
|
|
|
if [ ! -s "$delete_list" ]; then
|
|
echo "No old $DEPLOY_ENV package versions to delete."
|
|
exit 0
|
|
fi
|
|
|
|
echo "Package versions selected for deletion:"
|
|
sed 's/^/ - /' "$delete_list"
|
|
|
|
if [ "${PRUNE_DRY_RUN:-}" = "1" ]; then
|
|
echo "Dry run enabled, skip DELETE requests."
|
|
exit 0
|
|
fi
|
|
|
|
while IFS= read -r version; do
|
|
[ -n "$version" ] || continue
|
|
encoded_owner="$(node -e 'process.stdout.write(encodeURIComponent(process.argv[1] || ""))' "$owner")"
|
|
encoded_package="$(node -e 'process.stdout.write(encodeURIComponent(process.argv[1] || ""))' "$package")"
|
|
encoded_version="$(node -e 'process.stdout.write(encodeURIComponent(process.argv[1] || ""))' "$version")"
|
|
curl -fsS \
|
|
-X DELETE \
|
|
-H "Authorization: token $TOKEN" \
|
|
"$api_base/packages/$encoded_owner/container/$encoded_package/$encoded_version" \
|
|
>/dev/null
|
|
echo "Deleted package version: $version"
|
|
done < "$delete_list"
|
|
|
|
echo "=== package prune done ==="
|