diff --git a/scripts/ci/lib-forgejo.sh b/scripts/ci/lib-forgejo.sh index 6d82338..ade9a81 100644 --- a/scripts/ci/lib-forgejo.sh +++ b/scripts/ci/lib-forgejo.sh @@ -50,6 +50,8 @@ PYEOF } # create_release — sets global RELEASE_ID on success. +# 幂等:若该 tag 的 Release 已存在(重跑发版时 Forgejo 回 409),不再硬失败, +# 改为取回既有 Release 复用其 id 继续(配合 upload_asset 的覆盖上传,重跑安全)。 create_release() { local tag="$1" body="$2" http_code resp echo "==> release: creating Forgejo Release ${tag}" @@ -60,6 +62,15 @@ create_release() { -d "{\"tag_name\":\"${tag}\",\"name\":\"Release ${tag}\",\"body\":${body},\"draft\":false,\"prerelease\":false}") resp=$(cat /tmp/release_resp.json) echo "==> release: API response (HTTP ${http_code}): ${resp}" + if [ "$http_code" = "409" ]; then + # Release 已存在(重跑)→ 幂等复用:按 tag 取回既有 Release。 + echo "==> release: 该 tag 的 Release 已存在,改为复用(幂等重跑)" + http_code=$(curl -k -w "%{http_code}" -o /tmp/release_resp.json \ + -H "Authorization: token ${FORGEJO_TOKEN}" \ + "${FORGEJO_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases/tags/${tag}") + resp=$(cat /tmp/release_resp.json) + echo "==> release: 既有 Release 查询 (HTTP ${http_code}): ${resp}" + fi if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then echo "==> release: FAILED — HTTP ${http_code}" >&2 return 1 @@ -69,8 +80,18 @@ create_release() { } # upload_asset — requires RELEASE_ID. +# 幂等:若同名 asset 已存在(重跑),先删旧再传新,避免 Forgejo 409 重名冲突。 upload_asset() { - local file="$1" code + local file="$1" code name existing_id + name=$(basename "$file") + existing_id=$(curl -ks -H "Authorization: token ${FORGEJO_TOKEN}" \ + "${FORGEJO_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases/${RELEASE_ID}/assets" \ + | python3 -c "import sys,json; a=json.load(sys.stdin); print(next((str(x['id']) for x in a if x.get('name')==sys.argv[1]), ''))" "$name" 2>/dev/null || true) + if [ -n "$existing_id" ]; then + echo "==> release: asset ${name} 已存在(id=${existing_id}),先删旧再重传" + curl -ks -X DELETE -H "Authorization: token ${FORGEJO_TOKEN}" \ + "${FORGEJO_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases/${RELEASE_ID}/assets/${existing_id}" >/dev/null || true + fi code=$(curl -k -w "%{http_code}" -o /tmp/upload_resp.json \ -X POST "${FORGEJO_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases/${RELEASE_ID}/assets" \ -H "Authorization: token ${FORGEJO_TOKEN}" \