@invarn/cibuild 1.9.7 → 1.9.8
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.
|
@@ -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;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;AAmFF;;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;YA0GzF,iBAAiB;
|
|
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;AAmFF;;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;YA0GzF,iBAAiB;CAqMhC;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;YAgKzF,iBAAiB;CAmIhC"}
|
|
@@ -237,13 +237,20 @@ export class CachePullStepExecutor extends BaseStepExecutor {
|
|
|
237
237
|
commands.push('fi');
|
|
238
238
|
}
|
|
239
239
|
else {
|
|
240
|
-
// Fallback chain:
|
|
240
|
+
// Fallback chain: probe every lockfile up front, then branch on the
|
|
241
|
+
// results. The probes must precede the if/elif — emitting a probe
|
|
242
|
+
// inside a prior preset's `then` body (the old shape) meant the
|
|
243
|
+
// second lockfile was only checked when the FIRST one was found, so
|
|
244
|
+
// an SPM project with no Podfile.lock never reached the Package.resolved
|
|
245
|
+
// branch and fell through to `<first>-no-lockfile`.
|
|
246
|
+
for (let i = 0; i < chain.length; i++) {
|
|
247
|
+
commands.push(`__ci_lockfile_${i}=$(__ci_find_lockfile "${this.escapeBash(chain[i].lockfile)}")`);
|
|
248
|
+
}
|
|
241
249
|
for (let i = 0; i < chain.length; i++) {
|
|
242
250
|
const preset = chain[i];
|
|
243
251
|
const cond = i === 0 ? 'if' : 'elif';
|
|
244
|
-
commands.push(
|
|
245
|
-
commands.push(
|
|
246
|
-
commands.push(' LOCKFILE="$__ci_lockfile_candidate"');
|
|
252
|
+
commands.push(`${cond} [ -n "$__ci_lockfile_${i}" ] && [ -f "$__ci_lockfile_${i}" ]; then`);
|
|
253
|
+
commands.push(` LOCKFILE="$__ci_lockfile_${i}"`);
|
|
247
254
|
commands.push(` CHECKSUM=$(shasum -a 256 "$LOCKFILE" | cut -d ' ' -f1 | head -c 16)`);
|
|
248
255
|
commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-\${__ci_proj}-\${CHECKSUM}"`);
|
|
249
256
|
if (isDebugMode) {
|
|
@@ -545,12 +552,19 @@ export class CachePushStepExecutor extends BaseStepExecutor {
|
|
|
545
552
|
commands.push('fi');
|
|
546
553
|
}
|
|
547
554
|
else {
|
|
555
|
+
// Fallback chain: probe every lockfile up front, then branch — same
|
|
556
|
+
// fix as cache-pull. A probe nested in a prior preset's `then` body
|
|
557
|
+
// only ran when the first lockfile was found, so push wrote the
|
|
558
|
+
// `<first>-no-lockfile` key for SPM projects, mismatching what a
|
|
559
|
+
// correct pull would look for.
|
|
560
|
+
for (let i = 0; i < chain.length; i++) {
|
|
561
|
+
commands.push(`__ci_lockfile_${i}=$(__ci_find_lockfile "${this.escapeBash(chain[i].lockfile)}")`);
|
|
562
|
+
}
|
|
548
563
|
for (let i = 0; i < chain.length; i++) {
|
|
549
564
|
const preset = chain[i];
|
|
550
565
|
const cond = i === 0 ? 'if' : 'elif';
|
|
551
|
-
commands.push(
|
|
552
|
-
commands.push(
|
|
553
|
-
commands.push(' LOCKFILE="$__ci_lockfile_candidate"');
|
|
566
|
+
commands.push(`${cond} [ -n "$__ci_lockfile_${i}" ] && [ -f "$__ci_lockfile_${i}" ]; then`);
|
|
567
|
+
commands.push(` LOCKFILE="$__ci_lockfile_${i}"`);
|
|
554
568
|
commands.push(` CHECKSUM=$(shasum -a 256 "$LOCKFILE" | cut -d ' ' -f1 | head -c 16)`);
|
|
555
569
|
commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-\${__ci_proj}-\${CHECKSUM}"`);
|
|
556
570
|
}
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
* Tests each step executor with sample inputs
|
|
4
4
|
*/
|
|
5
5
|
import { describe, test, expect } from '@jest/globals';
|
|
6
|
+
import { execFileSync } from 'node:child_process';
|
|
7
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
import { join } from 'node:path';
|
|
6
10
|
import { GitCloneStepExecutor } from './git-clone.js';
|
|
7
11
|
import { ScriptStepExecutor } from './script.js';
|
|
8
12
|
import { CachePullStepExecutor, CachePushStepExecutor } from './cache.js';
|
|
@@ -166,6 +170,70 @@ describe('Step Implementations', () => {
|
|
|
166
170
|
expect(result.script).toContain('Package.resolved');
|
|
167
171
|
expect(result.script).toContain('spm-');
|
|
168
172
|
});
|
|
173
|
+
// A static `toContain` check can't catch a control-flow bug in the
|
|
174
|
+
// fallback chain (the script "contains" both Podfile.lock and
|
|
175
|
+
// Package.resolved either way). So actually execute the generated
|
|
176
|
+
// key-derivation in a fixture repo and read the resolved key back.
|
|
177
|
+
describe('ios fallback chain (executed in a fixture repo)', () => {
|
|
178
|
+
async function resolveIosCacheKey(build) {
|
|
179
|
+
const script = (await new CachePullStepExecutor().execute({ technology: 'ios' }, {}, testConfigNoPeer)).script;
|
|
180
|
+
const dir = mkdtempSync(join(tmpdir(), 'cibuild-cache-'));
|
|
181
|
+
try {
|
|
182
|
+
build(dir);
|
|
183
|
+
const scriptPath = join(dir, '__cache_pull.sh');
|
|
184
|
+
writeFileSync(scriptPath, script);
|
|
185
|
+
let out = '';
|
|
186
|
+
try {
|
|
187
|
+
out = execFileSync('bash', [scriptPath], {
|
|
188
|
+
cwd: dir,
|
|
189
|
+
encoding: 'utf-8',
|
|
190
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
catch (e) {
|
|
194
|
+
const err = e;
|
|
195
|
+
out = `${err.stdout ?? ''}${err.stderr ?? ''}`;
|
|
196
|
+
}
|
|
197
|
+
const m = out.match(/CACHE_KEY=(\S+)/);
|
|
198
|
+
if (!m)
|
|
199
|
+
throw new Error(`No CACHE_KEY in output:\n${out}`);
|
|
200
|
+
return m[1];
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
rmSync(dir, { recursive: true, force: true });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
test('SPM project (Package.resolved, no Podfile.lock) resolves an spm- key', async () => {
|
|
207
|
+
const key = await resolveIosCacheKey((dir) => {
|
|
208
|
+
// Real Xcode SPM location — Package.resolved committed under
|
|
209
|
+
// the shared xcworkspace data, no Podfile.lock anywhere.
|
|
210
|
+
const swiftpm = join(dir, 'Everli.xcodeproj/project.xcworkspace/xcshareddata/swiftpm');
|
|
211
|
+
mkdirSync(swiftpm, { recursive: true });
|
|
212
|
+
writeFileSync(join(swiftpm, 'Package.resolved'), '{"pins":[],"version":3}');
|
|
213
|
+
});
|
|
214
|
+
expect(key).toMatch(/^spm-/);
|
|
215
|
+
expect(key).not.toContain('no-lockfile');
|
|
216
|
+
});
|
|
217
|
+
test('CocoaPods project (Podfile.lock) resolves a pods- key', async () => {
|
|
218
|
+
const key = await resolveIosCacheKey((dir) => {
|
|
219
|
+
writeFileSync(join(dir, 'Podfile.lock'), 'PODS:\n - Alamofire\n');
|
|
220
|
+
});
|
|
221
|
+
expect(key).toMatch(/^pods-/);
|
|
222
|
+
expect(key).not.toContain('no-lockfile');
|
|
223
|
+
});
|
|
224
|
+
test('Podfile.lock wins over Package.resolved when both exist', async () => {
|
|
225
|
+
const key = await resolveIosCacheKey((dir) => {
|
|
226
|
+
writeFileSync(join(dir, 'Podfile.lock'), 'PODS:\n');
|
|
227
|
+
writeFileSync(join(dir, 'Package.resolved'), '{"pins":[]}');
|
|
228
|
+
});
|
|
229
|
+
expect(key).toMatch(/^pods-/);
|
|
230
|
+
expect(key).not.toContain('no-lockfile');
|
|
231
|
+
});
|
|
232
|
+
test('neither lockfile present falls back to a no-lockfile key', async () => {
|
|
233
|
+
const key = await resolveIosCacheKey(() => { });
|
|
234
|
+
expect(key).toContain('no-lockfile');
|
|
235
|
+
});
|
|
236
|
+
});
|
|
169
237
|
test('should auto-configure for yarn technology', async () => {
|
|
170
238
|
const executor = new CachePullStepExecutor();
|
|
171
239
|
const result = await executor.execute({ technology: 'yarn' }, {}, testConfig);
|