Bumps [actions/cache](https://github.com/actions/cache) from 4 to 6. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/actions/cache/releases">actions/cache's releases</a>.</em></p> <blockquote> <h2>v6.0.0</h2> <h2>What's Changed</h2> <ul> <li>Update packages, migrate to ESM by <a href="https://github.com/Samirat"><code>@Samirat</code></a> in <a href="https://redirect.github.com/actions/cache/pull/1760">actions/cache#1760</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/actions/cache/compare/v5...v6.0.0">https://github.com/actions/cache/compare/v5...v6.0.0</a></p> <h2>v5.1.0</h2> <h2>What's Changed</h2> <ul> <li>Bump <code>@actions/cache</code> to v5.1.0 - handle read-only cache access by <a href="https://github.com/jasongin"><code>@jasongin</code></a> in <a href="https://redirect.github.com/actions/cache/pull/1775">actions/cache#1775</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/actions/cache/compare/v5...v5.1.0">https://github.com/actions/cache/compare/v5...v5.1.0</a></p> <h2>v5.0.5</h2> <h2>What's Changed</h2> <ul> <li>Update ts-http-runtime dependency by <a href="https://github.com/yacaovsnc"><code>@yacaovsnc</code></a> in <a href="https://redirect.github.com/actions/cache/pull/1747">actions/cache#1747</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/actions/cache/compare/v5...v5.0.5">https://github.com/actions/cache/compare/v5...v5.0.5</a></p> <h2>v5.0.4</h2> <h2>What's Changed</h2> <ul> <li>Add release instructions and update maintainer docs by <a href="https://github.com/Link"><code>@Link</code></a>- in <a href="https://redirect.github.com/actions/cache/pull/1696">actions/cache#1696</a></li> <li>Potential fix for code scanning alert no. 52: Workflow does not contain permissions by <a href="https://github.com/Link"><code>@Link</code></a>- in <a href="https://redirect.github.com/actions/cache/pull/1697">actions/cache#1697</a></li> <li>Fix workflow permissions and cleanup workflow names / formatting by <a href="https://github.com/Link"><code>@Link</code></a>- in <a href="https://redirect.github.com/actions/cache/pull/1699">actions/cache#1699</a></li> <li>docs: Update examples to use the latest version by <a href="https://github.com/XZTDean"><code>@XZTDean</code></a> in <a href="https://redirect.github.com/actions/cache/pull/1690">actions/cache#1690</a></li> <li>Fix proxy integration tests by <a href="https://github.com/Link"><code>@Link</code></a>- in <a href="https://redirect.github.com/actions/cache/pull/1701">actions/cache#1701</a></li> <li>Fix cache key in examples.md for bun.lock by <a href="https://github.com/RyPeck"><code>@RyPeck</code></a> in <a href="https://redirect.github.com/actions/cache/pull/1722">actions/cache#1722</a></li> <li>Update dependencies & patch security vulnerabilities by <a href="https://github.com/Link"><code>@Link</code></a>- in <a href="https://redirect.github.com/actions/cache/pull/1738">actions/cache#1738</a></li> </ul> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/XZTDean"><code>@XZTDean</code></a> made their first contribution in <a href="https://redirect.github.com/actions/cache/pull/1690">actions/cache#1690</a></li> <li><a href="https://github.com/RyPeck"><code>@RyPeck</code></a> made their first contribution in <a href="https://redirect.github.com/actions/cache/pull/1722">actions/cache#1722</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/actions/cache/compare/v5...v5.0.4">https://github.com/actions/cache/compare/v5...v5.0.4</a></p> <h2>v5.0.3</h2> <h2>What's Changed</h2> <ul> <li>Bump <code>@actions/cache</code> to v5.0.5 (Resolves: <a href="https://github.com/actions/cache/security/dependabot/33">https://github.com/actions/cache/security/dependabot/33</a>)</li> <li>Bump <code>@actions/core</code> to v2.0.3</li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/actions/cache/compare/v5...v5.0.3">https://github.com/actions/cache/compare/v5...v5.0.3</a></p> <h2>v.5.0.2</h2> <h1>v5.0.2</h1> <h2>What's Changed</h2> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/actions/cache/blob/main/RELEASES.md">actions/cache's changelog</a>.</em></p> <blockquote> <h1>Releases</h1> <h2>How to prepare a release</h2> <blockquote> <p>[!NOTE] Relevant for maintainers with write access only.</p> </blockquote> <ol> <li>Switch to a new branch from <code>main</code>.</li> <li>Run <code>npm test</code> to ensure all tests are passing.</li> <li>Update the version in <a href="https://github.com/actions/cache/blob/main/package.json"><code>https://github.com/actions/cache/blob/main/package.json</code></a>.</li> <li>Run <code>npm run build</code> to update the compiled files.</li> <li>Update this <a href="https://github.com/actions/cache/blob/main/RELEASES.md"><code>https://github.com/actions/cache/blob/main/RELEASES.md</code></a> with the new version and changes in the <code>## Changelog</code> section.</li> <li>Run <code>licensed cache</code> to update the license report.</li> <li>Run <code>licensed status</code> and resolve any warnings by updating the <a href="https://github.com/actions/cache/blob/main/.licensed.yml"><code>https://github.com/actions/cache/blob/main/.licensed.yml</code></a> file with the exceptions.</li> <li>Commit your changes and push your branch upstream.</li> <li>Open a pull request against <code>main</code> and get it reviewed and merged.</li> <li>Draft a new release <a href="https://github.com/actions/cache/releases">https://github.com/actions/cache/releases</a> use the same version number used in <code>package.json</code> <ol> <li>Create a new tag with the version number.</li> <li>Auto generate release notes and update them to match the changes you made in <code>RELEASES.md</code>.</li> <li>Toggle the set as the latest release option.</li> <li>Publish the release.</li> </ol> </li> <li>Navigate to <a href="https://github.com/actions/cache/actions/workflows/release-new-action-version.yml">https://github.com/actions/cache/actions/workflows/release-new-action-version.yml</a> <ol> <li>There should be a workflow run queued with the same version number.</li> <li>Approve the run to publish the new version and update the major tags for this action.</li> </ol> </li> </ol> <h2>Changelog</h2> <h3>6.1.0</h3> <ul> <li>Bump <code>@actions/cache</code> to v6.1.0 to pick up <a href="https://redirect.github.com/actions/toolkit/pull/2435">actions/toolkit#2435 Handle cache write error due to read-only token</a></li> <li>Switch redundant "Cache save failed" warning to debug log in save-only</li> </ul> <h3>6.0.0</h3> <ul> <li>Updated <code>@actions/cache</code> to ^6.0.1, <code>@actions/core</code> to ^3.0.1, <code>@actions/exec</code> to ^3.0.0, <code>@actions/io</code> to ^3.0.2</li> <li>Migrated to ESM module system</li> <li>Upgraded Jest to v30 and test infrastructure to be ESM compatible</li> </ul> <h3>5.0.4</h3> <ul> <li>Bump <code>minimatch</code> to v3.1.5 (fixes ReDoS via globstar patterns)</li> <li>Bump <code>undici</code> to v6.24.1 (WebSocket decompression bomb protection, header validation fixes)</li> <li>Bump <code>fast-xml-parser</code> to v5.5.6</li> </ul> <h3>5.0.3</h3> <ul> <li>Bump <code>@actions/cache</code> to v5.0.5 (Resolves: <a href="https://github.com/actions/cache/security/dependabot/33">https://github.com/actions/cache/security/dependabot/33</a>)</li> <li>Bump <code>@actions/core</code> to v2.0.3</li> </ul> <h3>5.0.2</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="55cc834586"><code>55cc834</code></a> Merge pull request <a href="https://redirect.github.com/actions/cache/issues/1768">#1768</a> from jasongin/readonly-cache</li> <li><a href="d8cd72f230"><code>d8cd72f</code></a> Bump <code>@actions/cache</code> to v6.1.0 - handle cache write error due to RO token</li> <li><a href="2c8a9bd745"><code>2c8a9bd</code></a> Merge pull request <a href="https://redirect.github.com/actions/cache/issues/1760">#1760</a> from actions/samirat/esm_migration_and_package_update</li> <li><a href="e9b91fdc3f"><code>e9b91fd</code></a> Prettier fixes</li> <li><a href="e4884b8ff7"><code>e4884b8</code></a> Rebuild dist</li> <li><a href="10baf0191a"><code>10baf01</code></a> Fixed licenses</li> <li><a href="e39b386c90"><code>e39b386</code></a> Fix test mock return order</li> <li><a href="b692820337"><code>b692820</code></a> PR feedback</li> <li><a href="60749128a4"><code>6074912</code></a> Rebuild dist bundles as ESM to match type:module</li> <li><a href="5a912e8b4a"><code>5a912e8</code></a> Fix lint and jest issues</li> <li>Additional commits viewable in <a href="https://github.com/actions/cache/compare/v4...v6">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
539 lines
22 KiB
YAML
539 lines
22 KiB
YAML
# Test Release workflow
|
|
#
|
|
# Manual workflow for testing binary builds without creating a real release.
|
|
# Triggered via workflow_dispatch from the GitHub Actions UI.
|
|
|
|
name: Test Release
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
# ── Build and test platform-specific binaries ─────────────────────────
|
|
build-binaries:
|
|
name: Build & Test ${{ matrix.target }}
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- os: ubuntu-latest
|
|
target: bun-linux-x64
|
|
binary: fn-cli-linux-x64
|
|
- os: ubuntu-24.04-arm
|
|
target: bun-linux-arm64
|
|
binary: fn-cli-linux-arm64
|
|
- os: macos-latest
|
|
target: bun-darwin-arm64
|
|
binary: fn-cli-darwin-arm64
|
|
# bun-darwin-x64 (Intel) dropped: macos-13 runner scarcity — CLI is
|
|
# Apple-Silicon-only for macOS. Keep in sync with release.yml.
|
|
- os: windows-latest
|
|
target: bun-windows-x64
|
|
binary: fn-cli-windows-x64.exe
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node and install dependencies
|
|
uses: ./.github/actions/setup-node-pnpm
|
|
|
|
- name: Install Bun
|
|
uses: oven-sh/setup-bun@v2
|
|
|
|
- name: Build
|
|
run: pnpm build
|
|
|
|
- name: Build binary
|
|
run: pnpm --filter @runfusion/fusion build:exe -- --target ${{ matrix.target }}
|
|
|
|
- name: Verify binary exists
|
|
shell: bash
|
|
run: test -f packages/cli/dist/${{ matrix.binary }}
|
|
|
|
- name: Smoke test (Linux/macOS)
|
|
if: runner.os != 'Windows'
|
|
run: |
|
|
chmod +x packages/cli/dist/${{ matrix.binary }}
|
|
packages/cli/dist/${{ matrix.binary }} --help
|
|
|
|
- name: Smoke test (Windows)
|
|
if: runner.os == 'Windows'
|
|
shell: pwsh
|
|
run: |
|
|
& packages/cli/dist/${{ matrix.binary }} --help
|
|
|
|
- name: Sign macOS binary
|
|
if: runner.os == 'macOS' && env.APPLE_CERTIFICATE_BASE64 != ''
|
|
env:
|
|
APPLE_CERTIFICATE_BASE64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
|
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
APPLE_IDENTITY: ${{ secrets.APPLE_IDENTITY }}
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
|
|
run: bash scripts/sign-macos.sh packages/cli/dist/${{ matrix.binary }} packages/cli/dist/runtime
|
|
|
|
- name: Sign Windows binary
|
|
if: runner.os == 'Windows' && env.WINDOWS_CERTIFICATE_BASE64 != ''
|
|
env:
|
|
WINDOWS_CERTIFICATE_BASE64: ${{ secrets.WINDOWS_CERTIFICATE_BASE64 }}
|
|
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
|
run: pwsh scripts/sign-windows.ps1 packages/cli/dist/${{ matrix.binary }}
|
|
|
|
- name: Generate checksum (Linux)
|
|
if: runner.os == 'Linux'
|
|
run: |
|
|
cd packages/cli/dist
|
|
sha256sum ${{ matrix.binary }} > ${{ matrix.binary }}.sha256
|
|
|
|
- name: Generate checksum (macOS)
|
|
if: runner.os == 'macOS'
|
|
run: |
|
|
cd packages/cli/dist
|
|
shasum -a 256 ${{ matrix.binary }} > ${{ matrix.binary }}.sha256
|
|
|
|
- name: Generate checksum (Windows)
|
|
if: runner.os == 'Windows'
|
|
shell: pwsh
|
|
run: |
|
|
cd packages/cli/dist
|
|
$hash = (Get-FileHash ${{ matrix.binary }} -Algorithm SHA256).Hash.ToLower()
|
|
"$hash ${{ matrix.binary }}" | Out-File -Encoding ascii ${{ matrix.binary }}.sha256
|
|
|
|
- name: Upload artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: ${{ matrix.binary }}
|
|
path: |
|
|
packages/cli/dist/${{ matrix.binary }}
|
|
packages/cli/dist/${{ matrix.binary }}.sha256
|
|
packages/cli/dist/runtime/**/*
|
|
|
|
# ── Build Windows desktop EXE artifacts ──────────────────────────────
|
|
# Code-signing with WINDOWS_CERTIFICATE_BASE64 / WINDOWS_CERTIFICATE_PASSWORD
|
|
# is intentionally deferred to FN-5592. Desktop Windows remains x64 because
|
|
# embedded-postgres does not publish a native Windows ARM64 payload.
|
|
build-desktop-windows:
|
|
name: Build Desktop Windows EXE
|
|
runs-on: windows-latest
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node and install dependencies
|
|
uses: ./.github/actions/setup-node-pnpm
|
|
|
|
# FNXC:DesktopEmbeddedPostgres 2026-07-14-09:39:
|
|
# Test releases use the same native database proof as production releases.
|
|
- name: Smoke embedded Postgres on Windows
|
|
run: pnpm --filter @fusion/core test:embedded-postgres
|
|
|
|
- name: Build
|
|
run: pnpm build
|
|
|
|
- name: Build desktop package
|
|
run: pnpm --filter @fusion/desktop build
|
|
|
|
- name: Package Windows desktop EXE
|
|
run: pnpm --filter @fusion/desktop dist:win -- --publish never
|
|
env:
|
|
CSC_IDENTITY_AUTO_DISCOVERY: "false"
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Verify desktop EXE artifacts
|
|
shell: pwsh
|
|
run: |
|
|
$exes = Get-ChildItem packages/desktop/dist-electron -Filter "Fusion-*-win-*.exe"
|
|
if ($exes.Count -eq 0) {
|
|
Write-Error "No Fusion Windows EXE artifacts produced"
|
|
exit 1
|
|
}
|
|
|
|
- name: Generate desktop EXE checksums
|
|
shell: pwsh
|
|
run: |
|
|
$exes = Get-ChildItem packages/desktop/dist-electron -Filter "Fusion-*-win-*.exe"
|
|
foreach ($exe in $exes) {
|
|
$hash = (Get-FileHash $exe.FullName -Algorithm SHA256).Hash.ToLower()
|
|
"$hash $($exe.Name)" | Out-File -Encoding ascii "$($exe.FullName).sha256"
|
|
}
|
|
|
|
- name: Upload desktop Windows artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: fusion-desktop-windows
|
|
path: |
|
|
packages/desktop/dist-electron/Fusion-*-win-*.exe
|
|
packages/desktop/dist-electron/Fusion-*-win-*.exe.sha256
|
|
packages/desktop/dist-electron/Fusion-*-win-*.exe.blockmap
|
|
packages/desktop/dist-electron/latest.yml
|
|
|
|
# ── Build macOS desktop artifacts ────────────────────────────────────
|
|
build-desktop-macos:
|
|
name: Build Desktop macOS DMG/ZIP
|
|
runs-on: macos-latest
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node and install dependencies
|
|
uses: ./.github/actions/setup-node-pnpm
|
|
|
|
- name: Smoke embedded Postgres on macOS
|
|
run: pnpm --filter @fusion/core test:embedded-postgres
|
|
|
|
- name: Build
|
|
run: pnpm build
|
|
|
|
- name: Build desktop package
|
|
run: pnpm --filter @fusion/desktop build
|
|
|
|
- name: Package signed macOS desktop DMG/ZIP
|
|
if: ${{ env.APPLE_CERTIFICATE_BASE64 != '' }}
|
|
run: pnpm --filter @fusion/desktop dist:mac -- --publish never
|
|
env:
|
|
APPLE_CERTIFICATE_BASE64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
|
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
CSC_IDENTITY_AUTO_DISCOVERY: "true"
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Package unsigned macOS desktop DMG/ZIP
|
|
if: ${{ env.APPLE_CERTIFICATE_BASE64 == '' }}
|
|
run: pnpm --filter @fusion/desktop dist:mac -- --publish never -c.mac.notarize=false
|
|
env:
|
|
APPLE_CERTIFICATE_BASE64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
|
CSC_IDENTITY_AUTO_DISCOVERY: "false"
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Verify signed and notarized macOS artifacts
|
|
if: ${{ env.APPLE_CERTIFICATE_BASE64 != '' }}
|
|
env:
|
|
APPLE_CERTIFICATE_BASE64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
shopt -s nullglob
|
|
dmgs=(packages/desktop/dist-electron/Fusion-*-mac-*.dmg)
|
|
zips=(packages/desktop/dist-electron/Fusion-*-mac-*.zip)
|
|
if [ ${#dmgs[@]} -eq 0 ]; then
|
|
echo "No Fusion macOS DMG artifacts produced" >&2
|
|
exit 1
|
|
fi
|
|
if [ ${#zips[@]} -eq 0 ]; then
|
|
echo "No Fusion macOS ZIP artifacts produced" >&2
|
|
exit 1
|
|
fi
|
|
for dmg in "${dmgs[@]}"; do
|
|
echo "Verifying signed DMG: $dmg"
|
|
codesign --verify --deep --strict --verbose=2 "$dmg"
|
|
spctl --assess --type open --context context:primary-signature -v "$dmg"
|
|
xcrun stapler validate "$dmg"
|
|
done
|
|
for zip in "${zips[@]}"; do
|
|
echo "Verifying ZIP app bundle: $zip"
|
|
tmpdir="$(mktemp -d)"
|
|
unzip -q "$zip" -d "$tmpdir"
|
|
app="$(find "$tmpdir" -type d -name '*.app' -print -quit)"
|
|
if [ -z "$app" ]; then
|
|
echo "No .app bundle found in $zip" >&2
|
|
rm -rf "$tmpdir"
|
|
exit 1
|
|
fi
|
|
codesign --verify --deep --strict --verbose=2 "$app"
|
|
spctl --assess --type exec -v "$app"
|
|
xcrun stapler validate "$app"
|
|
rm -rf "$tmpdir"
|
|
done
|
|
|
|
- name: Generate desktop macOS checksums
|
|
shell: bash
|
|
run: |
|
|
shopt -s nullglob
|
|
for file in packages/desktop/dist-electron/Fusion-*-mac-*.dmg packages/desktop/dist-electron/Fusion-*-mac-*.zip; do
|
|
shasum -a 256 "$file" > "$file.sha256"
|
|
done
|
|
|
|
- name: Upload desktop macOS artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: fusion-desktop-macos
|
|
path: |
|
|
packages/desktop/dist-electron/Fusion-*-mac-*.dmg
|
|
packages/desktop/dist-electron/Fusion-*-mac-*.dmg.sha256
|
|
packages/desktop/dist-electron/Fusion-*-mac-*.zip
|
|
packages/desktop/dist-electron/Fusion-*-mac-*.zip.sha256
|
|
packages/desktop/dist-electron/Fusion-*-mac-*.blockmap
|
|
packages/desktop/dist-electron/latest-mac.yml
|
|
|
|
# ── Build Linux desktop artifacts ────────────────────────────────────
|
|
build-desktop-linux:
|
|
name: Build Desktop Linux Artifacts
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node and install dependencies
|
|
uses: ./.github/actions/setup-node-pnpm
|
|
|
|
- name: Smoke embedded Postgres on Linux
|
|
run: pnpm --filter @fusion/core test:embedded-postgres
|
|
|
|
- name: Build
|
|
run: pnpm build
|
|
|
|
- name: Build desktop package
|
|
run: pnpm --filter @fusion/desktop build
|
|
|
|
- name: Package Linux desktop artifacts
|
|
# Linux desktop code-signing is deferred to FN-5605; Linux ARM64 CLI binaries are tracked in FN-5606.
|
|
run: pnpm --filter @fusion/desktop dist:linux -- --x64 --arm64 --publish never
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Verify desktop Linux AppImage artifacts
|
|
shell: bash
|
|
run: |
|
|
shopt -s nullglob
|
|
arm64_appimages=(packages/desktop/dist-electron/Fusion-*-linux-arm64.AppImage)
|
|
x64_appimages=(packages/desktop/dist-electron/Fusion-*-linux-x86_64.AppImage)
|
|
if [ ${#arm64_appimages[@]} -eq 0 ]; then
|
|
echo "No Fusion Linux arm64 AppImage artifacts produced" >&2
|
|
exit 1
|
|
fi
|
|
if [ ${#x64_appimages[@]} -eq 0 ]; then
|
|
echo "No Fusion Linux x64 AppImage artifacts produced" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# FNXC:DesktopEmbeddedPostgres 2026-07-15-00:20:
|
|
# AppImage filename presence is not enough — v0.60.0 shipped without
|
|
# embedded-postgres / main-bootstrap / omp-runtime. Inspect the linux-*-unpacked
|
|
# trees electron-builder leaves beside the AppImage.
|
|
- name: Verify Linux AppImage embedded Postgres packaging
|
|
run: node scripts/verify-desktop-linux-pg-packaging.mjs
|
|
|
|
- name: Sign Linux desktop artifacts
|
|
if: ${{ env.LINUX_GPG_PRIVATE_KEY != '' }}
|
|
env:
|
|
LINUX_GPG_PRIVATE_KEY: ${{ secrets.LINUX_GPG_PRIVATE_KEY }}
|
|
LINUX_GPG_PASSPHRASE: ${{ secrets.LINUX_GPG_PASSPHRASE }}
|
|
LINUX_GPG_KEY_ID: ${{ secrets.LINUX_GPG_KEY_ID }}
|
|
shell: bash
|
|
run: |
|
|
shopt -s nullglob
|
|
artifacts=(
|
|
packages/desktop/dist-electron/Fusion-*-linux-*.AppImage
|
|
packages/desktop/dist-electron/Fusion-*-linux-*.deb
|
|
packages/desktop/dist-electron/Fusion-*-linux-*.tar.gz
|
|
)
|
|
bash scripts/sign-linux.sh "${artifacts[@]}"
|
|
|
|
- name: Generate desktop Linux checksums
|
|
shell: bash
|
|
run: |
|
|
shopt -s nullglob
|
|
for file in packages/desktop/dist-electron/Fusion-*-linux-*.AppImage packages/desktop/dist-electron/Fusion-*-linux-*.deb packages/desktop/dist-electron/Fusion-*-linux-*.tar.gz; do
|
|
sha256sum "$file" > "$file.sha256"
|
|
done
|
|
|
|
- name: Upload desktop Linux artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
# Single glob set covers both linux-x64 and linux-arm64 artifact filenames.
|
|
name: fusion-desktop-linux
|
|
if-no-files-found: ignore
|
|
path: |
|
|
packages/desktop/dist-electron/Fusion-*-linux-*.AppImage
|
|
packages/desktop/dist-electron/Fusion-*-linux-*.AppImage.sha256
|
|
packages/desktop/dist-electron/Fusion-*-linux-*.AppImage.asc
|
|
packages/desktop/dist-electron/Fusion-*-linux-*.deb
|
|
packages/desktop/dist-electron/Fusion-*-linux-*.deb.sha256
|
|
packages/desktop/dist-electron/Fusion-*-linux-*.deb.asc
|
|
packages/desktop/dist-electron/Fusion-*-linux-*.tar.gz
|
|
packages/desktop/dist-electron/Fusion-*-linux-*.tar.gz.sha256
|
|
packages/desktop/dist-electron/Fusion-*-linux-*.tar.gz.asc
|
|
packages/desktop/dist-electron/latest-linux.yml
|
|
|
|
|
|
# ── Build Android APK/AAB artifacts ──────────────────────────────────
|
|
# FNXC:Release 2026-06-25-12:00:
|
|
# Keep the tag-less rehearsal workflow in parity with release.yml so APK
|
|
# generation, checksum output, and artifact collection are validated before a
|
|
# version tag tries to publish the Android asset publicly.
|
|
# FNXC:Release 2026-06-25-18:10:
|
|
# Android signing is optional and secret-gated on ANDROID_KEYSTORE_BASE64,
|
|
# ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_ALIAS, and ANDROID_KEY_PASSWORD.
|
|
# The Capacitor Android project is gitignored/regenerated, so CI injects
|
|
# signing with android.injected.signing.* Gradle properties instead of
|
|
# committing native build.gradle edits. When the keystore is absent, keep the
|
|
# FN-7014 unsigned debug APK fallback; Play Store upload remains out of scope
|
|
# and is tracked separately from sideload release artifacts.
|
|
build-android:
|
|
name: Build Android APK/AAB
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
# Job-level env mirrors the desktop signing pattern: step `if:` conditions
|
|
# can inspect env values, but cannot read secrets.* directly.
|
|
env:
|
|
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node and install dependencies
|
|
uses: ./.github/actions/setup-node-pnpm
|
|
|
|
# FNXC:MobileAndroidBuild 2026-06-28-00:00:
|
|
# Capacitor 7 @capacitor/android compiles its Android library with JavaVersion.VERSION_21; rehearsal APK/AAB Gradle builds must provision JDK 21 because JDK 17 fails with `invalid source release: 21`.
|
|
- name: Setup Java 21
|
|
uses: actions/setup-java@v4
|
|
with:
|
|
distribution: temurin
|
|
java-version: "21"
|
|
|
|
- name: Cache Android Gradle caches
|
|
uses: actions/cache@v6
|
|
with:
|
|
path: |
|
|
~/.gradle/caches
|
|
~/.gradle/wrapper
|
|
key: ${{ runner.os }}-gradle-${{ hashFiles('pnpm-lock.yaml', 'packages/mobile/capacitor.config.ts') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-gradle-
|
|
|
|
- name: Build dashboard client
|
|
run: pnpm --filter @fusion/dashboard build
|
|
|
|
- name: Create and sync Capacitor Android project
|
|
run: |
|
|
# FNXC:Release 2026-06-25-12:00:
|
|
# The Capacitor Android platform directory is gitignored and absent in
|
|
# clean release checkouts, so initialize it from pinned package metadata
|
|
# before syncing web assets instead of silently skipping the APK leg.
|
|
if [ ! -d packages/mobile/android ]; then
|
|
pnpm --filter @fusion/mobile cap add android
|
|
fi
|
|
pnpm --filter @fusion/mobile cap sync android
|
|
|
|
- name: Decode Android signing keystore
|
|
if: ${{ env.ANDROID_KEYSTORE_BASE64 != '' }}
|
|
run: |
|
|
printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 --decode > "$RUNNER_TEMP/fusion-release.keystore"
|
|
|
|
- name: Build signed Android release APK and AAB
|
|
if: ${{ env.ANDROID_KEYSTORE_BASE64 != '' }}
|
|
env:
|
|
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
|
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
|
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
|
run: |
|
|
cd packages/mobile/android
|
|
chmod +x gradlew
|
|
./gradlew assembleRelease bundleRelease \
|
|
-Pandroid.injected.signing.store.file="$RUNNER_TEMP/fusion-release.keystore" \
|
|
-Pandroid.injected.signing.store.password="$ANDROID_KEYSTORE_PASSWORD" \
|
|
-Pandroid.injected.signing.key.alias="$ANDROID_KEY_ALIAS" \
|
|
-Pandroid.injected.signing.key.password="$ANDROID_KEY_PASSWORD"
|
|
|
|
- name: Normalize signed Android release assets
|
|
if: ${{ env.ANDROID_KEYSTORE_BASE64 != '' }}
|
|
run: |
|
|
APK="packages/mobile/android/app/build/outputs/apk/release/app-release.apk"
|
|
AAB="packages/mobile/android/app/build/outputs/bundle/release/app-release.aab"
|
|
if [ ! -f "$APK" ]; then
|
|
echo "::error::Expected signed Android APK missing at $APK" >&2
|
|
exit 1
|
|
fi
|
|
if [ ! -f "$AAB" ]; then
|
|
echo "::error::Expected signed Android AAB missing at $AAB" >&2
|
|
exit 1
|
|
fi
|
|
mkdir -p packages/mobile/dist
|
|
cp "$APK" packages/mobile/dist/fusion-android-release.apk
|
|
cp "$AAB" packages/mobile/dist/fusion-android-release.aab
|
|
|
|
- name: Verify signed Android APK signature
|
|
if: ${{ env.ANDROID_KEYSTORE_BASE64 != '' }}
|
|
run: |
|
|
APK="packages/mobile/dist/fusion-android-release.apk"
|
|
APKSIGNER=""
|
|
if [ -n "${ANDROID_SDK_ROOT:-}" ] && [ -d "$ANDROID_SDK_ROOT/build-tools" ]; then
|
|
APKSIGNER=$(find "$ANDROID_SDK_ROOT/build-tools" -maxdepth 2 -type f -name apksigner | sort -V | tail -n 1 || true)
|
|
fi
|
|
if [ -n "$APKSIGNER" ]; then
|
|
"$APKSIGNER" verify --verbose "$APK"
|
|
else
|
|
jarsigner -verify -strict "$APK"
|
|
fi
|
|
|
|
- name: Build unsigned Android debug APK
|
|
if: ${{ env.ANDROID_KEYSTORE_BASE64 == '' }}
|
|
run: |
|
|
cd packages/mobile/android
|
|
chmod +x gradlew
|
|
./gradlew assembleDebug
|
|
|
|
- name: Normalize unsigned Android APK asset
|
|
if: ${{ env.ANDROID_KEYSTORE_BASE64 == '' }}
|
|
run: |
|
|
APK="packages/mobile/android/app/build/outputs/apk/debug/app-debug.apk"
|
|
if [ ! -f "$APK" ]; then
|
|
echo "::error::Expected Android APK missing at $APK" >&2
|
|
exit 1
|
|
fi
|
|
mkdir -p packages/mobile/dist
|
|
cp "$APK" packages/mobile/dist/fusion-android.apk
|
|
|
|
- name: Generate Android artifact checksums
|
|
run: |
|
|
cd packages/mobile/dist
|
|
for file in fusion-android*.apk fusion-android-release.aab; do
|
|
[ -f "$file" ] || continue
|
|
sha256sum "$file" > "$file.sha256"
|
|
done
|
|
|
|
- name: Upload Android artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: fusion-android-apk
|
|
path: |
|
|
packages/mobile/dist/fusion-android*.apk
|
|
packages/mobile/dist/fusion-android*.apk.sha256
|
|
packages/mobile/dist/fusion-android-release.aab
|
|
packages/mobile/dist/fusion-android-release.aab.sha256
|
|
|
|
# ── Collect all artifacts ─────────────────────────────────────────────
|
|
collect:
|
|
name: Collect Artifacts
|
|
needs: [build-binaries, build-desktop-windows, build-desktop-macos, build-desktop-linux, build-android]
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: artifacts
|
|
|
|
- name: Combine artifacts
|
|
run: |
|
|
mkdir combined
|
|
find artifacts -type f \( -name "fn-*" -o -name "*.sha256" -o -name "*.asc" -o -name "*.exe" -o -name "*.exe.sha256" -o -name "*.blockmap" -o -name "*.dmg" -o -name "*.dmg.sha256" -o -name "*.zip" -o -name "*.zip.sha256" -o -name "*.apk" -o -name "*.aab" -o -name "*.AppImage" -o -name "*.AppImage.sha256" -o -name "*.deb" -o -name "*.deb.sha256" -o -name "*.tar.gz" -o -name "*.tar.gz.sha256" -o -name "latest*.yml" \) -exec cp {} combined/ \;
|
|
ls -la combined/
|
|
|
|
- name: Upload combined archive
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: all-binaries
|
|
path: combined/*
|