Skip to content

Release

Release #15

Workflow file for this run

name: Release
on:
workflow_dispatch:
concurrency:
group: release
jobs:
gates:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 24
cache: pnpm
- run: pnpm install --frozen-lockfile
- uses: swatinem/rust-cache@v2
with:
workspaces: './src-tauri -> target'
- run: pnpm licenses:check
- run: pnpm attribution:check
- run: pnpm coverage:check
- run: pnpm lint
- run: pnpm test
# Regenerate before `pnpm build` so the Vite plugin ships the freshly
# validated .md into dist/; the diff fails the build on any drift.
- name: rust attribution freshness
run: |
curl -fsSL https://github.com/EmbarkStudios/cargo-about/releases/download/0.9.1/cargo-about-0.9.1-x86_64-unknown-linux-musl.tar.gz \
| tar xz --strip-components=1 -C /tmp
cd src-tauri
cargo fetch
/tmp/cargo-about generate about.hbs -o THIRD-PARTY-LICENSES-RUST.md
git diff --exit-code -- THIRD-PARTY-LICENSES-RUST.md
- run: pnpm build
- uses: EmbarkStudios/cargo-deny-action@v2
with:
command: check licenses advisories
manifest-path: ./src-tauri/Cargo.toml
- id: version
run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"
- name: stage web dist for the release zip
run: cp .github/release/web-README.md dist/README.md
- uses: actions/upload-artifact@v7
with:
name: web-dist
path: dist
# Single creation point: tauri-action's own tag lookup races across matrix
# legs and can split assets over duplicate drafts (tauri-action#914).
create-release:
needs: gates
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
release_id: ${{ steps.create.outputs.release_id }}
steps:
- id: create
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="v${{ needs.gates.outputs.version }}"
# Keep head off the gh pipe: piping into head masks a failed lookup
# (rate limit / 5xx) as "no draft" and would POST a duplicate.
DRAFTS=$(gh api "repos/$GITHUB_REPOSITORY/releases" --paginate \
--jq ".[] | select(.tag_name==\"$TAG\" and .draft) | .id")
ID=$(printf '%s\n' "$DRAFTS" | head -n1)
if [ -z "$ID" ]; then
# prerelease default: 0.x must not become "latest" by a publish
# click alone (the updater endpoint serves releases/latest).
ID=$(gh api -X POST "repos/$GITHUB_REPOSITORY/releases" \
-f tag_name="$TAG" \
-f name="ZPLab $TAG" \
-f body="See the assets to download this version and install." \
-F draft=true -F prerelease=true --jq .id)
fi
echo "release_id=$ID" >> "$GITHUB_OUTPUT"
publish-tauri:
needs: create-release
permissions:
contents: write
strategy:
fail-fast: false
matrix:
include:
- platform: macos-latest # Arm (M1+)
args: '--target aarch64-apple-darwin'
- platform: macos-latest # Intel, cross-compiled on the arm64 runner
args: '--target x86_64-apple-darwin'
# Oldest LTS with webkit2gtk-4.1, standard support until April 2027. glibc is forward compatible
# only, so a newer runner drops Debian 12 and Ubuntu 22.04. Moving the runner is a release decision.
- platform: ubuntu-22.04
args: ''
- platform: windows-latest
args: ''
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v7
- name: install dependencies (ubuntu only)
if: startsWith(matrix.platform, 'ubuntu')
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf xdg-utils libcups2-dev libdbus-1-dev
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 24
cache: pnpm
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
- uses: swatinem/rust-cache@v2
with:
workspaces: './src-tauri -> target'
- run: pnpm install --frozen-lockfile
# The SEA sidecar clones a node binary; the arm64 runner cross-builds
# x86_64, so that leg needs a target-arch node of the exact same version
# (the build script rejects a skew).
- name: fetch x86_64 node for the SEA sidecar
if: matrix.args == '--target x86_64-apple-darwin'
run: |
V=$(node --version)
curl -fsSL "https://nodejs.org/dist/${V}/node-${V}-darwin-x64.tar.gz" | tar xz -C "$RUNNER_TEMP"
echo "ZPLAB_SEA_NODE=$RUNNER_TEMP/node-${V}-darwin-x64/bin/node" >> "$GITHUB_ENV"
- uses: tauri-apps/tauri-action@v1
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:
releaseId: ${{ needs.create-release.outputs.release_id }}
updaterJsonPreferNsis: true
args: ${{ matrix.args }}
- name: glibc floor
if: startsWith(matrix.platform, 'ubuntu')
run: |
# deb and rpm link the system glibc, so the floor is what RHEL 9 ships.
# The AppImage bundles the runner's libraries, so the guard does not lower its 2.35.
FLOOR=GLIBC_2.34
BIN="src-tauri/target/release/$(jq -r .mainBinaryName src-tauri/tauri.conf.json)"
MAX=$(objdump -T "$BIN" | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -1)
echo "$BIN requires ${MAX:?no glibc symbols found}, floor $FLOOR"
[ "$(printf '%s\n%s\n' "$MAX" "$FLOOR" | sort -V | tail -1)" = "$FLOOR" ] || { echo "$MAX is newer than the floor $FLOOR"; exit 1; }
msix:
needs: gates
uses: ./.github/workflows/msix.yml
upload-web-dist:
needs: [gates, create-release]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v8
with:
name: web-dist
path: dist
- name: zip browser build
run: |
cd dist
zip -r "../ZPLab_${{ needs.gates.outputs.version }}_web.zip" .
- name: upload to draft release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
# gh resolves the tag to the draft release even though the git ref
# does not exist until the release is published
run: gh release upload "v${{ needs.gates.outputs.version }}" "ZPLab_${{ needs.gates.outputs.version }}_web.zip" --clobber