Files
at-container-registry/scripts/publish-artifact.sh
2026-04-04 14:39:50 -05:00

64 lines
2.1 KiB
Bash
Executable File

#!/usr/bin/env bash
set -e
# Serialize across parallel invocations from goreleaser to avoid slamming the
# PDS with simultaneous uploads. `goat account login` happens once in the
# release workflow before goreleaser runs, so this script just reuses the
# existing session.
exec 9>/tmp/atcr-publish-artifact.lock
flock 9
retry() {
local max=5 attempt=1
while true; do
if "$@"; then return 0; fi
[ $attempt -ge $max ] && { echo "giving up after $max attempts: $*" >&2; return 1; }
local sleep_s=$((attempt * 3))
echo "attempt $attempt failed; retrying in ${sleep_s}s..." >&2
sleep $sleep_s
attempt=$((attempt + 1))
done
}
TAG_HASH=$(git rev-parse "$TANGLED_REF_NAME")
TAG_BYTES=$(printf "$(printf '%s' "$TAG_HASH" | sed 's/../\\x&/g')" | base64 | tr -d '=')
BLOB_OUTPUT=$(retry goat blob upload "$ARTIFACT_PATH")
echo "$BLOB_OUTPUT"
# Deterministic rkey from (tag, artifact name) makes record create idempotent.
# Needed because tangled's PDS returns HTTP 500 (not 409) on duplicate rkey,
# so a retry after a mid-write 500 would otherwise create a duplicate record.
RKEY=$(printf '%s|%s' "$TANGLED_REF_NAME" "$ARTIFACT_NAME" | sha256sum | cut -c1-24)
RECORD_URI="at://${TANGLED_REPO_DID}/sh.tangled.repo.artifact/${RKEY}"
CREATED_AT=$(date -Iseconds)
cat > temp_artifact.json <<EOF
{
"\$type": "sh.tangled.repo.artifact",
"tag": {"\$bytes": "${TAG_BYTES}"},
"name": "${ARTIFACT_NAME}",
"repo": "${REPO_URL}",
"artifact": ${BLOB_OUTPUT},
"createdAt": "${CREATED_AT}"
}
EOF
cat temp_artifact.json
# Attempt create; on failure, check whether the record actually landed.
# Handles both transient 5xx and tangled's 500-on-duplicate-rkey behaviour.
for attempt in 1 2 3 4 5; do
if goat record create --rkey "$RKEY" temp_artifact.json -n; then
break
fi
if goat record get "$RECORD_URI" >/dev/null 2>&1; then
echo "record already exists at $RECORD_URI — treating as success"
break
fi
[ $attempt -eq 5 ] && { echo "record create failed and record does not exist" >&2; exit 1; }
sleep $((attempt * 3))
done
rm temp_artifact.json
sleep 2