Skip to content

Commit 77a3149

Browse files
Merge main and explain unavailable project environments
2 parents 79f1ad0 + ba006f2 commit 77a3149

2,704 files changed

Lines changed: 198604 additions & 36925 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/actions/setup-ci-deps/action.yml‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
name: Setup CI dependencies
22
description: Install Vite+ and the workspace dependencies from cache.
3+
inputs:
4+
task-cache-read-token:
5+
description: Read-only credential for the private maintainer task cache
6+
required: false
7+
default: ""
38
runs:
49
using: composite
510
steps:
@@ -65,3 +70,20 @@ runs:
6570
- name: Install dependencies
6671
shell: bash
6772
run: vp install
73+
74+
- name: Enable shared task cache
75+
if: >-
76+
github.repository == 'pingdotgg/t3code' &&
77+
(github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) &&
78+
hashFiles('.task-cache.json') != '' &&
79+
inputs.task-cache-read-token != ''
80+
shell: bash
81+
env:
82+
T3_TASK_CACHE_READ_TOKEN: ${{ inputs.task-cache-read-token }}
83+
run: |
84+
node infra/task-cache/scripts/install-ci.ts
85+
if [[ ( "$GITHUB_EVENT_NAME" == pull_request && "$GITHUB_BASE_REF" == main ) || ( "$GITHUB_EVENT_NAME" == push && "$GITHUB_REF" == refs/heads/main ) ]]; then
86+
echo 'VP_REMOTE_CACHE=read-write' >> "$GITHUB_ENV"
87+
else
88+
echo 'VP_REMOTE_CACHE=read' >> "$GITHUB_ENV"
89+
fi

‎.github/scripts/ci-changes.cjs‎

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,24 @@
1-
// Decides which CI jobs a change needs. Prints `key=value` lines for
2-
// $GITHUB_OUTPUT; a job runs unless its key is "false".
3-
//
4-
// node ci-changes.cjs --paths <file> gate by the listed paths
5-
// node ci-changes.cjs --paths <file> --full run every Linux job, gate only the macOS lint
6-
// node ci-changes.cjs changed paths unknown: run everything
7-
//
8-
// scripts/check-changed.ts requires the same decisions so local runs match CI.
9-
//
10-
// Every changed path maps to workspace packages, which then pull in their
11-
// dependents from package.json. A path this file does not recognize runs
12-
// everything, so a new root file or directory can only cost minutes.
1+
// Unknown paths run every job; recognized packages pull in their dependents.
2+
// scripts/check-changed.ts shares these decisions so local checks match CI.
133
const fs = require("node:fs");
144
const path = require("node:path");
155

166
const root = path.resolve(__dirname, "../..");
177

18-
// Never read by a build, typecheck, or test. Lint still formats them.
198
const INERT = [
209
/^docs\//,
2110
/^\.(agents|cursor|vscode|devcontainer|macroscope|repos)\//,
2211
/^[^/]+\.md$/,
2312
/^LICENSE$/,
2413
];
2514

26-
// Run everything: the root vite.config.ts loads the first as setup for every
27-
// package's tests, and the vendored mobile tarballs are installed dependencies.
15+
// Shared test setup and vendored mobile dependencies affect every package.
2816
const RUNS_EVERYTHING = [
2917
/^packages\/shared\/src\/(HostProcess|testing\/longTempDir)\.ts$/,
3018
/^apps\/mobile\/deps\//,
3119
];
3220

