release: v0.5.7 #42
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 | |
| # Tag-triggered release. Push a semver tag to cut a release: | |
| # git tag v0.1.0 && git push origin v0.1.0 | |
| # | |
| # The `build` matrix runs the Tauri bundler on each host OS to produce a | |
| # platform-native INSTALLER (not a raw binary): | |
| # - macOS -> .dmg | |
| # - Linux -> .deb + .AppImage | |
| # - Windows -> NSIS .exe setup | |
| # Each installer is uploaded as an artifact. The single `release` job then | |
| # gathers all artifacts and publishes ONE draft GitHub Release — building the | |
| # release in one job avoids the create-race you'd hit if three matrix runners | |
| # each tried to create it. | |
| # | |
| # macOS signing: the build step is wired for Developer ID signing + | |
| # notarization, driven by repo secrets (APPLE_CERTIFICATE, APPLE_SIGNING_IDENTITY, | |
| # APPLE_ID, ... — see the "macOS signing" section of the release-runbook for how | |
| # to generate them). When those secrets are unset the .dmg builds UNSIGNED and | |
| # macOS Gatekeeper shows "is damaged" on first launch — provision the secrets to | |
| # get a clean launch. Windows installers remain UNSIGNED (SmartScreen warns). | |
| # | |
| # GUI-first: the unified `git-sync` binary lives INSIDE the bundle | |
| # (Sync.app/Contents/MacOS/git-sync, Program Files, /usr/bin/Sync). The CLI / | |
| # MCP server is reached by extracting or symlinking it onto PATH — see the | |
| # "CLI from an installer" section of the release-runbook. | |
| on: | |
| push: | |
| tags: ["v*"] | |
| # Least privilege: only the publishing job needs write. | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false | |
| env: | |
| CARGO_TERM_COLOR: always | |
| CARGO_INCREMENTAL: 0 | |
| jobs: | |
| build: | |
| name: build / ${{ matrix.target }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: macos-14 | |
| target: aarch64-apple-darwin | |
| - os: ubuntu-24.04 | |
| target: x86_64-unknown-linux-gnu | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Reclaim runner disk space | |
| if: runner.os == 'Linux' | |
| run: | | |
| # The release build of this dependency tree (datafusion + arrow + | |
| # lance + llama.cpp) sits close to the runner's ~21 GB of free | |
| # space. Drop preinstalled toolchains we never use to reclaim ~20 GB. | |
| sudo rm -rf \ | |
| /usr/local/lib/android \ | |
| /usr/share/dotnet \ | |
| /opt/ghc \ | |
| /opt/hostedtoolcache/CodeQL \ | |
| /usr/local/share/boost \ | |
| /usr/local/graalvm | |
| sudo docker image prune --all --force || true | |
| df -h / | |
| - name: Install Linux Tauri prerequisites | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| # patchelf + file are required by the AppImage bundler (on top of | |
| # the webkit/gtk deps the build itself links). | |
| sudo apt-get install -y \ | |
| libwebkit2gtk-4.1-dev \ | |
| libgtk-3-dev \ | |
| libayatana-appindicator3-dev \ | |
| librsvg2-dev \ | |
| libsoup-3.0-dev \ | |
| libssl-dev \ | |
| patchelf \ | |
| file | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22.12.0" | |
| cache: "npm" | |
| cache-dependency-path: web/package-lock.json | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| key: ${{ matrix.target }} | |
| - name: Install protoc | |
| uses: arduino/setup-protoc@v3 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build frontend | |
| # The bundler embeds web/dist. We build it explicitly here and disable | |
| # the config's beforeBuildCommand (via tauri.ci.conf.json below) so the | |
| # bundler doesn't try to re-run it — the in-repo beforeBuildCommand | |
| # path is relative to a dev cwd and isn't reliable in CI. | |
| working-directory: web | |
| run: | | |
| npm ci --ignore-scripts | |
| npm run build | |
| - name: Build installer (tauri bundle) | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| # macOS code signing + notarization. tauri-action imports the cert | |
| # into a throwaway keychain and notarizes the .dmg when these are set. | |
| # When the secrets are absent (forks, or before an Apple Developer ID | |
| # cert is provisioned) the values are empty strings and the bundler | |
| # falls back to an UNSIGNED build — the release still succeeds, users | |
| # just hit the Gatekeeper "damaged" warning. A clean first launch | |
| # needs ALL THREE signing vars AND one notarization method below. | |
| # Non-macOS runners ignore these. See release-runbook "macOS signing". | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} | |
| # Notarization via Apple ID + app-specific password (APPLE_TEAM_ID | |
| # disambiguates if the Apple ID belongs to multiple teams). | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| # Updater artifact signing (s-auto-update): a minisign keypair, | |
| # separate from the Apple cert. The private key signs the | |
| # .app.tar.gz / .AppImage / -setup.exe so installed apps verify | |
| # downloads against the pubkey baked into tauri.conf.json. The | |
| # password var is intentionally set even when empty — an unset var | |
| # makes the bundler prompt interactively and hang the runner. | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| with: | |
| # Non-root Tauri crate -> point at it explicitly. The layered | |
| # tauri.ci.conf.json (resolved relative to projectPath) empties | |
| # beforeBuildCommand since the frontend is already built above. | |
| # tauri.updater.conf.json (createUpdaterArtifacts) is layered on | |
| # ONLY when the signing key is provisioned: with it on and no key | |
| # the bundler hard-fails, which would break forks — without it the | |
| # build just skips the updater artifacts and stays green. | |
| projectPath: crates/sync-app | |
| args: --target ${{ matrix.target }} --config tauri.ci.conf.json ${{ secrets.TAURI_SIGNING_PRIVATE_KEY != '' && '--config tauri.updater.conf.json' || '' }} | |
| - name: Collect installers | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p dist | |
| # Cargo workspaces share one target dir at the repo root. | |
| base="target/${{ matrix.target }}/release/bundle" | |
| shopt -s nullglob | |
| # Copy each installer to a STABLE, version-less filename. The README | |
| # links to github.com/.../releases/latest/download/<stable-name>, which | |
| # GitHub resolves to the newest release — so those links are evergreen | |
| # and never need editing on a new release. The version is carried by | |
| # the release tag/title, not the filename. Keep these names in sync | |
| # with the download links in README.md. | |
| stable_copy() { # <src-glob> <stable-name> | |
| local src | |
| for src in $1; do | |
| cp "$src" "dist/$2" | |
| done | |
| } | |
| stable_copy "$base/dmg/*.dmg" "Sync_macOS_aarch64.dmg" | |
| stable_copy "$base/appimage/*.AppImage" "Sync_Linux_x86_64.AppImage" | |
| stable_copy "$base/deb/*.deb" "Sync_Linux_x86_64.deb" | |
| stable_copy "$base/nsis/*-setup.exe" "Sync_Windows_x64-setup.exe" | |
| # Updater artifacts (s-auto-update): the signed packages the | |
| # in-app updater downloads, plus their minisign signatures. | |
| # `scripts/release.sh --publish-manifest` later reads the .sig | |
| # assets off the GitHub release to assemble updater/latest.json. | |
| # Absent on unsigned (fork) builds — nullglob just skips them. | |
| # macOS updates ship as .app.tar.gz; Linux re-uses the AppImage | |
| # and Windows the NSIS setup copied above, so only their .sig | |
| # files are added here. | |
| stable_copy "$base/macos/*.app.tar.gz" "Sync_macOS_aarch64.app.tar.gz" | |
| stable_copy "$base/macos/*.app.tar.gz.sig" "Sync_macOS_aarch64.app.tar.gz.sig" | |
| stable_copy "$base/appimage/*.AppImage.sig" "Sync_Linux_x86_64.AppImage.sig" | |
| stable_copy "$base/nsis/*-setup.exe.sig" "Sync_Windows_x64-setup.exe.sig" | |
| ls -la dist | |
| # Only the wrapped installers are shipped — the loose .app / unpacked | |
| # dirs are intentionally not uploaded. Fail loudly if nothing matched. | |
| [ -n "$(ls -A dist)" ] || { echo "::error::no installers produced for ${{ matrix.target }}"; exit 1; } | |
| - name: Upload installer artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-${{ matrix.target }} | |
| path: dist/* | |
| if-no-files-found: error | |
| retention-days: 7 | |
| release: | |
| name: publish github release | |
| needs: build | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: write # create the release + upload assets | |
| steps: | |
| - name: Gather all built installers | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: dist | |
| merge-multiple: true # flatten every release-* artifact into dist/ | |
| - name: Publish release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: dist/* | |
| fail_on_unmatched_files: true | |
| generate_release_notes: true | |
| # Created as a draft: review the attached installers + notes, then | |
| # click "Publish" in the GitHub UI. Set to false for fully | |
| # hands-off publishing the moment the tag is pushed. | |
| draft: false |