@invarn/cibuild 2.0.8 → 2.1.0
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.
- package/dist/cli.cjs +688 -69
- package/dist/src/lib.d.ts +2 -0
- package/dist/src/lib.d.ts.map +1 -1
- package/dist/src/lib.js +1 -0
- package/dist/src/yaml/steps/index.d.ts.map +1 -1
- package/dist/src/yaml/steps/index.js +22 -0
- package/dist/src/yaml/steps/render-post-processor.d.ts +73 -0
- package/dist/src/yaml/steps/render-post-processor.d.ts.map +1 -0
- package/dist/src/yaml/steps/render-post-processor.js +303 -0
- package/dist/src/yaml/steps/render-post-processor.test.d.ts +16 -0
- package/dist/src/yaml/steps/render-post-processor.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/render-post-processor.test.js +238 -0
- package/dist/src/yaml/steps/ui-fidelity-preview-android.d.ts +66 -0
- package/dist/src/yaml/steps/ui-fidelity-preview-android.d.ts.map +1 -0
- package/dist/src/yaml/steps/ui-fidelity-preview-android.js +249 -0
- package/dist/src/yaml/steps/ui-fidelity-preview-android.test.d.ts +13 -0
- package/dist/src/yaml/steps/ui-fidelity-preview-android.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/ui-fidelity-preview-android.test.js +299 -0
- package/dist/src/yaml/steps/ui-fidelity-render-android.d.ts +92 -0
- package/dist/src/yaml/steps/ui-fidelity-render-android.d.ts.map +1 -0
- package/dist/src/yaml/steps/ui-fidelity-render-android.js +726 -0
- package/dist/src/yaml/steps/ui-fidelity-render-android.test.d.ts +2 -0
- package/dist/src/yaml/steps/ui-fidelity-render-android.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/ui-fidelity-render-android.test.js +377 -0
- package/dist/src/yaml/steps/ui-fidelity-render.d.ts +0 -28
- package/dist/src/yaml/steps/ui-fidelity-render.d.ts.map +1 -1
- package/dist/src/yaml/steps/ui-fidelity-render.js +1 -259
- package/dist/src/yaml/steps/ui-fidelity-render.test.js +1 -57
- package/package.json +1 -1
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the local Android ui-fidelity render preview engine.
|
|
3
|
+
*
|
|
4
|
+
* The orchestration (archive, params, result shaping) and the toolchain-missing
|
|
5
|
+
* guard run with a PATH-shimmed fake `java`/`gradlew`/`swift` toolchain: the
|
|
6
|
+
* engine spawns the real generated Android render script, which spawns the
|
|
7
|
+
* toolchain. The actual Roborazzi/Robolectric render and the CoreGraphics trim
|
|
8
|
+
* are covered by an opt-in real-toolchain test, gated on
|
|
9
|
+
* CIBUILD_UI_FIDELITY_REAL_ANDROID, since the fake toolchain cannot exercise the
|
|
10
|
+
* real pixel render/trim.
|
|
11
|
+
*/
|
|
12
|
+
import { describe, expect, test, afterAll } from '@jest/globals';
|
|
13
|
+
import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from 'node:fs';
|
|
14
|
+
import { tmpdir } from 'node:os';
|
|
15
|
+
import { dirname, join, resolve } from 'node:path';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
import { renderUiFidelityPreviewAndroid } from './ui-fidelity-preview-android.js';
|
|
18
|
+
const PNG_MAGIC = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
19
|
+
// Fake `java`: presence is all the toolchain guard checks (command -v java).
|
|
20
|
+
const FAKE_JAVA = ['#!/bin/bash', 'exit 0'].join('\n');
|
|
21
|
+
// Fake project `gradlew`: mimics a Roborazzi record by writing one PNG per
|
|
22
|
+
// screen named in FAKE_ROBORAZZI_SCREENS (comma-separated) to
|
|
23
|
+
// proof/build/outputs/roborazzi/<Screen>.png.
|
|
24
|
+
const FAKE_GRADLEW = [
|
|
25
|
+
'#!/bin/bash',
|
|
26
|
+
'out="proof/build/outputs/roborazzi"',
|
|
27
|
+
'mkdir -p "$out"',
|
|
28
|
+
'IFS=","',
|
|
29
|
+
'for s in $FAKE_ROBORAZZI_SCREENS; do',
|
|
30
|
+
' [ -z "$s" ] && continue',
|
|
31
|
+
" printf '\\x89PNG\\r\\n\\x1a\\n' > \"$out/$s.png\"",
|
|
32
|
+
' printf \'roborazzi:%s\' "$s" >> "$out/$s.png"',
|
|
33
|
+
'done',
|
|
34
|
+
'exit 0',
|
|
35
|
+
].join('\n');
|
|
36
|
+
// Fake `swift`: only the script-interpreter branch the shared trim stage uses
|
|
37
|
+
// (`swift <Trim.swift> <in> <out> <aligned> <ref>`). Writes trimmed + aligned
|
|
38
|
+
// PNGs and emits a fixed TRIMDIMS line.
|
|
39
|
+
const FAKE_SWIFT = [
|
|
40
|
+
'#!/bin/bash',
|
|
41
|
+
'case "$1" in',
|
|
42
|
+
' *.swift)',
|
|
43
|
+
' in_png="$2"; out_png="$3"; aligned_png="$4"',
|
|
44
|
+
" printf '\\x89PNG\\r\\n\\x1a\\n' > \"$out_png\"",
|
|
45
|
+
' printf \'trimmed:%s\' "$(basename "$in_png")" >> "$out_png"',
|
|
46
|
+
' if [ -n "$aligned_png" ]; then',
|
|
47
|
+
" printf '\\x89PNG\\r\\n\\x1a\\n' > \"$aligned_png\"",
|
|
48
|
+
' printf \'aligned:%s\' "$(basename "$in_png")" >> "$aligned_png"',
|
|
49
|
+
' fi',
|
|
50
|
+
' echo "TRIMDIMS 320 640 160 320 400 800"',
|
|
51
|
+
' exit 0 ;;',
|
|
52
|
+
' *) exit 0 ;;',
|
|
53
|
+
'esac',
|
|
54
|
+
].join('\n');
|
|
55
|
+
function fakeToolchain() {
|
|
56
|
+
const bin = tempDir('ui-fidelity-android-fakebin-');
|
|
57
|
+
for (const [name, body] of [
|
|
58
|
+
['java', FAKE_JAVA],
|
|
59
|
+
['swift', FAKE_SWIFT],
|
|
60
|
+
]) {
|
|
61
|
+
const p = join(bin, name);
|
|
62
|
+
writeFileSync(p, body + '\n');
|
|
63
|
+
chmodSync(p, 0o755);
|
|
64
|
+
}
|
|
65
|
+
return bin;
|
|
66
|
+
}
|
|
67
|
+
function isPng(filePath) {
|
|
68
|
+
return readFileSync(filePath).subarray(0, PNG_MAGIC.length).equals(PNG_MAGIC);
|
|
69
|
+
}
|
|
70
|
+
const tempDirs = [];
|
|
71
|
+
afterAll(() => {
|
|
72
|
+
for (const dir of tempDirs) {
|
|
73
|
+
try {
|
|
74
|
+
rmSync(dir, { recursive: true, force: true });
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// best effort
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
function tempDir(prefix) {
|
|
82
|
+
const dir = mkdtempSync(join(tmpdir(), prefix));
|
|
83
|
+
tempDirs.push(dir);
|
|
84
|
+
return dir;
|
|
85
|
+
}
|
|
86
|
+
function writeReference() {
|
|
87
|
+
const dir = tempDir('ui-fidelity-android-ref-');
|
|
88
|
+
const ref = join(dir, 'reference.png');
|
|
89
|
+
writeFileSync(ref, Buffer.concat([PNG_MAGIC, Buffer.from('ref')]));
|
|
90
|
+
return ref;
|
|
91
|
+
}
|
|
92
|
+
/** A minimal Gradle render-project directory with a fake gradlew. */
|
|
93
|
+
function gradleProject() {
|
|
94
|
+
const dir = tempDir('ui-fidelity-android-pkg-');
|
|
95
|
+
writeFileSync(join(dir, 'settings.gradle.kts'), 'rootProject.name = "p"\ninclude(":proof")\n');
|
|
96
|
+
mkdirSync(join(dir, 'proof'), { recursive: true });
|
|
97
|
+
writeFileSync(join(dir, 'proof', 'build.gradle.kts'), '// module\n');
|
|
98
|
+
const gradlew = join(dir, 'gradlew');
|
|
99
|
+
writeFileSync(gradlew, FAKE_GRADLEW + '\n');
|
|
100
|
+
chmodSync(gradlew, 0o755);
|
|
101
|
+
return dir;
|
|
102
|
+
}
|
|
103
|
+
/** Run `fn` with ANDROID_HOME and the named screens set for the fake gradlew. */
|
|
104
|
+
function withAndroidEnv(screens, fn) {
|
|
105
|
+
const home = tempDir('ui-fidelity-android-sdk-');
|
|
106
|
+
const saved = {
|
|
107
|
+
home: process.env.ANDROID_HOME,
|
|
108
|
+
root: process.env.ANDROID_SDK_ROOT,
|
|
109
|
+
screens: process.env.FAKE_ROBORAZZI_SCREENS,
|
|
110
|
+
};
|
|
111
|
+
process.env.ANDROID_HOME = home;
|
|
112
|
+
delete process.env.ANDROID_SDK_ROOT;
|
|
113
|
+
process.env.FAKE_ROBORAZZI_SCREENS = screens;
|
|
114
|
+
try {
|
|
115
|
+
return fn();
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
for (const [k, v] of [
|
|
119
|
+
['ANDROID_HOME', saved.home],
|
|
120
|
+
['ANDROID_SDK_ROOT', saved.root],
|
|
121
|
+
['FAKE_ROBORAZZI_SCREENS', saved.screens],
|
|
122
|
+
]) {
|
|
123
|
+
if (v === undefined)
|
|
124
|
+
delete process.env[k];
|
|
125
|
+
else
|
|
126
|
+
process.env[k] = v;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
describe('renderUiFidelityPreviewAndroid — option validation', () => {
|
|
131
|
+
test('requires exactly one of packagePath or packageArchive', () => {
|
|
132
|
+
expect(() => renderUiFidelityPreviewAndroid({ screens: [] })).toThrow(/exactly one/);
|
|
133
|
+
expect(() => renderUiFidelityPreviewAndroid({
|
|
134
|
+
packagePath: gradleProject(),
|
|
135
|
+
packageArchive: '/tmp/x.tar.gz',
|
|
136
|
+
screens: [{ screen: 'XProof', reference: writeReference() }],
|
|
137
|
+
})).toThrow(/exactly one/);
|
|
138
|
+
});
|
|
139
|
+
test('requires at least one screen', () => {
|
|
140
|
+
expect(() => renderUiFidelityPreviewAndroid({ packagePath: gradleProject(), screens: [] })).toThrow(/at least one screen/);
|
|
141
|
+
});
|
|
142
|
+
test('rejects a missing reference image', () => {
|
|
143
|
+
expect(() => renderUiFidelityPreviewAndroid({
|
|
144
|
+
packagePath: gradleProject(),
|
|
145
|
+
screens: [{ screen: 'XProof', reference: '/no/such/reference.png' }],
|
|
146
|
+
})).toThrow(/reference for XProof not found/);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
describe('renderUiFidelityPreviewAndroid — fake toolchain', () => {
|
|
150
|
+
test('archives the project, renders in inputs mode, and returns image paths + dims', () => {
|
|
151
|
+
const result = withAndroidEnv('XProof', () => renderUiFidelityPreviewAndroid({
|
|
152
|
+
packagePath: gradleProject(),
|
|
153
|
+
screens: [{ screen: 'XProof', reference: writeReference() }],
|
|
154
|
+
toolchainPath: fakeToolchain(),
|
|
155
|
+
}));
|
|
156
|
+
expect(result.packageSource).toBe('inputs');
|
|
157
|
+
expect(result.buildError).toBeNull();
|
|
158
|
+
expect(result.ok).toBe(true);
|
|
159
|
+
expect(result.screens).toHaveLength(1);
|
|
160
|
+
const [screen] = result.screens;
|
|
161
|
+
expect(screen.screen).toBe('XProof');
|
|
162
|
+
expect(screen.status).toBe('rendered');
|
|
163
|
+
expect(screen.error).toBeNull();
|
|
164
|
+
// Paths are absolute and point at real files the caller can read.
|
|
165
|
+
expect(screen.renderedImagePath && isPng(screen.renderedImagePath)).toBe(true);
|
|
166
|
+
expect(screen.alignedImagePath && isPng(screen.alignedImagePath)).toBe(true);
|
|
167
|
+
expect(screen.referenceImagePath && isPng(screen.referenceImagePath)).toBe(true);
|
|
168
|
+
// logical_pt = rendered_px / scale (default 2); reference from the fake trim.
|
|
169
|
+
expect(screen.dimensions).toEqual({
|
|
170
|
+
rendered_px: [320, 640],
|
|
171
|
+
logical_pt: [160, 320],
|
|
172
|
+
reference_px: [160, 320],
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
test('writes images under the requested outDir', () => {
|
|
176
|
+
const outDir = tempDir('ui-fidelity-android-out-');
|
|
177
|
+
const result = withAndroidEnv('XProof', () => renderUiFidelityPreviewAndroid({
|
|
178
|
+
packagePath: gradleProject(),
|
|
179
|
+
screens: [{ screen: 'XProof', reference: writeReference() }],
|
|
180
|
+
outDir,
|
|
181
|
+
toolchainPath: fakeToolchain(),
|
|
182
|
+
}));
|
|
183
|
+
expect(result.artifactsDir).toBe(outDir);
|
|
184
|
+
expect(result.screens[0].renderedImagePath?.startsWith(outDir)).toBe(true);
|
|
185
|
+
expect(existsSync(join(outDir, 'ui-fidelity', 'rendered', 'XProof.png'))).toBe(true);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
describe('renderUiFidelityPreviewAndroid — missing local toolchain', () => {
|
|
189
|
+
test('reports a clear toolchain-missing build error instead of crashing', () => {
|
|
190
|
+
const savedHome = process.env.ANDROID_HOME;
|
|
191
|
+
const savedRoot = process.env.ANDROID_SDK_ROOT;
|
|
192
|
+
const savedUserHome = process.env.HOME;
|
|
193
|
+
delete process.env.ANDROID_HOME;
|
|
194
|
+
delete process.env.ANDROID_SDK_ROOT;
|
|
195
|
+
// Point HOME at an empty dir so the default-location auto-detect
|
|
196
|
+
// (~/Library/Android/sdk, ~/Android/Sdk) finds nothing — otherwise a dev
|
|
197
|
+
// machine with the SDK installed would resolve one and this guard wouldn't fire.
|
|
198
|
+
process.env.HOME = tempDir('ui-fidelity-android-emptyhome-');
|
|
199
|
+
try {
|
|
200
|
+
const result = renderUiFidelityPreviewAndroid({
|
|
201
|
+
packagePath: gradleProject(),
|
|
202
|
+
screens: [{ screen: 'XProof', reference: writeReference() }],
|
|
203
|
+
});
|
|
204
|
+
expect(result.ok).toBe(false);
|
|
205
|
+
expect(result.buildError?.code).toBe('ANDROID_TOOLCHAIN_MISSING');
|
|
206
|
+
expect(result.buildError?.message).toMatch(/Android SDK|JDK/);
|
|
207
|
+
// Degrades cleanly: it never tried to render.
|
|
208
|
+
expect(result.screens).toEqual([]);
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
if (savedHome === undefined)
|
|
212
|
+
delete process.env.ANDROID_HOME;
|
|
213
|
+
else
|
|
214
|
+
process.env.ANDROID_HOME = savedHome;
|
|
215
|
+
if (savedRoot === undefined)
|
|
216
|
+
delete process.env.ANDROID_SDK_ROOT;
|
|
217
|
+
else
|
|
218
|
+
process.env.ANDROID_SDK_ROOT = savedRoot;
|
|
219
|
+
if (savedUserHome === undefined)
|
|
220
|
+
delete process.env.HOME;
|
|
221
|
+
else
|
|
222
|
+
process.env.HOME = savedUserHome;
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
test('auto-detects the SDK at the default install location when ANDROID_HOME is unset', () => {
|
|
226
|
+
const savedHome = process.env.ANDROID_HOME;
|
|
227
|
+
const savedRoot = process.env.ANDROID_SDK_ROOT;
|
|
228
|
+
const savedUserHome = process.env.HOME;
|
|
229
|
+
const savedScreens = process.env.FAKE_ROBORAZZI_SCREENS;
|
|
230
|
+
delete process.env.ANDROID_HOME;
|
|
231
|
+
delete process.env.ANDROID_SDK_ROOT;
|
|
232
|
+
// A clean HOME with an SDK at the macOS default location, but no ANDROID_HOME.
|
|
233
|
+
const fakeHome = tempDir('ui-fidelity-android-home-');
|
|
234
|
+
mkdirSync(join(fakeHome, 'Library', 'Android', 'sdk'), { recursive: true });
|
|
235
|
+
process.env.HOME = fakeHome;
|
|
236
|
+
process.env.FAKE_ROBORAZZI_SCREENS = 'XProof';
|
|
237
|
+
try {
|
|
238
|
+
const result = renderUiFidelityPreviewAndroid({
|
|
239
|
+
packagePath: gradleProject(),
|
|
240
|
+
screens: [{ screen: 'XProof', reference: writeReference() }],
|
|
241
|
+
toolchainPath: fakeToolchain(),
|
|
242
|
+
});
|
|
243
|
+
// Auto-detected the SDK and rendered, rather than bailing with TOOLCHAIN_MISSING.
|
|
244
|
+
expect(result.buildError).toBeNull();
|
|
245
|
+
expect(result.ok).toBe(true);
|
|
246
|
+
expect(result.screens[0]?.status).toBe('rendered');
|
|
247
|
+
}
|
|
248
|
+
finally {
|
|
249
|
+
if (savedHome === undefined)
|
|
250
|
+
delete process.env.ANDROID_HOME;
|
|
251
|
+
else
|
|
252
|
+
process.env.ANDROID_HOME = savedHome;
|
|
253
|
+
if (savedRoot === undefined)
|
|
254
|
+
delete process.env.ANDROID_SDK_ROOT;
|
|
255
|
+
else
|
|
256
|
+
process.env.ANDROID_SDK_ROOT = savedRoot;
|
|
257
|
+
if (savedUserHome === undefined)
|
|
258
|
+
delete process.env.HOME;
|
|
259
|
+
else
|
|
260
|
+
process.env.HOME = savedUserHome;
|
|
261
|
+
if (savedScreens === undefined)
|
|
262
|
+
delete process.env.FAKE_ROBORAZZI_SCREENS;
|
|
263
|
+
else
|
|
264
|
+
process.env.FAKE_ROBORAZZI_SCREENS = savedScreens;
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
// Opt-in: previews the committed Roborazzi fixture with the real Android
|
|
269
|
+
// toolchain and asserts a non-blank paired render at the expected size. Requires
|
|
270
|
+
// the Android toolchain (JDK + SDK) and warm Roborazzi caches; gated behind
|
|
271
|
+
// CIBUILD_UI_FIDELITY_REAL_ANDROID=1 (the Android analog of the iOS real-Swift
|
|
272
|
+
// gate). ANDROID_HOME need not be exported — a standard SDK install at the
|
|
273
|
+
// default location (~/Library/Android/sdk etc.) is auto-detected.
|
|
274
|
+
describe('renderUiFidelityPreviewAndroid — real toolchain', () => {
|
|
275
|
+
const realAndroidTest = process.env.CIBUILD_UI_FIDELITY_REAL_ANDROID === '1' ? test : test.skip;
|
|
276
|
+
// A real, decodable 1x1 PNG so the trim helper's reference load/align succeeds.
|
|
277
|
+
const ONE_BY_ONE_PNG = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==', 'base64');
|
|
278
|
+
const FIXTURE_DIR = resolve(dirname(fileURLToPath(import.meta.url)), '../../../../cibuild-runner/scripts/roborazzi-fixture');
|
|
279
|
+
realAndroidTest('previews the Roborazzi fixture and returns a paired, non-blank render', () => {
|
|
280
|
+
const refDir = tempDir('ui-fidelity-android-realref-');
|
|
281
|
+
const reference = join(refDir, 'reference.png');
|
|
282
|
+
writeFileSync(reference, ONE_BY_ONE_PNG);
|
|
283
|
+
const result = renderUiFidelityPreviewAndroid({
|
|
284
|
+
packagePath: FIXTURE_DIR,
|
|
285
|
+
screens: [{ screen: 'XProof', reference }],
|
|
286
|
+
scale: 2,
|
|
287
|
+
});
|
|
288
|
+
expect(result.buildError).toBeNull();
|
|
289
|
+
expect(result.ok).toBe(true);
|
|
290
|
+
const [screen] = result.screens;
|
|
291
|
+
expect(screen.status).toBe('rendered');
|
|
292
|
+
expect(screen.renderedImagePath && isPng(screen.renderedImagePath)).toBe(true);
|
|
293
|
+
expect(screen.alignedImagePath && isPng(screen.alignedImagePath)).toBe(true);
|
|
294
|
+
const [rw, rh] = screen.dimensions.rendered_px;
|
|
295
|
+
expect(rw).toBeGreaterThan(0);
|
|
296
|
+
expect(rh).toBeGreaterThan(0);
|
|
297
|
+
}, 600_000);
|
|
298
|
+
});
|
|
299
|
+
//# sourceMappingURL=ui-fidelity-preview-android.test.js.map
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ui-fidelity-render-android step implementation.
|
|
3
|
+
*
|
|
4
|
+
* Renders parameterless Jetpack Compose wrappers from a self-contained Gradle
|
|
5
|
+
* project to PNGs via Roborazzi + Robolectric on the JVM — no device, no
|
|
6
|
+
* emulator — on a macOS runner. The step returns a self-contained node script
|
|
7
|
+
* that, at runtime:
|
|
8
|
+
*
|
|
9
|
+
* 1. Reads `.ci/inputs/params.json`
|
|
10
|
+
* ({ "screens": { "<ScreenName>": "<referenceFileBasename>" } });
|
|
11
|
+
* reference images live at `.ci/inputs/<basename>`.
|
|
12
|
+
* 2. Extracts and validates the shipped Gradle project shipped as
|
|
13
|
+
* `.ci/inputs/package.tar.gz` (single project root carrying a settings
|
|
14
|
+
* script, bounded extracted size, safe member paths).
|
|
15
|
+
* 3. Runs the project's Roborazzi record task (default
|
|
16
|
+
* `recordRoborazziDebug`) once. A build/compile failure means the project
|
|
17
|
+
* does not render and every screen is marked RENDER_UNSUPPORTED — the
|
|
18
|
+
* Android analog of the iOS probe gate (one Gradle module compiles as a
|
|
19
|
+
* unit, so a wrapper compile error cannot be isolated to one screen).
|
|
20
|
+
* 4. Locates each screen's Roborazzi golden inside the project (recorded as
|
|
21
|
+
* `build/outputs/roborazzi/...render<ScreenName>.png` from a test method
|
|
22
|
+
* named render<ScreenName>, or a flat `<ScreenName>.png`), runs it through
|
|
23
|
+
* the shared render-output
|
|
24
|
+
* post-processor (content trim, reference alignment, dimension
|
|
25
|
+
* reporting), and writes, inside the artifacts dir
|
|
26
|
+
* (${CIBUILD_ARTIFACTS_DIR:-.ci/artifacts}):
|
|
27
|
+
* - ui-fidelity/rendered/<Screen>.png
|
|
28
|
+
* - ui-fidelity/references/<Screen>.png
|
|
29
|
+
* - ui-fidelity/aligned/<Screen>.png
|
|
30
|
+
* - protocol-result.json (always written, even on partial/total failure)
|
|
31
|
+
* 5. Exits non-zero iff the archive was invalid or any screen is not
|
|
32
|
+
* "rendered".
|
|
33
|
+
*
|
|
34
|
+
* The result payload and artifact layout are identical in shape to the iOS
|
|
35
|
+
* ui-fidelity-render step, so the dashboard compare view, the artifact
|
|
36
|
+
* download tool, and the agent's compare flow are reused unchanged. Image
|
|
37
|
+
* paths in protocol-result.json are relative to the artifacts dir, and error
|
|
38
|
+
* messages are sanitized so absolute runner paths are rewritten before they
|
|
39
|
+
* are stored.
|
|
40
|
+
*/
|
|
41
|
+
import { BaseStepExecutor } from './base.js';
|
|
42
|
+
import type { StepDef, CIConfig } from '../../types.js';
|
|
43
|
+
import type { ValidationRequirement } from '../validation-types.js';
|
|
44
|
+
/** Inputs for the ui-fidelity-render-android step. */
|
|
45
|
+
export interface UiFidelityRenderAndroidInputs {
|
|
46
|
+
/**
|
|
47
|
+
* Display scale factor applied when reporting logical points (default 2).
|
|
48
|
+
* Must match the density qualifier the render test pins (xhdpi = 2x), so
|
|
49
|
+
* logical_pt = rendered_px / scale lines up with design references.
|
|
50
|
+
*/
|
|
51
|
+
scale?: number | string;
|
|
52
|
+
/**
|
|
53
|
+
* Gradle task that records the Roborazzi PNGs (default
|
|
54
|
+
* "recordRoborazziDebug"). Run from the project root, so it executes in
|
|
55
|
+
* whichever module declares it.
|
|
56
|
+
*/
|
|
57
|
+
gradle_task?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Default Roborazzi record task. Run from the project root so Gradle resolves
|
|
61
|
+
* it in whichever subproject declares it.
|
|
62
|
+
*/
|
|
63
|
+
export declare const DEFAULT_GRADLE_TASK = "recordRoborazziDebug";
|
|
64
|
+
/** Basename of the shipped Gradle-project archive inside the run-inputs dir. */
|
|
65
|
+
export declare const PACKAGE_ARCHIVE_BASENAME = "package.tar.gz";
|
|
66
|
+
/** Renderer identifier recorded in protocol-result.json. */
|
|
67
|
+
export declare const ANDROID_RENDERER = "roborazzi-robolectric";
|
|
68
|
+
/**
|
|
69
|
+
* Validates a Gradle task name: a non-empty token of letters, digits, and the
|
|
70
|
+
* separators Gradle allows in a task path (`:`, `-`, `_`). Rejects shell
|
|
71
|
+
* metacharacters so the task is safe to pass to the runner.
|
|
72
|
+
*/
|
|
73
|
+
export declare function isValidGradleTask(task: string): boolean;
|
|
74
|
+
/** Config baked into the generated runtime script at YAML-conversion time. */
|
|
75
|
+
export interface AndroidRenderScriptConfig {
|
|
76
|
+
scale: number;
|
|
77
|
+
gradleTask: string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Generates the self-contained runtime node script for the step. Pure function
|
|
81
|
+
* of its config — exported so tests can execute the script directly.
|
|
82
|
+
*/
|
|
83
|
+
export declare function generateAndroidRenderScript(config: AndroidRenderScriptConfig): string;
|
|
84
|
+
/**
|
|
85
|
+
* ui-fidelity-render-android step executor. Returns a node-kind StepDef whose
|
|
86
|
+
* script performs the render at runtime on the macOS runner.
|
|
87
|
+
*/
|
|
88
|
+
export declare class UiFidelityRenderAndroidStepExecutor extends BaseStepExecutor {
|
|
89
|
+
getValidationRequirements(_inputs: UiFidelityRenderAndroidInputs, _env: Record<string, string>, _config: CIConfig): ValidationRequirement[];
|
|
90
|
+
execute(inputs: UiFidelityRenderAndroidInputs, _env: Record<string, string>, _config: CIConfig): Promise<StepDef>;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=ui-fidelity-render-android.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-fidelity-render-android.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/ui-fidelity-render-android.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;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;AAIpE,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,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;CACpB;AAqnBD;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,yBAAyB,GAAG,MAAM,CAUrF;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;IAepB,OAAO,CACX,MAAM,EAAE,6BAA6B,EACrC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,OAAO,CAAC;CAgBpB"}
|