@invarn/cibuild 1.9.3 → 1.9.4

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;CA8LhC;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;CA2IhC"}
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;CA8LhC;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;CAoHhC"}
@@ -593,34 +593,11 @@ export class CachePushStepExecutor extends BaseStepExecutor {
593
593
  if (isDebugMode) {
594
594
  commands.push(' echo "Cache size: $(du -h "$CACHE_FILE" | cut -f1)"');
595
595
  }
596
- // Retention per-scope: (1) keep N newest by mtime touched on hit in
597
- // cache-pull so this is LRU, not strictly creation-order; (2) delete
598
- // anything past the age cap regardless of position; (3) enforce a size
599
- // budget, oldest-out. Two passes are required: the size pass needs the
600
- // post-cleanup set, otherwise its running sum counts tarballs that the
601
- // count/age pass is about to delete and over-evicts.
602
- commands.push(' __ci_ret_scope="${CACHE_KEY%-*}"');
603
- commands.push(' __ci_ret_count_cap=5');
604
- commands.push(' __ci_ret_age_cap=$((30 * 86400))');
605
- commands.push(' __ci_ret_size_cap_kb="${CIBUILD_CACHE_SCOPE_BUDGET_KB:-10485760}"');
606
- commands.push(' __ci_ret_now=$(date +%s)');
607
- commands.push(' __ci_ret_idx=0');
608
- commands.push(' while IFS= read -r __ci_ret_f; do');
609
- commands.push(' __ci_ret_idx=$((__ci_ret_idx + 1))');
610
- commands.push(' __ci_ret_age=$(( __ci_ret_now - $(stat -f %m "$__ci_ret_f" 2>/dev/null || echo "$__ci_ret_now") ))');
611
- commands.push(' if [ "$__ci_ret_idx" -gt "$__ci_ret_count_cap" ] || [ "$__ci_ret_age" -gt "$__ci_ret_age_cap" ]; then');
612
- commands.push(' rm -f "$__ci_ret_f"');
613
- commands.push(' fi');
614
- commands.push(' done < <(ls -t "$CACHE_DIR"/"$__ci_ret_scope"-*.tar.zst 2>/dev/null)');
615
- commands.push(' __ci_ret_running_kb=0');
616
- commands.push(' while IFS= read -r __ci_ret_f; do');
617
- commands.push(' __ci_ret_size=$(du -k "$__ci_ret_f" 2>/dev/null | cut -f1)');
618
- commands.push(' __ci_ret_size=${__ci_ret_size:-0}');
619
- commands.push(' __ci_ret_running_kb=$((__ci_ret_running_kb + __ci_ret_size))');
620
- commands.push(' if [ "$__ci_ret_running_kb" -gt "$__ci_ret_size_cap_kb" ]; then');
621
- commands.push(' rm -f "$__ci_ret_f"');
622
- commands.push(' fi');
623
- commands.push(' done < <(ls -t "$CACHE_DIR"/"$__ci_ret_scope"-*.tar.zst 2>/dev/null)');
596
+ // Retention is no longer applied here (ADR 0002 / CBR-6). It moved into the
597
+ // long-lived peer cache daemon, which owns ~/cache and — unlike the guest —
598
+ // knows (via the manager) which scopes this runner OWNS and must never evict.
599
+ // A guest-side prune would have to run blind to ownership and could reap the
600
+ // fleet's single durable copy, so the daemon owns the whole policy now.
624
601
  commands.push(' else');
625
602
  commands.push(' echo "Warning: Failed to create cache file"');
626
603
  commands.push(' fi');
@@ -424,17 +424,21 @@ describe('Step Implementations', () => {
424
424
  expect(result.script).toContain('> "$CACHE_FILE.tmp"');
425
425
  expect(result.script).toContain('mv "$CACHE_FILE.tmp" "$CACHE_FILE"');
426
426
  });
427
- test('should sweep retention (count + age + size budget) after successful preset push', async () => {
427
+ test('should NOT emit guest-side retention (the peer cache daemon owns it, CBR-6)', async () => {
428
+ // ADR 0002 / CBR-6: retention moved into the long-lived peer cache daemon,
429
+ // which knows (via the manager) which scopes this runner owns and must never
430
+ // evict. The guest cache-push no longer prunes — it could only reap an owner's
431
+ // durable copy, having no ownership knowledge of its own.
428
432
  const executor = new CachePushStepExecutor();
429
433
  const result = await executor.execute({ technology: 'kmm' }, {}, testConfig);
430
- expect(result.script).toContain('__ci_ret_scope="${CACHE_KEY%-*}"');
431
- expect(result.script).toContain('ls -t "$CACHE_DIR"/"$__ci_ret_scope"-*.tar.zst');
432
- expect(result.script).toContain('__ci_ret_count_cap=5');
433
- expect(result.script).toContain('__ci_ret_age_cap=$((30 * 86400))');
434
- expect(result.script).toContain('CIBUILD_CACHE_SCOPE_BUDGET_KB');
435
- expect(result.script).toContain('rm -f "$__ci_ret_f"');
436
- });
437
- test('should not run retention for manual cache_key push (no scope)', async () => {
434
+ expect(result.script).not.toContain('__ci_ret_scope');
435
+ expect(result.script).not.toContain('__ci_ret_count_cap');
436
+ expect(result.script).not.toContain('__ci_ret_age_cap');
437
+ expect(result.script).not.toContain('CIBUILD_CACHE_SCOPE_BUDGET_KB');
438
+ // The successful-push path itself is unchanged.
439
+ expect(result.script).toContain('Cache created successfully');
440
+ });
441
+ test('should not emit retention for a manual cache_key push either', async () => {
438
442
  const executor = new CachePushStepExecutor();
439
443
  const result = await executor.execute({ cache_key: 'my-key', cache_paths: ['build'] }, {}, testConfig);
440
444
  expect(result.script).not.toContain('__ci_ret_scope');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@invarn/cibuild",
3
- "version": "1.9.3",
3
+ "version": "1.9.4",
4
4
  "description": "CI Build CLI — local pipeline orchestration and validation",
5
5
  "type": "module",
6
6
  "main": "dist/cli.cjs",