publish-package: read current link state before re-linking

Gitea's /-/link/{repo} endpoint returns HTTP 400 "invalid argument"
whenever the package already has ANY linked repo, and /-/unlink returns
the same 400 when nothing is linked. Both are non-idempotent. Fix by
GET-ing the package version first, comparing the current repository to
the target, and only unlinking/linking when the state actually needs to
change. Idempotent across repeated publishes of the same image.
This commit is contained in:
lyn
2026-04-15 11:03:32 +00:00
parent 7745bc8bbc
commit 1e7af09245

View File

@@ -118,17 +118,49 @@ do_docker() {
fi fi
fi fi
LINK_RESP=$(curl -s -w "%{http_code}" -X POST \ # Gitea's link/unlink endpoints are not idempotent: POST /-/link/{repo}
-u "${OWNER}:${TOKEN}" \ # returns HTTP 400 "invalid argument" when the package already has ANY link
"https://git.hangman-lab.top/api/v1/packages/${OWNER}/container/${IMAGE}/-/link/${REPO_NAME}") # (even to the same repo), and POST /-/unlink returns 400 when nothing is
LINK_STATUS="${LINK_RESP: -3}" # linked. So read the current link first and branch accordingly.
LINK_BODY="${LINK_RESP:0:-3}" TARGET_LINK="${REPO_OWNER}/${REPO_NAME}"
STATE_RESP=$(curl -s -w "\n%{http_code}" -u "${OWNER}:${TOKEN}" \
"https://git.hangman-lab.top/api/v1/packages/${OWNER}/container/${IMAGE}/${TAG}")
STATE_STATUS=$(printf "%s" "$STATE_RESP" | tail -n1)
STATE_BODY=$(printf "%s" "$STATE_RESP" | sed '$d')
if [[ "$LINK_STATUS" != "200" && "$LINK_STATUS" != "201" ]]; then CURRENT_LINK=""
if echo "$LINK_BODY" | grep -q '"message".*repository does not exist'; then if [[ "$STATE_STATUS" == "200" ]]; then
echo "Warning: repository '$REPO_NAME' is not owned by '$OWNER' — skipping link (requires site admin or matching owner)." CURRENT_LINK=$(printf "%s" "$STATE_BODY" | python3 -c \
'import sys, json; p=json.load(sys.stdin); r=p.get("repository") or {}; print(r.get("full_name") or "")' \
2>/dev/null || echo "")
fi
if [[ "$CURRENT_LINK" == "$TARGET_LINK" ]]; then
echo "Package already linked to ${TARGET_LINK}, skipping link step."
else
if [[ -n "$CURRENT_LINK" ]]; then
echo "Package currently linked to ${CURRENT_LINK}, unlinking first..."
UNLINK_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST -u "${OWNER}:${TOKEN}" \
"https://git.hangman-lab.top/api/v1/packages/${OWNER}/container/${IMAGE}/-/unlink")
if [[ "$UNLINK_STATUS" != "204" ]]; then
echo "Warning: unlink returned HTTP $UNLINK_STATUS, proceeding with link attempt anyway..."
fi
fi
LINK_RESP=$(curl -s -w "%{http_code}" -X POST \
-u "${OWNER}:${TOKEN}" \
"https://git.hangman-lab.top/api/v1/packages/${OWNER}/container/${IMAGE}/-/link/${REPO_NAME}")
LINK_STATUS="${LINK_RESP: -3}"
LINK_BODY="${LINK_RESP:0:-3}"
if [[ "$LINK_STATUS" != "200" && "$LINK_STATUS" != "201" ]]; then
if echo "$LINK_BODY" | grep -q '"message".*repository does not exist'; then
echo "Warning: repository '$REPO_NAME' is not owned by '$OWNER' — skipping link (requires site admin or matching owner)."
else
echo "Warning: package link failed (HTTP $LINK_STATUS): $LINK_BODY"
fi
else else
echo "Warning: package link failed (HTTP $LINK_STATUS): $LINK_BODY" echo "Linked package to ${TARGET_LINK}."
fi fi
fi fi