| ... | ... | @@ -359,13 +359,25 @@ jobs: |
| 359 | 359 | # the Windows desktop entry embeds it as the WSL runtime. Building it once |
| 360 | 360 | # here means the WSL backend runs the exact bytes a Linux user downloads. |
| 361 | 361 | build_linux_cli: |
| 362 | | name: Build CLI archive (linux-x64) |
| 362 | name: Build CLI archive (linux-${{ matrix.arch }}) |
| 363 | 363 | # Same gating as relay_public_config: only the release commit is needed, so |
| 364 | 364 | # this runs alongside preflight. See the condition comment there. |
| 365 | 365 | needs: [resolve_commit, preflight, relay_public_config] |
| 366 | 366 | if: ${{ !cancelled() && needs.preflight.result == 'success' && needs.relay_public_config.result == 'success' }} |
| 367 | | runs-on: blacksmith-32vcpu-ubuntu-2404 |
| 368 | | timeout-minutes: 20 |
| 367 | runs-on: ${{ matrix.runner }} |
| 368 | timeout-minutes: 30 |
| 369 | strategy: |
| 370 | fail-fast: false |
| 371 | matrix: |
| 372 | include: |
| 373 | - arch: x64 |
| 374 | runner: blacksmith-32vcpu-ubuntu-2404 |
| 375 | rust_target: x86_64-unknown-linux-gnu |
| 376 | # node-pty has no Linux prebuild and compiles from source, so the |
| 377 | # arm64 archive is built on arm64 hardware rather than cross-built. |
| 378 | - arch: arm64 |
| 379 | runner: ubuntu-24.04-arm |
| 380 | rust_target: aarch64-unknown-linux-gnu |
| 369 | 381 | env: |
| 370 | 382 | T3CODE_CLERK_PUBLISHABLE_KEY: ${{ needs.relay_public_config.outputs.clerk_publishable_key }} |
| 371 | 383 | T3CODE_CLERK_JWT_TEMPLATE: ${{ needs.relay_public_config.outputs.clerk_jwt_template }} |
| ... | ... | @@ -396,18 +408,18 @@ jobs: |
| 396 | 408 | id: resource_monitor_cache |
| 397 | 409 | uses: actions/cache@v6 |
| 398 | 410 | with: |
| 399 | | path: native/resource-monitor/target/x86_64-unknown-linux-gnu/release/t3-resource-monitor |
| 400 | | key: resource-monitor-x86_64-unknown-linux-gnu-${{ hashFiles('native/resource-monitor/Cargo.lock', 'native/resource-monitor/Cargo.toml', 'native/resource-monitor/src/**') }} |
| 411 | path: native/resource-monitor/target/${{ matrix.rust_target }}/release/t3-resource-monitor |
| 412 | key: resource-monitor-${{ matrix.rust_target }}-${{ hashFiles('native/resource-monitor/Cargo.lock', 'native/resource-monitor/Cargo.toml', 'native/resource-monitor/src/**') }} |
| 401 | 413 | |
| 402 | 414 | - name: Setup Rust |
| 403 | 415 | if: steps.resource_monitor_cache.outputs.cache-hit != 'true' |
| 404 | 416 | uses: dtolnay/rust-toolchain@stable |
| 405 | 417 | with: |
| 406 | | targets: x86_64-unknown-linux-gnu |
| 418 | targets: ${{ matrix.rust_target }} |
| 407 | 419 | |
| 408 | 420 | - name: Build resource monitor |
| 409 | 421 | if: steps.resource_monitor_cache.outputs.cache-hit != 'true' |
| 410 | | run: cargo build --locked --release --manifest-path native/resource-monitor/Cargo.toml --target x86_64-unknown-linux-gnu |
| 422 | run: cargo build --locked --release --manifest-path native/resource-monitor/Cargo.toml --target ${{ matrix.rust_target }} |
| 411 | 423 | |
| 412 | 424 | - name: Download relay client tracing config |
| 413 | 425 | uses: actions/download-artifact@v8 |
| ... | ... | @@ -442,15 +454,15 @@ jobs: |
| 442 | 454 | - name: Stage resource monitor for the CLI archive |
| 443 | 455 | run: | |
| 444 | 456 | set -euo pipefail |
| 445 | | target_dir="$RUNNER_TEMP/cli-resource-monitor/linux-x64" |
| 457 | target_dir="$RUNNER_TEMP/cli-resource-monitor/linux-${{ matrix.arch }}" |
| 446 | 458 | mkdir -p "$target_dir" |
| 447 | | cp native/resource-monitor/target/x86_64-unknown-linux-gnu/release/t3-resource-monitor "$target_dir/" |
| 459 | cp native/resource-monitor/target/${{ matrix.rust_target }}/release/t3-resource-monitor "$target_dir/" |
| 448 | 460 | |
| 449 | 461 | - name: Build CLI archive |
| 450 | 462 | run: | |
| 451 | 463 | node scripts/build-cli-archive.ts \ |
| 452 | 464 | --platform linux \ |
| 453 | | --arch x64 \ |
| 465 | --arch ${{ matrix.arch }} \ |
| 454 | 466 | --version "${{ needs.preflight.outputs.version }}" \ |
| 455 | 467 | --resource-monitor-dir "$RUNNER_TEMP/cli-resource-monitor" \ |
| 456 | 468 | --output-dir release-cli |
| ... | ... | @@ -461,7 +473,183 @@ jobs: |
| 461 | 473 | - name: Upload CLI archive |
| 462 | 474 | uses: actions/upload-artifact@v7 |
| 463 | 475 | with: |
| 464 | | name: cli-linux-x64 |
| 476 | name: cli-linux-${{ matrix.arch }} |
| 477 | path: release-cli/* |
| 478 | if-no-files-found: error |
| 479 | |
| 480 | # Windows arm64 has no desktop build yet (the NSIS arm64 row is still off), |
| 481 | # but the CLI archive is built here on arm64 hardware so it is signed and |
| 482 | # smoke-tested on the architecture it targets, like every other archive. |
| 483 | build_windows_arm64_cli: |
| 484 | name: Build CLI archive (win32-arm64) |
| 485 | needs: [resolve_commit, preflight, relay_public_config] |
| 486 | if: ${{ !cancelled() && needs.preflight.result == 'success' && needs.relay_public_config.result == 'success' }} |
| 487 | runs-on: windows-11-arm |
| 488 | timeout-minutes: 30 |
| 489 | env: |
| 490 | T3CODE_CLERK_PUBLISHABLE_KEY: ${{ needs.relay_public_config.outputs.clerk_publishable_key }} |
| 491 | T3CODE_CLERK_JWT_TEMPLATE: ${{ needs.relay_public_config.outputs.clerk_jwt_template }} |
| 492 | T3CODE_CLERK_CLI_OAUTH_CLIENT_ID: ${{ needs.relay_public_config.outputs.clerk_cli_oauth_client_id }} |
| 493 | T3CODE_RELAY_URL: ${{ needs.relay_public_config.outputs.relay_url }} |
| 494 | steps: |
| 495 | - name: Checkout |
| 496 | uses: actions/checkout@v6 |
| 497 | with: |
| 498 | ref: ${{ needs.preflight.outputs.ref }} |
| 499 | sparse-checkout: | |
| 500 | /* |
| 501 | !/.repos/ |
| 502 | sparse-checkout-cone-mode: false |
| 503 | |
| 504 | - name: Setup Vite+ |
| 505 | uses: voidzero-dev/setup-vp@v1 |
| 506 | with: |
| 507 | node-version-file: package.json |
| 508 | cache: false |
| 509 | run-install: false |
| 510 | |
| 511 | - name: Download dependency verification |
| 512 | continue-on-error: true |
| 513 | uses: actions/download-artifact@v8 |
| 514 | with: |
| 515 | name: release-dependency-verification |
| 516 | path: ${{ runner.temp }}/pnpm-metadata |
| 517 | |
| 518 | - name: Install dependencies |
| 519 | env: |
| 520 | pnpm_config_cache_dir: ${{ runner.temp }}/pnpm-metadata |
| 521 | run: vp install --filter=t3... --filter=@t3tools/web... --filter=@t3tools/scripts... |
| 522 | |
| 523 | - name: Setup Rust |
| 524 | uses: dtolnay/rust-toolchain@stable |
| 525 | with: |
| 526 | targets: aarch64-pc-windows-msvc |
| 527 | |
| 528 | - name: Build resource monitor |
| 529 | run: cargo build --locked --release --manifest-path native/resource-monitor/Cargo.toml --target aarch64-pc-windows-msvc |
| 530 | |
| 531 | - name: Download relay client tracing config |
| 532 | uses: actions/download-artifact@v8 |
| 533 | with: |
| 534 | name: relay-client-tracing-config |
| 535 | path: ${{ runner.temp }}/relay-client-tracing |
| 536 | |
| 537 | - name: Load relay client tracing config |
| 538 | shell: bash |
| 539 | run: | |
| 540 | config_path="$RUNNER_TEMP/relay-client-tracing/relay-client-tracing.env" |
| 541 | tracing_token="$(sed -n 's/^T3CODE_RELAY_CLIENT_OTLP_TRACES_TOKEN=//p' "$config_path")" |
| 542 | echo "::add-mask::$tracing_token" |
| 543 | cat "$config_path" >> "$GITHUB_ENV" |
| 544 | |
| 545 | - name: Align package versions to release version |
| 546 | run: node scripts/update-release-package-versions.ts "${{ needs.preflight.outputs.version }}" |
| 547 | |
| 548 | # The t3 build task depends on @t3tools/web#build, so the web client is |
| 549 | # built as part of this step. |
| 550 | - name: Build CLI package |
| 551 | run: vp run --filter t3 build |
| 552 | |
| 553 | - name: Build CLI single-executable |
| 554 | shell: bash |
| 555 | env: |
| 556 | VP_NODE_VERSION: "26.8.2" |
| 557 | run: node apps/server/scripts/cli.ts build-exe --verbose |
| 558 | |
| 559 | - name: Prepare Azure Trusted Signing |
| 560 | shell: pwsh |
| 561 | env: |
| 562 | AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} |
| 563 | AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} |
| 564 | AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} |
| 565 | AZURE_TRUSTED_SIGNING_ENDPOINT: ${{ secrets.AZURE_TRUSTED_SIGNING_ENDPOINT }} |
| 566 | AZURE_TRUSTED_SIGNING_ACCOUNT_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }} |
| 567 | AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME }} |
| 568 | AZURE_TRUSTED_SIGNING_PUBLISHER_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_PUBLISHER_NAME }} |
| 569 | run: | |
| 570 | $ErrorActionPreference = "Stop" |
| 571 | |
| 572 | $requiredSecrets = @( |
| 573 | $env:AZURE_TENANT_ID, |
| 574 | $env:AZURE_CLIENT_ID, |
| 575 | $env:AZURE_CLIENT_SECRET, |
| 576 | $env:AZURE_TRUSTED_SIGNING_ENDPOINT, |
| 577 | $env:AZURE_TRUSTED_SIGNING_ACCOUNT_NAME, |
| 578 | $env:AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME, |
| 579 | $env:AZURE_TRUSTED_SIGNING_PUBLISHER_NAME |
| 580 | ) |
| 581 | if ($requiredSecrets | Where-Object { [string]::IsNullOrWhiteSpace($_) }) { |
| 582 | Write-Host "Azure Trusted Signing disabled; skipping TrustedSigning module preparation." |
| 583 | exit 0 |
| 584 | } |
| 585 | |
| 586 | try { |
| 587 | Install-PackageProvider ` |
| 588 | -Name NuGet ` |
| 589 | -MinimumVersion 2.8.5.201 ` |
| 590 | -Force ` |
| 591 | -Scope CurrentUser ` |
| 592 | -ErrorAction Stop |
| 593 | } catch { |
| 594 | Write-Warning "Could not bootstrap NuGet package provider. Continuing because the runner may already have a usable provider. $($_.Exception.Message)" |
| 595 | } |
| 596 | |
| 597 | Install-Module ` |
| 598 | -Name TrustedSigning ` |
| 599 | -MinimumVersion 0.5.0 ` |
| 600 | -Force ` |
| 601 | -AllowClobber ` |
| 602 | -Repository PSGallery ` |
| 603 | -Scope CurrentUser ` |
| 604 | -ErrorAction Stop |
| 605 | |
| 606 | Import-Module TrustedSigning -MinimumVersion 0.5.0 -Force |
| 607 | Get-Command Invoke-TrustedSigning -ErrorAction Stop |
| 608 | |
| 609 | $moduleRoots = @( |
| 610 | [System.IO.Path]::Combine([Environment]::GetFolderPath("MyDocuments"), "PowerShell", "Modules"), |
| 611 | [System.IO.Path]::Combine([Environment]::GetFolderPath("MyDocuments"), "WindowsPowerShell", "Modules"), |
| 612 | [System.IO.Path]::Combine($env:ProgramFiles, "PowerShell", "Modules"), |
| 613 | [System.IO.Path]::Combine($env:ProgramFiles, "WindowsPowerShell", "Modules") |
| 614 | ) |
| 615 | $modulePathEntries = @($moduleRoots + ($env:PSModulePath -split ";")) | |
| 616 | Where-Object { $_ -and (Test-Path $_) } | |
| 617 | Select-Object -Unique |
| 618 | "PSModulePath=$($modulePathEntries -join ';')" >> $env:GITHUB_ENV |
| 619 | |
| 620 | - name: Stage resource monitor for the CLI archive |
| 621 | shell: bash |
| 622 | run: | |
| 623 | set -euo pipefail |
| 624 | target_dir="$RUNNER_TEMP/cli-resource-monitor/win32-arm64" |
| 625 | mkdir -p "$target_dir" |
| 626 | cp native/resource-monitor/target/aarch64-pc-windows-msvc/release/t3-resource-monitor.exe "$target_dir/" |
| 627 | |
| 628 | - name: Build CLI archive |
| 629 | shell: bash |
| 630 | env: |
| 631 | AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} |
| 632 | AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} |
| 633 | AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} |
| 634 | AZURE_TRUSTED_SIGNING_ENDPOINT: ${{ secrets.AZURE_TRUSTED_SIGNING_ENDPOINT }} |
| 635 | AZURE_TRUSTED_SIGNING_ACCOUNT_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }} |
| 636 | AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME }} |
| 637 | run: | |
| 638 | node scripts/build-cli-archive.ts \ |
| 639 | --platform win \ |
| 640 | --arch arm64 \ |
| 641 | --version "${{ needs.preflight.outputs.version }}" \ |
| 642 | --resource-monitor-dir "$RUNNER_TEMP/cli-resource-monitor" \ |
| 643 | --output-dir release-cli |
| 644 | |
| 645 | - name: Smoke-test CLI archive |
| 646 | shell: bash |
| 647 | run: node scripts/smoke-cli-archive.ts --archive release-cli/* --expect-version "${{ needs.preflight.outputs.version }}" |
| 648 | |
| 649 | - name: Upload CLI archive |
| 650 | uses: actions/upload-artifact@v7 |
| 651 | with: |
| 652 | name: cli-win-arm64 |
| 465 | 653 | path: release-cli/* |
| 466 | 654 | if-no-files-found: error |
| 467 | 655 | |
| ... | ... | @@ -488,11 +676,9 @@ jobs: |
| 488 | 676 | matrix: |
| 489 | 677 | include: |
| 490 | 678 | # cli_archive: whether the job also builds the self-contained CLI |
| 491 | | # archive. The executable is built on the runner's own Node, so only |
| 492 | | # native runners qualify. macOS x64 has no native runner: a |
| 493 | | # cross-built executable crashed under Rosetta in the smoke test and |
| 494 | | # cannot be verified on real x64 hardware in CI, so it is skipped |
| 495 | | # until it can be. |
| 679 | # archive for its own platform/arch, on this runner, and smoke-tests |
| 680 | # it here. Every archive is built on hardware of its own |
| 681 | # architecture: Linux and Windows arm64 have their own jobs below. |
| 496 | 682 | - label: macOS arm64 |
| 497 | 683 | runner: blacksmith-12vcpu-macos-26 |
| 498 | 684 | platform: mac |
| ... | ... | @@ -501,6 +687,9 @@ jobs: |
| 501 | 687 | rust_target: aarch64-apple-darwin |
| 502 | 688 | resource_key: darwin-arm64 |
| 503 | 689 | cli_archive: true |
| 690 | # No CLI archive: Node single-executables are unsupported on x64 |
| 691 | # macOS (the SEA docs list macOS as arm64 only) and the built binary |
| 692 | # segfaults on start. The x64 desktop app is Electron and unaffected. |
| 504 | 693 | - label: macOS x64 |
| 505 | 694 | runner: blacksmith-12vcpu-macos-26 |
| 506 | 695 | platform: mac |
| ... | ... | @@ -1058,8 +1247,8 @@ jobs: |
| 1058 | 1247 | |
| 1059 | 1248 | release: |
| 1060 | 1249 | name: Publish GitHub Release |
| 1061 | | needs: [preflight, build, publish_cli] |
| 1062 | | if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' && needs.build.result == 'success' && (needs.publish_cli.result == 'success' || (needs.preflight.outputs.release_channel == 'preview' && needs.publish_cli.result == 'skipped')) }} |
| 1250 | needs: [preflight, build, build_windows_arm64_cli, publish_cli] |
| 1251 | if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' && needs.build.result == 'success' && needs.build_windows_arm64_cli.result == 'success' && (needs.publish_cli.result == 'success' || (needs.preflight.outputs.release_channel == 'preview' && needs.publish_cli.result == 'skipped')) }} |
| 1063 | 1252 | runs-on: blacksmith-8vcpu-ubuntu-2404 |
| 1064 | 1253 | timeout-minutes: 30 |
| 1065 | 1254 | permissions: |