mirror of
https://github.com/VibedByKaKi/t3-code-android-nightly.git
synced 2026-10-09 20:01:15 +02:00
627 lines
27 KiB
YAML
627 lines
27 KiB
YAML
name: Release desktop build
|
|
|
|
# One desktop platform/arch build, called once per target from release.yml so
|
|
# each target is its own job with its own `needs`. The JS bundle (server, web
|
|
# client, Electron main) comes from the `js-bundle` artifact that build_bundle
|
|
# produced; this job only packages it, builds the native helpers, and, where
|
|
# `cli_archive` is set, the self-contained CLI archive for its platform.
|
|
|
|
on:
|
|
workflow_call:
|
|
secrets:
|
|
CSC_LINK:
|
|
required: false
|
|
CSC_KEY_PASSWORD:
|
|
required: false
|
|
APPLE_API_KEY:
|
|
required: false
|
|
APPLE_API_KEY_ID:
|
|
required: false
|
|
APPLE_API_ISSUER:
|
|
required: false
|
|
MACOS_PROVISIONING_PROFILE:
|
|
required: false
|
|
AZURE_TENANT_ID:
|
|
required: false
|
|
AZURE_CLIENT_ID:
|
|
required: false
|
|
AZURE_CLIENT_SECRET:
|
|
required: false
|
|
AZURE_TRUSTED_SIGNING_ENDPOINT:
|
|
required: false
|
|
AZURE_TRUSTED_SIGNING_ACCOUNT_NAME:
|
|
required: false
|
|
AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME:
|
|
required: false
|
|
AZURE_TRUSTED_SIGNING_PUBLISHER_NAME:
|
|
required: false
|
|
inputs:
|
|
label:
|
|
required: true
|
|
type: string
|
|
runner:
|
|
required: true
|
|
type: string
|
|
platform:
|
|
required: true
|
|
type: string
|
|
target:
|
|
required: true
|
|
type: string
|
|
arch:
|
|
required: true
|
|
type: string
|
|
rust_target:
|
|
required: true
|
|
type: string
|
|
resource_key:
|
|
required: true
|
|
type: string
|
|
# Whether the job also builds the self-contained CLI archive for its own
|
|
# platform/arch, on this runner, and smoke-tests it here. Every archive
|
|
# is built on hardware of its own architecture.
|
|
cli_archive:
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
version:
|
|
required: true
|
|
type: string
|
|
ref:
|
|
required: true
|
|
type: string
|
|
release_channel:
|
|
required: true
|
|
type: string
|
|
# Whether a `relay-client-tracing-config` artifact from the production
|
|
# relay state is expected. PR previews carry no tracing config.
|
|
relay_client_tracing:
|
|
required: false
|
|
default: true
|
|
type: boolean
|
|
clerk_publishable_key:
|
|
required: true
|
|
type: string
|
|
clerk_jwt_template:
|
|
required: true
|
|
type: string
|
|
clerk_cli_oauth_client_id:
|
|
required: true
|
|
type: string
|
|
relay_url:
|
|
required: true
|
|
type: string
|
|
|
|
permissions:
|
|
# Windows builds read this run's artifact list to wait for the Linux CLI archive.
|
|
actions: read
|
|
contents: read
|
|
|
|
jobs:
|
|
build:
|
|
name: Build ${{ inputs.label }}
|
|
runs-on: ${{ inputs.runner }}
|
|
# Windows waits for the Linux CLI archive inside its own budget (see
|
|
# "Wait for Linux CLI archive"), so it gets that wait on top of the usual 30.
|
|
timeout-minutes: ${{ inputs.platform == 'win' && 70 || 30 }}
|
|
env:
|
|
T3CODE_CLERK_PUBLISHABLE_KEY: ${{ inputs.clerk_publishable_key }}
|
|
T3CODE_CLERK_JWT_TEMPLATE: ${{ inputs.clerk_jwt_template }}
|
|
T3CODE_CLERK_CLI_OAUTH_CLIENT_ID: ${{ inputs.clerk_cli_oauth_client_id }}
|
|
T3CODE_RELAY_URL: ${{ inputs.relay_url }}
|
|
steps:
|
|
# This repository is public, so Git needs no credentials. checkout's
|
|
# credential cleanup runs submodule foreach even with submodules disabled,
|
|
# which fails on the orphaned gitlinks in our vendored .repos tree.
|
|
# checkout.workers=0 writes the files on every core. Alternating both ways
|
|
# in one job on the Windows runners, it wrote the files about 10s faster
|
|
# (about 40% on arm64).
|
|
- name: Checkout
|
|
shell: bash
|
|
env:
|
|
CHECKOUT_REF: ${{ inputs.ref }}
|
|
GIT_TERMINAL_PROMPT: "0"
|
|
run: |
|
|
set -euo pipefail
|
|
git init .
|
|
git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
|
git fetch --no-tags --depth=1 origin "$CHECKOUT_REF"
|
|
git sparse-checkout set --no-cone '/*' '!/.repos/'
|
|
git -c checkout.workers=0 checkout --detach FETCH_HEAD
|
|
|
|
# Windows installs straight from the registry. There, linking the packages
|
|
# takes the time, not downloading them, so a ~700 MB package cache did not
|
|
# pay for its own restore. Across recent nightlies, restore plus install
|
|
# took 183-233s on arm64 and 116-172s on x64, while a plain install took
|
|
# 142-210s and 84-160s. The arm64 entries also filled 4 GB of the
|
|
# repository's 10 GB Actions cache.
|
|
- name: Setup Vite+
|
|
uses: voidzero-dev/setup-vp@250f29ce396baf5e8f24498e17c0dfdebabc26eb # v1
|
|
with:
|
|
node-version-file: package.json
|
|
cache: ${{ inputs.platform != 'win' }}
|
|
run-install: false
|
|
|
|
# pnpm checks the lockfile and policy before reusing this result. A missing
|
|
# artifact leaves the cache empty, so installation runs the checks again.
|
|
- name: Download dependency verification
|
|
continue-on-error: true
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: release-dependency-verification
|
|
path: ${{ runner.temp }}/pnpm-metadata
|
|
|
|
- name: Install desktop dependencies
|
|
env:
|
|
pnpm_config_cache_dir: ${{ runner.temp }}/pnpm-metadata
|
|
run: vp install --filter=@t3tools/desktop... --filter=t3... --filter=@t3tools/scripts...
|
|
|
|
- name: Cache resource monitor
|
|
id: resource_monitor_cache
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: native/resource-monitor/target/${{ inputs.rust_target }}/release/t3-resource-monitor${{ inputs.platform == 'win' && '.exe' || '' }}
|
|
key: resource-monitor-${{ inputs.rust_target }}-${{ hashFiles('native/resource-monitor/Cargo.lock', 'native/resource-monitor/Cargo.toml', 'native/resource-monitor/src/**') }}
|
|
|
|
- name: Cache Linux capture helpers
|
|
if: inputs.platform == 'linux'
|
|
id: capture_helper_cache
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
native/kde-snap-shot/target/${{ inputs.rust_target }}/release/t3-kde-snap-shot
|
|
native/hyprland-snap-shot/target/${{ inputs.rust_target }}/release/t3-hyprland-snap-shot
|
|
key: linux-capture-helpers-${{ inputs.rust_target }}-${{ hashFiles('native/kde-snap-shot/Cargo.lock', 'native/kde-snap-shot/Cargo.toml', 'native/kde-snap-shot/src/**', 'native/hyprland-snap-shot/Cargo.lock', 'native/hyprland-snap-shot/Cargo.toml', 'native/hyprland-snap-shot/src/**', 'native/hyprland-snap-shot/protocols/**') }}
|
|
|
|
- name: Setup Rust
|
|
if: steps.resource_monitor_cache.outputs.cache-hit != 'true' || (inputs.platform == 'linux' && steps.capture_helper_cache.outputs.cache-hit != 'true')
|
|
uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable
|
|
with:
|
|
toolchain: stable
|
|
targets: ${{ inputs.rust_target }}
|
|
|
|
- name: Download relay client tracing config
|
|
if: inputs.relay_client_tracing
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: relay-client-tracing-config
|
|
path: ${{ runner.temp }}/relay-client-tracing
|
|
|
|
- name: Load relay client tracing config
|
|
if: inputs.relay_client_tracing
|
|
shell: bash
|
|
run: |
|
|
config_path="$RUNNER_TEMP/relay-client-tracing/relay-client-tracing.env"
|
|
tracing_token="$(sed -n 's/^T3CODE_RELAY_CLIENT_OTLP_TRACES_TOKEN=//p' "$config_path")"
|
|
echo "::add-mask::$tracing_token"
|
|
cat "$config_path" >> "$GITHUB_ENV"
|
|
|
|
- name: Align package versions to release version
|
|
run: node scripts/update-release-package-versions.ts "${{ inputs.version }}"
|
|
|
|
# The artifact root is `apps/` (upload-artifact keeps the least common
|
|
# ancestor of its paths), so extracting into `apps` restores
|
|
# apps/server/dist and apps/desktop/dist-electron at their build paths.
|
|
- name: Download JS bundle
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: js-bundle
|
|
path: apps
|
|
|
|
# Only the resource monitor build needs these libraries. With a cached
|
|
# monitor, the desktop build's preflight skips its MSVC check, and node-pty
|
|
# ships prebuilt Windows binaries, so the 30-60s install is skipped too.
|
|
- name: Install Spectre-mitigated MSVC libs
|
|
if: inputs.platform == 'win' && steps.resource_monitor_cache.outputs.cache-hit != 'true'
|
|
shell: pwsh
|
|
run: |
|
|
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
|
|
$installPath = & $vswhere -products * -latest -property installationPath
|
|
$setupExe = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\setup.exe"
|
|
$proc = Start-Process -FilePath $setupExe `
|
|
-ArgumentList "modify", "--installPath", "`"$installPath`"", "--add", `
|
|
"Microsoft.VisualStudio.Component.VC.Runtimes.${{ inputs.arch == 'arm64' && 'ARM64' || 'x86.x64' }}.Spectre", "--quiet", "--norestart" `
|
|
-Wait -PassThru -NoNewWindow
|
|
if ($null -eq $proc -or $proc.ExitCode -ne 0) {
|
|
$code = if ($null -ne $proc) { $proc.ExitCode } else { 1 }
|
|
Write-Error "Visual Studio Installer failed with exit code $code"
|
|
exit $code
|
|
}
|
|
|
|
- uses: ./.github/actions/setup-apt-mirrors
|
|
if: inputs.platform == 'linux'
|
|
|
|
- name: Install Linux desktop build libraries
|
|
if: inputs.platform == 'linux'
|
|
shell: bash
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y libsecret-1-dev pkg-config
|
|
if ! command -v magick >/dev/null 2>&1 && ! command -v convert >/dev/null 2>&1; then
|
|
sudo apt-get install -y imagemagick
|
|
fi
|
|
|
|
if command -v magick >/dev/null 2>&1; then
|
|
magick -version
|
|
else
|
|
convert -version
|
|
fi
|
|
|
|
- name: Prepare Azure Trusted Signing
|
|
if: inputs.platform == 'win'
|
|
shell: pwsh
|
|
env:
|
|
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
|
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
|
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
|
|
AZURE_TRUSTED_SIGNING_ENDPOINT: ${{ secrets.AZURE_TRUSTED_SIGNING_ENDPOINT }}
|
|
AZURE_TRUSTED_SIGNING_ACCOUNT_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
|
|
AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME }}
|
|
AZURE_TRUSTED_SIGNING_PUBLISHER_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_PUBLISHER_NAME }}
|
|
run: |
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$requiredSecrets = @(
|
|
$env:AZURE_TENANT_ID,
|
|
$env:AZURE_CLIENT_ID,
|
|
$env:AZURE_CLIENT_SECRET,
|
|
$env:AZURE_TRUSTED_SIGNING_ENDPOINT,
|
|
$env:AZURE_TRUSTED_SIGNING_ACCOUNT_NAME,
|
|
$env:AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME,
|
|
$env:AZURE_TRUSTED_SIGNING_PUBLISHER_NAME
|
|
)
|
|
if ($requiredSecrets | Where-Object { [string]::IsNullOrWhiteSpace($_) }) {
|
|
Write-Host "Azure Trusted Signing disabled; skipping TrustedSigning module preparation."
|
|
exit 0
|
|
}
|
|
|
|
try {
|
|
Install-PackageProvider `
|
|
-Name NuGet `
|
|
-MinimumVersion 2.8.5.201 `
|
|
-Force `
|
|
-Scope CurrentUser `
|
|
-ErrorAction Stop
|
|
} catch {
|
|
Write-Warning "Could not bootstrap NuGet package provider. Continuing because the runner may already have a usable provider. $($_.Exception.Message)"
|
|
}
|
|
|
|
Install-Module `
|
|
-Name TrustedSigning `
|
|
-MinimumVersion 0.5.0 `
|
|
-Force `
|
|
-AllowClobber `
|
|
-Repository PSGallery `
|
|
-Scope CurrentUser `
|
|
-ErrorAction Stop
|
|
|
|
Import-Module TrustedSigning -MinimumVersion 0.5.0 -Force
|
|
Get-Command Invoke-TrustedSigning -ErrorAction Stop
|
|
|
|
$moduleRoots = @(
|
|
[System.IO.Path]::Combine([Environment]::GetFolderPath("MyDocuments"), "PowerShell", "Modules"),
|
|
[System.IO.Path]::Combine([Environment]::GetFolderPath("MyDocuments"), "WindowsPowerShell", "Modules"),
|
|
[System.IO.Path]::Combine($env:ProgramFiles, "PowerShell", "Modules"),
|
|
[System.IO.Path]::Combine($env:ProgramFiles, "WindowsPowerShell", "Modules")
|
|
)
|
|
$modulePathEntries = @($moduleRoots + ($env:PSModulePath -split ";")) |
|
|
Where-Object { $_ -and (Test-Path $_) } |
|
|
Select-Object -Unique
|
|
"PSModulePath=$($modulePathEntries -join ';')" >> $env:GITHUB_ENV
|
|
|
|
# The WSL backend runs the Linux CLI archive inside the distro, so the
|
|
# Windows desktop embeds the same-arch archive the release attaches.
|
|
# This job starts alongside that Linux job instead of after it, and the
|
|
# Linux job uploads the archive partway through, so the wait is placed
|
|
# after all other setup. It stops early if the Linux job ended without
|
|
# uploading the archive.
|
|
- name: Wait for Linux CLI archive
|
|
if: inputs.platform == 'win'
|
|
shell: pwsh
|
|
timeout-minutes: 40
|
|
env:
|
|
GITHUB_TOKEN: ${{ github.token }}
|
|
ARTIFACT: cli-linux-${{ inputs.arch }}
|
|
LINUX_JOB: Build Linux ${{ inputs.arch }}
|
|
run: |
|
|
$headers = @{ Authorization = "Bearer $env:GITHUB_TOKEN"; Accept = "application/vnd.github+json" }
|
|
$run = "$env:GITHUB_API_URL/repos/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID"
|
|
function Test-Archive {
|
|
(Invoke-RestMethod -Headers $headers -Uri "$run/artifacts?name=$env:ARTIFACT").total_count -gt 0
|
|
}
|
|
$missingSince = $null
|
|
while ($true) {
|
|
try {
|
|
if (Test-Archive) {
|
|
Write-Host "$env:ARTIFACT is ready."
|
|
exit 0
|
|
}
|
|
$jobs = Invoke-RestMethod -Headers $headers -Uri "$run/attempts/$env:GITHUB_RUN_ATTEMPT/jobs?per_page=100"
|
|
$linux = $jobs.jobs | Where-Object { $_.name.EndsWith($env:LINUX_JOB) } | Select-Object -First 1
|
|
if (-not $linux) {
|
|
# Both jobs start together, so a Linux job still missing after a
|
|
# few minutes means a renamed or skipped job, not a slow one.
|
|
if (-not $missingSince) {
|
|
$missingSince = Get-Date
|
|
} elseif (((Get-Date) - $missingSince).TotalMinutes -ge 5) {
|
|
Write-Host "::error::No job named '$env:LINUX_JOB' in this run, so $env:ARTIFACT will not arrive."
|
|
exit 1
|
|
}
|
|
} elseif ($linux.conclusion) {
|
|
# The upload may have landed between the two requests above.
|
|
if (Test-Archive) {
|
|
Write-Host "$env:ARTIFACT is ready."
|
|
exit 0
|
|
}
|
|
Write-Host "::error::$env:LINUX_JOB ended ($($linux.conclusion)) without uploading $env:ARTIFACT."
|
|
exit 1
|
|
}
|
|
} catch {
|
|
Write-Warning "Could not read this run's artifacts or jobs: $($_.Exception.Message)"
|
|
}
|
|
Write-Host "Waiting for $env:ARTIFACT..."
|
|
Start-Sleep -Seconds 10
|
|
}
|
|
|
|
- name: Download Linux CLI archive for WSL
|
|
if: inputs.platform == 'win'
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: cli-linux-${{ inputs.arch }}
|
|
path: wsl-runtime
|
|
|
|
- name: Build desktop artifact
|
|
shell: bash
|
|
env:
|
|
pnpm_config_cache_dir: ${{ runner.temp }}/pnpm-metadata
|
|
T3CODE_DESKTOP_REUSE_RESOURCE_MONITOR: ${{ steps.resource_monitor_cache.outputs.cache-hit == 'true' }}
|
|
T3CODE_DESKTOP_REUSE_LINUX_CAPTURE_HELPERS: ${{ steps.capture_helper_cache.outputs.cache-hit == 'true' }}
|
|
CSC_LINK: ${{ secrets.CSC_LINK }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
|
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
|
|
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
|
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
|
APPLE_TEAM_ID: ${{ vars.APPLE_TEAM_ID }}
|
|
MACOS_PROVISIONING_PROFILE: ${{ secrets.MACOS_PROVISIONING_PROFILE }}
|
|
T3CODE_CLERK_PASSKEY_RP_DOMAINS: ${{ vars.CLERK_PASSKEY_RP_DOMAINS }}
|
|
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
|
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
|
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
|
|
AZURE_TRUSTED_SIGNING_ENDPOINT: ${{ secrets.AZURE_TRUSTED_SIGNING_ENDPOINT }}
|
|
AZURE_TRUSTED_SIGNING_ACCOUNT_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
|
|
AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME }}
|
|
AZURE_TRUSTED_SIGNING_PUBLISHER_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_PUBLISHER_NAME }}
|
|
run: |
|
|
args=(
|
|
--platform "${{ inputs.platform }}"
|
|
--target "${{ inputs.target }}"
|
|
--arch "${{ inputs.arch }}"
|
|
--build-version "${{ inputs.version }}"
|
|
--skip-build
|
|
--verbose
|
|
)
|
|
|
|
has_all() {
|
|
for value in "$@"; do
|
|
if [[ -z "$value" ]]; then
|
|
return 1
|
|
fi
|
|
done
|
|
return 0
|
|
}
|
|
|
|
if [[ "${{ inputs.platform }}" == "mac" ]]; then
|
|
if has_all "$CSC_LINK" "$CSC_KEY_PASSWORD" "$APPLE_API_KEY" "$APPLE_API_KEY_ID" "$APPLE_API_ISSUER"; then
|
|
if ! has_all "$APPLE_TEAM_ID" "$MACOS_PROVISIONING_PROFILE"; then
|
|
echo "macOS signing is configured, but APPLE_TEAM_ID or MACOS_PROVISIONING_PROFILE is missing." >&2
|
|
exit 1
|
|
fi
|
|
|
|
key_path="$RUNNER_TEMP/AuthKey_${APPLE_API_KEY_ID}.p8"
|
|
printf '%s' "$APPLE_API_KEY" > "$key_path"
|
|
export APPLE_API_KEY="$key_path"
|
|
|
|
profile_path="$RUNNER_TEMP/t3code.provisionprofile"
|
|
printf '%s' "$MACOS_PROVISIONING_PROFILE" | base64 -D > "$profile_path"
|
|
security cms -D -i "$profile_path" >/dev/null
|
|
export T3CODE_APPLE_TEAM_ID="$APPLE_TEAM_ID"
|
|
export T3CODE_MACOS_PROVISIONING_PROFILE="$profile_path"
|
|
|
|
echo "macOS signing enabled."
|
|
args+=(--signed)
|
|
else
|
|
echo "macOS signing disabled (missing one or more Apple signing secrets)."
|
|
fi
|
|
elif [[ "${{ inputs.platform }}" == "win" ]]; then
|
|
# Embed the Linux CLI archive built by the same-arch Linux job as
|
|
# the WSL runtime. Required for a working WSL backend on Windows.
|
|
args+=(--wsl-runtime "$GITHUB_WORKSPACE"/wsl-runtime/t3-*-linux-${{ inputs.arch }}.tar.gz)
|
|
if has_all \
|
|
"$AZURE_TENANT_ID" \
|
|
"$AZURE_CLIENT_ID" \
|
|
"$AZURE_CLIENT_SECRET" \
|
|
"$AZURE_TRUSTED_SIGNING_ENDPOINT" \
|
|
"$AZURE_TRUSTED_SIGNING_ACCOUNT_NAME" \
|
|
"$AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME" \
|
|
"$AZURE_TRUSTED_SIGNING_PUBLISHER_NAME"; then
|
|
echo "Windows signing enabled (Azure Trusted Signing)."
|
|
args+=(--signed)
|
|
else
|
|
echo "Windows signing disabled (missing one or more Azure Trusted Signing secrets)."
|
|
fi
|
|
else
|
|
echo "Signing disabled for ${{ inputs.platform }}."
|
|
fi
|
|
|
|
vp run dist:desktop:artifact "${args[@]}"
|
|
|
|
# The single-executable is built with a Node that supports --build-sea
|
|
# (25.7+); the repo itself stays on the engines.node version. It always
|
|
# injects into the runner's own Node: tsdown's cross-target download path
|
|
# runs `tar` on a drive-letter path on Windows, which GNU tar reads as a
|
|
# remote host, and a cross-built macOS binary cannot be smoke-tested.
|
|
- name: Build CLI single-executable
|
|
if: inputs.cli_archive
|
|
shell: bash
|
|
env:
|
|
# The exact version, not a major: vp downloads it from nodejs.org/dist on
|
|
# the runner, and only exact versions have a dist directory. Keep in
|
|
# step with SEA_NODE_VERSION in apps/server/vite.config.ts.
|
|
VP_NODE_VERSION: "26.8.2"
|
|
run: node apps/server/scripts/cli.ts build-exe --verbose
|
|
|
|
- name: Import macOS signing certificate for the CLI archive
|
|
if: inputs.cli_archive && inputs.platform == 'mac'
|
|
shell: bash
|
|
env:
|
|
CSC_LINK: ${{ secrets.CSC_LINK }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ -z "$CSC_LINK" || -z "$CSC_KEY_PASSWORD" ]]; then
|
|
echo "macOS CLI signing disabled (missing CSC_LINK); the archive is signed ad hoc."
|
|
exit 0
|
|
fi
|
|
keychain="$RUNNER_TEMP/t3-cli-signing.keychain-db"
|
|
keychain_password="$(openssl rand -hex 16)"
|
|
cert_path="$RUNNER_TEMP/t3-cli-signing.p12"
|
|
printf '%s' "$CSC_LINK" | base64 --decode > "$cert_path"
|
|
security create-keychain -p "$keychain_password" "$keychain"
|
|
security set-keychain-settings -lut 21600 "$keychain"
|
|
security unlock-keychain -p "$keychain_password" "$keychain"
|
|
security import "$cert_path" -k "$keychain" -P "$CSC_KEY_PASSWORD" -T /usr/bin/codesign
|
|
security set-key-partition-list -S apple-tool:,apple: -s -k "$keychain_password" "$keychain" >/dev/null
|
|
security list-keychains -d user -s "$keychain" $(security list-keychains -d user | tr -d '"')
|
|
identity="$(security find-identity -v -p codesigning "$keychain" | sed -n 's/.*"\(Developer ID Application: [^"]*\)".*/\1/p' | head -n 1)"
|
|
if [[ -z "$identity" ]]; then
|
|
echo "No Developer ID Application identity found in CSC_LINK." >&2
|
|
exit 1
|
|
fi
|
|
echo "::add-mask::$keychain_password"
|
|
echo "T3CODE_CLI_MAC_SIGN_IDENTITY=$identity" >> "$GITHUB_ENV"
|
|
echo "macOS CLI signing enabled."
|
|
|
|
- name: Stage resource monitor for the CLI archive
|
|
if: inputs.cli_archive
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
binary_name="t3-resource-monitor"
|
|
if [[ "${{ inputs.platform }}" == "win" ]]; then
|
|
binary_name="${binary_name}.exe"
|
|
fi
|
|
target_dir="$RUNNER_TEMP/cli-resource-monitor/${{ inputs.resource_key }}"
|
|
mkdir -p "$target_dir"
|
|
cp "native/resource-monitor/target/${{ inputs.rust_target }}/release/${binary_name}" "$target_dir/$binary_name"
|
|
|
|
- name: Build CLI archive
|
|
if: inputs.cli_archive
|
|
shell: bash
|
|
env:
|
|
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
|
|
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
|
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
|
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
|
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
|
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
|
|
AZURE_TRUSTED_SIGNING_ENDPOINT: ${{ secrets.AZURE_TRUSTED_SIGNING_ENDPOINT }}
|
|
AZURE_TRUSTED_SIGNING_ACCOUNT_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
|
|
AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ "${{ inputs.platform }}" == "mac" && -n "${APPLE_API_KEY:-}" ]]; then
|
|
key_path="$RUNNER_TEMP/AuthKey_cli_${APPLE_API_KEY_ID}.p8"
|
|
printf '%s' "$APPLE_API_KEY" > "$key_path"
|
|
export APPLE_API_KEY="$key_path"
|
|
fi
|
|
node scripts/build-cli-archive.ts \
|
|
--platform "${{ inputs.platform }}" \
|
|
--arch "${{ inputs.arch }}" \
|
|
--version "${{ inputs.version }}" \
|
|
--resource-monitor-dir "$RUNNER_TEMP/cli-resource-monitor" \
|
|
--output-dir release-cli
|
|
|
|
- name: Smoke-test CLI archive
|
|
if: inputs.cli_archive
|
|
shell: bash
|
|
run: node scripts/smoke-cli-archive.ts --archive release-cli/* --expect-version "${{ inputs.version }}"
|
|
|
|
- name: Upload CLI archive
|
|
if: inputs.cli_archive
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: cli-${{ inputs.platform }}-${{ inputs.arch }}
|
|
path: release-cli/*
|
|
if-no-files-found: error
|
|
|
|
- name: Collect release assets
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p release-publish
|
|
|
|
shopt -s nullglob
|
|
patterns=(
|
|
"release/*.dmg"
|
|
"release/*.zip"
|
|
"release/*.AppImage"
|
|
"release/*.deb"
|
|
"release/*.exe"
|
|
)
|
|
# Preview builds have no publish config, so electron-builder writes
|
|
# no feed manifest for them, but it still emits blockmaps beside the
|
|
# installers. Neither belongs on a release no updater may follow.
|
|
if [[ "${{ inputs.release_channel }}" != "preview" ]]; then
|
|
patterns+=("release/*.blockmap" "release/*.yml")
|
|
fi
|
|
for pattern in "${patterns[@]}"; do
|
|
for file in $pattern; do
|
|
cp "$file" release-publish/
|
|
done
|
|
done
|
|
|
|
if [[ "${{ inputs.platform }}" == "mac" && "${{ inputs.arch }}" != "arm64" ]]; then
|
|
shopt -s nullglob
|
|
for manifest in release-publish/*-mac.yml; do
|
|
mv "$manifest" "${manifest%.yml}-${{ inputs.arch }}.yml"
|
|
done
|
|
fi
|
|
|
|
# Windows updater metadata is channel-specific (for example
|
|
# "latest.yml" or "nightly.yml") and carries no arch, so the x64 and
|
|
# arm64 jobs would upload the same name. Suffix each per-arch copy;
|
|
# the release job merges them back into one manifest per channel.
|
|
# builder-debug.yml is electron-builder's config dump, not a feed.
|
|
if [[ "${{ inputs.platform }}" == "win" ]]; then
|
|
for manifest in release-publish/*.yml; do
|
|
[[ "$manifest" == */builder-debug.yml ]] && continue
|
|
mv "$manifest" "${manifest%.yml}-win-${{ inputs.arch }}.yml"
|
|
done
|
|
fi
|
|
|
|
- name: Collect resource monitor
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
binary_name="t3-resource-monitor"
|
|
if [[ "${{ inputs.platform }}" == "win" ]]; then
|
|
binary_name="${binary_name}.exe"
|
|
fi
|
|
source_path="native/resource-monitor/target/${{ inputs.rust_target }}/release/${binary_name}"
|
|
target_dir="resource-monitor-publish/${{ inputs.resource_key }}"
|
|
mkdir -p "$target_dir"
|
|
cp "$source_path" "$target_dir/$binary_name"
|
|
|
|
- name: Upload build artifacts
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: desktop-${{ inputs.platform }}-${{ inputs.arch }}
|
|
path: release-publish/*
|
|
if-no-files-found: error
|
|
|
|
- name: Upload resource monitor
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: resource-monitor-${{ inputs.resource_key }}
|
|
path: resource-monitor-publish/${{ inputs.resource_key }}/*
|
|
if-no-files-found: error
|