Release 0.2.6: align desktop runtime with Grok Build #30
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 | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| permissions: | |
| contents: write | |
| jobs: | |
| verify: | |
| name: Verify release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 24 | |
| cache: npm | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt, clippy | |
| - name: Verify all version sources match the tag | |
| shell: bash | |
| run: | | |
| tag="${GITHUB_REF_NAME}" | |
| npm_version="$(node -p "require('./package.json').version")" | |
| cargo_version="$(sed -n 's/^version = "\(.*\)"/\1/p' src-tauri/Cargo.toml | head -1)" | |
| tauri_version="$(node -p "require('./src-tauri/tauri.conf.json').version")" | |
| echo "tag=${tag}" | |
| echo "package.json=${npm_version}" | |
| echo "Cargo.toml=${cargo_version}" | |
| echo "tauri.conf.json=${tauri_version}" | |
| ok=true | |
| for v in "${cargo_version}" "${tauri_version}"; do | |
| if [ "${v}" != "${npm_version}" ]; then | |
| echo "::error::Version mismatch: package.json=${npm_version} but got ${v}" | |
| ok=false | |
| fi | |
| done | |
| if [ "${tag}" != "v${npm_version}" ]; then | |
| echo "::error::Tag ${tag} does not match package.json version ${npm_version}" | |
| ok=false | |
| fi | |
| if [ "${ok}" != "true" ]; then exit 1; fi | |
| - name: Install dependencies | |
| run: npm ci | |
| # Frontend checks + rustfmt (fast). Full clippy/test run on Windows pack jobs | |
| # and on main CI; keep tag verify from shipping unformatted Rust (CI gap that | |
| # previously let Release succeed while the rust job failed on fmt). | |
| - name: Frontend checks | |
| run: npm run check:frontend | |
| - name: Rust format check | |
| run: cargo fmt --manifest-path src-tauri/Cargo.toml --check | |
| # Single canonical changelog for Release body + latest.json notes + UpdateModal. | |
| # Matrix pack jobs only consume this output (do not regenerate notes). | |
| prepare-notes: | |
| name: Prepare release notes | |
| needs: verify | |
| runs-on: ubuntu-latest | |
| # generate-notes API requires contents:write (read-only GITHUB_TOKEN → 403). | |
| permissions: | |
| contents: write | |
| outputs: | |
| body: ${{ steps.gen.outputs.body }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 24 | |
| - name: Generate release notes | |
| id: gen | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| RELEASE_TAG: ${{ github.ref_name }} | |
| run: | | |
| set -euo pipefail | |
| node scripts/generate-release-notes.mjs | tee release-notes.md | |
| echo "----- release notes -----" | |
| cat release-notes.md | |
| release: | |
| name: ${{ matrix.name }} | |
| needs: [verify, prepare-notes] | |
| permissions: | |
| contents: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - name: Windows x64 | |
| platform: windows-latest | |
| rustTarget: "" | |
| # NSIS installer is also the Windows updater artifact (.exe + .sig). | |
| args: "--bundles nsis" | |
| - name: macOS Apple Silicon | |
| platform: macos-latest | |
| rustTarget: aarch64-apple-darwin | |
| # `app` is required for createUpdaterArtifacts (.app.tar.gz + .sig). | |
| # DMG alone is only the first-install package — updater ignores it. | |
| args: "--target aarch64-apple-darwin --bundles app,dmg" | |
| - name: macOS Intel | |
| platform: macos-latest | |
| rustTarget: x86_64-apple-darwin | |
| args: "--target x86_64-apple-darwin --bundles app,dmg" | |
| runs-on: ${{ matrix.platform }} | |
| timeout-minutes: 60 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 24 | |
| cache: npm | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.rustTarget }} | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: src-tauri | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Configure ad-hoc macOS signing | |
| if: runner.os == 'macOS' | |
| shell: bash | |
| run: echo "APPLE_SIGNING_IDENTITY=-" >> "$GITHUB_ENV" | |
| - name: Require updater signing key | |
| shell: bash | |
| env: | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| run: | | |
| if [ -z "${TAURI_SIGNING_PRIVATE_KEY}" ]; then | |
| echo "::error::TAURI_SIGNING_PRIVATE_KEY secret is empty — in-app updates cannot be signed." | |
| exit 1 | |
| fi | |
| - name: Build and publish installers | |
| uses: tauri-apps/tauri-action@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Required for signed updater artifacts (must match pubkey in tauri.conf.json). | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| with: | |
| tagName: ${{ github.ref_name }} | |
| releaseName: "PinkCode ${{ github.ref_name }}" | |
| # Same body on every matrix leg (from prepare-notes only). | |
| releaseBody: ${{ needs.prepare-notes.outputs.body }} | |
| releaseDraft: false | |
| prerelease: false | |
| # Publishes latest.json for tauri-plugin-updater endpoints. | |
| uploadUpdaterJson: true | |
| args: ${{ matrix.args }} | |
| # Drop [bundle] so we don't get dmg.dmg / msi.msi / nsis.exe. | |
| # Result: PinkCode_0.1.2_darwin_aarch64.dmg, …_windows_x64.msi, …_windows_x64.exe | |
| # macOS updater: PinkCode_…_darwin_*.app.tar.gz (+ .sig) | |
| releaseAssetNamePattern: "[name]_[version]_[platform]_[arch][ext]" | |
| - name: Verify signed updater artifacts | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # Fail the job if this platform did not produce a minisign signature. | |
| # Without .sig files, tauri-action omits the platform from latest.json | |
| # and clients on that OS never see an update. | |
| if [ "${{ runner.os }}" = "macOS" ]; then | |
| target="${{ matrix.rustTarget }}" | |
| root="src-tauri/target/${target}/release/bundle/macos" | |
| echo "Looking for updater artifacts under ${root}" | |
| ls -la "${root}" || true | |
| sigs=( "${root}"/*.app.tar.gz.sig ) | |
| if [ ! -e "${sigs[0]}" ]; then | |
| echo "::error::Missing macOS updater signature (*.app.tar.gz.sig). In-app updates will not work on Mac." | |
| echo "Ensure createUpdaterArtifacts is true and --bundles includes app (not only dmg)." | |
| exit 1 | |
| fi | |
| tars=( "${root}"/*.app.tar.gz ) | |
| if [ ! -e "${tars[0]}" ]; then | |
| echo "::error::Missing macOS updater bundle (*.app.tar.gz)." | |
| exit 1 | |
| fi | |
| echo "OK: $(basename "${tars[0]}") + $(basename "${sigs[0]}")" | |
| else | |
| root="src-tauri/target/release/bundle/nsis" | |
| echo "Looking for updater artifacts under ${root}" | |
| ls -la "${root}" || true | |
| sigs=( "${root}"/*.sig ) | |
| if [ ! -e "${sigs[0]}" ]; then | |
| echo "::error::Missing Windows updater signature (*.sig)." | |
| exit 1 | |
| fi | |
| echo "OK: $(basename "${sigs[0]}")" | |
| fi | |
| # Patch latest.json: public download URLs + notes === release body (UpdateModal source). | |
| rewrite-updater-json: | |
| name: Patch latest.json for updater | |
| needs: release | |
| if: always() && needs.release.result == 'success' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 24 | |
| - name: Rewrite platform URLs and sync notes | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| RELEASE_TAG: ${{ github.ref_name }} | |
| run: node scripts/rewrite-updater-json.mjs |