Skip to content

Release Flow Simulation (Current Architecture) #40

Release Flow Simulation (Current Architecture)

Release Flow Simulation (Current Architecture) #40

name: Release Flow Simulation (Current Architecture)
# ============================================================================
# Workflow Overview
# ============================================================================
# This workflow simulates the release.yml flow for quick validation.
# Fully synced with release.yml architecture for testing workflow logic.
#
# Architecture:
# - validate-tag: Validates git ref and computes version
# - build-windows: Simulates Windows amd64 build + code signing check
# - build-macos: Matrix simulation for macOS (amd64 + aarch64) + signing/notarization checks
# - upload-to-s3: Simulates S3 upload and OTA feed generation
#
# ============================================================================
# Purpose
# ============================================================================
# - Quickly validate workflow flow logic (< 5 minutes)
# - Test conditional logic correctness
# - Verify artifact naming and passing
# - Simulate code signing and notarization requirements
# - No actual build execution, only creates simulated artifacts
#
# Note: This simulation does not include:
# - Inno Setup installation or language pack processing
# - Actual code signing (certificates not required)
# - Actual Apple notarization (credentials not required)
# - External OTA frameworks (using self-contained OTA system)
#
# The actual release.yml uses .islu (Unicode) language files exclusively
# and ENFORCES code signing and notarization for production/staging builds.
#
# ============================================================================
# Supported Test Scenarios
# ============================================================================
# 1. platform=windows, arch=amd64 - Build Windows only
# 2. platform=macos, arch=amd64 - Build macOS Intel only
# 3. platform=macos, arch=aarch64 - Build macOS ARM only
# 4. platform=macos, arch=all - Build all macOS
# 5. platform=all, arch=amd64 - Build all Intel
# 6. platform=all, arch=aarch64 - Build macOS ARM only (Windows doesn't support ARM)
# 7. platform=all, arch=all - Complete build
on:
workflow_dispatch:
inputs:
platform:
description: 'Build platform (windows, macos, all)'
required: true
default: 'all'
type: choice
options:
- all
- windows
- macos
arch:
description: 'CPU architecture (all, amd64, aarch64)'
required: true
default: 'all'
type: choice
options:
- all
- amd64
- aarch64
ref:
description: 'Git ref to build (not used in simulation)'
required: true
default: 'master'
type: string
# Note: Environment is LOCKED to 'simulation' for safety
# This prevents accidental uploads to production/staging/test environments
environment:
description: 'Target environment (LOCKED to simulation for safety)'
required: false
default: 'simulation'
type: choice
options:
- simulation
# Note: Channel is LOCKED to 'simulation' for safety
channel:
description: 'Release channel (LOCKED to simulation for safety)'
required: false
default: 'simulation'
type: choice
options:
- simulation
upload_artifacts:
description: 'Upload artifacts to GitHub Artifacts (debug only)'
required: false
default: 'false'
type: choice
options:
- 'true'
- 'false'
concurrency:
group: ecan-release-sim-${{ github.ref }}-${{ github.event.inputs.platform }}-${{ github.event.inputs.arch }}
cancel-in-progress: true
jobs:
# ============================================================================
# VALIDATION LAYER: Tag and Version Validation
# ============================================================================
validate-tag:
runs-on: ubuntu-latest
outputs:
tag-valid: ${{ steps.out.outputs.valid }}
version: ${{ steps.out.outputs.version }}
is-branch: ${{ steps.out.outputs.is_branch }}
ref-name: ${{ steps.out.outputs.ref_name }}
environment: ${{ steps.detect-env.outputs.environment }}
channel: ${{ steps.detect-env.outputs.channel }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- id: out
shell: bash
run: |
set -euo pipefail
INPUT_REF="${{ github.event.inputs.ref }}"
REF_FULL="${GITHUB_REF}"
# Determine the actual ref to use
if [ -n "$INPUT_REF" ]; then
REF_NAME="$INPUT_REF"
else
REF_NAME="${REF_FULL#refs/*/}"
fi
echo "ref_name=$REF_NAME" >> $GITHUB_OUTPUT
echo "Selected ref: $REF_NAME"
# Check if it's a tag (semantic version format)
if [[ "$REF_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.-]+)?(\+[A-Za-z0-9.-]+)?$ ]]; then
echo "valid=true" >> $GITHUB_OUTPUT
echo "is_branch=false" >> $GITHUB_OUTPUT
# Tag: use tag version + -sim suffix
VERSION="${REF_NAME#v}"
echo "version=${VERSION}-sim" >> $GITHUB_OUTPUT
echo "Tag detected: $REF_NAME -> ${VERSION}-sim"
else
# Branch: read VERSION file as base version
if [ -f "VERSION" ]; then
BASE_VERSION=$(cat VERSION | tr -d '[:space:]')
echo "Read base version from VERSION file: $BASE_VERSION"
else
BASE_VERSION="0.0.0"
echo "VERSION file not found, using default: $BASE_VERSION"
fi
SHORT_SHA=$(git rev-parse --short HEAD)
SAFE_BRANCH=$(echo "$REF_NAME" | tr '/' '-')
# Branch: use VERSION-branch-commit-sim format
FALLBACK="${BASE_VERSION}-${SAFE_BRANCH}-${SHORT_SHA}-sim"
echo "valid=true" >> $GITHUB_OUTPUT
echo "is_branch=true" >> $GITHUB_OUTPUT
echo "version=$FALLBACK" >> $GITHUB_OUTPUT
echo "Branch detected: $REF_NAME -> version=$FALLBACK"
fi
- name: Detect environment and channel
id: detect-env
shell: bash
run: |
REF_NAME="${{ steps.out.outputs.ref_name }}"
VERSION="${{ steps.out.outputs.version }}"
echo "=== Environment Configuration (Simulation Workflow) ==="
echo "Ref: $REF_NAME"
echo "Version: $VERSION"
# SAFETY: Force simulation environment and channel
# This prevents accidental uploads to production/staging/test
ENV="simulation"
CHANNEL="simulation"
echo "environment=$ENV" >> $GITHUB_OUTPUT
echo "channel=$CHANNEL" >> $GITHUB_OUTPUT
echo "=== Final Configuration (LOCKED for Safety) ==="
echo "Environment: $ENV (LOCKED)"
echo "Channel: $CHANNEL (LOCKED)"
echo "S3 Path: s3://ecan-releases/simulation/"
echo ""
echo "⚠️ This workflow is ISOLATED from production environments"
echo "⚠️ All uploads go to: simulation/ prefix only"
# ============================================================================
# BUILD LAYER: Windows amd64 (Simulation)
# ============================================================================
build-windows:
name: Build Windows amd64
needs: validate-tag
if: |
needs.validate-tag.outputs.tag-valid == 'true' &&
(github.event.inputs.platform == 'windows' ||
github.event.inputs.platform == 'all') &&
(github.event.inputs.arch == 'amd64' ||
github.event.inputs.arch == 'all')
runs-on: ubuntu-latest # Use ubuntu for faster simulation
env:
BUILD_ARCH: amd64
steps:
# Note: Frontend is always built in real workflow (no change detection)
# Simulation doesn't need frontend build steps
- name: Checkout code for signing
uses: actions/checkout@v4
- name: Simulate Windows build
run: |
echo "=== Simulating Windows amd64 Build ==="
echo "Platform: Windows"
echo "Architecture: $BUILD_ARCH"
echo "Note: Real workflow always builds frontend (no skip logic)"
VERSION="${{ needs.validate-tag.outputs.version }}"
mkdir -p dist artifacts
# Create fake installer
echo "fake windows installer" > "dist/eCan-${VERSION}-windows-${BUILD_ARCH}-Setup.exe"
cp "dist/eCan-${VERSION}-windows-${BUILD_ARCH}-Setup.exe" artifacts/
echo "✅ Windows build simulated"
# ------------------------------------------------------------------------
# Step: Setup OTA Signing Key from GitHub Secrets
# ------------------------------------------------------------------------
- name: Setup OTA signing key
if: |
needs.validate-tag.outputs.environment == 'production' ||
needs.validate-tag.outputs.environment == 'staging' ||
needs.validate-tag.outputs.environment == 'test' ||
needs.validate-tag.outputs.environment == 'simulation'
env:
OTA_PRIVATE_KEY: ${{ secrets.OTA_ED25519_PRIVATE_KEY }}
run: |
echo "=== Setting up OTA signing key ==="
echo "Environment: ${{ needs.validate-tag.outputs.environment }}"
# Create certificates directory
mkdir -p build_system/certificates
# Check if secret is available
if [ -z "$OTA_PRIVATE_KEY" ]; then
echo "[WARNING] OTA_ED25519_PRIVATE_KEY secret is NOT configured"
echo "Signature generation will be skipped"
else
# Decode base64 and write private key
KEY_PATH="build_system/certificates/ed25519_private_key.pem"
echo "$OTA_PRIVATE_KEY" | base64 -d > "$KEY_PATH"
chmod 600 "$KEY_PATH"
echo "✓ OTA signing key configured successfully"
fi
- name: Generate real Ed25519 signature
run: |
VERSION="${{ needs.validate-tag.outputs.version }}"
INSTALLER="dist/eCan-${VERSION}-windows-${BUILD_ARCH}-Setup.exe"
# Install OpenSSL if needed
if ! command -v openssl &> /dev/null; then
echo "Installing OpenSSL..."
sudo apt-get update && sudo apt-get install -y openssl
fi
# Generate real Ed25519 signature
if [ -f "build_system/certificates/ed25519_private_key.pem" ]; then
echo "Generating real Ed25519 signature..."
# Use signing_manager.py for Ed25519 signing (OpenSSL pkeyutl doesn't support Ed25519 in all versions)
python build_system/signing_manager.py \
"$INSTALLER" \
"build_system/certificates/ed25519_private_key.pem" \
"${INSTALLER}.sig"
# Check if signature was generated successfully
if [ -f "${INSTALLER}.sig" ]; then
SIG_SIZE=$(wc -c < "${INSTALLER}.sig" | tr -d ' ')
if [ "$SIG_SIZE" -eq 64 ]; then
cp "${INSTALLER}.sig" artifacts/
echo "✅ Real signature generated (64 bytes)"
else
echo "⚠️ Invalid signature size: $SIG_SIZE bytes (expected 64), creating placeholder"
echo "simulation_signature" > "${INSTALLER}.sig"
cp "${INSTALLER}.sig" artifacts/
fi
else
echo "⚠️ Signature generation failed, creating placeholder"
echo "simulation_signature" > "${INSTALLER}.sig"
cp "${INSTALLER}.sig" artifacts/
fi
else
echo "⚠️ Private key not found, creating placeholder signature"
echo "simulation_signature" > "${INSTALLER}.sig"
cp "${INSTALLER}.sig" artifacts/
fi
# ------------------------------------------------------------------------
# OTA Signing Simulation
# In real workflow, OTA signing is REQUIRED for test/staging/production
# ------------------------------------------------------------------------
# Note: OTA signing is now done in the build step above with real signatures
# ------------------------------------------------------------------------
# Code Signing Simulation
# In real workflow, Authenticode signing is REQUIRED for production/staging
# ------------------------------------------------------------------------
- name: Simulate code signing check (production/staging requirement)
if: |
needs.validate-tag.outputs.environment == 'production' ||
needs.validate-tag.outputs.environment == 'staging'
run: |
echo "=== Simulating Code Signing Requirement Check ==="
echo "Environment: ${{ needs.validate-tag.outputs.environment }}"
echo "In real workflow: Authenticode certificate REQUIRED"
echo " - WIN_CERT_PFX"
echo " - WIN_CERT_PASSWORD"
echo "✅ Simulation: Skipping actual certificate check"
- name: Simulate code signing execution
run: |
echo "=== Simulating Code Signing ==="
echo "In real workflow: signtool sign /f certificate.pfx /fd SHA256"
echo "✅ Simulation: Code signing skipped"
- name: Upload Windows artifacts for S3 transfer (always, short retention)
uses: actions/upload-artifact@v4
with:
name: eCan-windows-amd64-${{ needs.validate-tag.outputs.version }}-s3-transfer
path: artifacts/
retention-days: 1
compression-level: 6
if-no-files-found: error
- name: Upload Windows artifacts for users (optional, long retention)
if: github.event.inputs.upload_artifacts == 'true'
uses: actions/upload-artifact@v4
with:
name: eCan-Windows-${{ needs.validate-tag.outputs.version }}
path: artifacts/
retention-days: 7
compression-level: 6
# ============================================================================
# BUILD LAYER: macOS (Matrix: amd64 + aarch64) (Simulation)
# ============================================================================
build-macos:
name: Build macOS
needs: validate-tag
if: |
needs.validate-tag.outputs.tag-valid == 'true' &&
(github.event.inputs.platform == 'macos' ||
github.event.inputs.platform == 'all')
runs-on: ubuntu-latest # Use ubuntu for faster simulation
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
runner: macos-15-intel # Intel x86_64 runner (newer than macos-13)
target_arch: x86_64
pyinstaller_arch: x86_64
- arch: aarch64
runner: macos-latest # Would use Apple Silicon runner in real workflow
target_arch: arm64
pyinstaller_arch: arm64
env:
BUILD_ARCH: ${{ matrix.arch }}
TARGET_ARCH: ${{ matrix.target_arch }}
PYINSTALLER_TARGET_ARCH: ${{ matrix.pyinstaller_arch }}
steps:
# ------------------------------------------------------------------------
# Step 0: Architecture Filtering (MUST BE FIRST - No dependencies)
# ------------------------------------------------------------------------
- name: Check if this architecture should be built
id: arch_check
run: |
ARCH="${{ matrix.arch }}"
INPUT="${{ github.event.inputs.arch }}"
echo "Matrix architecture: $ARCH"
echo "Requested architecture: $INPUT"
if [ "$INPUT" = "all" ] || [ -z "$INPUT" ] || [ "$INPUT" = "$ARCH" ]; then
echo "✅ This architecture will be built"
echo "should_build=true" >> $GITHUB_OUTPUT
else
echo "⏭️ Skipping this architecture (not requested)"
echo "should_build=false" >> $GITHUB_OUTPUT
exit 0
fi
# Early exit if architecture not needed - saves all setup time
- name: Exit early if architecture not needed
if: steps.arch_check.outputs.should_build != 'true'
run: |
echo "Architecture ${{ matrix.arch }} not needed for this build"
echo "Exiting early to save resources"
exit 0
# Note: Frontend is always built in real workflow (no change detection)
# Simulation doesn't need frontend build steps
- name: Checkout code for signing
if: steps.arch_check.outputs.should_build == 'true'
uses: actions/checkout@v4
- name: Simulate macOS build
if: steps.arch_check.outputs.should_build == 'true'
run: |
echo "=== Simulating macOS ${{ matrix.arch }} Build ==="
echo "Platform: macOS"
echo "Architecture: ${{ matrix.arch }} (${{ matrix.target_arch }})"
echo "Note: Real workflow always builds frontend (no skip logic)"
VERSION="${{ needs.validate-tag.outputs.version }}"
ARCH="${{ matrix.arch }}"
mkdir -p dist artifacts
# Create fake installer
echo "fake macos installer" > "dist/eCan-${VERSION}-macos-${ARCH}.pkg"
cp "dist/eCan-${VERSION}-macos-${ARCH}.pkg" artifacts/
echo "✅ macOS ${{ matrix.arch }} build simulated"
# ------------------------------------------------------------------------
# Step: Setup OTA Signing Key from GitHub Secrets
# ------------------------------------------------------------------------
- name: Setup OTA signing key
if: |
steps.arch_check.outputs.should_build == 'true' && (
needs.validate-tag.outputs.environment == 'production' ||
needs.validate-tag.outputs.environment == 'staging' ||
needs.validate-tag.outputs.environment == 'test' ||
needs.validate-tag.outputs.environment == 'simulation'
)
env:
OTA_PRIVATE_KEY: ${{ secrets.OTA_ED25519_PRIVATE_KEY }}
run: |
echo "=== Setting up OTA signing key ==="
echo "Environment: ${{ needs.validate-tag.outputs.environment }}"
# Create certificates directory
mkdir -p build_system/certificates
# Check if secret is available
if [ -z "$OTA_PRIVATE_KEY" ]; then
echo "[WARNING] OTA_ED25519_PRIVATE_KEY secret is NOT configured"
echo "Signature generation will be skipped"
else
# Decode base64 and write private key
KEY_PATH="build_system/certificates/ed25519_private_key.pem"
echo "$OTA_PRIVATE_KEY" | base64 -d > "$KEY_PATH"
chmod 600 "$KEY_PATH"
echo "✓ OTA signing key configured successfully"
fi
- name: Generate real Ed25519 signature
if: steps.arch_check.outputs.should_build == 'true'
run: |
VERSION="${{ needs.validate-tag.outputs.version }}"
ARCH="${{ matrix.arch }}"
INSTALLER="dist/eCan-${VERSION}-macos-${ARCH}.pkg"
# Install OpenSSL if needed
if ! command -v openssl &> /dev/null; then
echo "Installing OpenSSL..."
sudo apt-get update && sudo apt-get install -y openssl
fi
# Generate real Ed25519 signature
if [ -f "build_system/certificates/ed25519_private_key.pem" ]; then
echo "Generating real Ed25519 signature..."
# Use signing_manager.py for Ed25519 signing (OpenSSL pkeyutl doesn't support Ed25519 in all versions)
python build_system/signing_manager.py \
"$INSTALLER" \
"build_system/certificates/ed25519_private_key.pem" \
"${INSTALLER}.sig"
# Check if signature was generated successfully
if [ -f "${INSTALLER}.sig" ]; then
SIG_SIZE=$(wc -c < "${INSTALLER}.sig" | tr -d ' ')
if [ "$SIG_SIZE" -eq 64 ]; then
cp "${INSTALLER}.sig" artifacts/
echo "✅ Real signature generated for macOS ${{ matrix.arch }} (64 bytes)"
else
echo "⚠️ Invalid signature size: $SIG_SIZE bytes (expected 64), creating placeholder"
echo "simulation_signature" > "${INSTALLER}.sig"
cp "${INSTALLER}.sig" artifacts/
fi
else
echo "⚠️ Signature generation failed, creating placeholder"
echo "simulation_signature" > "${INSTALLER}.sig"
cp "${INSTALLER}.sig" artifacts/
fi
else
echo "⚠️ Private key not found, creating placeholder signature"
echo "simulation_signature" > "${INSTALLER}.sig"
cp "${INSTALLER}.sig" artifacts/
fi
# ------------------------------------------------------------------------
# OTA Signing Simulation
# In real workflow, OTA signing is REQUIRED for test/staging/production
# ------------------------------------------------------------------------
# Note: OTA signing is now done in the build step above with real signatures
# ------------------------------------------------------------------------
# Code Signing and Notarization Simulation
# In real workflow, these are REQUIRED for production/staging
# ------------------------------------------------------------------------
- name: Simulate code signing check (production/staging requirement)
if: |
steps.arch_check.outputs.should_build == 'true' &&
(needs.validate-tag.outputs.environment == 'production' ||
needs.validate-tag.outputs.environment == 'staging')
run: |
echo "=== Simulating Code Signing Requirement Check ==="
echo "Environment: ${{ needs.validate-tag.outputs.environment }}"
echo "In real workflow: Code signing certificates REQUIRED"
echo " - MAC_CERT_P12"
echo " - MAC_CERT_PASSWORD"
echo " - MAC_CODESIGN_IDENTITY"
echo "✅ Simulation: Skipping actual certificate check"
- name: Simulate code signing execution
if: steps.arch_check.outputs.should_build == 'true'
run: |
echo "=== Simulating Code Signing ==="
echo "In real workflow: codesign --deep --force --options runtime"
echo "✅ Simulation: Code signing skipped"
- name: Simulate notarization check (production/staging requirement)
if: |
steps.arch_check.outputs.should_build == 'true' &&
(needs.validate-tag.outputs.environment == 'production' ||
needs.validate-tag.outputs.environment == 'staging')
run: |
echo "=== Simulating Notarization Requirement Check ==="
echo "Environment: ${{ needs.validate-tag.outputs.environment }}"
echo "In real workflow: Notarization REQUIRED"
echo " - APPLE_ID"
echo " - APPLE_APP_SPECIFIC_PASSWORD"
echo " - TEAM_ID"
echo "✅ Simulation: Skipping actual notarization check"
- name: Simulate notarization execution
if: steps.arch_check.outputs.should_build == 'true'
run: |
echo "=== Simulating Notarization ==="
echo "In real workflow: xcrun notarytool submit --wait"
echo "In real workflow: xcrun stapler staple"
echo "✅ Simulation: Notarization skipped"
- name: Upload macOS artifacts for S3 transfer (always, short retention)
if: steps.arch_check.outputs.should_build == 'true'
uses: actions/upload-artifact@v4
with:
name: eCan-macos-${{ matrix.arch }}-${{ needs.validate-tag.outputs.version }}-s3-transfer
path: artifacts/
retention-days: 1
compression-level: 6
if-no-files-found: error
- name: Upload macOS artifacts for users (optional, long retention)
if: steps.arch_check.outputs.should_build == 'true' && github.event.inputs.upload_artifacts == 'true'
uses: actions/upload-artifact@v4
with:
name: eCan-macos-${{ matrix.arch }}-${{ needs.validate-tag.outputs.version }}
path: artifacts/
retention-days: 7
compression-level: 6
# ============================================================================
# DISTRIBUTION LAYER: S3 Upload and OTA Feed Generation (Simulation)
# ============================================================================
# This layer uses reusable workflows (same as release.yml) in simulation mode:
# 1. upload-to-s3: Simulates S3 upload (shared-s3-upload.yml)
# 2. generate-appcast: Simulates appcast generation (shared-appcast-generation.yml)
# 3. generate-download-links: Simulates download links (shared-download-links.yml)
# ============================================================================
# ----------------------------------------------------------------------------
# Step 1: Upload artifacts to S3 (Simulation)
# ----------------------------------------------------------------------------
upload-to-s3:
name: Upload to S3 (Simulation)
needs: [validate-tag, build-windows, build-macos]
if: |
always() &&
needs.validate-tag.outputs.tag-valid == 'true' &&
(needs.build-windows.result == 'success' || needs.build-windows.result == 'skipped') &&
(needs.build-macos.result == 'success' || needs.build-macos.result == 'skipped')
uses: ./.github/workflows/shared-s3-upload.yml
with:
version: ${{ needs.validate-tag.outputs.version }}
environment: ${{ needs.validate-tag.outputs.environment }}
windows-build-result: ${{ needs.build-windows.result }}
macos-build-result: ${{ needs.build-macos.result }}
secrets: inherit
# ----------------------------------------------------------------------------
# Step 2: Generate OTA update feeds (Simulation)
# ----------------------------------------------------------------------------
# Generate Appcast for Windows (if built)
generate-appcast-windows:
name: Generate Appcast (Windows Simulation)
needs: [validate-tag, upload-to-s3, build-windows]
if: |
always() &&
needs.validate-tag.outputs.tag-valid == 'true' &&
needs.upload-to-s3.result == 'success' &&
needs.build-windows.result == 'success'
uses: ./.github/workflows/shared-appcast-generation.yml
with:
environment: ${{ needs.validate-tag.outputs.environment }}
channel: ${{ needs.validate-tag.outputs.channel }}
version: ${{ needs.validate-tag.outputs.version }}
platform: 'windows'
arch: 'amd64'
secrets: inherit
# Generate Appcast for macOS amd64 (if built)
generate-appcast-macos-amd64:
name: Generate Appcast (macOS Intel Simulation)
needs: [validate-tag, upload-to-s3, build-macos]
if: |
always() &&
needs.validate-tag.outputs.tag-valid == 'true' &&
needs.upload-to-s3.result == 'success' &&
needs.build-macos.result == 'success' &&
(github.event.inputs.arch == 'all' || github.event.inputs.arch == '' || github.event.inputs.arch == 'amd64')
uses: ./.github/workflows/shared-appcast-generation.yml
with:
environment: ${{ needs.validate-tag.outputs.environment }}
channel: ${{ needs.validate-tag.outputs.channel }}
version: ${{ needs.validate-tag.outputs.version }}
platform: 'macos'
arch: 'amd64'
secrets: inherit
# Generate Appcast for macOS aarch64 (if built)
generate-appcast-macos-aarch64:
name: Generate Appcast (macOS ARM Simulation)
needs: [validate-tag, upload-to-s3, build-macos]
if: |
always() &&
needs.validate-tag.outputs.tag-valid == 'true' &&
needs.upload-to-s3.result == 'success' &&
needs.build-macos.result == 'success' &&
(github.event.inputs.arch == 'all' || github.event.inputs.arch == '' || github.event.inputs.arch == 'aarch64')
uses: ./.github/workflows/shared-appcast-generation.yml
with:
environment: ${{ needs.validate-tag.outputs.environment }}
channel: ${{ needs.validate-tag.outputs.channel }}
version: ${{ needs.validate-tag.outputs.version }}
platform: 'macos'
arch: 'aarch64'
secrets: inherit
# ----------------------------------------------------------------------------
# Step 2.5: Generate latest.json (after all Appcasts)
# ----------------------------------------------------------------------------
generate-latest-json:
name: Generate latest.json (Simulation)
needs: [
validate-tag,
upload-to-s3,
generate-appcast-windows,
generate-appcast-macos-amd64,
generate-appcast-macos-aarch64
]
if: |
always() &&
needs.validate-tag.outputs.tag-valid == 'true' &&
needs.upload-to-s3.result == 'success' &&
(needs.generate-appcast-windows.result == 'success' ||
needs.generate-appcast-macos-amd64.result == 'success' ||
needs.generate-appcast-macos-aarch64.result == 'success')
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install boto3 pyyaml packaging
- name: Generate latest.json
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.AWS_REGION || 'us-east-1' }}
run: |
python3 << 'PYTHON_SCRIPT'
import sys
sys.path.insert(0, 'build_system/scripts')
from generate_appcast import AppcastGenerator
generator = AppcastGenerator(
environment='${{ needs.validate-tag.outputs.environment }}',
channel='${{ needs.validate-tag.outputs.channel }}'
)
print('[INFO] Generating latest.json only (Simulation)...')
success = generator.generate_latest_json()
if success:
print('[OK] latest.json generated successfully')
sys.exit(0)
else:
print('[ERROR] Failed to generate latest.json')
sys.exit(1)
PYTHON_SCRIPT
# ----------------------------------------------------------------------------
# Step 3: Generate download links (Simulation)
# ----------------------------------------------------------------------------
generate-download-links:
name: Generate Download Links (Simulation)
needs: [validate-tag, build-windows, build-macos, upload-to-s3]
if: |
always() &&
needs.validate-tag.outputs.tag-valid == 'true' &&
needs.upload-to-s3.result == 'success'
uses: ./.github/workflows/shared-download-links.yml
with:
version: ${{ needs.validate-tag.outputs.version }}
environment: ${{ needs.validate-tag.outputs.environment }}
channel: ${{ needs.validate-tag.outputs.channel }}
windows-build-result: ${{ needs.build-windows.result }}
macos-build-result: ${{ needs.build-macos.result }}
macos-built-amd64: ${{ (github.event.inputs.platform == 'macos' || github.event.inputs.platform == 'all') && (github.event.inputs.arch == 'amd64' || github.event.inputs.arch == 'all') }}
macos-built-aarch64: ${{ (github.event.inputs.platform == 'macos' || github.event.inputs.platform == 'all') && (github.event.inputs.arch == 'aarch64' || github.event.inputs.arch == 'all') }}
secrets: inherit
# ----------------------------------------------------------------------------
# Step 4: Final status summary (Simulation)
# ----------------------------------------------------------------------------
final-status:
name: Final Status Summary (Simulation)
needs: [
validate-tag,
build-windows,
build-macos,
upload-to-s3,
generate-appcast-windows,
generate-appcast-macos-amd64,
generate-appcast-macos-aarch64,
generate-latest-json,
generate-download-links
]
if: always()
uses: ./.github/workflows/shared-final-status.yml
with:
version: ${{ needs.validate-tag.outputs.version }}
windows-result: ${{ needs.build-windows.result }}
macos-result: ${{ needs.build-macos.result }}
upload-result: ${{ needs.upload-to-s3.result }}
appcast-result: ${{ (needs.generate-appcast-windows.result == 'success' || needs.generate-appcast-macos-amd64.result == 'success' || needs.generate-appcast-macos-aarch64.result == 'success') && 'success' || 'failure' }}
links-result: ${{ needs.generate-download-links.result }}
is-simulation: true
secrets: inherit