@invarn/cibuild 1.5.1 → 1.5.3
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;AA8DF;;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;
|
|
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;AA8DF;;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;CA8KhC;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;YA4JzF,iBAAiB;CA6HhC"}
|
|
@@ -274,10 +274,13 @@ export class CachePullStepExecutor extends BaseStepExecutor {
|
|
|
274
274
|
// and creates a fresh tarball under the new key for future exact hits.
|
|
275
275
|
commands.push('else');
|
|
276
276
|
commands.push(' __ci_fb_scope="${CACHE_KEY%-*}"');
|
|
277
|
-
|
|
277
|
+
// `|| true` defuses pipefail+errexit when ls finds no matches: bare
|
|
278
|
+
// assignment would abort the whole cache-pull step silently on an empty
|
|
279
|
+
// cache dir, flipping any cold miss into a non-zero exit.
|
|
280
|
+
commands.push(' __ci_fb=$(ls -t "$CACHE_DIR"/"$__ci_fb_scope"-*.tar.zst 2>/dev/null | head -1 || true)');
|
|
278
281
|
if (peerCacheDir) {
|
|
279
282
|
commands.push(' if [ -z "$__ci_fb" ] || [ ! -f "$__ci_fb" ]; then');
|
|
280
|
-
commands.push(' __ci_fb=$(ls -t "$PEER_CACHE_DIR"/"$__ci_fb_scope"-*.tar.zst 2>/dev/null | head -1)');
|
|
283
|
+
commands.push(' __ci_fb=$(ls -t "$PEER_CACHE_DIR"/"$__ci_fb_scope"-*.tar.zst 2>/dev/null | head -1 || true)');
|
|
281
284
|
commands.push(' __ci_fb_src=peer');
|
|
282
285
|
commands.push(' else');
|
|
283
286
|
commands.push(' __ci_fb_src=local');
|
|
@@ -288,14 +291,23 @@ export class CachePullStepExecutor extends BaseStepExecutor {
|
|
|
288
291
|
}
|
|
289
292
|
commands.push(' if [ -n "$__ci_fb" ] && [ -f "$__ci_fb" ]; then');
|
|
290
293
|
commands.push(' __ci_fb_key=$(basename "$__ci_fb" .tar.zst)');
|
|
291
|
-
|
|
294
|
+
// Age cap: a fallback older than 30d likely carries obsolete .konan
|
|
295
|
+
// installs or Gradle entries from a pre-wrapper-bump world. Go cold
|
|
296
|
+
// rather than seed from ancient state. Exact-key hits are unaffected.
|
|
297
|
+
commands.push(' __ci_fb_age_days=$(( ($(date +%s) - $(stat -f %m "$__ci_fb")) / 86400 ))');
|
|
298
|
+
commands.push(' if [ "$__ci_fb_age_days" -le 30 ]; then');
|
|
299
|
+
commands.push(' echo "Cache fallback ($__ci_fb_src): using prior tarball $__ci_fb_key (${__ci_fb_age_days}d old)"');
|
|
292
300
|
if (isDebugMode) {
|
|
293
|
-
commands.push('
|
|
294
|
-
}
|
|
295
|
-
commands.push('
|
|
296
|
-
commands.push('
|
|
301
|
+
commands.push(' echo "Fallback size: $(du -h "$__ci_fb" | cut -f1)"');
|
|
302
|
+
}
|
|
303
|
+
commands.push(' zstd -dc "$__ci_fb" | tar -xf - -C /');
|
|
304
|
+
commands.push(' echo "CACHE_SOURCE=fallback_$__ci_fb_src CACHE_KEY=$CACHE_KEY FALLBACK_KEY=$__ci_fb_key"');
|
|
305
|
+
commands.push(' else');
|
|
306
|
+
commands.push(' echo "Cache fallback candidate $__ci_fb_key is ${__ci_fb_age_days}d old, exceeds 30d cap — going cold"');
|
|
307
|
+
commands.push(' echo "CACHE_SOURCE=cold CACHE_KEY=$CACHE_KEY FALLBACK_REJECTED=$__ci_fb_key"');
|
|
308
|
+
commands.push(' fi');
|
|
297
309
|
commands.push(' else');
|
|
298
|
-
// 4. Cold miss — no exact key, no fallback
|
|
310
|
+
// 4. Cold miss — no exact key, no fallback candidate
|
|
299
311
|
commands.push(' echo "No cache found for key: $CACHE_KEY"');
|
|
300
312
|
commands.push(' echo "CACHE_SOURCE=cold CACHE_KEY=$CACHE_KEY"');
|
|
301
313
|
commands.push(' fi');
|
|
@@ -543,6 +555,20 @@ export class CachePushStepExecutor extends BaseStepExecutor {
|
|
|
543
555
|
if (isDebugMode) {
|
|
544
556
|
commands.push(' echo "Cache size: $(du -h "$CACHE_FILE" | cut -f1)"');
|
|
545
557
|
}
|
|
558
|
+
// Retention: keep 5 newest tarballs per <keyPrefix>-<projectId> scope,
|
|
559
|
+
// delete older ones to bound disk usage. Runs inline after every push;
|
|
560
|
+
// no cron required.
|
|
561
|
+
commands.push(' __ci_ret_scope="${CACHE_KEY%-*}"');
|
|
562
|
+
// `|| true` guards against pipefail when ls matches nothing (first push
|
|
563
|
+
// for a new scope) — otherwise the step would silently exit non-zero.
|
|
564
|
+
commands.push(' __ci_ret_old=$(ls -t "$CACHE_DIR"/"$__ci_ret_scope"-*.tar.zst 2>/dev/null | tail -n +6 || true)');
|
|
565
|
+
commands.push(' if [ -n "$__ci_ret_old" ]; then');
|
|
566
|
+
commands.push(' __ci_ret_count=$(printf "%s\\n" "$__ci_ret_old" | wc -l | tr -d " ")');
|
|
567
|
+
commands.push(' echo "Retention: removing $__ci_ret_count older tarball(s) from scope $__ci_ret_scope"');
|
|
568
|
+
commands.push(' printf "%s\\n" "$__ci_ret_old" | while IFS= read -r __ci_ret_f; do');
|
|
569
|
+
commands.push(' [ -f "$__ci_ret_f" ] && rm -f "$__ci_ret_f"');
|
|
570
|
+
commands.push(' done');
|
|
571
|
+
commands.push(' fi');
|
|
546
572
|
commands.push(' else');
|
|
547
573
|
commands.push(' echo "Warning: Failed to create cache file"');
|
|
548
574
|
commands.push(' fi');
|
|
@@ -259,6 +259,15 @@ describe('Step Implementations', () => {
|
|
|
259
259
|
expect(result.script).toContain('__ci_proj=$');
|
|
260
260
|
expect(result.script).toContain('CACHE_KEY="pods-${__ci_proj}-${CHECKSUM}"');
|
|
261
261
|
});
|
|
262
|
+
test('should enforce 30-day age cap on fallback, going cold when older', async () => {
|
|
263
|
+
const executor = new CachePullStepExecutor();
|
|
264
|
+
const result = await executor.execute({ technology: 'kmm' }, {}, testConfig);
|
|
265
|
+
// Computes age in days from stat mtime, rejects if over 30
|
|
266
|
+
expect(result.script).toContain('__ci_fb_age_days=$(( ($(date +%s) - $(stat -f %m "$__ci_fb")) / 86400 ))');
|
|
267
|
+
expect(result.script).toContain('if [ "$__ci_fb_age_days" -le 30 ]');
|
|
268
|
+
expect(result.script).toContain('exceeds 30d cap — going cold');
|
|
269
|
+
expect(result.script).toContain('FALLBACK_REJECTED=');
|
|
270
|
+
});
|
|
262
271
|
});
|
|
263
272
|
describe('CachePushStepExecutor', () => {
|
|
264
273
|
test('should generate cache push script', async () => {
|
|
@@ -370,6 +379,21 @@ describe('Step Implementations', () => {
|
|
|
370
379
|
expect(result.script).toContain('> "$CACHE_FILE.tmp"');
|
|
371
380
|
expect(result.script).toContain('mv "$CACHE_FILE.tmp" "$CACHE_FILE"');
|
|
372
381
|
});
|
|
382
|
+
test('should sweep retention (keep 5 newest per scope) after successful push', async () => {
|
|
383
|
+
const executor = new CachePushStepExecutor();
|
|
384
|
+
const result = await executor.execute({ technology: 'kmm' }, {}, testConfig);
|
|
385
|
+
// Scope = prefix + projectId; retention globs that scope and keeps 5 newest
|
|
386
|
+
expect(result.script).toContain('__ci_ret_scope="${CACHE_KEY%-*}"');
|
|
387
|
+
expect(result.script).toContain('ls -t "$CACHE_DIR"/"$__ci_ret_scope"-*.tar.zst');
|
|
388
|
+
expect(result.script).toContain('tail -n +6');
|
|
389
|
+
expect(result.script).toContain('rm -f "$__ci_ret_f"');
|
|
390
|
+
});
|
|
391
|
+
test('should not run retention for manual cache_key push (no scope)', async () => {
|
|
392
|
+
const executor = new CachePushStepExecutor();
|
|
393
|
+
const result = await executor.execute({ cache_key: 'my-key', cache_paths: ['build'] }, {}, testConfig);
|
|
394
|
+
expect(result.script).not.toContain('__ci_ret_scope');
|
|
395
|
+
expect(result.script).not.toContain('tail -n +6');
|
|
396
|
+
});
|
|
373
397
|
test('should use atomic write (tmp + mv) for manual cache_key push', async () => {
|
|
374
398
|
const executor = new CachePushStepExecutor();
|
|
375
399
|
const result = await executor.execute({ cache_key: 'my-key', cache_paths: ['build'] }, {}, testConfig);
|