Files
FreeCrawl-SEO-Tool/.github/workflows/release.yml
T

160 lines
7.0 KiB
YAML

name: Release
on:
push:
tags:
- 'v*.*.*'
# Manual runs rebuild the assets of an existing release: pass its tag
# and the job uploads into that release instead of one named after the
# branch. Used when a leg failed after the tag was pushed.
workflow_dispatch:
inputs:
tag:
description: 'Existing release tag to (re)build assets for, e.g. v1.0.0'
required: true
type: string
permissions:
contents: write
jobs:
# Each platform is its own job because electron-builder needs the
# native toolchain (NSIS for .exe, hdiutil for .dmg, etc.) of the
# runner OS — cross-compiling is not supported. The matrix wires both
# jobs to the same release tag; whichever finishes first creates the
# release, the other appends its artifacts via softprops/action-gh-release
# which handles the duplicate-tag case idempotently.
build:
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
build_script: build:win
build_args: ''
artifact_name: windows-installer
artifact_paths: |
apps/desktop/release/*.exe
apps/desktop/release/*.exe.blockmap
apps/desktop/release/latest.yml
# macOS is built once per architecture rather than both arches
# in one job. The bundled Playwright browsers are arch-specific
# (`chrome-mac-arm64` vs `chrome-mac-x64`), so a single job on
# an Apple-silicon runner used to ship arm64 binaries inside the
# Intel .dmg — where Playwright looked for `chrome-mac-x64`,
# found nothing, and every Intel user landed on the "browser
# missing" dialog. Each job now downloads the browsers for the
# architecture it is packaging. The `--arm64` / `--x64` flag is
# the ONLY place the arch is chosen: electron-builder.yml must not
# list `mac.target[].arch`, or the config list silently overrides
# the flag and each leg builds both images again (that is what
# broke 1.0.0's first run).
#
# Each leg also names its .dmg with the words a user actually
# knows ("Apple-Silicon" / "Intel") instead of arm64 / x64.
# electron-builder's artifactName template cannot branch on
# arch, so the override rides on the CLI; single quotes keep
# ${version} / ${ext} away from the shell so electron-builder
# expands them. Keep in sync with pickInstallerAsset() in
# apps/desktop/src/main/index.ts.
- os: macos-latest
build_script: build:mac
build_args: "-- --arm64 -c.mac.artifactName='FreeCrawl-SEO-Tool-${version}-macOS-Apple-Silicon.${ext}'"
artifact_name: macos-installer-arm64
artifact_paths: |
apps/desktop/release/*Apple-Silicon*.dmg
apps/desktop/release/*Apple-Silicon*.dmg.blockmap
apps/desktop/release/*Apple-Silicon*.zip
apps/desktop/release/latest-mac.yml
- os: macos-latest
build_script: build:mac
build_args: "-- --x64 -c.mac.artifactName='FreeCrawl-SEO-Tool-${version}-macOS-Intel.${ext}'"
# Cross-download the Intel browsers on the arm64 runner.
# Playwright picks its download by host platform, so this
# override is what makes the x64 bundle actually x64.
playwright_host_platform: mac15
artifact_name: macos-installer-x64
# latest-mac.yml is published by the arm64 job only — both
# jobs would otherwise upload a same-named file describing
# just their own arch, and the winner would be whichever
# finished last.
artifact_paths: |
apps/desktop/release/*.dmg
apps/desktop/release/*.dmg.blockmap
apps/desktop/release/*.zip
- os: ubuntu-latest
build_script: build:linux
build_args: ''
artifact_name: linux-installer
artifact_paths: |
apps/desktop/release/*.AppImage
apps/desktop/release/*.deb
apps/desktop/release/*.rpm
apps/desktop/release/latest-linux.yml
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
env:
# Skip the postinstall browser download on cross-arch jobs so
# the cache holds only the target architecture — otherwise the
# installer would carry both (~+180 MB of dead weight).
PLAYWRIGHT_SKIP_BROWSER_INSTALL: ${{ matrix.playwright_host_platform && '1' || '0' }}
- name: Build shared packages
run: npx tsc -b
- name: Ensure Playwright browsers downloaded
# `npm ci` runs `postinstall` which already pulls Chromium +
# chrome-headless-shell, but we re-invoke explicitly to make
# the dependency obvious in the workflow logs and to force a
# re-check if Playwright was upgraded since the lockfile was
# written.
run: npm run playwright:install
env:
PLAYWRIGHT_HOST_PLATFORM_OVERRIDE: ${{ matrix.playwright_host_platform }}
- name: Build installer (with bundled Playwright browsers)
run: npm --workspace apps/desktop run ${{ matrix.build_script }} ${{ matrix.build_args }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Disable mac code-signing — we don't have an Apple Developer
# cert in CI yet. Users will see a Gatekeeper warning on first
# launch and must right-click → Open the .dmg's app once.
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
# V2 Faz 1 — Bundle the Playwright Chromium browser into the
# installer so JS rendering works offline / on first launch
# with zero extra download. The prepare-playwright-bundle.mjs
# script reads this env var and copies the OS cache into
# apps/desktop/resources/playwright-browsers/ before
# electron-builder packs the installer.
BUNDLE_PLAYWRIGHT: '1'
# Also read by prepare-playwright-bundle.mjs, which refuses to
# package a browser cache that doesn't match the architecture
# being built — the exact mismatch that shipped an arm64
# Chromium inside the Intel .dmg.
PLAYWRIGHT_HOST_PLATFORM_OVERRIDE: ${{ matrix.playwright_host_platform }}
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact_name }}
path: ${{ matrix.artifact_paths }}
if-no-files-found: warn
- name: Publish GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.tag || github.ref_name }}
files: ${{ matrix.artifact_paths }}
generate_release_notes: true
draft: false
prerelease: false