@invarn/cibuild 2.4.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -76,12 +76,16 @@ export interface UiFidelityRenderAndroidInputs {
76
76
  */
77
77
  export declare const DEFAULT_GRADLE_TASK = "recordRoborazziDebug";
78
78
  /** Valid values for the package_source input. */
79
- export declare const PACKAGE_SOURCES: readonly ["repo", "inputs"];
79
+ export declare const PACKAGE_SOURCES: readonly ["repo", "inputs", "url"];
80
80
  export type PackageSource = (typeof PACKAGE_SOURCES)[number];
81
81
  /**
82
82
  * Default package source: the Gradle project ships as package.tar.gz in the
83
83
  * run-inputs directory (the agent-upload path). "repo" instead renders the
84
84
  * committed project at package_path, for a triggered (agent-less) run.
85
+ * "url" (fidelity-linux 03) downloads the same package.tar.gz from a signed
86
+ * package_url into the run-inputs directory and then proceeds byte-for-byte
87
+ * like inputs mode — the clone-free delivery for triggered runs, on macOS
88
+ * and Linux workers alike.
85
89
  */
86
90
  export declare const DEFAULT_PACKAGE_SOURCE: PackageSource;
87
91
  /** Valid values for the reference_source input. */
@@ -107,16 +111,23 @@ export interface AndroidRenderScriptConfig {
107
111
  scale: number;
108
112
  gradleTask: string;
109
113
  /**
110
- * Only present (and only ever "repo") when package_source was explicitly set
111
- * to "repo". When absent, the project ships as package.tar.gz and is
114
+ * Only present when package_source was explicitly set to a non-default mode
115
+ * ("repo" or "url"). When absent, the project ships as package.tar.gz and is
112
116
  * extracted/validated exactly as the default, byte-identical script.
113
117
  */
114
118
  packageSource?: PackageSource;
115
119
  /**
116
120
  * Repo-relative path to the committed Gradle project. Present (and required)
117
- * only with packageSource "repo"; ignored otherwise.
121
+ * with packageSource "repo" (the checkout dir to render) and "url" (the
122
+ * prefix committed reference paths are resolved under, inside the extracted
123
+ * package); ignored otherwise.
118
124
  */
119
125
  packagePath?: string;
126
+ /**
127
+ * Signed download URL for package.tar.gz. Present (and required) only with
128
+ * packageSource "url"; ignored otherwise.
129
+ */
130
+ packageUrl?: string;
120
131
  /**
121
132
  * Only present (and only ever "repo") when reference_source was explicitly set
122
133
  * to "repo". When absent, references are read from `.ci/inputs/<basename>` and
@@ -138,7 +149,7 @@ export declare function generateAndroidRenderScript(config: AndroidRenderScriptC
138
149
  * script performs the render at runtime on the macOS runner.
139
150
  */
140
151
  export declare class UiFidelityRenderAndroidStepExecutor extends BaseStepExecutor {
141
- getValidationRequirements(_inputs: UiFidelityRenderAndroidInputs, _env: Record<string, string>, _config: CIConfig): ValidationRequirement[];
152
+ getValidationRequirements(inputs: UiFidelityRenderAndroidInputs, _env: Record<string, string>, _config: CIConfig): ValidationRequirement[];
142
153
  execute(inputs: UiFidelityRenderAndroidInputs, _env: Record<string, string>, _config: CIConfig): Promise<StepDef>;
143
154
  }
144
155
  //# sourceMappingURL=ui-fidelity-render-android.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ui-fidelity-render-android.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/ui-fidelity-render-android.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAMpE,sDAAsD;AACtD,MAAM,WAAW,6BAA6B;IAC5C;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,yBAAyB,CAAC;AAE1D,iDAAiD;AACjD,eAAO,MAAM,eAAe,6BAA8B,CAAC;AAC3D,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,aAAwB,CAAC;AAE9D,mDAAmD;AACnD,eAAO,MAAM,iBAAiB,6BAA8B,CAAC;AAC7D,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EAAE,eAA0B,CAAC;AAElE,gFAAgF;AAChF,eAAO,MAAM,wBAAwB,mBAAmB,CAAC;AAEzD,4DAA4D;AAC5D,eAAO,MAAM,gBAAgB,0BAA0B,CAAC;AAExD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,8EAA8E;AAC9E,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAuhCD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,yBAAyB,GAAG,MAAM,CAqBrF;AAED;;;GAGG;AACH,qBAAa,mCAAoC,SAAQ,gBAAgB;IACvE,yBAAyB,CACvB,OAAO,EAAE,6BAA6B,EACtC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,qBAAqB,EAAE;IAapB,OAAO,CACX,MAAM,EAAE,6BAA6B,EACrC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,OAAO,CAAC;CA0EpB"}
1
+ {"version":3,"file":"ui-fidelity-render-android.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/ui-fidelity-render-android.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAMpE,sDAAsD;AACtD,MAAM,WAAW,6BAA6B;IAC5C;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,yBAAyB,CAAC;AAE1D,iDAAiD;AACjD,eAAO,MAAM,eAAe,oCAAqC,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,EAAE,aAAwB,CAAC;AAE9D,mDAAmD;AACnD,eAAO,MAAM,iBAAiB,6BAA8B,CAAC;AAC7D,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EAAE,eAA0B,CAAC;AAElE,gFAAgF;AAChF,eAAO,MAAM,wBAAwB,mBAAmB,CAAC;AAEzD,4DAA4D;AAC5D,eAAO,MAAM,gBAAgB,0BAA0B,CAAC;AAExD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,8EAA8E;AAC9E,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAurCD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,yBAAyB,GAAG,MAAM,CA0BrF;AAED;;;GAGG;AACH,qBAAa,mCAAoC,SAAQ,gBAAgB;IACvE,yBAAyB,CACvB,MAAM,EAAE,6BAA6B,EACrC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,qBAAqB,EAAE;IAyBpB,OAAO,CACX,MAAM,EAAE,6BAA6B,EACrC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,OAAO,CAAC;CAiGpB"}
@@ -63,11 +63,15 @@ import { RENDER_SCRIPT_SOURCE_DIGEST_STAGE } from '../fidelity-input-digest.js';
63
63
  */
64
64
  export const DEFAULT_GRADLE_TASK = 'recordRoborazziDebug';
65
65
  /** Valid values for the package_source input. */
66
- export const PACKAGE_SOURCES = ['repo', 'inputs'];
66
+ export const PACKAGE_SOURCES = ['repo', 'inputs', 'url'];
67
67
  /**
68
68
  * Default package source: the Gradle project ships as package.tar.gz in the
69
69
  * run-inputs directory (the agent-upload path). "repo" instead renders the
70
70
  * committed project at package_path, for a triggered (agent-less) run.
71
+ * "url" (fidelity-linux 03) downloads the same package.tar.gz from a signed
72
+ * package_url into the run-inputs directory and then proceeds byte-for-byte
73
+ * like inputs mode — the clone-free delivery for triggered runs, on macOS
74
+ * and Linux workers alike.
71
75
  */
72
76
  export const DEFAULT_PACKAGE_SOURCE = 'inputs';
73
77
  /** Valid values for the reference_source input. */
@@ -1114,6 +1118,145 @@ function buildAndroidReferenceRepoMain(base) {
1114
1118
  ' }\n' +
1115
1119
  ' var source = path.resolve(refPath);');
1116
1120
  }
1121
+ /**
1122
+ * Builds the runtime main for package_source "url" (fidelity-linux 03) by
1123
+ * patching the default (inputs) runtime text. Three departures from the
1124
+ * default, all forced by the same fact — a clone-free worker has no checkout:
1125
+ *
1126
+ * 1. The package is DOWNLOADED (curl, already a runner requirement in this
1127
+ * mode) to `.ci/inputs/package.tar.gz` and extracted BEFORE the per-screen
1128
+ * reference stage, because committed references travel inside it. A failed
1129
+ * download is one structured per-build error, never per-screen noise.
1130
+ * 2. Each screen's reference is the committed repo-relative path resolved
1131
+ * INSIDE the extracted package: the path must sit under packagePath, and
1132
+ * the remainder resolves against the extracted project root.
1133
+ * 3. The render stage reuses the already-extracted root (no second extract);
1134
+ * cleanup mirrors the inputs path. The result document records
1135
+ * package_source "url".
1136
+ *
1137
+ * ANDROID_RENDER_SCRIPT_MAIN itself is never modified, so omitting
1138
+ * package_source keeps the generated script byte-identical to the default.
1139
+ */
1140
+ function buildAndroidPackageUrlMain(base) {
1141
+ let main = base;
1142
+ // The result document advertises the url package source.
1143
+ main = replaceOnce(main, "package_source: 'inputs',", "package_source: 'url',");
1144
+ // Download + extract FIRST — the reference stage below reads from inside
1145
+ // the extracted package.
1146
+ main = replaceOnce(main, ' // 2. Per-screen validation + reference copies. Each screen gets its OWN copy\n' +
1147
+ ' // named by screen, even when two screens share a reference basename.\n' +
1148
+ ' currentEntries.forEach(function (entry) {', ' // 2a. Download + extract the shipped package FIRST (URL mode): committed\n' +
1149
+ ' // references live inside it, so the per-screen reference copies below\n' +
1150
+ ' // need the extracted project root. A failed download or an invalid\n' +
1151
+ ' // archive is ONE structured per-build error; per-screen reference\n' +
1152
+ ' // work then stops cleanly (no bogus REFERENCE_MISSING noise).\n' +
1153
+ ' var urlProjectRoot = null;\n' +
1154
+ ' (function () {\n' +
1155
+ ' try {\n' +
1156
+ ' fs.mkdirSync(inputsDir, { recursive: true });\n' +
1157
+ ' } catch (mkdirError) {\n' +
1158
+ ' // statSync below reports the real failure\n' +
1159
+ ' }\n' +
1160
+ ' var dest = path.join(inputsDir, PACKAGE_ARCHIVE_NAME);\n' +
1161
+ " log('downloading render package');\n" +
1162
+ ' var download = cp.spawnSync(\n' +
1163
+ " 'curl',\n" +
1164
+ " ['-fsSL', '--retry', '2', '--max-time', '300', '-o', dest, CONFIG.packageUrl],\n" +
1165
+ " { encoding: 'utf-8', maxBuffer: 16 * 1024 * 1024 }\n" +
1166
+ ' );\n' +
1167
+ ' if (download.error) {\n' +
1168
+ ' download.status = download.status == null ? 127 : download.status;\n' +
1169
+ " download.stderr = (download.stderr || '') + String(download.error.message || download.error);\n" +
1170
+ ' }\n' +
1171
+ ' if (download.status !== 0) {\n' +
1172
+ ' setBuildError(\n' +
1173
+ " 'ANDROID_PACKAGE_DOWNLOAD_FAILED',\n" +
1174
+ " 'render package download failed (curl exit ' + download.status + '):\\n' + outputTail(download)\n" +
1175
+ ' );\n' +
1176
+ ' return;\n' +
1177
+ ' }\n' +
1178
+ ' urlProjectRoot = prepareShippedProject();\n' +
1179
+ ' })();\n' +
1180
+ '\n' +
1181
+ ' // 2. Per-screen validation + reference copies. Each screen gets its OWN copy\n' +
1182
+ ' // named by screen, even when two screens share a reference basename.\n' +
1183
+ ' currentEntries.forEach(function (entry) {');
1184
+ // References resolve INSIDE the extracted package: repo-relative path minus
1185
+ // the packagePath prefix, against the extracted project root.
1186
+ main = replaceOnce(main, 'var basename = params.screens[entry.screen];\n' +
1187
+ ' if (\n' +
1188
+ " typeof basename !== 'string' || basename === '' ||\n" +
1189
+ " basename === '.' || basename === '..' ||\n" +
1190
+ ' basename !== path.basename(basename)\n' +
1191
+ ' ) {\n' +
1192
+ ' setError(\n' +
1193
+ ' entry,\n' +
1194
+ " 'REFERENCE_MISSING',\n" +
1195
+ " 'reference for ' + entry.screen + ' must be a plain file basename inside ' +\n" +
1196
+ " inputsDir + ', got: ' + JSON.stringify(basename)\n" +
1197
+ ' );\n' +
1198
+ ' return;\n' +
1199
+ ' }\n' +
1200
+ ' var source = path.join(inputsDir, basename);', 'var refPath = params.screens[entry.screen];\n' +
1201
+ " if (typeof refPath !== 'string' || refPath === '') {\n" +
1202
+ ' setError(\n' +
1203
+ ' entry,\n' +
1204
+ " 'REFERENCE_MISSING',\n" +
1205
+ " 'reference for ' + entry.screen + ' must be a non-empty repo-relative path, got: ' +\n" +
1206
+ ' JSON.stringify(refPath)\n' +
1207
+ ' );\n' +
1208
+ ' return;\n' +
1209
+ ' }\n' +
1210
+ ' if (urlProjectRoot === null) {\n' +
1211
+ ' // Package unavailable: the per-build error above carries the cause.\n' +
1212
+ ' return;\n' +
1213
+ ' }\n' +
1214
+ " var packagePrefix = CONFIG.packagePath.replace(/^\\.\\//, '').replace(/\\/+$/, '');\n" +
1215
+ " var normalizedRef = refPath.replace(/^\\.\\//, '');\n" +
1216
+ " if (normalizedRef.indexOf(packagePrefix + '/') !== 0) {\n" +
1217
+ ' setError(\n' +
1218
+ ' entry,\n' +
1219
+ " 'REFERENCE_MISSING',\n" +
1220
+ " 'reference for ' + entry.screen + ' must live inside the shipped package (' +\n" +
1221
+ " packagePrefix + '), got: ' + JSON.stringify(refPath)\n" +
1222
+ ' );\n' +
1223
+ ' return;\n' +
1224
+ ' }\n' +
1225
+ ' var source = path.join(urlProjectRoot, normalizedRef.slice(packagePrefix.length + 1));');
1226
+ // Render from the package extracted in stage 2a — no second extract.
1227
+ main = replaceOnce(main, ' // 3. Extract + validate the shipped Gradle project, then render the\n' +
1228
+ ' // renderable screens. The project stage runs even when no screen is\n' +
1229
+ ' // renderable, so packaging mistakes are always reported.\n' +
1230
+ ' var renderable = currentEntries.filter(function (entry) { return entry.error === null; });\n' +
1231
+ ' try {\n' +
1232
+ ' var projectRoot = prepareShippedProject();\n' +
1233
+ ' if (projectRoot !== null) {\n' +
1234
+ ' if (renderable.length > 0) {\n' +
1235
+ ' renderScreens(renderable, projectRoot);\n' +
1236
+ ' } else if (currentEntries.length > 0) {\n' +
1237
+ " log('no renderable screens, skipping render');\n" +
1238
+ ' }\n' +
1239
+ ' }\n' +
1240
+ ' } finally {\n' +
1241
+ ' cleanupShippedProject();\n' +
1242
+ ' }', ' // 3. Render from the package downloaded + extracted in stage 2a. The\n' +
1243
+ ' // extraction already reported packaging mistakes as the per-build\n' +
1244
+ ' // error, so a null root here just skips the render.\n' +
1245
+ ' var renderable = currentEntries.filter(function (entry) { return entry.error === null; });\n' +
1246
+ ' try {\n' +
1247
+ ' if (urlProjectRoot !== null) {\n' +
1248
+ ' if (renderable.length > 0) {\n' +
1249
+ ' renderScreens(renderable, urlProjectRoot);\n' +
1250
+ ' } else if (currentEntries.length > 0) {\n' +
1251
+ " log('no renderable screens, skipping render');\n" +
1252
+ ' }\n' +
1253
+ ' }\n' +
1254
+ ' } finally {\n' +
1255
+ ' cleanupShippedProject();\n' +
1256
+ ' }');
1257
+ return main;
1258
+ }
1259
+ const ANDROID_RENDER_SCRIPT_MAIN_URL = buildAndroidPackageUrlMain(ANDROID_RENDER_SCRIPT_MAIN);
1117
1260
  /**
1118
1261
  * Generates the self-contained runtime node script for the step. Pure function
1119
1262
  * of its config — exported so tests can execute the script directly.
@@ -1123,10 +1266,15 @@ function buildAndroidReferenceRepoMain(base) {
1123
1266
  * runtime is used).
1124
1267
  */
1125
1268
  export function generateAndroidRenderScript(config) {
1126
- let main = config.packageSource === 'repo' ? ANDROID_RENDER_SCRIPT_MAIN_REPO : ANDROID_RENDER_SCRIPT_MAIN;
1269
+ let main = config.packageSource === 'repo'
1270
+ ? ANDROID_RENDER_SCRIPT_MAIN_REPO
1271
+ : config.packageSource === 'url'
1272
+ ? ANDROID_RENDER_SCRIPT_MAIN_URL
1273
+ : ANDROID_RENDER_SCRIPT_MAIN;
1127
1274
  // Reference-from-repo is an independent dimension layered on top of whichever
1128
1275
  // package base applies. Absent → byte-identical reference block (default
1129
- // basename behaviour).
1276
+ // basename behaviour). URL mode embeds its own reference sourcing and the
1277
+ // executor rejects the combination before this point.
1130
1278
  if (config.referenceSource === 'repo') {
1131
1279
  main = buildAndroidReferenceRepoMain(main);
1132
1280
  }
@@ -1148,13 +1296,19 @@ export function generateAndroidRenderScript(config) {
1148
1296
  * script performs the render at runtime on the macOS runner.
1149
1297
  */
1150
1298
  export class UiFidelityRenderAndroidStepExecutor extends BaseStepExecutor {
1151
- getValidationRequirements(_inputs, _env, _config) {
1299
+ getValidationRequirements(inputs, _env, _config) {
1152
1300
  // No platform-toolchain requirement: trim/align is pure JS inside the ci
1153
1301
  // binary (fidelity-linux 06), so the step validates on macOS and Linux
1154
1302
  // runners alike.
1155
- return [
1303
+ const requirements = [
1156
1304
  this.requireCommand('tar', 'Archive tool used to extract the shipped Gradle project', 'Install tar on the runner'),
1157
1305
  ];
1306
+ // URL mode (fidelity-linux 03) downloads the package at runtime; existing
1307
+ // inputs/repo runs gain no new requirement.
1308
+ if (this.getInput(inputs, 'package_source', undefined) === 'url') {
1309
+ requirements.push(this.requireCommand('curl', 'Downloader used to fetch the render package by signed URL', 'Install curl on the runner'));
1310
+ }
1311
+ return requirements;
1158
1312
  }
1159
1313
  async execute(inputs, _env, _config) {
1160
1314
  const stepName = 'ui-fidelity-render-android';
@@ -1165,9 +1319,11 @@ export class UiFidelityRenderAndroidStepExecutor extends BaseStepExecutor {
1165
1319
  'expected a Gradle task path (letters, digits, and : - _)');
1166
1320
  }
1167
1321
  // package_source: validate when provided, but only record (and patch the
1168
- // script for) the non-default "repo" so omitting it — or setting the default
1322
+ // script for) the non-default modes so omitting it — or setting the default
1169
1323
  // "inputs" — keeps the default archive-extract script byte-identical. In
1170
- // repo mode package_path is required (the committed project to render).
1324
+ // repo mode package_path is required (the committed project to render); in
1325
+ // url mode (fidelity-linux 03) package_url and package_path are required
1326
+ // (the signed download + the prefix committed reference paths sit under).
1171
1327
  const rawPackageSource = this.getInput(inputs, 'package_source', undefined);
1172
1328
  let packageSource;
1173
1329
  if (rawPackageSource !== undefined) {
@@ -1176,14 +1332,21 @@ export class UiFidelityRenderAndroidStepExecutor extends BaseStepExecutor {
1176
1332
  throw new Error(`Invalid package_source '${value}' for step '${stepName}': ` +
1177
1333
  `expected one of: ${PACKAGE_SOURCES.join(', ')}`);
1178
1334
  }
1179
- if (value === 'repo') {
1180
- packageSource = 'repo';
1335
+ if (value === 'repo' || value === 'url') {
1336
+ packageSource = value;
1181
1337
  }
1182
1338
  }
1183
1339
  let packagePath;
1184
- if (packageSource === 'repo') {
1340
+ if (packageSource === 'repo' || packageSource === 'url') {
1185
1341
  packagePath = String(this.getRequiredInput(inputs, 'package_path', stepName));
1186
1342
  }
1343
+ let packageUrl;
1344
+ if (packageSource === 'url') {
1345
+ packageUrl = String(this.getRequiredInput(inputs, 'package_url', stepName));
1346
+ if (!/^https?:\/\//.test(packageUrl)) {
1347
+ throw new Error(`Invalid package_url for step '${stepName}': expected an http(s) URL`);
1348
+ }
1349
+ }
1187
1350
  // reference_source: validate when provided, but only record (and patch the
1188
1351
  // script for) the non-default "repo" so omitting it — or setting the default
1189
1352
  // "inputs" — keeps the default basename reference block intact.
@@ -1195,6 +1358,13 @@ export class UiFidelityRenderAndroidStepExecutor extends BaseStepExecutor {
1195
1358
  throw new Error(`Invalid reference_source '${value}' for step '${stepName}': ` +
1196
1359
  `expected one of: ${REFERENCE_SOURCES.join(', ')}`);
1197
1360
  }
1361
+ // URL mode owns reference sourcing (inside the extracted package) —
1362
+ // an explicit reference_source alongside it is a contradiction.
1363
+ if (packageSource === 'url') {
1364
+ throw new Error(`Invalid reference_source for step '${stepName}': ` +
1365
+ "package_source 'url' resolves references inside the downloaded " +
1366
+ 'package; omit reference_source');
1367
+ }
1198
1368
  if (value === 'repo') {
1199
1369
  referenceSource = 'repo';
1200
1370
  }
@@ -1206,6 +1376,9 @@ export class UiFidelityRenderAndroidStepExecutor extends BaseStepExecutor {
1206
1376
  if (packagePath !== undefined) {
1207
1377
  config.packagePath = packagePath;
1208
1378
  }
1379
+ if (packageUrl !== undefined) {
1380
+ config.packageUrl = packageUrl;
1381
+ }
1209
1382
  if (referenceSource !== undefined) {
1210
1383
  config.referenceSource = referenceSource;
1211
1384
  }
@@ -1,4 +1,4 @@
1
- import { spawnSync } from 'node:child_process';
1
+ import { spawn, spawnSync } from 'node:child_process';
2
2
  import { chmodSync, cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from 'node:fs';
3
3
  import { gzipSync } from 'node:zlib';
4
4
  import { tmpdir } from 'node:os';
@@ -826,6 +826,161 @@ describe('package_source: repo', () => {
826
826
  expect(screen?.reference_image_path).toBe('ui-fidelity/references/XProof.png');
827
827
  });
828
828
  });
829
+ // Clone-free package delivery (fidelity-linux 03): the dispatched YAML carries
830
+ // a signed package_url; the runtime downloads it to .ci/inputs/package.tar.gz
831
+ // and proceeds byte-for-byte like inputs mode, resolving each screen's
832
+ // committed reference INSIDE the extracted package (repo-relative path minus
833
+ // the package_path prefix) — there is no checkout on a clone-free worker.
834
+ describe('package_source: url', () => {
835
+ /**
836
+ * Serve one tar.gz (or a 404) from a loopback HTTP server IN A CHILD
837
+ * PROCESS. runScript executes the generated script via spawnSync, which
838
+ * blocks this process's event loop — an in-process server would deadlock
839
+ * against the script's curl. The child prints its port once listening.
840
+ */
841
+ const SERVE_PACKAGE_SRC = [
842
+ "var http = require('http');",
843
+ "var fs = require('fs');",
844
+ 'var filePath = process.argv[1];',
845
+ 'var server = http.createServer(function (req, res) {',
846
+ " if (filePath === '-') { res.statusCode = 404; res.end('gone'); return; }",
847
+ " res.setHeader('content-type', 'application/gzip');",
848
+ ' res.end(fs.readFileSync(filePath));',
849
+ '});',
850
+ "server.listen(0, '127.0.0.1', function () {",
851
+ " console.log('PORT ' + server.address().port);",
852
+ '});',
853
+ ].join('\n');
854
+ async function servePackage(archive) {
855
+ let filePath = '-';
856
+ if (archive !== null) {
857
+ const dir = mkdtempSync(join(tmpdir(), 'ui-fidelity-url-serve-'));
858
+ tempDirs.push(dir);
859
+ filePath = join(dir, 'package.tar.gz');
860
+ writeFileSync(filePath, archive);
861
+ }
862
+ const child = spawn('node', ['-e', SERVE_PACKAGE_SRC, filePath], {
863
+ stdio: ['ignore', 'pipe', 'inherit'],
864
+ });
865
+ const port = await new Promise((resolvePort, rejectPort) => {
866
+ let buffered = '';
867
+ const timer = setTimeout(() => rejectPort(new Error('package server did not start')), 10_000);
868
+ child.stdout.on('data', (chunk) => {
869
+ buffered += chunk.toString();
870
+ const match = /PORT (\d+)/.exec(buffered);
871
+ if (match) {
872
+ clearTimeout(timer);
873
+ resolvePort(Number(match[1]));
874
+ }
875
+ });
876
+ child.on('exit', () => rejectPort(new Error('package server exited early')));
877
+ });
878
+ return {
879
+ url: `http://127.0.0.1:${port}/api/fidelity/packages/blob1?exp=1&sig=ab`,
880
+ close: () => new Promise((resolveClose) => {
881
+ child.once('exit', () => resolveClose(undefined));
882
+ child.kill('SIGKILL');
883
+ }),
884
+ };
885
+ }
886
+ /** Archive shaped like the dashboard's assembly: package-dir contents at the
887
+ * archive root, committed references under references/. */
888
+ function packagedProject() {
889
+ return makeTarGz([
890
+ ...gradleProjectEntries(''),
891
+ { name: 'references/x.png', content: Buffer.concat([PNG_MAGIC, Buffer.from('ref:url-x')]) },
892
+ ]);
893
+ }
894
+ test('package_source url requires package_url and package_path', async () => {
895
+ const executor = new UiFidelityRenderAndroidStepExecutor();
896
+ await expect(executor.execute({ package_source: 'url', package_path: 'android-app' }, {}, testConfig)).rejects.toThrow(/package_url/);
897
+ await expect(executor.execute({ package_source: 'url', package_url: 'https://x.test/p' }, {}, testConfig)).rejects.toThrow(/package_path/);
898
+ });
899
+ test('rejects reference_source alongside package_source url (URL mode owns references)', async () => {
900
+ const executor = new UiFidelityRenderAndroidStepExecutor();
901
+ await expect(executor.execute({
902
+ package_source: 'url',
903
+ package_url: 'https://x.test/p',
904
+ package_path: 'android-app',
905
+ reference_source: 'repo',
906
+ }, {}, testConfig)).rejects.toThrow(/reference_source/);
907
+ });
908
+ test('url mode requires curl on the runner (validation requirement)', () => {
909
+ const executor = new UiFidelityRenderAndroidStepExecutor();
910
+ const urlReqs = executor.getValidationRequirements({ package_source: 'url' }, {}, testConfig);
911
+ expect(urlReqs.some((r) => r.name === 'curl')).toBe(true);
912
+ // Default inputs mode keeps tar only — no new requirement for existing runs.
913
+ const defaultReqs = executor.getValidationRequirements({}, {}, testConfig);
914
+ expect(defaultReqs.some((r) => r.name === 'curl')).toBe(false);
915
+ });
916
+ test('downloads the package, renders, and resolves references inside it', async () => {
917
+ const project = makeProject({ screens: { XProof: 'android-app/references/x.png' } });
918
+ const served = await servePackage(packagedProject());
919
+ try {
920
+ const run = runScript(project, await buildScript({
921
+ package_source: 'url',
922
+ package_url: served.url,
923
+ package_path: 'android-app',
924
+ }), { FAKE_ROBORAZZI_SCREENS: 'XProof' });
925
+ expect(run.status).toBe(0);
926
+ const doc = readResult(project);
927
+ expect(doc.package_source).toBe('url');
928
+ const screen = doc.screens.find((s) => s.screen === 'XProof');
929
+ expect(screen?.status).toBe('rendered');
930
+ expect(screen?.reference_image_path).toBe('ui-fidelity/references/XProof.png');
931
+ expect(isPng(artifact(project, 'ui-fidelity/references/XProof.png'))).toBe(true);
932
+ }
933
+ finally {
934
+ await served.close();
935
+ }
936
+ });
937
+ test('a failed download is one structured build error, not per-screen noise', async () => {
938
+ const project = makeProject({ screens: { XProof: 'android-app/references/x.png' } });
939
+ const served = await servePackage(null); // 404
940
+ try {
941
+ const run = runScript(project, await buildScript({
942
+ package_source: 'url',
943
+ package_url: served.url,
944
+ package_path: 'android-app',
945
+ }));
946
+ expect(run.status).not.toBe(0);
947
+ const doc = readResult(project);
948
+ expect(doc.error?.code).toBe('ANDROID_PACKAGE_DOWNLOAD_FAILED');
949
+ const screen = doc.screens.find((s) => s.screen === 'XProof');
950
+ // The failure is the build's, not the screen's — no bogus
951
+ // REFERENCE_MISSING masking the real cause.
952
+ expect(screen?.error).toBeNull();
953
+ }
954
+ finally {
955
+ await served.close();
956
+ }
957
+ });
958
+ test('a reference outside the package directory fails that screen only', async () => {
959
+ const project = makeProject({
960
+ screens: {
961
+ XProof: 'android-app/references/x.png',
962
+ Stray: 'design/elsewhere/stray.png',
963
+ },
964
+ });
965
+ const served = await servePackage(packagedProject());
966
+ try {
967
+ const run = runScript(project, await buildScript({
968
+ package_source: 'url',
969
+ package_url: served.url,
970
+ package_path: 'android-app',
971
+ }), { FAKE_ROBORAZZI_SCREENS: 'XProof' });
972
+ expect(run.status).not.toBe(0);
973
+ const doc = readResult(project);
974
+ expect(doc.screens.find((s) => s.screen === 'XProof')?.status).toBe('rendered');
975
+ const stray = doc.screens.find((s) => s.screen === 'Stray');
976
+ expect(stray?.status).toBe('render_failed');
977
+ expect(stray?.error?.code).toBe('REFERENCE_MISSING');
978
+ }
979
+ finally {
980
+ await served.close();
981
+ }
982
+ });
983
+ });
829
984
  describe('reference_source: repo', () => {
830
985
  test('rejects an unknown reference_source value', async () => {
831
986
  const executor = new UiFidelityRenderAndroidStepExecutor();
@@ -71,8 +71,17 @@ export interface UiFidelityRenderInputs {
71
71
  * behavior; omitting package_source generates a byte-identical script).
72
72
  * - "inputs": the package ships as .ci/inputs/package.tar.gz and is
73
73
  * extracted, validated, and built from a scratch directory at runtime.
74
+ * - "url" (fidelity-linux 03): the same package.tar.gz is downloaded from
75
+ * the signed package_url into the run-inputs directory, then extracted
76
+ * and built exactly like inputs mode — the clone-free delivery for
77
+ * triggered runs. References resolve INSIDE the extracted package.
74
78
  */
75
- package_source?: 'repo' | 'inputs';
79
+ package_source?: 'repo' | 'inputs' | 'url';
80
+ /**
81
+ * Signed download URL for package.tar.gz. Required with package_source
82
+ * "url"; ignored otherwise.
83
+ */
84
+ package_url?: string;
76
85
  /**
77
86
  * Path to the user's SwiftPM package (the package that defines the
78
87
  * screens). Required in repo mode; ignored with package_source "inputs".
@@ -110,7 +119,7 @@ export declare const DEFAULT_RENDER_SIZE = "393x852";
110
119
  /** Default display scale (@2x), matching how references are typically exported. */
111
120
  export declare const DEFAULT_SCALE = 2;
112
121
  /** Valid values for the package_source input. */
113
- export declare const PACKAGE_SOURCES: readonly ["repo", "inputs"];
122
+ export declare const PACKAGE_SOURCES: readonly ["repo", "inputs", "url"];
114
123
  export type PackageSource = (typeof PACKAGE_SOURCES)[number];
115
124
  /** Default package source: the package lives in the repo checkout. */
116
125
  export declare const DEFAULT_PACKAGE_SOURCE: PackageSource;
@@ -157,14 +166,21 @@ export declare function parseScale(value: number | string): number;
157
166
  * `error` (null, or `{ code, message }` for per-build package failures).
158
167
  */
159
168
  export interface RenderScriptConfig {
160
- /** null only with packageSource "inputs", where the package is shipped. */
169
+ /** null only with packageSource "inputs", where the package is shipped.
170
+ * With packageSource "url" it carries the repo-relative package directory
171
+ * committed reference paths are resolved under (never a local path). */
161
172
  packagePath: string | null;
162
- /** null only with packageSource "inputs", where it may be discovered. */
173
+ /** null with packageSource "inputs"/"url" when it is to be discovered. */
163
174
  target: string | null;
164
175
  width: number;
165
176
  height: number;
166
177
  scale: number;
167
178
  packageSource?: PackageSource;
179
+ /**
180
+ * Signed download URL for package.tar.gz. Present (and required) only with
181
+ * packageSource "url"; ignored otherwise.
182
+ */
183
+ packageUrl?: string;
168
184
  /**
169
185
  * Only present (and only ever "repo") when reference_source was explicitly set
170
186
  * to "repo". When absent, references are read from `.ci/inputs/<basename>` and
@@ -1 +1 @@
1
- {"version":3,"file":"ui-fidelity-render.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/ui-fidelity-render.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ui-fidelity-render.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/ui-fidelity-render.ts"],"names":[],"mappings":"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"}