33-
// Paths outside a package, or files inside one that other packages read
34-
// through relative imports rather than a package.json dependency.
21+
// Includes cross-package reads absent from package.json dependencies.
3522
const EXTRA_OWNERS = [
3623
// Vite configs and tsconfigs of these apps import scripts/lib directly.
3724
[/^scripts\/lib\//, ["@t3tools/desktop", "@t3tools/mobile", "@t3tools/web", "t3"]],
@@ -43,9 +30,7 @@ const EXTRA_OWNERS = [
4330
];
4431
const RUST = /^native\/(resource-monitor|kde-snap-shot|hyprland-snap-shot)\//;
4532

46-
// Tests that read another package's files without declaring it. The scripts
47-
// tests read app manifests, assets, and sources (cursor-sdk-packaging,
48-
// third-party-licenses, brand-assets, build-desktop-artifact).
33+
// These tests read other packages without declaring dependencies.
4934
const TEST_ONLY_DEPS = {
5035
"@t3tools/provider-pi": ["@t3tools/client-runtime"],
5136
"@t3tools/scripts": [
@@ -56,17 +41,12 @@ const TEST_ONLY_DEPS = {
5641
"@t3tools/provider-cursor",
5742
],
5843
};
59-
// Declared dependencies that only feed a build step: the server bundles the
60-
// built web app (apps/server/vite.config.ts) but never imports it.
44+
// The server bundles the web build without importing it.
6145
const BUILD_ONLY_DEPS = { t3: ["@t3tools/web"] };
6246

63-
// Sources scripts/mobile-native-static-check.ts lints, plus the tool and rule
64-
// configuration that decides how it lints them, plus the root package.json
65-
// that defines the lint:mobile command.
6647
const MOBILE_NATIVE =
6748
/^apps\/mobile\/.*\.(swift|kt|kts)$|^apps\/mobile\/(\.swiftlint\.yml|detekt\.yml|\.editorconfig|Brewfile)$|^scripts\/mobile-native-static-check\.ts$|^package\.json$|^\.github\/workflows\/ci\.yml$|^\.github\/scripts\/ci-changes\.cjs$|^\.github\/actions\/ci-changes\//;
6849

69-
// Jobs that test every package except these, which have jobs of their own.
7050
const OWN_TEST_JOB = new Set(["t3", "@t3tools/web", "@t3tools/monorepo"]);
7151

7252
function readWorkspace() {
@@ -108,8 +88,7 @@ function readWorkspace() {
10888
return packages;
10989
}
11090

111-
// Returns the packages a path touches, [] for an inert path, or null when the
112-
// path is not understood and everything must run.
91+
// [] means inert; null means unknown and requires every job.
11392
function ownersOf(file, packages) {
11493
if (INERT.some((pattern) => pattern.test(file))) return [];
11594
// A manifest can change dependencies or versions other packages read.
@@ -148,7 +127,6 @@ function decide(files, packages, full) {
148127
if (everything) {
149128
affected = all;
150129
} else {
151-
// Add dependents until nothing changes.
152130
let grew = true;
153131
while (grew) {
154132
grew = false;

‎.github/scripts/mirror-play-apk.cjs‎

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
// Publishes closed-testing betas, or downloads the internal APK for a normal
2-
// nightly release. Play generates and signs the APK from the
3-
// uploaded bundle with the app signing key, so it carries the same signature
4-
// as the Play Store install. Run by .github/workflows/mobile-android-apk.yml.
1+
// Play signs generated APKs with the app signing key, matching Play Store installs.
52
const { execFileSync } = require("node:child_process");
63
const crypto = require("node:crypto");
74
const fs = require("node:fs");
@@ -50,10 +47,7 @@ async function play(token, method, url) {
5047
return response;
5148
}
5249

53-
// Highest version code the track serves, with its release name. Play names a
54-
// release after the bundle's versionName unless the uploader sets one. This
55-
// endpoint reads without opening an edit; an edit would invalidate any open
56-
// EAS Submit edit made with the same service account.
50+
// Opening an edit would invalidate any EAS Submit edit using the same service account.
5751
async function newestTrackBuild(token, appUrl, trackName) {
5852
const { releases = [] } = await (
5953
await play(token, "GET", `${appUrl}/tracks/${trackName}/releases`)
@@ -82,8 +76,7 @@ function readRelease(tag) {
8276
}
8377
}
8478

85-
// Download to a temporary directory so a failed request cannot leave a partial
86-
// APK among the release assets.
79+
// Stage downloads so failed requests cannot leave partial release assets.
8780
async function downloadApk({ token, appUrl, build, apkName }) {
8881
const generated = await (
8982
await play(token, "GET", `${appUrl}/generatedApks/${build.versionCode}`)

‎.github/scripts/stage-preview-bundle.py‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
"server/dist/client/index.html",
1313
"desktop/dist-electron/main.cjs",
1414
}
15-
# The current bundle is about 32 MiB compressed. Bound extraction on the
16-
# trusted runner even when the PR replaces the uploader entirely.
15+
# Bound trusted-runner extraction even when a PR replaces the uploader.
1716
MAX_ARCHIVE_BYTES = 512 * 1024 * 1024
1817
MAX_EXPANDED_BYTES = 2 * 1024 * 1024 * 1024
1918
MAX_ENTRIES = 50_000
@@ -58,9 +57,7 @@ def stage_bundle(archive: Path, destination: Path):
5857
files.add(name)
5958
if not REQUIRED_FILES <= files:
6059
raise ValueError("Preview bundle is missing required entry points")
61-
# Validate all names before writing anything. This is a fresh directory
62-
# outside the checkout; neither pre-existing links nor trusted files
63-
# can be followed or overwritten. ZIP permissions are never restored.
60+
# Validate before writing into a fresh directory so existing links/files cannot be followed or overwritten.
6461
destination.mkdir(parents=True, exist_ok=False)
6562
for entry in entries:
6663
target = destination / entry.filename

‎.github/scripts/thread-transfer-report.cjs‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,7 @@ async function resolve({ github, context, core }) {
294294

295295
const sourceArtifacts = await artifactsForRun(github, owner, repo, source.id);
296296
const sourceArtifact = findResultArtifact(sourceArtifacts);
297-
// CI requires the artifact whenever the server tests run, so a passing run
298-
// without one skipped them because the PR cannot affect the server.
297+
// Successful server tests require this artifact; its absence means CI skipped them.
299298
if (!sourceArtifact && source.conclusion === "success") {
300299
core.info("CI skipped the server tests for this change; nothing to report.");
301300
core.setOutput("publish", "false");

‎.github/workflows/ci.yml‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ jobs:
5959
# file, docs included. The `Check` job at the end of this file passes only
6060
# when every other job passes or was skipped by `changes`.
6161
lint:
62+
permissions:
63+
contents: read
64+
id-token: write
6265
name: Lint
6366
runs-on: blacksmith-8vcpu-ubuntu-2404
6467
timeout-minutes: 10
@@ -82,6 +85,8 @@ jobs:
8285
8386
- name: Setup Vite+
8487
uses: ./.github/actions/setup-ci-deps
88+
with:
89+
task-cache-read-token: ${{ secrets.T3_TASK_CACHE_READ_TOKEN }}
8590

8691
# electron's install.js (run by ensure:electron) reads this cache before it
8792
# downloads from GitHub. The key changes only with the Electron version.
@@ -108,6 +113,9 @@ jobs:
108113
run: vp check
109114

110115
build:
116+
permissions:
117+
contents: read
118+
id-token: write
111119
name: Build and Typecheck
112120
needs: changes
113121
if: ${{ !cancelled() && (needs.changes.outputs.build != 'false' || needs.changes.outputs.typecheck != 'false') }}
@@ -139,6 +147,8 @@ jobs:
139147
140148
- name: Setup Vite+
141149
uses: ./.github/actions/setup-ci-deps
150+
with:
151+
task-cache-read-token: ${{ secrets.T3_TASK_CACHE_READ_TOKEN }}
142152

143153
# electron's install.js (run by ensure:electron) reads this cache before it
144154
# downloads from GitHub. The key changes only with the Electron version.
@@ -197,6 +207,9 @@ jobs:
197207
# dependency layers. The concurrency limit stays at the default 4 so peak load
198208
# per runner is unchanged.
199209
test:
210+
permissions:
211+
contents: read
212+
id-token: write
200213
name: Test
201214
needs: changes
202215
if: ${{ !cancelled() && needs.changes.outputs.test != 'false' }}
@@ -237,6 +250,8 @@ jobs:
237250
238251
- name: Setup Vite+
239252
uses: ./.github/actions/setup-ci-deps
253+
with:
254+
task-cache-read-token: ${{ secrets.T3_TASK_CACHE_READ_TOKEN }}
240255

241256
# electron's install.js (run by ensure:electron) reads this cache before it
242257
# downloads from GitHub. The key changes only with the Electron version.
@@ -278,6 +293,9 @@ jobs:
278293
# started last and ran alone for about 40s after everything else finished.
279294
# release.yml mirrors this test, test_web, and test_server split.
280295
test_web:
296+
permissions:
297+
contents: read
298+
id-token: write
281299
name: Test Web
282300
needs: changes
283301
if: ${{ !cancelled() && needs.changes.outputs.test_web != 'false' }}
@@ -295,6 +313,8 @@ jobs:
295313

296314
- name: Setup Vite+
297315
uses: ./.github/actions/setup-ci-deps
316+
with:
317+
task-cache-read-token: ${{ secrets.T3_TASK_CACHE_READ_TOKEN }}
298318

299319
# The browser project runs React tests in headless Chromium. Same cache key as
300320
# test_server, so both jobs share one downloaded browser.
@@ -333,6 +353,9 @@ jobs:
333353
# The shards are the longest jobs, so they gate themselves instead of waiting
334354
# ~15s for `changes`: a shard the change cannot affect stops after checkout.
335355
test_server:
356+
permissions:
357+
contents: read
358+
id-token: write
336359
name: Test Server ${{ matrix.shard }}
337360
runs-on: blacksmith-4vcpu-ubuntu-2404
338361
timeout-minutes: 10
@@ -359,6 +382,8 @@ jobs:
359382
- name: Setup Vite+
360383
if: steps.changes.outputs.test_server != 'false'
361384
uses: ./.github/actions/setup-ci-deps
385+
with:
386+
task-cache-read-token: ${{ secrets.T3_TASK_CACHE_READ_TOKEN }}
362387

363388
# No Electron setup here: `t3` (apps/server) has no Electron dependency
364389
# and none of its tests touch the runtime. Only the non-server `test`
@@ -495,6 +520,9 @@ jobs:
495520
run: vp run lint:mobile
496521

497522
release_smoke:
523+
permissions:
524+
contents: read
525+
id-token: write
498526
name: Release Smoke
499527
needs: changes
500528
if: ${{ !cancelled() && needs.changes.outputs.release_smoke != 'false' }}
@@ -512,6 +540,8 @@ jobs:
512540

513541
- name: Setup Vite+
514542
uses: ./.github/actions/setup-ci-deps
543+
with:
544+
task-cache-read-token: ${{ secrets.T3_TASK_CACHE_READ_TOKEN }}
515545

516546
- name: Exercise release-only workflow steps
517547
run: node scripts/release-smoke.ts

0 commit comments

Comments
 (0)