diff --git a/gitea-python-ci-cd.md b/gitea-python-ci-cd.md index fcc93bb..f938597 100644 --- a/gitea-python-ci-cd.md +++ b/gitea-python-ci-cd.md @@ -168,6 +168,8 @@ build-docker: ### 2.3. Upload Assets to Gitea Release +**IMPORTANT:** Gitea does not reject duplicate asset names — it silently appends duplicates. When re-triggering a failed release workflow (where `create-release` reuses an existing release), build jobs will upload a second copy of every artifact. Always **delete existing assets with the same name before uploading**. + ```yaml - name: Attach assets to release env: @@ -176,12 +178,31 @@ build-docker: RELEASE_ID="${{ needs.create-release.outputs.release_id }}" BASE_URL="${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}" + upload_asset() { + local FILE="$1" + local NAME=$(basename "$FILE") + + # Delete existing asset with the same name (prevents duplicates on re-run) + EXISTING_ID=$(curl -s "$BASE_URL/releases/$RELEASE_ID/assets" \ + -H "Authorization: token $GITEA_TOKEN" \ + | python3 -c "import sys,json; assets=json.load(sys.stdin); print(next((str(a['id']) for a in assets if a['name']=='$NAME'),''))" 2>/dev/null) + + if [ -n "$EXISTING_ID" ]; then + curl -s -X DELETE "$BASE_URL/releases/$RELEASE_ID/assets/$EXISTING_ID" \ + -H "Authorization: token $GITEA_TOKEN" + echo "Replaced existing asset: $NAME" + fi + + curl -s -X POST \ + "$BASE_URL/releases/$RELEASE_ID/assets?name=$NAME" \ + -H "Authorization: token $GITEA_TOKEN" \ + -H "Content-Type: application/octet-stream" \ + --data-binary "@$FILE" + echo "Uploaded: $NAME" + } + FILE=$(ls build/App-*.zip | head -1) - curl -s -X POST \ - "$BASE_URL/releases/$RELEASE_ID/assets?name=$(basename "$FILE")" \ - -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/octet-stream" \ - --data-binary "@$FILE" + [ -f "$FILE" ] && upload_asset "$FILE" ``` ## 3. Version Detection Pattern