| ... | @@ -359,13 +359,25 @@ jobs: | ... | @@ -359,13 +359,25 @@ jobs: |
| 359 | # the Windows desktop entry embeds it as the WSL runtime. Building it once | 359 | # the Windows desktop entry embeds it as the WSL runtime. Building it once |
| 360 | # here means the WSL backend runs the exact bytes a Linux user downloads. | 360 | # here means the WSL backend runs the exact bytes a Linux user downloads. |
| 361 | build_linux_cli: | 361 | build_linux_cli: |
| 362 | name: Build CLI archive (linux-x64) | 362 | name: Build CLI archive (linux-${{ matrix.arch }}) |
| 363 | # Same gating as relay_public_config: only the release commit is needed, so | 363 | # Same gating as relay_public_config: only the release commit is needed, so |
| 364 | # this runs alongside preflight. See the condition comment there. | 364 | # this runs alongside preflight. See the condition comment there. |
| 365 | needs: [resolve_commit, preflight, relay_public_config] | 365 | needs: [resolve_commit, preflight, relay_public_config] |
| 366 | if: ${{ !cancelled() && needs.preflight.result == 'success' && needs.relay_public_config.result == 'success' }} | 366 | if: ${{ !cancelled() && needs.preflight.result == 'success' && needs.relay_public_config.result == 'success' }} |
| 367 | runs-on: blacksmith-32vcpu-ubuntu-2404 | 367 | runs-on: ${{ matrix.runner }} |
| 368 | timeout-minutes: 20 | 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 | env: | 381 | env: |
| 370 | T3CODE_CLERK_PUBLISHABLE_KEY: ${{ needs.relay_public_config.outputs.clerk_publishable_key }} | 382 | T3CODE_CLERK_PUBLISHABLE_KEY: ${{ needs.relay_public_config.outputs.clerk_publishable_key }} |
| 371 | T3CODE_CLERK_JWT_TEMPLATE: ${{ needs.relay_public_config.outputs.clerk_jwt_template }} | 383 | T3CODE_CLERK_JWT_TEMPLATE: ${{ needs.relay_public_config.outputs.clerk_jwt_template }} |
| ... | @@ -396,18 +408,18 @@ jobs: | ... | @@ -396,18 +408,18 @@ jobs: |
| 396 | id: resource_monitor_cache | 408 | id: resource_monitor_cache |
| 397 | uses: actions/cache@v6 | 409 | uses: actions/cache@v6 |
| 398 | with: | 410 | with: |
| 399 | path: native/resource-monitor/target/x86_64-unknown-linux-gnu/release/t3-resource-monitor | 411 | path: native/resource-monitor/target/${{ matrix.rust_target }}/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/**') }} | 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 | - name: Setup Rust | 414 | - name: Setup Rust |
| 403 | if: steps.resource_monitor_cache.outputs.cache-hit != 'true' | 415 | if: steps.resource_monitor_cache.outputs.cache-hit != 'true' |
| 404 | uses: dtolnay/rust-toolchain@stable | 416 | uses: dtolnay/rust-toolchain@stable |
| 405 | with: | 417 | with: |
| 406 | targets: x86_64-unknown-linux-gnu | 418 | targets: ${{ matrix.rust_target }} |
| 407 | | 419 | |
| 408 | - name: Build resource monitor | 420 | - name: Build resource monitor |
| 409 | if: steps.resource_monitor_cache.outputs.cache-hit != 'true' | 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 | - name: Download relay client tracing config | 424 | - name: Download relay client tracing config |
| 413 | uses: actions/download-artifact@v8 | 425 | uses: actions/download-artifact@v8 |
| ... | @@ -442,15 +454,15 @@ jobs: | ... | @@ -442,15 +454,15 @@ jobs: |
| 442 | - name: Stage resource monitor for the CLI archive | 454 | - name: Stage resource monitor for the CLI archive |
| 443 | run: | | 455 | run: | |
| 444 | set -euo pipefail | 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 | mkdir -p "$target_dir" | 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 | - name: Build CLI archive | 461 | - name: Build CLI archive |
| 450 | run: | | 462 | run: | |
| 451 | node scripts/build-cli-archive.ts \ | 463 | node scripts/build-cli-archive.ts \ |
| 452 | --platform linux \ | 464 | --platform linux \ |
| 453 | --arch x64 \ | 465 | --arch ${{ matrix.arch }} \ |
| 454 | --version "${{ needs.preflight.outputs.version }}" \ | 466 | --version "${{ needs.preflight.outputs.version }}" \ |
| 455 | --resource-monitor-dir "$RUNNER_TEMP/cli-resource-monitor" \ | 467 | --resource-monitor-dir "$RUNNER_TEMP/cli-resource-monitor" \ |
| 456 | --output-dir release-cli | 468 | --output-dir release-cli |
| ... | @@ -461,7 +473,183 @@ jobs: | ... | @@ -461,7 +473,183 @@ jobs: |
| 461 | - name: Upload CLI archive | 473 | - name: Upload CLI archive |
| 462 | uses: actions/upload-artifact@v7 | 474 | uses: actions/upload-artifact@v7 |
| 463 | with: | 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 | path: release-cli/* | 653 | path: release-cli/* |
| 466 | if-no-files-found: error | 654 | if-no-files-found: error |
| 467 | | 655 | |
| ... | @@ -488,11 +676,9 @@ jobs: | ... | @@ -488,11 +676,9 @@ jobs: |
| 488 | matrix: | 676 | matrix: |
| 489 | include: | 677 | include: |
| 490 | # cli_archive: whether the job also builds the self-contained CLI | 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 | 679 | # archive for its own platform/arch, on this runner, and smoke-tests |
| 492 | # native runners qualify. macOS x64 has no native runner: a | 680 | # it here. Every archive is built on hardware of its own |
| 493 | # cross-built executable crashed under Rosetta in the smoke test and | 681 | # architecture: Linux and Windows arm64 have their own jobs below. |
| 494 | # cannot be verified on real x64 hardware in CI, so it is skipped | | |
| 495 | # until it can be. | | |
| 496 | - label: macOS arm64 | 682 | - label: macOS arm64 |
| 497 | runner: blacksmith-12vcpu-macos-26 | 683 | runner: blacksmith-12vcpu-macos-26 |
| 498 | platform: mac | 684 | platform: mac |
| ... | @@ -501,6 +687,9 @@ jobs: | ... | @@ -501,6 +687,9 @@ jobs: |
| 501 | rust_target: aarch64-apple-darwin | 687 | rust_target: aarch64-apple-darwin |
| 502 | resource_key: darwin-arm64 | 688 | resource_key: darwin-arm64 |
| 503 | cli_archive: true | 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 | - label: macOS x64 | 693 | - label: macOS x64 |
| 505 | runner: blacksmith-12vcpu-macos-26 | 694 | runner: blacksmith-12vcpu-macos-26 |
| 506 | platform: mac | 695 | platform: mac |
| ... | @@ -1058,8 +1247,8 @@ jobs: | ... | @@ -1058,8 +1247,8 @@ jobs: |
| 1058 | | 1247 | |
| 1059 | release: | 1248 | release: |
| 1060 | name: Publish GitHub Release | 1249 | name: Publish GitHub Release |
| 1061 | needs: [preflight, build, publish_cli] | 1250 | needs: [preflight, build, build_windows_arm64_cli, 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')) }} | 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 | runs-on: blacksmith-8vcpu-ubuntu-2404 | 1252 | runs-on: blacksmith-8vcpu-ubuntu-2404 |
| 1064 | timeout-minutes: 30 | 1253 | timeout-minutes: 30 |
| 1065 | permissions: | 1254 | permissions: |