1308ec1433
AppImage files use SquashFS format (ELF + embedded squashfs), so bsdtar fails with "Unrecognized archive format". This was causing Linux beta builds to fail at the verification step. Changes: - Replace bsdtar with unsquashfs for AppImage inspection, with fallback to --appimage-extract and finally size validation - Use boundary-safe regex for app.asar detection (avoids false positive from app.asar.unpacked) - Tool execution failures now correctly trigger verification failure - Missing package targets are hard failures instead of warnings - Install squashfs-tools instead of libarchive-tools in CI workflows Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
659 lines
26 KiB
YAML
659 lines
26 KiB
YAML
name: Beta Release
|
|
|
|
# Manual trigger for beta releases from develop branch
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
version:
|
|
description: 'Beta version (e.g., 2.8.0-beta.1)'
|
|
required: true
|
|
type: string
|
|
dry_run:
|
|
description: 'Test build without creating release'
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
|
|
jobs:
|
|
validate-version:
|
|
name: Validate beta version format
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Validate version format
|
|
run: |
|
|
VERSION="${{ github.event.inputs.version }}"
|
|
|
|
# Check if version matches beta semver pattern
|
|
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+-(beta|alpha|rc)\.[0-9]+$ ]]; then
|
|
echo "::error::Invalid version format: $VERSION"
|
|
echo "Version must match pattern: X.Y.Z-beta.N (e.g., 2.8.0-beta.1)"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Valid beta version: $VERSION"
|
|
|
|
create-tag:
|
|
name: Create beta tag
|
|
needs: validate-version
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
outputs:
|
|
version: ${{ github.event.inputs.version }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: develop
|
|
|
|
- name: Create and push tag
|
|
if: ${{ github.event.inputs.dry_run != 'true' }}
|
|
run: |
|
|
VERSION="${{ github.event.inputs.version }}"
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
git tag -a "v$VERSION" -m "Beta release v$VERSION"
|
|
git push origin "v$VERSION"
|
|
echo "Created tag v$VERSION"
|
|
|
|
- name: Create tag only (dry run)
|
|
if: ${{ github.event.inputs.dry_run == 'true' }}
|
|
run: |
|
|
VERSION="${{ github.event.inputs.version }}"
|
|
echo "DRY RUN: Would create tag v$VERSION"
|
|
|
|
# Intel build on Intel runner for native compilation
|
|
build-macos-intel:
|
|
needs: create-tag
|
|
runs-on: macos-15-intel
|
|
outputs:
|
|
notarization_id: ${{ steps.notarize.outputs.notarization-id }}
|
|
dmg_file: ${{ steps.notarize.outputs.dmg-file }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
# Use tag for real releases, develop branch for dry runs
|
|
ref: ${{ github.event.inputs.dry_run == 'true' && 'develop' || format('v{0}', needs.create-tag.outputs.version) }}
|
|
|
|
- name: Setup Node.js and install dependencies
|
|
uses: ./.github/actions/setup-node-frontend
|
|
|
|
- name: Build application
|
|
run: cd apps/desktop && npm run build
|
|
env:
|
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
|
SENTRY_TRACES_SAMPLE_RATE: ${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}
|
|
SENTRY_PROFILES_SAMPLE_RATE: ${{ secrets.SENTRY_PROFILES_SAMPLE_RATE }}
|
|
|
|
- name: Package macOS (Intel)
|
|
run: |
|
|
VERSION="${{ needs.create-tag.outputs.version }}"
|
|
cd apps/desktop && npm run package:mac -- --x64 --config.extraMetadata.version="$VERSION"
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
CSC_LINK: ${{ secrets.MAC_CERTIFICATE }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
|
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
|
SENTRY_TRACES_SAMPLE_RATE: ${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}
|
|
SENTRY_PROFILES_SAMPLE_RATE: ${{ secrets.SENTRY_PROFILES_SAMPLE_RATE }}
|
|
|
|
- name: Submit notarization (async)
|
|
id: notarize
|
|
uses: ./.github/actions/submit-macos-notarization
|
|
with:
|
|
apple-id: ${{ secrets.APPLE_ID }}
|
|
apple-app-specific-password: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
|
apple-team-id: ${{ secrets.APPLE_TEAM_ID }}
|
|
|
|
- name: Upload artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: macos-intel-builds
|
|
path: |
|
|
apps/desktop/dist/*.dmg
|
|
apps/desktop/dist/*.zip
|
|
apps/desktop/dist/*.yml
|
|
|
|
# Apple Silicon build on ARM64 runner for native compilation
|
|
build-macos-arm64:
|
|
needs: create-tag
|
|
runs-on: macos-15
|
|
outputs:
|
|
notarization_id: ${{ steps.notarize.outputs.notarization-id }}
|
|
dmg_file: ${{ steps.notarize.outputs.dmg-file }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
# Use tag for real releases, develop branch for dry runs
|
|
ref: ${{ github.event.inputs.dry_run == 'true' && 'develop' || format('v{0}', needs.create-tag.outputs.version) }}
|
|
|
|
- name: Setup Node.js and install dependencies
|
|
uses: ./.github/actions/setup-node-frontend
|
|
|
|
- name: Build application
|
|
run: cd apps/desktop && npm run build
|
|
env:
|
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
|
SENTRY_TRACES_SAMPLE_RATE: ${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}
|
|
SENTRY_PROFILES_SAMPLE_RATE: ${{ secrets.SENTRY_PROFILES_SAMPLE_RATE }}
|
|
|
|
- name: Package macOS (Apple Silicon)
|
|
run: |
|
|
VERSION="${{ needs.create-tag.outputs.version }}"
|
|
cd apps/desktop && npm run package:mac -- --arm64 --config.extraMetadata.version="$VERSION"
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
CSC_LINK: ${{ secrets.MAC_CERTIFICATE }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
|
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
|
SENTRY_TRACES_SAMPLE_RATE: ${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}
|
|
SENTRY_PROFILES_SAMPLE_RATE: ${{ secrets.SENTRY_PROFILES_SAMPLE_RATE }}
|
|
|
|
- name: Submit notarization (async)
|
|
id: notarize
|
|
uses: ./.github/actions/submit-macos-notarization
|
|
with:
|
|
apple-id: ${{ secrets.APPLE_ID }}
|
|
apple-app-specific-password: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
|
apple-team-id: ${{ secrets.APPLE_TEAM_ID }}
|
|
|
|
- name: Upload artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: macos-arm64-builds
|
|
path: |
|
|
apps/desktop/dist/*.dmg
|
|
apps/desktop/dist/*.zip
|
|
apps/desktop/dist/*.yml
|
|
|
|
build-windows:
|
|
needs: create-tag
|
|
runs-on: windows-latest
|
|
permissions:
|
|
id-token: write # Required for OIDC authentication with Azure
|
|
contents: read
|
|
env:
|
|
# Job-level env so AZURE_CLIENT_ID is available for step-level if conditions
|
|
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
# Use tag for real releases, develop branch for dry runs
|
|
ref: ${{ github.event.inputs.dry_run == 'true' && 'develop' || format('v{0}', needs.create-tag.outputs.version) }}
|
|
|
|
- name: Setup Node.js and install dependencies
|
|
uses: ./.github/actions/setup-node-frontend
|
|
|
|
- name: Build application
|
|
run: cd apps/desktop && npm run build
|
|
env:
|
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
|
SENTRY_TRACES_SAMPLE_RATE: ${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}
|
|
SENTRY_PROFILES_SAMPLE_RATE: ${{ secrets.SENTRY_PROFILES_SAMPLE_RATE }}
|
|
|
|
- name: Package Windows
|
|
shell: bash
|
|
run: |
|
|
VERSION="${{ needs.create-tag.outputs.version }}"
|
|
cd apps/desktop && npm run package:win -- --config.extraMetadata.version="$VERSION"
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
# Disable electron-builder's built-in signing (we use Azure Trusted Signing instead)
|
|
CSC_IDENTITY_AUTO_DISCOVERY: false
|
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
|
SENTRY_TRACES_SAMPLE_RATE: ${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}
|
|
SENTRY_PROFILES_SAMPLE_RATE: ${{ secrets.SENTRY_PROFILES_SAMPLE_RATE }}
|
|
|
|
- name: Azure Login (OIDC)
|
|
if: env.AZURE_CLIENT_ID != ''
|
|
uses: azure/login@v2
|
|
with:
|
|
client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
|
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
|
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
|
|
|
- name: Sign Windows executable with Azure Trusted Signing
|
|
if: env.AZURE_CLIENT_ID != ''
|
|
uses: azure/trusted-signing-action@v0.5.11
|
|
with:
|
|
endpoint: https://neu.codesigning.azure.net/
|
|
trusted-signing-account-name: ${{ secrets.AZURE_SIGNING_ACCOUNT }}
|
|
certificate-profile-name: ${{ secrets.AZURE_CERTIFICATE_PROFILE }}
|
|
files-folder: apps/desktop/dist
|
|
files-folder-filter: exe
|
|
file-digest: SHA256
|
|
timestamp-rfc3161: http://timestamp.acs.microsoft.com
|
|
timestamp-digest: SHA256
|
|
|
|
- name: Verify Windows executable is signed
|
|
if: env.AZURE_CLIENT_ID != ''
|
|
shell: pwsh
|
|
run: |
|
|
cd apps/desktop/dist
|
|
$exeFile = Get-ChildItem -Filter "*.exe" | Select-Object -First 1
|
|
if ($exeFile) {
|
|
Write-Host "Verifying signature on $($exeFile.Name)..."
|
|
$sig = Get-AuthenticodeSignature -FilePath $exeFile.FullName
|
|
if ($sig.Status -ne 'Valid') {
|
|
Write-Host "::error::Signature verification failed: $($sig.Status)"
|
|
Write-Host "::error::Status Message: $($sig.StatusMessage)"
|
|
exit 1
|
|
}
|
|
Write-Host "✅ Signature verified successfully"
|
|
Write-Host " Subject: $($sig.SignerCertificate.Subject)"
|
|
Write-Host " Issuer: $($sig.SignerCertificate.Issuer)"
|
|
Write-Host " Thumbprint: $($sig.SignerCertificate.Thumbprint)"
|
|
} else {
|
|
Write-Host "::error::No .exe file found to verify"
|
|
exit 1
|
|
}
|
|
|
|
- name: Regenerate checksums after signing
|
|
if: env.AZURE_CLIENT_ID != ''
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = "Stop"
|
|
cd apps/desktop/dist
|
|
|
|
# Find the installer exe (electron-builder names it with "Setup" or just the app name)
|
|
# electron-builder produces one installer exe per build
|
|
$exeFiles = Get-ChildItem -Filter "*.exe"
|
|
if ($exeFiles.Count -eq 0) {
|
|
Write-Host "::error::No .exe files found in dist folder"
|
|
exit 1
|
|
}
|
|
|
|
Write-Host "Found $($exeFiles.Count) exe file(s): $($exeFiles.Name -join ', ')"
|
|
|
|
$ymlFile = "latest.yml"
|
|
if (-not (Test-Path $ymlFile)) {
|
|
Write-Host "::error::$ymlFile not found - cannot update checksums"
|
|
exit 1
|
|
}
|
|
|
|
$content = Get-Content $ymlFile -Raw
|
|
$originalContent = $content
|
|
|
|
# Process each exe file and update its hash in latest.yml
|
|
foreach ($exeFile in $exeFiles) {
|
|
Write-Host "Processing $($exeFile.Name)..."
|
|
|
|
# Compute SHA512 hash and convert to base64 (electron-builder format)
|
|
$bytes = [System.IO.File]::ReadAllBytes($exeFile.FullName)
|
|
$sha512 = [System.Security.Cryptography.SHA512]::Create()
|
|
$hashBytes = $sha512.ComputeHash($bytes)
|
|
$hash = [System.Convert]::ToBase64String($hashBytes)
|
|
$size = $exeFile.Length
|
|
|
|
Write-Host " Hash: $hash"
|
|
Write-Host " Size: $size"
|
|
}
|
|
|
|
# For electron-builder, latest.yml has a single file entry for the installer
|
|
# Update the sha512 and size for the primary exe (first one, typically the installer)
|
|
$primaryExe = $exeFiles | Select-Object -First 1
|
|
$bytes = [System.IO.File]::ReadAllBytes($primaryExe.FullName)
|
|
$sha512 = [System.Security.Cryptography.SHA512]::Create()
|
|
$hashBytes = $sha512.ComputeHash($bytes)
|
|
$hash = [System.Convert]::ToBase64String($hashBytes)
|
|
$size = $primaryExe.Length
|
|
|
|
# Update sha512 hash (base64 pattern: alphanumeric, +, /, =)
|
|
$content = $content -replace 'sha512: [A-Za-z0-9+/=]+', "sha512: $hash"
|
|
# Update size
|
|
$content = $content -replace 'size: \d+', "size: $size"
|
|
|
|
if ($content -eq $originalContent) {
|
|
Write-Host "::error::Checksum replacement failed - content unchanged. Check if latest.yml format has changed."
|
|
exit 1
|
|
}
|
|
|
|
Set-Content -Path $ymlFile -Value $content -NoNewline
|
|
Write-Host "✅ Updated $ymlFile with new base64 hash and size for $($primaryExe.Name)"
|
|
|
|
- name: Skip signing notice
|
|
if: env.AZURE_CLIENT_ID == ''
|
|
run: echo "::warning::Windows signing skipped - AZURE_CLIENT_ID not configured. The .exe will be unsigned."
|
|
|
|
- name: Upload artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: windows-builds
|
|
path: |
|
|
apps/desktop/dist/*.exe
|
|
apps/desktop/dist/*.yml
|
|
|
|
build-linux:
|
|
needs: create-tag
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
# Use tag for real releases, develop branch for dry runs
|
|
ref: ${{ github.event.inputs.dry_run == 'true' && 'develop' || format('v{0}', needs.create-tag.outputs.version) }}
|
|
|
|
- name: Setup Node.js and install dependencies
|
|
uses: ./.github/actions/setup-node-frontend
|
|
|
|
- name: Setup Flatpak and verification tools
|
|
run: |
|
|
set -e
|
|
sudo apt-get update
|
|
sudo apt-get install -y flatpak flatpak-builder squashfs-tools
|
|
flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
|
flatpak install -y --user flathub org.freedesktop.Platform//25.08 org.freedesktop.Sdk//25.08
|
|
flatpak install -y --user flathub org.electronjs.Electron2.BaseApp//25.08
|
|
|
|
- name: Build application
|
|
run: cd apps/desktop && npm run build
|
|
env:
|
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
|
SENTRY_TRACES_SAMPLE_RATE: ${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}
|
|
SENTRY_PROFILES_SAMPLE_RATE: ${{ secrets.SENTRY_PROFILES_SAMPLE_RATE }}
|
|
|
|
- name: Package Linux
|
|
run: |
|
|
VERSION="${{ needs.create-tag.outputs.version }}"
|
|
cd apps/desktop && npm run package:linux -- --config.extraMetadata.version="$VERSION"
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
|
SENTRY_TRACES_SAMPLE_RATE: ${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}
|
|
SENTRY_PROFILES_SAMPLE_RATE: ${{ secrets.SENTRY_PROFILES_SAMPLE_RATE }}
|
|
|
|
- name: Verify Linux packages
|
|
run: cd apps/desktop && npm run verify:linux
|
|
|
|
- name: Upload artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: linux-builds
|
|
path: |
|
|
apps/desktop/dist/*.AppImage
|
|
apps/desktop/dist/*.deb
|
|
apps/desktop/dist/*.flatpak
|
|
apps/desktop/dist/*.yml
|
|
|
|
# Finalize macOS notarization (runs in parallel with Windows/Linux builds)
|
|
finalize-notarization:
|
|
needs: [build-macos-intel, build-macos-arm64]
|
|
runs-on: macos-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Download Intel DMG
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: macos-intel-builds
|
|
path: intel
|
|
|
|
- name: Download ARM64 DMG
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: macos-arm64-builds
|
|
path: arm64
|
|
|
|
- name: Wait for notarization and staple
|
|
uses: ./.github/actions/finalize-macos-notarization
|
|
with:
|
|
apple-id: ${{ secrets.APPLE_ID }}
|
|
apple-app-specific-password: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
|
apple-team-id: ${{ secrets.APPLE_TEAM_ID }}
|
|
intel-notarization-id: ${{ needs.build-macos-intel.outputs.notarization_id }}
|
|
arm64-notarization-id: ${{ needs.build-macos-arm64.outputs.notarization_id }}
|
|
intel-dmg-file: ${{ needs.build-macos-intel.outputs.dmg_file }}
|
|
arm64-dmg-file: ${{ needs.build-macos-arm64.outputs.dmg_file }}
|
|
|
|
- name: Upload stapled Intel DMG
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: macos-intel-stapled
|
|
path: intel/*.dmg
|
|
|
|
- name: Upload stapled ARM64 DMG
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: macos-arm64-stapled
|
|
path: arm64/*.dmg
|
|
|
|
create-release:
|
|
needs: [create-tag, finalize-notarization, build-windows, build-linux]
|
|
runs-on: ubuntu-latest
|
|
if: ${{ github.event.inputs.dry_run != 'true' }}
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: v${{ needs.create-tag.outputs.version }}
|
|
fetch-depth: 0
|
|
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
path: dist
|
|
|
|
- name: Flatten binary artifacts
|
|
run: |
|
|
mkdir -p release-assets
|
|
|
|
# Copy stapled macOS DMGs (from finalize-notarization job)
|
|
# Validate that stapled DMGs exist before copying
|
|
if ! find dist/macos-intel-stapled dist/macos-arm64-stapled -type f -name "*.dmg" 2>/dev/null | grep -q .; then
|
|
echo "::warning::No stapled DMGs found. Using un-stapled DMGs from build artifacts."
|
|
find dist/macos-intel-builds dist/macos-arm64-builds -type f -name "*.dmg" -exec cp {} release-assets/ \; 2>/dev/null || true
|
|
else
|
|
find dist/macos-intel-stapled dist/macos-arm64-stapled -type f -name "*.dmg" -exec cp {} release-assets/ \; 2>/dev/null || true
|
|
fi
|
|
|
|
# Copy other macOS artifacts (zip, yml, blockmap for delta updates) from original build
|
|
find dist/macos-intel-builds dist/macos-arm64-builds -type f \( -name "*.zip" -o -name "*.yml" -o -name "*.blockmap" \) -exec cp {} release-assets/ \; 2>/dev/null || true
|
|
|
|
# Copy Windows and Linux artifacts (including blockmap for delta updates)
|
|
find dist/windows-builds dist/linux-builds -type f \( -name "*.exe" -o -name "*.AppImage" -o -name "*.deb" -o -name "*.flatpak" -o -name "*.yml" -o -name "*.blockmap" \) -exec cp {} release-assets/ \; 2>/dev/null || true
|
|
|
|
# Validate that at least one artifact was copied
|
|
artifact_count=$(find release-assets -type f \( -name "*.dmg" -o -name "*.zip" -o -name "*.exe" -o -name "*.AppImage" -o -name "*.deb" -o -name "*.flatpak" \) | wc -l)
|
|
if [ "$artifact_count" -eq 0 ]; then
|
|
echo "::error::No build artifacts found! Expected .dmg, .zip, .exe, .AppImage, .deb, or .flatpak files."
|
|
exit 1
|
|
fi
|
|
|
|
echo "Found $artifact_count binary artifact(s):"
|
|
ls -la release-assets/
|
|
|
|
# Merge macOS manifests from Intel and ARM64 builds
|
|
# See: https://github.com/electron-userland/electron-builder/issues/5592
|
|
- name: Merge macOS manifests
|
|
uses: ./.github/actions/merge-macos-manifests
|
|
with:
|
|
dist-path: dist
|
|
output-path: release-assets
|
|
copy-other-manifests: 'true'
|
|
|
|
- name: Rename and validate beta manifests
|
|
run: |
|
|
cd release-assets
|
|
|
|
echo "=== Current manifest files ==="
|
|
ls -la *.yml 2>/dev/null || echo "No yml files found yet"
|
|
|
|
# electron-builder generates latest*.yml files by default
|
|
# For beta channel, electron-updater expects beta*.yml files
|
|
# Rename: latest.yml -> beta.yml, latest-mac.yml -> beta-mac.yml, latest-linux.yml -> beta-linux.yml
|
|
|
|
# Windows: latest.yml -> beta.yml
|
|
if [ -f "latest.yml" ]; then
|
|
echo "Renaming latest.yml -> beta.yml (Windows)"
|
|
mv latest.yml beta.yml
|
|
fi
|
|
|
|
# macOS: latest-mac.yml -> beta-mac.yml
|
|
if [ -f "latest-mac.yml" ]; then
|
|
echo "Renaming latest-mac.yml -> beta-mac.yml (macOS)"
|
|
mv latest-mac.yml beta-mac.yml
|
|
fi
|
|
|
|
# Linux: latest-linux.yml -> beta-linux.yml
|
|
if [ -f "latest-linux.yml" ]; then
|
|
echo "Renaming latest-linux.yml -> beta-linux.yml (Linux)"
|
|
mv latest-linux.yml beta-linux.yml
|
|
fi
|
|
|
|
# Linux ARM64: latest-linux-arm64.yml -> beta-linux-arm64.yml (if exists)
|
|
if [ -f "latest-linux-arm64.yml" ]; then
|
|
echo "Renaming latest-linux-arm64.yml -> beta-linux-arm64.yml (Linux ARM64)"
|
|
mv latest-linux-arm64.yml beta-linux-arm64.yml
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== Beta manifest files after rename ==="
|
|
ls -la *.yml 2>/dev/null || echo "No yml files found"
|
|
|
|
# Validate required beta manifests exist
|
|
missing_manifests=""
|
|
|
|
if [ ! -f "beta-mac.yml" ]; then
|
|
missing_manifests="$missing_manifests beta-mac.yml"
|
|
fi
|
|
|
|
if [ ! -f "beta.yml" ]; then
|
|
missing_manifests="$missing_manifests beta.yml"
|
|
fi
|
|
|
|
if [ ! -f "beta-linux.yml" ]; then
|
|
missing_manifests="$missing_manifests beta-linux.yml"
|
|
fi
|
|
|
|
if [ -n "$missing_manifests" ]; then
|
|
echo "::error::Missing required beta manifests:$missing_manifests"
|
|
echo "::error::Auto-update will fail on affected platforms without these files!"
|
|
exit 1
|
|
fi
|
|
|
|
echo ""
|
|
echo "All required beta manifests present:"
|
|
echo " - beta-mac.yml (macOS)"
|
|
echo " - beta.yml (Windows)"
|
|
echo " - beta-linux.yml (Linux)"
|
|
|
|
- name: Generate checksums
|
|
run: |
|
|
cd release-assets
|
|
sha256sum ./* > checksums.sha256
|
|
cat checksums.sha256
|
|
|
|
- name: Create Beta Release
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: v${{ needs.create-tag.outputs.version }}
|
|
name: v${{ needs.create-tag.outputs.version }} (Beta)
|
|
body: |
|
|
## Beta Release v${{ needs.create-tag.outputs.version }}
|
|
|
|
This is a **beta release** for testing new features. It may contain bugs or incomplete functionality.
|
|
|
|
### How to opt-in to beta updates
|
|
1. Open Auto Claude
|
|
2. Go to Settings > Updates
|
|
3. Enable "Beta Updates" toggle
|
|
|
|
### Reporting Issues
|
|
Please report any issues at https://github.com/AndyMik90/Auto-Claude/issues
|
|
|
|
---
|
|
|
|
**Full Changelog**: https://github.com/${{ github.repository }}/compare/main...v${{ needs.create-tag.outputs.version }}
|
|
files: release-assets/*
|
|
draft: false
|
|
prerelease: true
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
dry-run-summary:
|
|
needs: [create-tag, finalize-notarization, build-windows, build-linux]
|
|
runs-on: ubuntu-latest
|
|
if: ${{ github.event.inputs.dry_run == 'true' }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
path: dist
|
|
|
|
- name: Flatten binary artifacts
|
|
run: |
|
|
mkdir -p release-assets
|
|
|
|
# Copy stapled macOS DMGs (from finalize-notarization job)
|
|
find dist/macos-intel-stapled dist/macos-arm64-stapled -type f -name "*.dmg" -exec cp {} release-assets/ \; 2>/dev/null || true
|
|
|
|
# Copy other macOS artifacts (zip, yml, blockmap for delta updates) from original build
|
|
find dist/macos-intel-builds dist/macos-arm64-builds -type f \( -name "*.zip" -o -name "*.yml" -o -name "*.blockmap" \) -exec cp {} release-assets/ \; 2>/dev/null || true
|
|
|
|
# Copy Windows and Linux artifacts (including blockmap for delta updates)
|
|
find dist/windows-builds dist/linux-builds -type f \( -name "*.exe" -o -name "*.AppImage" -o -name "*.deb" -o -name "*.flatpak" -o -name "*.yml" -o -name "*.blockmap" \) -exec cp {} release-assets/ \; 2>/dev/null || true
|
|
|
|
# Merge macOS manifests (same logic as real release)
|
|
- name: Merge macOS manifests
|
|
uses: ./.github/actions/merge-macos-manifests
|
|
with:
|
|
dist-path: dist
|
|
output-path: release-assets
|
|
copy-other-manifests: 'true'
|
|
|
|
- name: Validate and rename beta manifests
|
|
run: |
|
|
cd release-assets
|
|
|
|
# Rename latest*.yml to beta*.yml
|
|
[ -f "latest.yml" ] && mv latest.yml beta.yml
|
|
[ -f "latest-mac.yml" ] && mv latest-mac.yml beta-mac.yml
|
|
[ -f "latest-linux.yml" ] && mv latest-linux.yml beta-linux.yml
|
|
[ -f "latest-linux-arm64.yml" ] && mv latest-linux-arm64.yml beta-linux-arm64.yml
|
|
|
|
# Validate required manifests
|
|
missing=""
|
|
[ ! -f "beta-mac.yml" ] && missing="$missing beta-mac.yml"
|
|
[ ! -f "beta.yml" ] && missing="$missing beta.yml"
|
|
[ ! -f "beta-linux.yml" ] && missing="$missing beta-linux.yml"
|
|
|
|
if [ -n "$missing" ]; then
|
|
echo "::warning::DRY RUN: Missing required beta manifests:$missing"
|
|
echo "MANIFEST_STATUS=FAILED" >> $GITHUB_ENV
|
|
else
|
|
echo "MANIFEST_STATUS=PASSED" >> $GITHUB_ENV
|
|
|
|
# Show merged manifest content for verification
|
|
echo ""
|
|
echo "=== beta-mac.yml content (should have both architectures) ==="
|
|
cat beta-mac.yml
|
|
fi
|
|
|
|
- name: Dry run summary
|
|
run: |
|
|
echo "## Beta Release Dry Run Complete" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "**Version:** ${{ needs.create-tag.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
|
|
echo "### Build Artifacts" >> $GITHUB_STEP_SUMMARY
|
|
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
|
find dist -type f \( -name "*.dmg" -o -name "*.zip" -o -name "*.exe" -o -name "*.AppImage" -o -name "*.deb" -o -name "*.flatpak" \) >> $GITHUB_STEP_SUMMARY
|
|
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
|
|
echo "### Update Manifests (Required for Auto-Update)" >> $GITHUB_STEP_SUMMARY
|
|
if [ "$MANIFEST_STATUS" = "PASSED" ]; then
|
|
echo "All required beta manifests present:" >> $GITHUB_STEP_SUMMARY
|
|
echo "- beta-mac.yml (macOS)" >> $GITHUB_STEP_SUMMARY
|
|
echo "- beta.yml (Windows)" >> $GITHUB_STEP_SUMMARY
|
|
echo "- beta-linux.yml (Linux)" >> $GITHUB_STEP_SUMMARY
|
|
else
|
|
echo "**WARNING: Missing required manifests! Auto-update will fail.**" >> $GITHUB_STEP_SUMMARY
|
|
echo "Check build logs for details." >> $GITHUB_STEP_SUMMARY
|
|
fi
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
|
|
echo "To create a real release, run this workflow again with dry_run unchecked." >> $GITHUB_STEP_SUMMARY
|