name: Release on: push: tags: - 'v*' jobs: # --- Create Gitea release --- create-release: runs-on: ubuntu-latest outputs: release_id: ${{ steps.create.outputs.release_id }} version: ${{ steps.create.outputs.version }} steps: - name: Fetch RELEASE_NOTES.md only uses: actions/checkout@v4 with: sparse-checkout: RELEASE_NOTES.md sparse-checkout-cone-mode: false - name: Create Gitea release id: create env: DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }} run: | TAG="${{ gitea.ref_name }}" VERSION="${TAG#v}" BASE_URL="${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}" IS_PRE="false" if echo "$TAG" | grep -qE '(alpha|beta|rc)'; then IS_PRE="true" fi 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_JSON=$(python3 -c " import json, os, textwrap tag = '$TAG' release_notes = os.environ.get('RELEASE_NOTES', '') sections = [] if release_notes.strip(): sections.append(release_notes.strip()) sections.append(textwrap.dedent(f''' ## Downloads | Platform | File | |----------|------| | Windows (installer) | \`MediaServer-{tag}-setup.exe\` | | Windows (portable) | \`MediaServer-{tag}-win-x64.zip\` | | Linux | \`MediaServer-{tag}-linux-x64.tar.gz\` | ''').strip()) print(json.dumps('\n\n'.join(sections))) ") RELEASE=$(curl -s -X POST "$BASE_URL/releases" \ -H "Authorization: token $DEPLOY_TOKEN" \ -H "Content-Type: application/json" \ -d "{ \"tag_name\": \"$TAG\", \"name\": \"Media Server $TAG\", \"body\": $BODY_JSON, \"draft\": false, \"prerelease\": $IS_PRE }") # Extract release ID; if creation failed (already exists), fetch existing RELEASE_ID=$(echo "$RELEASE" | python3 -c " import sys, json data = json.load(sys.stdin) if 'id' in data: print(data['id']) else: print('FAILED', file=sys.stderr) print(json.dumps(data, indent=2), file=sys.stderr) sys.exit(1) " 2>&1) || { echo "::warning::Release already exists for tag $TAG — reusing existing release" RELEASE=$(curl -s "$BASE_URL/releases/tags/$TAG" \ -H "Authorization: token $DEPLOY_TOKEN") RELEASE_ID=$(echo "$RELEASE" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])") } echo "release_id=$RELEASE_ID" >> "$GITHUB_OUTPUT" echo "version=$VERSION" >> "$GITHUB_OUTPUT" # --- Build Windows installer + portable ZIP --- build-windows: needs: create-release runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' - name: Build frontend run: npm ci && npm run build - uses: actions/setup-python@v5 with: python-version: '3.11' - name: Install build tools run: sudo apt-get update && sudo apt-get install -y --no-install-recommends nsis zip - name: Build Windows distribution run: | chmod +x build-dist-windows.sh ./build-dist-windows.sh "${{ gitea.ref_name }}" - name: Build NSIS installer run: | VERSION="${{ needs.create-release.outputs.version }}" makensis -DVERSION="${VERSION}" installer.nsi - name: Upload assets to release env: DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }} run: | 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 name=$(basename "$file") # Delete existing asset with the same name (idempotent re-runs) EXISTING=$(curl -s "$BASE_URL/releases/$RELEASE_ID/assets" \ -H "Authorization: token $DEPLOY_TOKEN") ASSET_ID=$(echo "$EXISTING" | python3 -c " import sys, json assets = json.load(sys.stdin) for a in assets: if a['name'] == '$name': print(a['id']) break " 2>/dev/null || true) if [ -n "$ASSET_ID" ]; then echo "Replacing existing asset: $name (id=$ASSET_ID)" curl -s -X DELETE "$BASE_URL/releases/$RELEASE_ID/assets/$ASSET_ID" \ -H "Authorization: token $DEPLOY_TOKEN" fi echo "Uploading $name..." curl -s -X POST \ "$BASE_URL/releases/$RELEASE_ID/assets?name=$name" \ -H "Authorization: token $DEPLOY_TOKEN" \ -H "Content-Type: application/octet-stream" \ --data-binary "@$file" } for FILE in build/MediaServer-*.zip build/MediaServer-*-setup.exe; do [ -f "$FILE" ] || continue upload_asset "$FILE" done # --- Build Linux tarball --- build-linux: needs: create-release runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' - name: Build frontend run: npm ci && npm run build - uses: actions/setup-python@v5 with: python-version: '3.11' - name: Build Linux distribution run: | chmod +x build-dist-linux.sh ./build-dist-linux.sh "${{ gitea.ref_name }}" - name: Upload assets to release env: DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }} run: | RELEASE_ID="${{ needs.create-release.outputs.release_id }}" BASE_URL="${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}" FILE=$(ls build/MediaServer-*-linux-x64.tar.gz | head -1) NAME=$(basename "$FILE") # Delete existing asset with the same name (idempotent re-runs) EXISTING=$(curl -s "$BASE_URL/releases/$RELEASE_ID/assets" \ -H "Authorization: token $DEPLOY_TOKEN") ASSET_ID=$(echo "$EXISTING" | python3 -c " import sys, json assets = json.load(sys.stdin) for a in assets: if a['name'] == '$NAME': print(a['id']) break " 2>/dev/null || true) if [ -n "$ASSET_ID" ]; then echo "Replacing existing asset: $NAME (id=$ASSET_ID)" curl -s -X DELETE "$BASE_URL/releases/$RELEASE_ID/assets/$ASSET_ID" \ -H "Authorization: token $DEPLOY_TOKEN" fi echo "Uploading $NAME..." curl -s -X POST \ "$BASE_URL/releases/$RELEASE_ID/assets?name=$NAME" \ -H "Authorization: token $DEPLOY_TOKEN" \ -H "Content-Type: application/octet-stream" \ --data-binary "@$FILE"