name: release-macos on: workflow_dispatch: inputs: tag: description: "Optional release tag to build (e.g. v1.2.1)" required: false type: string push: tags: - "v*" jobs: build-macos: strategy: matrix: include: - target: aarch64-apple-darwin artifact: qbz-macos-aarch64 arch: aarch64 - target: x86_64-apple-darwin artifact: qbz-macos-x86_64 arch: x86_64 runs-on: macos-latest permissions: contents: write steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v4 with: node-version: 24 cache: npm - name: Resolve release version id: release run: | VERSION="" if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then VERSION="${GITHUB_REF#refs/tags/v}" elif [[ -n "${{ inputs.tag }}" ]]; then VERSION="${{ inputs.tag }}" VERSION="${VERSION#v}" fi echo "version=$VERSION" >> "$GITHUB_OUTPUT" - name: Sync version to build metadata if: steps.release.outputs.version != '' env: QBZ_VERSION: ${{ steps.release.outputs.version }} run: | python3 - <<'PY' import json import os import pathlib import re version = os.environ["QBZ_VERSION"] def update_json(path, updater): p = pathlib.Path(path) data = json.loads(p.read_text(encoding="utf-8")) updater(data) p.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8") update_json("package.json", lambda d: d.__setitem__("version", version)) def update_lock(d): d["version"] = version packages = d.get("packages") if isinstance(packages, dict) and "" in packages: packages[""]["version"] = version update_json("package-lock.json", update_lock) update_json("src-tauri/tauri.conf.json", lambda d: d.__setitem__("version", version)) cargo_path = pathlib.Path("src-tauri/Cargo.toml") cargo_text = cargo_path.read_text(encoding="utf-8") cargo_text = re.sub(r'(?m)^version = \"[^\"]+\"', f'version = \"{version}\"', cargo_text, count=1) cargo_path.write_text(cargo_text, encoding="utf-8") PY - name: Setup Rust uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} - name: Rust cache uses: Swatinem/rust-cache@v2 with: workspaces: src-tauri -> target shared-key: macos-${{ matrix.target }} - name: Install JS dependencies run: npm ci - name: Build macOS bundles env: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} run: npm run tauri build -- --target ${{ matrix.target }} - name: Collect artifacts env: BUNDLE_DIR: src-tauri/target/${{ matrix.target }}/release/bundle ARCH: ${{ matrix.arch }} run: | set -euo pipefail mkdir -p dist # DMG for manual distribution (filename already includes arch). cp -v "$BUNDLE_DIR"/dmg/*.dmg dist/ # .app.tar.gz + .sig for auto-updater. Rename with arch suffix so the # two matrix jobs don't overwrite each other on the GitHub Release, # and so release-updater-manifest.yml's regex picks them up # ("aarch64.app.tar.gz$" / "(x64|x86_64).app.tar.gz$"). cp -v "$BUNDLE_DIR/macos/QBZ.app.tar.gz" "dist/QBZ_${ARCH}.app.tar.gz" cp -v "$BUNDLE_DIR/macos/QBZ.app.tar.gz.sig" "dist/QBZ_${ARCH}.app.tar.gz.sig" ls -la dist - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: ${{ matrix.artifact }} path: dist/* - name: Publish GitHub Release Assets if: startsWith(github.ref, 'refs/tags/') uses: softprops/action-gh-release@v2 with: files: dist/* prerelease: true