@invarn/cibuild 1.4.8 → 1.4.9
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.
|
@@ -5,11 +5,16 @@ import { BaseStepExecutor } from './base.js';
|
|
|
5
5
|
import type { StepDef, CIConfig } from '../../types.js';
|
|
6
6
|
/**
|
|
7
7
|
* Built-in cache presets per technology.
|
|
8
|
-
* When `technology` is set on a cache step, the lockfile is
|
|
9
|
-
*
|
|
8
|
+
* When `technology` is set on a cache step, either the single `lockfile` is
|
|
9
|
+
* checksummed, or the list of `fingerprint` filenames is discovered and
|
|
10
|
+
* content-hashed, to produce the cache key. The listed `paths` are then
|
|
11
|
+
* cached/restored under that key.
|
|
10
12
|
*/
|
|
11
13
|
export interface CachePreset {
|
|
12
|
-
lockfile
|
|
14
|
+
/** Single lockfile path to checksum. Use for toolchains with authoritative lockfiles (Podfile.lock, package-lock.json…). */
|
|
15
|
+
lockfile?: string;
|
|
16
|
+
/** Filenames to discover+hash across the repo. Use when no single file captures the full build graph (Gradle/KMM). */
|
|
17
|
+
fingerprint?: string[];
|
|
13
18
|
keyPrefix: string;
|
|
14
19
|
paths: string[];
|
|
15
20
|
/** Optional fallback preset name: if primary lockfile not found, use this preset's lockfile/key/paths */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAkBxD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,4HAA4H;IAC5H,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sHAAsH;IACtH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yGAAyG;IACzG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAUrD,CAAC;AAgDF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;IACnD,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAsGzF,iBAAiB;CA+HhC;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;IACnD,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAuKzF,iBAAiB;CAqHhC"}
|
|
@@ -2,17 +2,59 @@
|
|
|
2
2
|
* Cache step implementations (cache-pull and cache-push)
|
|
3
3
|
*/
|
|
4
4
|
import { BaseStepExecutor } from './base.js';
|
|
5
|
+
/**
|
|
6
|
+
* Files that together define a Gradle/KMM build graph. Hashing these catches
|
|
7
|
+
* module additions/removals, plugin changes, and version-catalog bumps — things
|
|
8
|
+
* that invalidate reusability of the `~/.gradle/caches` contents across branches.
|
|
9
|
+
* Source file edits do NOT affect this hash; Gradle's task cache inside the
|
|
10
|
+
* tarball handles source-level reuse.
|
|
11
|
+
*/
|
|
12
|
+
const GRADLE_FINGERPRINT = [
|
|
13
|
+
'settings.gradle',
|
|
14
|
+
'settings.gradle.kts',
|
|
15
|
+
'build.gradle',
|
|
16
|
+
'build.gradle.kts',
|
|
17
|
+
'libs.versions.toml',
|
|
18
|
+
'gradle-wrapper.properties',
|
|
19
|
+
];
|
|
5
20
|
export const CACHE_PRESETS = {
|
|
6
21
|
ios: { lockfile: 'Podfile.lock', keyPrefix: 'pods', paths: ['Pods'], fallback: 'spm' },
|
|
7
22
|
cocoapods: { lockfile: 'Podfile.lock', keyPrefix: 'pods', paths: ['Pods'] },
|
|
8
23
|
carthage: { lockfile: 'Cartfile.resolved', keyPrefix: 'carthage', paths: ['Carthage'] },
|
|
9
24
|
spm: { lockfile: 'Package.resolved', keyPrefix: 'spm', paths: ['~/Library/Developer/Xcode/DerivedData/*/SourcePackages'] },
|
|
10
|
-
gradle: {
|
|
11
|
-
kmm: {
|
|
25
|
+
gradle: { fingerprint: GRADLE_FINGERPRINT, keyPrefix: 'gradle', paths: ['~/.gradle/caches', '~/.gradle/wrapper/dists'] },
|
|
26
|
+
kmm: { fingerprint: GRADLE_FINGERPRINT, keyPrefix: 'kmm', paths: ['~/.gradle/caches', '~/.gradle/wrapper/dists', '~/.konan'] },
|
|
12
27
|
npm: { lockfile: 'package-lock.json', keyPrefix: 'npm', paths: ['node_modules'] },
|
|
13
28
|
yarn: { lockfile: 'yarn.lock', keyPrefix: 'yarn', paths: ['node_modules'] },
|
|
14
29
|
dart: { lockfile: 'pubspec.lock', keyPrefix: 'dart', paths: ['.dart_tool', '.pub-cache'] },
|
|
15
30
|
};
|
|
31
|
+
/**
|
|
32
|
+
* Emits bash that discovers fingerprint filenames across the repo, sorts them,
|
|
33
|
+
* and hashes their concatenated names+contents into CACHE_KEY.
|
|
34
|
+
* Used by presets (Gradle, KMM) where no single lockfile captures the build graph.
|
|
35
|
+
*/
|
|
36
|
+
function emitFingerprintKeyCommands(preset) {
|
|
37
|
+
const fp = preset.fingerprint ?? [];
|
|
38
|
+
const escape = (s) => s.replace(/'/g, "'\\''");
|
|
39
|
+
const nameArgs = fp
|
|
40
|
+
.map((n, i) => `${i === 0 ? '' : '-o '}-name '${escape(n)}'`)
|
|
41
|
+
.join(' ');
|
|
42
|
+
return [
|
|
43
|
+
`__ci_fp_files=$(find . -type f \\( ${nameArgs} \\) \\`,
|
|
44
|
+
` -not -path '*/build/*' \\`,
|
|
45
|
+
` -not -path '*/.gradle/*' \\`,
|
|
46
|
+
` -not -path '*/node_modules/*' \\`,
|
|
47
|
+
` -not -path '*/DerivedData/*' \\`,
|
|
48
|
+
` 2>/dev/null | LC_ALL=C sort)`,
|
|
49
|
+
`if [ -n "$__ci_fp_files" ]; then`,
|
|
50
|
+
` CHECKSUM=$(echo "$__ci_fp_files" | xargs shasum -a 256 2>/dev/null | shasum -a 256 | cut -c1-16)`,
|
|
51
|
+
` CACHE_KEY="${escape(preset.keyPrefix)}-\${CHECKSUM}"`,
|
|
52
|
+
`else`,
|
|
53
|
+
` echo "Warning: no fingerprint files found, using fallback cache key"`,
|
|
54
|
+
` CACHE_KEY="${escape(preset.keyPrefix)}-no-fingerprint"`,
|
|
55
|
+
`fi`,
|
|
56
|
+
];
|
|
57
|
+
}
|
|
16
58
|
/**
|
|
17
59
|
* Resolves a preset with its fallback chain into a flat list of
|
|
18
60
|
* {lockfile, keyPrefix, paths} entries to try in order at runtime.
|
|
@@ -139,7 +181,10 @@ export class CachePullStepExecutor extends BaseStepExecutor {
|
|
|
139
181
|
commands.push(' find . -name "$(basename "$1")" -not -path "*/DerivedData/*" -not -path "*/.build/*" 2>/dev/null | head -1');
|
|
140
182
|
commands.push('}');
|
|
141
183
|
commands.push('');
|
|
142
|
-
if (chain.length === 1) {
|
|
184
|
+
if (chain.length === 1 && chain[0].fingerprint && chain[0].fingerprint.length > 0) {
|
|
185
|
+
commands.push(...emitFingerprintKeyCommands(chain[0]));
|
|
186
|
+
}
|
|
187
|
+
else if (chain.length === 1) {
|
|
143
188
|
const preset = chain[0];
|
|
144
189
|
commands.push(`LOCKFILE=$(__ci_find_lockfile "${this.escapeBash(preset.lockfile)}")`);
|
|
145
190
|
commands.push('if [ -n "$LOCKFILE" ] && [ -f "$LOCKFILE" ]; then');
|
|
@@ -171,7 +216,6 @@ export class CachePullStepExecutor extends BaseStepExecutor {
|
|
|
171
216
|
}
|
|
172
217
|
commands.push('');
|
|
173
218
|
if (isDebugMode) {
|
|
174
|
-
commands.push('echo "Lockfile: $LOCKFILE"');
|
|
175
219
|
commands.push('echo "Cache key: $CACHE_KEY"');
|
|
176
220
|
}
|
|
177
221
|
commands.push('CACHE_FILE="$CACHE_DIR/$CACHE_KEY.tar.zst"');
|
|
@@ -391,7 +435,10 @@ export class CachePushStepExecutor extends BaseStepExecutor {
|
|
|
391
435
|
commands.push(' find . -name "$(basename "$1")" -not -path "*/DerivedData/*" -not -path "*/.build/*" 2>/dev/null | head -1');
|
|
392
436
|
commands.push('}');
|
|
393
437
|
commands.push('');
|
|
394
|
-
if (chain.length === 1) {
|
|
438
|
+
if (chain.length === 1 && chain[0].fingerprint && chain[0].fingerprint.length > 0) {
|
|
439
|
+
commands.push(...emitFingerprintKeyCommands(chain[0]));
|
|
440
|
+
}
|
|
441
|
+
else if (chain.length === 1) {
|
|
395
442
|
const preset = chain[0];
|
|
396
443
|
commands.push(`LOCKFILE=$(__ci_find_lockfile "${this.escapeBash(preset.lockfile)}")`);
|
|
397
444
|
commands.push('if [ -n "$LOCKFILE" ] && [ -f "$LOCKFILE" ]; then');
|
|
@@ -419,7 +466,6 @@ export class CachePushStepExecutor extends BaseStepExecutor {
|
|
|
419
466
|
}
|
|
420
467
|
commands.push('');
|
|
421
468
|
if (isDebugMode) {
|
|
422
|
-
commands.push('echo "Lockfile: $LOCKFILE"');
|
|
423
469
|
commands.push('echo "Cache key: $CACHE_KEY"');
|
|
424
470
|
}
|
|
425
471
|
commands.push('CACHE_FILE="$CACHE_DIR/$CACHE_KEY.tar.zst"');
|
|
@@ -138,7 +138,8 @@ describe('Step Implementations', () => {
|
|
|
138
138
|
test('should auto-configure for gradle technology', async () => {
|
|
139
139
|
const executor = new CachePullStepExecutor();
|
|
140
140
|
const result = await executor.execute({ technology: 'gradle' }, {}, testConfig);
|
|
141
|
-
expect(result.script).toContain('gradle
|
|
141
|
+
expect(result.script).toContain("-name 'gradle-wrapper.properties'");
|
|
142
|
+
expect(result.script).toContain("-name 'build.gradle.kts'");
|
|
142
143
|
expect(result.script).toContain('gradle-');
|
|
143
144
|
});
|
|
144
145
|
test('should auto-configure for npm technology', async () => {
|
|
@@ -174,7 +175,10 @@ describe('Step Implementations', () => {
|
|
|
174
175
|
test('should auto-configure for kmm technology', async () => {
|
|
175
176
|
const executor = new CachePullStepExecutor();
|
|
176
177
|
const result = await executor.execute({ technology: 'kmm' }, {}, testConfig);
|
|
177
|
-
expect(result.script).toContain('gradle
|
|
178
|
+
expect(result.script).toContain("-name 'gradle-wrapper.properties'");
|
|
179
|
+
expect(result.script).toContain("-name 'settings.gradle'");
|
|
180
|
+
expect(result.script).toContain("-name 'build.gradle.kts'");
|
|
181
|
+
expect(result.script).toContain("-name 'libs.versions.toml'");
|
|
178
182
|
expect(result.script).toContain('kmm-');
|
|
179
183
|
});
|
|
180
184
|
test('should use zstd compression format', async () => {
|
|
@@ -266,7 +270,8 @@ describe('Step Implementations', () => {
|
|
|
266
270
|
test('should auto-configure for gradle technology', async () => {
|
|
267
271
|
const executor = new CachePushStepExecutor();
|
|
268
272
|
const result = await executor.execute({ technology: 'gradle' }, {}, testConfig);
|
|
269
|
-
expect(result.script).toContain('gradle
|
|
273
|
+
expect(result.script).toContain("-name 'gradle-wrapper.properties'");
|
|
274
|
+
expect(result.script).toContain("-name 'build.gradle.kts'");
|
|
270
275
|
expect(result.script).toContain('~/.gradle/caches');
|
|
271
276
|
});
|
|
272
277
|
test('should auto-configure for npm technology', async () => {
|
|
@@ -285,7 +290,9 @@ describe('Step Implementations', () => {
|
|
|
285
290
|
test('should auto-configure for kmm technology', async () => {
|
|
286
291
|
const executor = new CachePushStepExecutor();
|
|
287
292
|
const result = await executor.execute({ technology: 'kmm' }, {}, testConfig);
|
|
288
|
-
expect(result.script).toContain('gradle
|
|
293
|
+
expect(result.script).toContain("-name 'gradle-wrapper.properties'");
|
|
294
|
+
expect(result.script).toContain("-name 'settings.gradle.kts'");
|
|
295
|
+
expect(result.script).toContain("-name 'libs.versions.toml'");
|
|
289
296
|
expect(result.script).toContain('kmm-');
|
|
290
297
|
expect(result.script).toContain('~/.gradle/caches');
|
|
291
298
|
expect(result.script).toContain('~/.gradle/wrapper/dists');
|