Files
notify-bridge/.gitea/workflows/release.yml
T
alexei.dolgolyov e12820f150
Release / release (push) Failing after 21s
ci: robust Gitea release creation with HTTP status + diagnostics
Previous implementation silently assumed any missing 'id' in POST
response meant "release already exists", then called an unguarded
python3 on the fallback response — which crashes (exit 1) if the
fallback also fails (e.g. release really doesn't exist).

New logic:
- Build JSON payload in Python (avoids shell escaping + CLI length limits)
- Capture HTTP status explicitly
- 201 → success
- 409 or "already exists" message → reuse existing (with HTTP check on fetch)
- Anything else → fail loudly with the response body printed

This also unblocks diagnosis of the current v0.1.0 failure by surfacing
the actual error the Gitea API is returning.
2026-04-21 20:09:55 +03:00

156 lines
5.6 KiB
YAML

name: Release
on:
push:
tags:
- 'v*'
env:
REGISTRY: git.dolgolyov-family.by
IMAGE_NAME: alexei.dolgolyov/notify-bridge
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract version from tag
id: version
run: |
TAG="${{ gitea.ref_name }}"
VERSION="${TAG#v}"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
IS_PRE="false"
if echo "$TAG" | grep -qE '(alpha|beta|rc)'; then
IS_PRE="true"
fi
echo "is_pre=$IS_PRE" >> "$GITHUB_OUTPUT"
- name: Login to Gitea Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ gitea.actor }}
password: ${{ secrets.DEPLOY_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}
${{ steps.version.outputs.is_pre == 'false' && format('{0}/{1}:latest', env.REGISTRY, env.IMAGE_NAME) || '' }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
- name: Trigger redeploy webhook
if: steps.version.outputs.is_pre == 'false'
continue-on-error: true
run: |
if [ -n "${{ secrets.DOCKER_REDEPLOY_WEBHOOK_URL }}" ]; then
echo "Triggering redeploy webhook..."
curl -sf -X POST "${{ secrets.DOCKER_REDEPLOY_WEBHOOK_URL }}" \
--max-time 30 || echo "::warning::Redeploy webhook failed"
else
echo "DOCKER_REDEPLOY_WEBHOOK_URL not set — skipping auto-deploy"
fi
- name: Generate changelog
id: changelog
run: |
PREV_TAG=$(git tag --sort=-v:refname | head -2 | tail -1)
if [ -z "$PREV_TAG" ] || [ "$PREV_TAG" = "${{ gitea.ref_name }}" ]; then
CHANGELOG=$(git log --oneline --no-decorate -n 20)
else
CHANGELOG=$(git log --oneline --no-decorate ${PREV_TAG}..HEAD)
fi
echo "$CHANGELOG" > /tmp/changelog.txt
- name: Create Gitea Release
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
run: |
TAG="${{ steps.version.outputs.tag }}"
VERSION="${{ steps.version.outputs.version }}"
IS_PRE="${{ steps.version.outputs.is_pre }}"
BASE_URL="https://${{ env.REGISTRY }}/api/v1/repos/${{ env.IMAGE_NAME }}"
if [ -f RELEASE_NOTES.md ]; then
export RELEASE_NOTES=$(cat RELEASE_NOTES.md)
echo "Found RELEASE_NOTES.md"
else
export RELEASE_NOTES=""
echo "No RELEASE_NOTES.md found"
fi
BODY=$(python3 -c "
import json, os
release_notes = os.environ.get('RELEASE_NOTES', '')
changelog = open('/tmp/changelog.txt').read().strip()
sections = []
if release_notes.strip():
sections.append(release_notes.strip())
if changelog:
sections.append('## Changelog\n\n' + changelog)
print(json.dumps('\n\n'.join(sections)))
")
# Send body via file to avoid CLI length limits / shell escaping
python3 -c "
import json, os
body = os.environ['BODY']
payload = {
'tag_name': os.environ['TAG'],
'name': f\"Notify Bridge {os.environ['VERSION']}\",
'body': json.loads(body),
'draft': False,
'prerelease': os.environ['IS_PRE'] == 'true',
}
open('/tmp/release-payload.json','w').write(json.dumps(payload))
" BODY="$BODY" TAG="$TAG" VERSION="$VERSION" IS_PRE="$IS_PRE"
HTTP=$(curl -s -o /tmp/release-resp.json -w "%{http_code}" \
-X POST "$BASE_URL/releases" \
-H "Authorization: token $DEPLOY_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @/tmp/release-payload.json)
echo "POST /releases → HTTP $HTTP"
echo "--- response ---"
head -c 2000 /tmp/release-resp.json; echo
echo "----------------"
if [ "$HTTP" = "201" ]; then
RELEASE_ID=$(python3 -c "import json; print(json.load(open('/tmp/release-resp.json'))['id'])")
echo "Created release $RELEASE_ID for $TAG"
elif [ "$HTTP" = "409" ] || grep -q "already exists" /tmp/release-resp.json; then
echo "::warning::Release already exists for tag $TAG — reusing"
HTTP2=$(curl -s -o /tmp/release-resp.json -w "%{http_code}" \
"$BASE_URL/releases/tags/$TAG" \
-H "Authorization: token $DEPLOY_TOKEN")
if [ "$HTTP2" != "200" ]; then
echo "::error::Failed to fetch existing release (HTTP $HTTP2)"
cat /tmp/release-resp.json
exit 1
fi
RELEASE_ID=$(python3 -c "import json; print(json.load(open('/tmp/release-resp.json'))['id'])")
echo "Reused release $RELEASE_ID for $TAG"
else
echo "::error::Failed to create release for $TAG (HTTP $HTTP)"
exit 1
fi