Skip to content

Release v0.3.5

Release v0.3.5 #11

Workflow file for this run

name: Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag_name:
description: 'Release tag to publish, for example v0.3.0'
required: true
type: string
permissions:
contents: write
jobs:
verify:
name: Verify release gates
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
- name: Install dependencies
run: npm ci
- name: Audit release configuration
run: npm run release:audit
- name: Build
run: npm run build
- name: Runtime tests
run: npm run test:runtime
- name: UI smoke
run: npm run ui:smoke
- name: UI maturity gate
run: npm run ui:maturity-gate
- name: Agent benchmark
run: npm run agent:benchmark
mac:
name: Build macOS release
needs: verify
runs-on: macos-latest
timeout-minutes: 90
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
CSC_NAME: Developer ID Application
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
- name: Install dependencies
run: npm ci
- name: Import macOS signing certificate
env:
MAC_CSC_LINK: ${{ secrets.MAC_CSC_LINK }}
MAC_CSC_KEY_PASSWORD: ${{ secrets.MAC_CSC_KEY_PASSWORD }}
run: |
set -euo pipefail
if [ -z "${MAC_CSC_LINK}" ]; then
echo "MAC_CSC_LINK must contain a base64-encoded Developer ID Application .p12 certificate."
exit 1
fi
certificate_path="$RUNNER_TEMP/funplay-mac-codesign.p12"
keychain_path="$RUNNER_TEMP/funplay-signing.keychain-db"
keychain_password="$(uuidgen)"
certificate_data="$MAC_CSC_LINK"
case "$certificate_data" in
data:*base64,*) certificate_data="${certificate_data#*,}" ;;
esac
if ! printf '%s' "$certificate_data" | base64 -D > "$certificate_path"; then
echo "MAC_CSC_LINK must be base64-encoded .p12 data, not a local path."
exit 1
fi
security create-keychain -p "$keychain_password" "$keychain_path"
security set-keychain-settings -lut 21600 "$keychain_path"
security unlock-keychain -p "$keychain_password" "$keychain_path"
security import "$certificate_path" -P "$MAC_CSC_KEY_PASSWORD" -f pkcs12 -A -k "$keychain_path" -T /usr/bin/codesign -T /usr/bin/productbuild -T /usr/bin/security
security list-keychains -d user -s "$keychain_path"
security default-keychain -s "$keychain_path"
identities="$(security find-identity -v -p codesigning "$keychain_path")"
echo "$identities"
if ! echo "$identities" | grep -q "Developer ID Application"; then
echo "The imported macOS certificate is not a Developer ID Application certificate."
exit 1
fi
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$keychain_password" "$keychain_path" || echo "::warning::Could not update key partition list; continuing because the signing identity was imported and the keychain is unlocked."
- name: Build split-architecture macOS artifacts
run: npm run dist:mac:split
- name: Verify packaged runtime dependencies
run: npm run release:verify-runtime-deps
- name: Verify macOS update metadata
run: npm run release:verify-mac-updates
- name: Restore Electron native ABI
if: always()
run: npm run rebuild:native:force
- name: Upload macOS artifacts
uses: actions/upload-artifact@v4
with:
name: funplay-macos
if-no-files-found: error
path: |
release/*.dmg
release/*.dmg.blockmap
release/*.zip
release/*.zip.blockmap
release/latest-mac.yml
release/latest-mac-arm64.yml
release/latest-mac-x64.yml
windows:
name: Build Windows release
needs: verify
runs-on: windows-latest
timeout-minutes: 75
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
- name: Install dependencies
run: npm ci
- name: Build Windows x64 artifacts
run: npm run dist:win:x64
- name: Verify packaged runtime dependencies
run: npm run release:verify-runtime-deps
- name: Restore Electron native ABI
if: always()
run: npm run rebuild:native:force
- name: Upload Windows artifacts
uses: actions/upload-artifact@v4
with:
name: funplay-windows
if-no-files-found: error
path: |
release/*.exe
release/*.exe.blockmap
release/latest.yml
publish:
name: Publish GitHub Release
needs:
- mac
- windows
runs-on: ubuntu-latest
timeout-minutes: 15
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag_name || github.ref_name }}
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Download release artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Prepare release notes
run: |
set -euo pipefail
node <<'NODE'
const fs = require('node:fs');
const version = process.env.RELEASE_TAG.replace(/^v/, '');
const changelog = fs.readFileSync('CHANGELOG.md', 'utf8').split(/\r?\n/);
const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const heading = new RegExp(`^##\\s+${escapeRegExp(version)}(?:\\s|$)`);
const start = changelog.findIndex((line) => heading.test(line));
if (start < 0) {
throw new Error(`CHANGELOG.md does not contain a section for ${version}.`);
}
let end = changelog.length;
for (let index = start + 1; index < changelog.length; index += 1) {
if (/^##\s+\S/.test(changelog[index])) {
end = index;
break;
}
}
const notes = changelog.slice(start + 1, end).join('\n').trim();
if (!notes) {
throw new Error(`CHANGELOG.md section for ${version} is empty.`);
}
fs.writeFileSync('release-notes.md', `${notes}\n`, 'utf8');
NODE
- name: Create or update release
run: |
set -euo pipefail
mapfile -d '' files < <(find artifacts -type f -print0 | sort -z)
if [ "${#files[@]}" -eq 0 ]; then
echo "No release artifacts found."
exit 1
fi
title="$RELEASE_TAG"
if gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
gh release upload "$RELEASE_TAG" "${files[@]}" --clobber --repo "$GITHUB_REPOSITORY"
gh release edit "$RELEASE_TAG" --draft=false --title "$title" --notes-file release-notes.md --repo "$GITHUB_REPOSITORY"
else
gh release create "$RELEASE_TAG" "${files[@]}" --title "$title" --notes-file release-notes.md --repo "$GITHUB_REPOSITORY"
fi