Release Build and Publish #4
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release Build and Publish | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Release version (e.g., v0.5.0)" | |
| required: true | |
| permissions: | |
| contents: write | |
| jobs: | |
| build-release: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: "macos-latest" | |
| args: "" | |
| rust-target: "aarch64-apple-darwin" | |
| sidecar-target: "aarch64-apple-darwin" | |
| slug: "macos-aarch64" | |
| - platform: "ubuntu-22.04" | |
| args: "" | |
| rust-target: "x86_64-unknown-linux-gnu" | |
| sidecar-target: "x86_64-unknown-linux-gnu" | |
| slug: "linux-x86_64" | |
| runs-on: ${{ matrix.platform }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Setup Rust | |
| uses: moonrepo/setup-rust@v1 | |
| with: | |
| channel: stable | |
| - name: Install dependencies (Ubuntu) | |
| if: matrix.platform == 'ubuntu-22.04' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev \ | |
| build-essential \ | |
| curl \ | |
| wget \ | |
| file \ | |
| libxdo-dev \ | |
| libssl-dev \ | |
| libayatana-appindicator3-dev \ | |
| librsvg2-dev | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: "./backend -> target" | |
| - name: Install frontend dependencies | |
| working-directory: frontend | |
| run: npm ci | |
| - name: Build backend (linggen-server) | |
| working-directory: backend | |
| run: cargo build --release --bin linggen-server | |
| - name: Build CLI (linggen) | |
| working-directory: linggen-cli | |
| run: cargo build --release | |
| - name: Package CLI and server tarballs | |
| run: | | |
| mkdir -p dist | |
| tar -C linggen-cli/target/release -czf dist/linggen-cli-${{ matrix.slug }}.tar.gz linggen | |
| tar -C backend/target/release -czf dist/linggen-server-${{ matrix.slug }}.tar.gz linggen-server | |
| - name: Setup Tauri sidecar | |
| shell: bash | |
| run: | | |
| SIDECAR_NAME="linggen-server-${{ matrix.sidecar-target }}" | |
| cp "backend/target/release/linggen-server" "frontend/src-tauri/${SIDECAR_NAME}" | |
| chmod +x "frontend/src-tauri/${SIDECAR_NAME}" | |
| echo "Sidecar created: ${SIDECAR_NAME}" | |
| - name: Build Tauri app | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| with: | |
| projectPath: frontend | |
| args: ${{ matrix.args }} | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: linggen-${{ matrix.platform }} | |
| path: | | |
| frontend/src-tauri/target/*/release/bundle/dmg/*.dmg | |
| frontend/src-tauri/target/*/release/bundle/dmg/*.dmg.tar.gz | |
| frontend/src-tauri/target/*/release/bundle/dmg/*.dmg.tar.gz.sig | |
| frontend/src-tauri/target/release/bundle/deb/*.deb | |
| frontend/src-tauri/target/release/bundle/deb/*.deb.tar.gz | |
| frontend/src-tauri/target/release/bundle/deb/*.deb.tar.gz.sig | |
| frontend/src-tauri/target/release/bundle/appimage/*.AppImage | |
| frontend/src-tauri/target/release/bundle/appimage/*.AppImage.tar.gz | |
| frontend/src-tauri/target/release/bundle/appimage/*.AppImage.tar.gz.sig | |
| dist/*.tar.gz | |
| if-no-files-found: ignore | |
| publish-to-releases-repo: | |
| needs: build-release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout linggen repository | |
| uses: actions/checkout@v4 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Get version | |
| id: version | |
| run: | | |
| if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then | |
| echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT | |
| fi | |
| - name: List artifacts | |
| run: | | |
| echo "Downloaded artifacts:" | |
| find artifacts -type f | |
| - name: Generate manifests | |
| run: | | |
| set -euo pipefail | |
| VERSION="${{ steps.version.outputs.version }}" | |
| VERSION_NUM="${VERSION#v}" | |
| BASE_URL="https://github.com/linggen/linggen-releases/releases/download/${VERSION}" | |
| DMG=$(find artifacts -name "*.dmg" | head -n 1 || true) | |
| DEB=$(find artifacts -name "*.deb" | head -n 1 || true) | |
| CLI_MAC_ARM64=$(find artifacts -name "linggen-cli-macos-aarch64.tar.gz" | head -n 1 || true) | |
| CLI_LINUX_X64=$(find artifacts -name "linggen-cli-linux-x86_64.tar.gz" | head -n 1 || true) | |
| SRV_MAC_ARM64=$(find artifacts -name "linggen-server-macos-aarch64.tar.gz" | head -n 1 || true) | |
| SRV_LINUX_X64=$(find artifacts -name "linggen-server-linux-x86_64.tar.gz" | head -n 1 || true) | |
| # Validate required artifacts exist | |
| if [ -z "$CLI_MAC_ARM64" ]; then | |
| echo "Error: CLI macOS ARM64 artifact not found" >&2 | |
| exit 1 | |
| fi | |
| if [ -z "$CLI_LINUX_X64" ]; then | |
| echo "Error: CLI Linux x86_64 artifact not found" >&2 | |
| exit 1 | |
| fi | |
| if [ -z "$SRV_MAC_ARM64" ]; then | |
| echo "Error: Server macOS ARM64 artifact not found" >&2 | |
| exit 1 | |
| fi | |
| if [ -z "$SRV_LINUX_X64" ]; then | |
| echo "Error: Server Linux x86_64 artifact not found" >&2 | |
| exit 1 | |
| fi | |
| DMG_BASENAME=$(basename "$DMG" 2>/dev/null || echo "") | |
| DEB_BASENAME=$(basename "$DEB" 2>/dev/null || echo "") | |
| CLI_MAC_ARM64_BASENAME=$(basename "$CLI_MAC_ARM64") | |
| CLI_LINUX_X64_BASENAME=$(basename "$CLI_LINUX_X64") | |
| SRV_MAC_ARM64_BASENAME=$(basename "$SRV_MAC_ARM64") | |
| SRV_LINUX_X64_BASENAME=$(basename "$SRV_LINUX_X64") | |
| # Generate latest.json only if DMG and DEB exist | |
| if [ -n "$DMG_BASENAME" ] && [ -n "$DEB_BASENAME" ]; then | |
| cat > latest.json << EOF | |
| { | |
| "version": "${VERSION_NUM}", | |
| "notes": "See release notes at https://github.com/linggen/linggen-releases/releases/tag/${VERSION}", | |
| "pub_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", | |
| "platforms": { | |
| "darwin-universal": { | |
| "signature": "", | |
| "url": "${BASE_URL}/${DMG_BASENAME}" | |
| }, | |
| "linux-x86_64": { | |
| "signature": "", | |
| "url": "${BASE_URL}/${DEB_BASENAME}" | |
| } | |
| } | |
| } | |
| EOF | |
| else | |
| echo "Warning: DMG or DEB not found, skipping latest.json generation" | |
| touch latest.json | |
| fi | |
| # Generate manifest.json with all artifacts | |
| { | |
| echo "{" | |
| echo " \"version\": \"${VERSION_NUM}\"," | |
| echo " \"artifacts\": {" | |
| echo " \"cli-macos-aarch64\": {\"url\": \"${BASE_URL}/${CLI_MAC_ARM64_BASENAME}\"}," | |
| echo " \"cli-linux-x86_64\": {\"url\": \"${BASE_URL}/${CLI_LINUX_X64_BASENAME}\"}," | |
| echo " \"server-macos-aarch64\": {\"url\": \"${BASE_URL}/${SRV_MAC_ARM64_BASENAME}\"}," | |
| if [ -n "$DMG_BASENAME" ] || [ -n "$DEB_BASENAME" ]; then | |
| echo " \"server-linux-x86_64\": {\"url\": \"${BASE_URL}/${SRV_LINUX_X64_BASENAME}\"}," | |
| else | |
| echo " \"server-linux-x86_64\": {\"url\": \"${BASE_URL}/${SRV_LINUX_X64_BASENAME}\"}" | |
| fi | |
| if [ -n "$DMG_BASENAME" ]; then | |
| if [ -n "$DEB_BASENAME" ]; then | |
| echo " \"app-macos-dmg\": {\"url\": \"${BASE_URL}/${DMG_BASENAME}\"}," | |
| else | |
| echo " \"app-macos-dmg\": {\"url\": \"${BASE_URL}/${DMG_BASENAME}\"}" | |
| fi | |
| fi | |
| if [ -n "$DEB_BASENAME" ]; then | |
| echo " \"app-linux-deb\": {\"url\": \"${BASE_URL}/${DEB_BASENAME}\"}" | |
| fi | |
| echo " }" | |
| echo "}" | |
| } > manifest.json | |
| echo "Generated latest.json:" | |
| cat latest.json | |
| echo "Generated manifest.json:" | |
| cat manifest.json | |
| - name: Checkout linggen-releases repository | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: linggen/linggen-releases | |
| token: ${{ secrets.RELEASES_PAT }} | |
| path: linggen-releases | |
| - name: Create release in linggen-releases | |
| env: | |
| GH_TOKEN: ${{ secrets.RELEASES_PAT }} | |
| run: | | |
| set -euo pipefail | |
| VERSION="${{ steps.version.outputs.version }}" | |
| VERSION_NUM="${VERSION#v}" | |
| cd linggen-releases | |
| gh release create "${VERSION}" \ | |
| --title "Linggen ${VERSION}" \ | |
| --notes "Release ${VERSION} - See main repository for details" \ | |
| --draft | |
| # Upload DMG, DEB, AppImage | |
| find ../artifacts -name "*.dmg" -exec gh release upload "${VERSION}" {} \; | |
| find ../artifacts -name "*.deb" -exec gh release upload "${VERSION}" {} \; | |
| find ../artifacts -name "*.AppImage" -exec gh release upload "${VERSION}" {} \; | |
| # Upload server tarballs | |
| find ../artifacts -name "linggen-server-*.tar.gz" -exec gh release upload "${VERSION}" {} \; | |
| # Upload CLI tarballs with base names, versioned names, and latest names | |
| for cli_tarball in ../artifacts/linggen-cli-*.tar.gz; do | |
| if [ -f "$cli_tarball" ]; then | |
| basename_file=$(basename "$cli_tarball") | |
| slug="${basename_file#linggen-cli-}" | |
| slug="${slug%.tar.gz}" | |
| # Upload with base name (linggen-cli-<slug>.tar.gz) | |
| gh release upload "${VERSION}" "$cli_tarball" | |
| # Create and upload versioned name (linggen-cli-<slug>-v<version>.tar.gz) | |
| versioned_name="linggen-cli-${slug}-v${VERSION_NUM}.tar.gz" | |
| cp "$cli_tarball" "/tmp/${versioned_name}" | |
| gh release upload "${VERSION}" "/tmp/${versioned_name}" | |
| # Create and upload latest name (linggen-cli-<slug>-latest.tar.gz) | |
| # The latest release will serve these when using /releases/latest/download/ | |
| latest_name="linggen-cli-${slug}-latest.tar.gz" | |
| cp "$cli_tarball" "/tmp/${latest_name}" | |
| gh release upload "${VERSION}" "/tmp/${latest_name}" | |
| fi | |
| done | |
| # Upload manifests | |
| gh release upload "${VERSION}" ../latest.json ../manifest.json | |
| gh release edit "${VERSION}" --draft=false | |
| echo "Release ${VERSION} published successfully!" |