name: Build Release on: push: tags: - 'v*' jobs: # ── Create the release first (shared by all build jobs) ──── create-release: runs-on: ubuntu-latest outputs: release_id: ${{ steps.create.outputs.release_id }} steps: - name: Create Gitea release id: create env: GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} run: | TAG="${{ gitea.ref_name }}" 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 # Build registry path for Docker instructions SERVER_HOST=$(echo "${{ gitea.server_url }}" | sed -E 's|https?://||') REPO=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]') DOCKER_IMAGE="${SERVER_HOST}/${REPO}" # Build release body via Python to avoid YAML escaping issues BODY_JSON=$(python3 -c " import json, sys tag = '$TAG' image = '$DOCKER_IMAGE' body = f'''## Downloads | Platform | File | Description | |----------|------|-------------| | Windows (installer) | \`LedGrab-{tag}-setup.exe\` | Install with Start Menu shortcut, optional autostart, uninstaller | | Windows (portable) | \`LedGrab-{tag}-win-x64.zip\` | Unzip anywhere, run LedGrab.bat | | Linux | \`LedGrab-{tag}-linux-x64.tar.gz\` | Extract, run ./run.sh | | Docker | See below | docker pull + docker run | After starting, open **http://localhost:8080** in your browser. ### Docker \`\`\`bash docker pull {image}:{tag} docker run -d --name ledgrab -p 8080:8080 -v ledgrab-data:/app/data {image}:{tag} \`\`\` ### First-time setup 1. Change the default API key in config/default_config.yaml 2. Open http://localhost:8080 and discover your WLED devices 3. See INSTALLATION.md for detailed configuration ''' import textwrap print(json.dumps(textwrap.dedent(body).strip())) ") RELEASE=$(curl -s -X POST "$BASE_URL/releases" \ -H "Authorization: token $GITEA_TOKEN" \ -H "Content-Type: application/json" \ -d "{ \"tag_name\": \"$TAG\", \"name\": \"LedGrab $TAG\", \"body\": $BODY_JSON, \"draft\": false, \"prerelease\": $IS_PRE }") RELEASE_ID=$(echo "$RELEASE" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])") echo "release_id=$RELEASE_ID" >> "$GITHUB_OUTPUT" echo "Created release ID: $RELEASE_ID" # ── Windows portable ZIP (cross-built from Linux) ───────── build-windows: needs: create-release runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.11' - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y --no-install-recommends zip libportaudio2 nsis msitools - name: Cross-build Windows distribution run: | chmod +x build-dist-windows.sh ./build-dist-windows.sh "${{ gitea.ref_name }}" - name: Upload build artifacts uses: actions/upload-artifact@v3 with: name: LedGrab-${{ gitea.ref_name }}-win-x64 path: | build/LedGrab-*.zip build/LedGrab-*-setup.exe retention-days: 90 - name: Attach assets to release env: GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} run: | RELEASE_ID="${{ needs.create-release.outputs.release_id }}" BASE_URL="${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}" # Upload ZIP ZIP_FILE=$(ls build/LedGrab-*.zip | head -1) if [ -f "$ZIP_FILE" ]; then curl -s -X POST \ "$BASE_URL/releases/$RELEASE_ID/assets?name=$(basename "$ZIP_FILE")" \ -H "Authorization: token $GITEA_TOKEN" \ -H "Content-Type: application/octet-stream" \ --data-binary "@$ZIP_FILE" echo "Uploaded: $(basename "$ZIP_FILE")" fi # Upload installer SETUP_FILE=$(ls build/LedGrab-*-setup.exe 2>/dev/null | head -1) if [ -f "$SETUP_FILE" ]; then curl -s -X POST \ "$BASE_URL/releases/$RELEASE_ID/assets?name=$(basename "$SETUP_FILE")" \ -H "Authorization: token $GITEA_TOKEN" \ -H "Content-Type: application/octet-stream" \ --data-binary "@$SETUP_FILE" echo "Uploaded: $(basename "$SETUP_FILE")" fi # ── Linux tarball ────────────────────────────────────────── build-linux: needs: create-release runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.11' - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y --no-install-recommends libportaudio2 - name: Build Linux distribution run: | chmod +x build-dist.sh ./build-dist.sh "${{ gitea.ref_name }}" - name: Upload build artifact uses: actions/upload-artifact@v3 with: name: LedGrab-${{ gitea.ref_name }}-linux-x64 path: build/LedGrab-*.tar.gz retention-days: 90 - name: Attach tarball to release env: GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} run: | TAG="${{ gitea.ref_name }}" RELEASE_ID="${{ needs.create-release.outputs.release_id }}" BASE_URL="${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}" TAR_FILE=$(ls build/LedGrab-*.tar.gz | head -1) TAR_NAME=$(basename "$TAR_FILE") curl -s -X POST \ "$BASE_URL/releases/$RELEASE_ID/assets?name=$TAR_NAME" \ -H "Authorization: token $GITEA_TOKEN" \ -H "Content-Type: application/octet-stream" \ --data-binary "@$TAR_FILE" echo "Uploaded: $TAR_NAME" # ── Docker image ─────────────────────────────────────────── build-docker: needs: create-release runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Extract version metadata id: meta run: | TAG="${{ gitea.ref_name }}" VERSION="${TAG#v}" # Strip protocol and lowercase for Docker registry path SERVER_HOST=$(echo "${{ gitea.server_url }}" | sed -E 's|https?://||') REPO=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]') REGISTRY="${SERVER_HOST}/${REPO}" echo "version=$VERSION" >> "$GITHUB_OUTPUT" echo "registry=$REGISTRY" >> "$GITHUB_OUTPUT" echo "server_host=$SERVER_HOST" >> "$GITHUB_OUTPUT" - name: Login to Gitea Container Registry id: docker-login continue-on-error: true run: | echo "${{ secrets.GITEA_TOKEN }}" | docker login \ "${{ steps.meta.outputs.server_host }}" \ -u "${{ gitea.actor }}" --password-stdin - name: Build Docker image if: steps.docker-login.outcome == 'success' run: | TAG="${{ gitea.ref_name }}" REGISTRY="${{ steps.meta.outputs.registry }}" docker build \ --label "org.opencontainers.image.version=${{ steps.meta.outputs.version }}" \ --label "org.opencontainers.image.revision=${{ gitea.sha }}" \ -t "$REGISTRY:$TAG" \ -t "$REGISTRY:${{ steps.meta.outputs.version }}" \ ./server # Tag as latest only for stable releases if ! echo "$TAG" | grep -qE '(alpha|beta|rc)'; then docker tag "$REGISTRY:$TAG" "$REGISTRY:latest" fi - name: Push Docker image if: steps.docker-login.outcome == 'success' run: | TAG="${{ gitea.ref_name }}" REGISTRY="${{ steps.meta.outputs.registry }}" docker push "$REGISTRY:$TAG" docker push "$REGISTRY:${{ steps.meta.outputs.version }}" if ! echo "$TAG" | grep -qE '(alpha|beta|rc)'; then docker push "$REGISTRY:latest" fi