name: Release on: push: tags: - 'v*.*.*' permissions: write-all env: CARGO_INCREMENTAL: 0 RUST_BACKTRACE: short concurrency: group: '${{ github.workflow }}-${{ github.ref }}' cancel-in-progress: true jobs: # ── Validate tag matches package.json version ────────── check-version: name: Check Version if: ${{ !contains(github.ref_name, '-test') }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Validate tag vs package.json run: | TAG="${GITHUB_REF_NAME}" PKG_VERSION="v$(jq -r .version package.json)" if [[ "$TAG" != "$PKG_VERSION" ]]; then echo "❌ Tag $TAG does not match package.json $PKG_VERSION" exit 1 fi echo "✅ Version $TAG is consistent" # ── Generate release notes via git-cliff ───────────── draft-release-notes: name: Generate Release Notes needs: [check-version] if: ${{ !contains(github.ref_name, '-test') }} runs-on: ubuntu-latest permissions: contents: write outputs: body: ${{ steps.cliff.outputs.content }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Generate changelog uses: orhun/git-cliff-action@v4 id: cliff with: config: cliff.toml args: --latest --strip header env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPO: ${{ github.repository }} CLIFF_REPO: ${{ github.repository }} - name: Create draft release uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.ref_name }} name: 'BoosApi ${{ github.ref_name }}' body: ${{ steps.cliff.outputs.content }} draft: true prerelease: ${{ contains(github.ref_name, '-rc') }} token: ${{ secrets.GITHUB_TOKEN }} # ── Build for macOS / Windows / Linux x86_64 ─────────── release: name: Build (${{ matrix.target }}) needs: [check-version, draft-release-notes] if: ${{ !contains(github.ref_name, '-test') }} strategy: fail-fast: false matrix: include: # macOS - os: macos-latest target: aarch64-apple-darwin - os: macos-latest target: x86_64-apple-darwin # Windows - os: windows-latest target: x86_64-pc-windows-msvc - os: windows-latest target: aarch64-pc-windows-msvc # Linux x86_64 - os: ubuntu-22.04 target: x86_64-unknown-linux-gnu runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Install Rust uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} - name: Rust cache uses: Swatinem/rust-cache@v2 with: prefix-key: 'v1' key: '${{ matrix.os }}-${{ matrix.target }}' workspaces: src-tauri -> target - name: Install Linux dependencies if: matrix.os == 'ubuntu-22.04' run: | sudo apt-get update sudo apt-get install -y \ libwebkit2gtk-4.1-dev \ libayatana-appindicator3-dev \ librsvg2-dev \ patchelf - name: Install x86_64 OpenSSL (macOS Intel cross-compile) if: matrix.target == 'x86_64-apple-darwin' run: | arch -x86_64 brew install openssl@3 echo "OPENSSL_DIR=$(arch -x86_64 brew --prefix openssl@3)" >> $GITHUB_ENV echo "OPENSSL_INCLUDE_DIR=$(arch -x86_64 brew --prefix openssl@3)/include" >> $GITHUB_ENV echo "OPENSSL_LIB_DIR=$(arch -x86_64 brew --prefix openssl@3)/lib" >> $GITHUB_ENV - name: Install Protoc uses: arduino/setup-protoc@v3 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Get linked dependency versions id: dep-versions shell: bash run: | SM_SHA=$(git -C libs/stream-monaco rev-parse HEAD) MS_SHA=$(git -C libs/markstream-vue rev-parse HEAD) echo "cache-key=${{ runner.os }}-${{ matrix.target }}-linked-deps-${SM_SHA:0:12}-${MS_SHA:0:12}" >> $GITHUB_OUTPUT - name: Cache linked dependencies id: cache-linked-deps uses: actions/cache@v4 with: path: | libs/stream-monaco/node_modules libs/stream-monaco/dist libs/markstream-vue/node_modules libs/markstream-vue/packages/markdown-parser/node_modules libs/markstream-vue/packages/markdown-parser/dist libs/markstream-vue/packages/markstream-react/node_modules libs/markstream-vue/packages/markstream-react/dist key: ${{ steps.dep-versions.outputs.cache-key }} - name: Build linked dependencies if: steps.cache-linked-deps.outputs.cache-hit != 'true' shell: bash run: | bun --cwd libs/stream-monaco install --frozen-lockfile bun --cwd libs/stream-monaco run build bun --cwd libs/markstream-vue install --frozen-lockfile bun --cwd libs/markstream-vue run build:parser bun --cwd libs/markstream-vue/packages/markstream-react run build - name: Install frontend dependencies run: bun install --frozen-lockfile - name: Build with Tauri uses: tauri-apps/tauri-action@v0 env: NODE_OPTIONS: '--max_old_space_size=4096' 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 }} APPLE_SIGNING_IDENTITY: ${{ matrix.os == 'macos-latest' && '-' || '' }} with: tagName: ${{ github.ref_name }} releaseName: 'BoosApi ${{ github.ref_name }}' releaseBody: ${{ needs.draft-release-notes.outputs.body }} releaseDraft: true prerelease: ${{ contains(github.ref_name, '-rc') }} tauriScript: bun run tauri args: --target ${{ matrix.target }} includeUpdaterJson: true - name: Package Windows portable (zip) if: contains(matrix.target, 'windows') shell: pwsh run: | $exe = "src-tauri/target/${{ matrix.target }}/release/BoosApi.exe" $arch = if ("${{ matrix.target }}" -match "aarch64") { "arm64" } else { "x64" } $zipName = "BoosApi_${{ github.ref_name }}_windows-${arch}-portable.zip" Compress-Archive -Path $exe -DestinationPath $zipName - name: Upload Windows portable to release if: contains(matrix.target, 'windows') uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.ref_name }} draft: true token: ${{ secrets.GITHUB_TOKEN }} files: BoosApi_${{ github.ref_name }}_windows-*-portable.zip # ── Build for Linux ARM64 (cross-compile) ────────────── release-linux-arm: name: Build (aarch64-unknown-linux-gnu) needs: [check-version, draft-release-notes] if: ${{ !contains(github.ref_name, '-test') }} runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Install Rust uses: dtolnay/rust-toolchain@stable with: targets: aarch64-unknown-linux-gnu - name: Rust cache uses: Swatinem/rust-cache@v2 with: prefix-key: 'v1' key: 'ubuntu-22.04-aarch64-unknown-linux-gnu' workspaces: src-tauri -> target - name: Setup cross-compilation sources run: | cat > /tmp/sources.list << 'EOF' deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy main multiverse universe restricted deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-security main multiverse universe restricted deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-updates main multiverse universe restricted deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy main multiverse universe restricted deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main multiverse universe restricted deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main multiverse universe restricted EOF sudo mv /etc/apt/sources.list /etc/apt/sources.list.bak sudo mv /tmp/sources.list /etc/apt/sources.list sudo dpkg --add-architecture arm64 sudo apt-get update - name: Install ARM64 dependencies run: | sudo apt-get install -y \ gcc-aarch64-linux-gnu \ g++-aarch64-linux-gnu \ libwebkit2gtk-4.1-dev:arm64 \ libayatana-appindicator3-dev:arm64 \ librsvg2-dev:arm64 \ libssl-dev:arm64 \ patchelf:arm64 - name: Install Protoc uses: arduino/setup-protoc@v3 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Get linked dependency versions id: dep-versions run: | SM_SHA=$(git -C libs/stream-monaco rev-parse HEAD) MS_SHA=$(git -C libs/markstream-vue rev-parse HEAD) echo "cache-key=${{ runner.os }}-aarch64-unknown-linux-gnu-linked-deps-${SM_SHA:0:12}-${MS_SHA:0:12}" >> $GITHUB_OUTPUT - name: Cache linked dependencies id: cache-linked-deps uses: actions/cache@v4 with: path: | libs/stream-monaco/node_modules libs/stream-monaco/dist libs/markstream-vue/node_modules libs/markstream-vue/packages/markdown-parser/node_modules libs/markstream-vue/packages/markdown-parser/dist libs/markstream-vue/packages/markstream-react/node_modules libs/markstream-vue/packages/markstream-react/dist key: ${{ steps.dep-versions.outputs.cache-key }} - name: Build linked dependencies if: steps.cache-linked-deps.outputs.cache-hit != 'true' run: | bun --cwd libs/stream-monaco install --frozen-lockfile bun --cwd libs/stream-monaco run build bun --cwd libs/markstream-vue install --frozen-lockfile bun --cwd libs/markstream-vue run build:parser bun --cwd libs/markstream-vue/packages/markstream-react run build - name: Install frontend dependencies run: bun install --frozen-lockfile - name: Build for Linux ARM64 run: | export PKG_CONFIG_ALLOW_CROSS=1 export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig/:$PKG_CONFIG_PATH export PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu/ bun run tauri build --target aarch64-unknown-linux-gnu --bundles deb,rpm env: NODE_OPTIONS: '--max_old_space_size=4096' CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc CC_aarch64_unknown_linux_gnu: aarch64-linux-gnu-gcc CXX_aarch64_unknown_linux_gnu: aarch64-linux-gnu-g++ AR_aarch64_unknown_linux_gnu: aarch64-linux-gnu-ar TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} - name: Upload Linux ARM64 artifacts uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.ref_name }} name: 'BoosApi ${{ github.ref_name }}' draft: true prerelease: ${{ contains(github.ref_name, '-rc') }} token: ${{ secrets.GITHUB_TOKEN }} files: | src-tauri/target/aarch64-unknown-linux-gnu/release/bundle/deb/*.deb src-tauri/target/aarch64-unknown-linux-gnu/release/bundle/rpm/*.rpm # ── Publish draft release as latest ──────────────────── publish-release: name: Publish Release needs: [release, release-linux-arm] if: ${{ !contains(github.ref_name, '-test') }} runs-on: ubuntu-latest permissions: contents: write steps: - name: Publish draft release uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.ref_name }} draft: false prerelease: ${{ contains(github.ref_name, '-rc') }} make_latest: true token: ${{ secrets.GITHUB_TOKEN }} # ── Deploy website after release ──────────────────────── deploy-website: name: Deploy Website needs: [publish-release] if: ${{ !contains(github.ref_name, '-test') }} runs-on: ubuntu-latest steps: - name: Trigger website deployment uses: actions/github-script@v7 with: script: | await github.rest.actions.createWorkflowDispatch({ owner: context.repo.owner, repo: context.repo.repo, workflow_id: 'deploy-website.yml', ref: 'main', });