1name: Desktop macOS Preview
2
3# Untrusted half of the macOS preview. This runs PR code (including fork PRs)
4# with a read-only token and no secrets, and only produces the JS bundle. The
5# trusted half, desktop-macos-preview-publish.yml, runs on workflow_run from
6# main, verifies the PR author is vouched, then packages, signs, notarizes, and
7# publishes the bundle without ever executing it.
8#
9# The label is a one-shot request for the commit it was applied to, not a
10# standing subscription: the trusted half removes it once this run completes,
11# and later pushes do not build until a maintainer applies it again. Each
12# signed preview is therefore an explicit per-commit decision.
13#
14# Closing the PR is handled by the publish workflow too, since deleting the
15# download needs a write token.
16
17on:
18 pull_request:
19 types: [labeled]
20
21permissions:
22 contents: read
23
24concurrency:
25 group: desktop-macos-preview-${{ github.event.pull_request.number }}
26 # Adding an unrelated label skips the job and must not cancel a build.
27 cancel-in-progress: ${{ github.event.label.name == 'preview:mac' }}
28
29jobs:
30 build:
31 name: Build preview JS bundle
32 if: github.event.label.name == 'preview:mac'
33 runs-on: blacksmith-32vcpu-ubuntu-2404
34 timeout-minutes: 30
35 steps:
36 # This repository is public, so Git needs no credentials. checkout's
37 # credential cleanup runs submodule foreach even with submodules disabled,
38 # which fails on the orphaned gitlinks in our vendored .repos tree.
39 - name: Checkout
40 shell: bash
41 env:
42 CHECKOUT_REF: ${{ github.event.pull_request.head.sha }}
43 GIT_TERMINAL_PROMPT: "0"
44 run: |
45 set -euo pipefail
46 git init .
47 git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
48 git fetch --no-tags --depth=1 origin "$CHECKOUT_REF"
49 git sparse-checkout set --no-cone '/*' '!/.repos/'
50 git checkout --detach FETCH_HEAD
51
52 - name: Setup Vite+
53 uses: voidzero-dev/setup-vp@250f29ce396baf5e8f24498e17c0dfdebabc26eb # v1
54 with:
55 node-version-file: package.json
56 cache: true
57 run-install: false
58
59 - name: Install bundle dependencies
60 run: vp install --filter=t3... --filter=@t3tools/web... --filter=@t3tools/desktop... --filter=@t3tools/scripts...
61
62 # The publish workflow derives the same version from this run's number,
63 # so the version baked into the bundle matches the packaged app.
64 - name: Set preview version and public configuration
65 shell: bash
66 env:
67 PR_NUMBER: ${{ github.event.pull_request.number }}
68 run: |
69 set -euo pipefail
70
71 base_version="$(node -p "require('./apps/desktop/package.json').version")"
72 node scripts/update-release-package-versions.ts "${base_version}-pr.${PR_NUMBER}.${GITHUB_RUN_NUMBER}"
73 # Public T3 Connect identifiers (Clerk publishable key, relay URL).
74 cp .env.example .env
75
76 - uses: ./.github/actions/setup-apt-mirrors
77
78 - name: Install browser secret helper build libraries
79 run: sudo apt-get update && sudo apt-get install -y libsecret-1-dev pkg-config
80
81 - name: Build JS bundle
82 run: vp run build:desktop
83
84 # Same layout as release.yml's js-bundle so release-desktop.yml can
85 # package it unchanged.
86 - name: Upload JS bundle
87 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
88 with:
89 name: js-bundle
90 path: |
91 apps/server/dist
92 apps/desktop/dist-electron
93 if-no-files-found: error
94 retention-days: 1