@firestartr/cli 2.8.0-snapshot-variant-cloning-test-1 → 2.8.0-snapshot-variant-cloning-2

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/build/index.js CHANGED
@@ -317375,10 +317375,12 @@ class InitializerClaimRef extends InitializerPatches {
317375
317375
  apply(cr) {
317376
317376
  cr.metadata = cr.metadata ?? {};
317377
317377
  cr.metadata.labels = cr.metadata.labels ?? {};
317378
- cr.metadata.labels['claim-ref'] = catalog_common/* default.generic.normalizeLabel */.Z.generic.normalizeLabel(claim.name);
317378
+ const claimName = claim._parentClaimName || claim.name;
317379
+ cr.metadata.labels['claim-ref'] =
317380
+ catalog_common/* default.generic.normalizeLabel */.Z.generic.normalizeLabel(claimName);
317379
317381
  cr.metadata.annotations = {
317380
317382
  ...(cr.metadata.annotations || {}),
317381
- [catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('claim-ref')]: `${claim.kind}/${claim.name}`,
317383
+ [catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('claim-ref')]: `${claim.kind}/${claimName}`,
317382
317384
  };
317383
317385
  return cr;
317384
317386
  },
@@ -320729,10 +320731,6 @@ const GithubSchemas = [
320729
320731
  description: 'Override fields for a variant of a TFWorkspaceClaim',
320730
320732
  type: 'object',
320731
320733
  properties: {
320732
- name: {
320733
- type: 'string',
320734
- description: 'override the terraform provider name',
320735
- },
320736
320734
  values: {
320737
320735
  type: 'object',
320738
320736
  additionalProperties: true,
@@ -320799,7 +320797,8 @@ const GithubSchemas = [
320799
320797
  properties: {
320800
320798
  name: {
320801
320799
  type: 'string',
320802
- description: 'name of the variant — used as claim name and CR name base',
320800
+ maxLength: 10,
320801
+ description: 'shorthand suffix — composed with main tf name to form the final CR name',
320803
320802
  },
320804
320803
  overrides: {
320805
320804
  $ref: 'firestartr.dev://terraform/TerraformProviderVariantOverride',
@@ -321327,26 +321326,26 @@ async function loadClaim(claimRef, org, defaults = loadClaimDefaults(), patchCla
321327
321326
  if (!variant.name || !variant.overrides) {
321328
321327
  throw new Error(`Variant in claim ${claimRef} is missing required field 'name' or 'overrides'`);
321329
321328
  }
321330
- const prohibitedOverrideFields = ['source', 'module'];
321329
+ const prohibitedOverrideFields = ['source', 'module', 'name'];
321331
321330
  for (const field of prohibitedOverrideFields) {
321332
321331
  if (field in variant.overrides) {
321333
321332
  throw new Error(`Variant '${variant.name}' in claim ${claimRef} cannot override '${field}'`);
321334
321333
  }
321335
321334
  }
321335
+ const composedName = claim.providers.terraform.name + '-' + variant.name;
321336
321336
  const variantClaim = lodash_default().cloneDeep(claim);
321337
- variantClaim.name = variant.name;
321337
+ variantClaim._parentClaimName = claim.name;
321338
+ variantClaim.name = composedName;
321338
321339
  variantClaim.providers.terraform = lodash_default().merge({}, claim.providers.terraform, variant.overrides);
321339
- if (!variant.overrides.name) {
321340
- variantClaim.providers.terraform.name = variant.name;
321341
- }
321340
+ variantClaim.providers.terraform.name = composedName;
321342
321341
  if (!variantClaim.annotations) {
321343
321342
  variantClaim.annotations = {};
321344
321343
  }
321345
321344
  variantClaim.annotations['firestartr.dev/variant-of'] =
321346
321345
  claim.providers.terraform.name;
321347
- const variantRef = `TFWorkspaceClaim-${variant.name}`;
321346
+ const variantRef = `TFWorkspaceClaim-${composedName}`;
321348
321347
  if (result[variantRef]) {
321349
- throw new Error(`Variant name '${variant.name}' from claim '${claimRef}' conflicts with existing claim '${variantRef}'`);
321348
+ throw new Error(`Variant name '${variant.name}' (composed: '${composedName}') from claim '${claimRef}' conflicts with existing claim '${variantRef}'`);
321350
321349
  }
321351
321350
  logger.info(`Creating synthetic variant claim ${variantRef}`);
321352
321351
  result[variantRef] = {};
@@ -331003,7 +331002,19 @@ var OperationType;
331003
331002
  OperationType["MARKED_TO_DELETION"] = "MARKED_TO_DELETION";
331004
331003
  OperationType["NOTHING"] = "NOTHING";
331005
331004
  OperationType["RETRY"] = "RETRY";
331005
+ OperationType["RETRY_SYNC"] = "RETRY_SYNC";
331006
331006
  })(OperationType || (OperationType = {}));
331007
+ function retryOpForReason(reason) {
331008
+ if (!reason)
331009
+ return OperationType.RETRY;
331010
+ const base = reason.startsWith('RETRY_') ? reason.slice(6) : reason;
331011
+ switch (base) {
331012
+ case 'SYNC':
331013
+ return OperationType.RETRY_SYNC;
331014
+ default:
331015
+ return OperationType.RETRY;
331016
+ }
331017
+ }
331007
331018
  var WorkStatus;
331008
331019
  (function (WorkStatus) {
331009
331020
  WorkStatus["PENDING"] = "PENDING";
@@ -331020,6 +331031,7 @@ const TIMEOUTS = {
331020
331031
  UPDATED: DAY_SECONDS,
331021
331032
  CREATED: DAY_SECONDS,
331022
331033
  RETRY: 120 * 60,
331034
+ RETRY_SYNC: 120 * 60,
331023
331035
  MARKED_TO_DELETION: DAY_SECONDS,
331024
331036
  SYNC: DAY_SECONDS,
331025
331037
  NOTHING: 10,
@@ -331257,13 +331269,13 @@ async function ctl_getItemByItemPath(itemPath, apiGroup = catalog_common/* defau
331257
331269
  const r = await fetchItemByItemPathResponse(itemPath, apiGroup, apiVersion);
331258
331270
  if (!r.ok) {
331259
331271
  const err = new Error(`Error on getItemByItemPath: ${itemPath}: ${r.statusText}`);
331260
- operator_src_logger.error(`Error on getItemByItemPath: ${itemPath}: ${r.statusText}`);
331272
+ operator_src_logger.warn(`Error on getItemByItemPath: ${itemPath}: ${r.statusText}`);
331261
331273
  throw err;
331262
331274
  }
331263
331275
  return await r.json();
331264
331276
  }
331265
331277
  catch (e) {
331266
- operator_src_logger.error(`Error on getItemByItemPath: ${e}`);
331278
+ operator_src_logger.warn(`Error on getItemByItemPath: ${e instanceof Error ? e.stack || e.message : JSON.stringify(e)}`);
331267
331279
  throw e;
331268
331280
  }
331269
331281
  });
@@ -331284,13 +331296,13 @@ async function getItemByItemPathOrNull(itemPath, apiGroup = catalog_common/* def
331284
331296
  }
331285
331297
  if (!r.ok) {
331286
331298
  const err = new Error(`Error on getItemByItemPathOrNull: ${itemPath}: ${r.statusText}`);
331287
- operator_src_logger.error(`Error on getItemByItemPathOrNull: ${itemPath}: ${r.statusText}`);
331299
+ operator_src_logger.warn(`Error on getItemByItemPathOrNull: ${itemPath}: ${r.statusText}`);
331288
331300
  throw err;
331289
331301
  }
331290
331302
  return await r.json();
331291
331303
  }
331292
331304
  catch (e) {
331293
- operator_src_logger.error(`Error on getItemByItemPathOrNull: ${e}`);
331305
+ operator_src_logger.warn(`Error on getItemByItemPathOrNull: ${e instanceof Error ? e.stack || e.message : JSON.stringify(e)}`);
331294
331306
  throw e;
331295
331307
  }
331296
331308
  });
@@ -331456,6 +331468,21 @@ async function upsertResult(namespace, item, result, exitCode = 0, existingRetry
331456
331468
  headers: opts.headers,
331457
331469
  body: JSON.stringify(resultObject),
331458
331470
  });
331471
+ if (r.status === 409) {
331472
+ operator_src_logger.debug(`TFResult '${tfResultName}' already exists (409), updating.`);
331473
+ const existingUrl = `${kc.getCurrentCluster().server}/apis/firestartr.dev/v1/namespaces/${namespace}/tfresults/${tfResultName}`;
331474
+ const getResp = await fetch(existingUrl, { ...opts, method: 'GET' });
331475
+ if (!getResp.ok) {
331476
+ throw `TFResult: failed to fetch existing '${tfResultName}': ${getResp.statusText}`;
331477
+ }
331478
+ const existing = await getResp.json();
331479
+ existing.spec.result = result.toString();
331480
+ const updated = await writeManifest('tfresults', namespace, existing, `apis/firestartr.dev/v1/namespaces/${namespace}/tfresults/${tfResultName}`);
331481
+ await tryWriteTFResultStatus(namespace, tfResultName, updated.metadata.resourceVersion, exitCode, newRetryCount);
331482
+ updated.status = updated.status || {};
331483
+ updated.status.retryCount = newRetryCount;
331484
+ return updated;
331485
+ }
331459
331486
  if (!r.ok) {
331460
331487
  throw `TFResult: ${r.statusText}`;
331461
331488
  }
@@ -332471,15 +332498,20 @@ async function syncer(enqueue) {
332471
332498
  async function loop(enqueueIfNeeded, api) {
332472
332499
  void loopKeeper(api);
332473
332500
  while (1) {
332474
- await fWait();
332475
- const needRevisionItems = Object.values(syncWatchers).filter((watcher) => watcher.needsRevision);
332476
- for (const watcher of needRevisionItems) {
332477
- const item = await getItemIfNeededSync(watcher);
332478
- operator_src_logger.debug(`Item needs revision ${watcher.itemPath}`);
332479
- if (item !== null) {
332480
- enqueueIfNeeded(item);
332501
+ try {
332502
+ await fWait();
332503
+ const needRevisionItems = Object.values(syncWatchers).filter((watcher) => watcher.needsRevision);
332504
+ for (const watcher of needRevisionItems) {
332505
+ const item = await getItemIfNeededSync(watcher);
332506
+ operator_src_logger.debug(`Item needs revision ${watcher.itemPath}`);
332507
+ if (item !== null) {
332508
+ enqueueIfNeeded(item);
332509
+ }
332510
+ watcher.needsRevision = false;
332481
332511
  }
332482
- watcher.needsRevision = false;
332512
+ }
332513
+ catch (err) {
332514
+ operator_src_logger.error(`Error in sync loop: ${err}`);
332483
332515
  }
332484
332516
  }
332485
332517
  }
@@ -332499,15 +332531,34 @@ async function loopKeeper(api) {
332499
332531
  process.exit(1);
332500
332532
  }
332501
332533
  }
332502
- async function getItemIfNeededSync(watcher) {
332503
- const item = await ctl_getItemByItemPath(watcher.itemPath);
332504
- const isProvisioning = item.status?.conditions?.find((condition) => condition.type === 'PROVISIONING' && condition.status === 'True');
332505
- if (isProvisioning)
332506
- return null;
332507
- const isDeleting = item.status?.conditions?.find((condition) => condition.type === 'DELETING' && condition.status === 'True');
332508
- if (isDeleting)
332534
+ async function getItemIfNeededSync(watcher, watchers) {
332535
+ const targetWatchers = watchers ?? syncWatchers;
332536
+ try {
332537
+ const item = await ctl_getItemByItemPath(watcher.itemPath);
332538
+ const isProvisioning = item.status?.conditions?.find((condition) => condition.type === 'PROVISIONING' && condition.status === 'True');
332539
+ if (isProvisioning)
332540
+ return null;
332541
+ const isDeleting = item.status?.conditions?.find((condition) => condition.type === 'DELETING' && condition.status === 'True');
332542
+ if (isDeleting)
332543
+ return null;
332544
+ return item;
332545
+ }
332546
+ catch (e) {
332547
+ if (e.message && e.message.includes('Error on getItemByItemPath')) {
332548
+ if (e.message.includes('Not Found')) {
332549
+ operator_src_logger.debug(`Item '${watcher.itemPath}' not found, removing from sync watchers.`);
332550
+ delete targetWatchers[watcher.itemPath];
332551
+ }
332552
+ else {
332553
+ operator_src_logger.warn(`Transient error fetching '${watcher.itemPath}', keeping sync watcher: ${e.message}`);
332554
+ }
332555
+ return null;
332556
+ }
332557
+ else {
332558
+ operator_src_logger.error(e);
332559
+ }
332509
332560
  return null;
332510
- return item;
332561
+ }
332511
332562
  }
332512
332563
  function fWait(segs = 1) {
332513
332564
  return new Promise((ok) => {
@@ -332515,19 +332566,122 @@ function fWait(segs = 1) {
332515
332566
  });
332516
332567
  }
332517
332568
 
332569
+ ;// CONCATENATED MODULE: ../operator/src/retry.debug.ts
332570
+
332571
+
332572
+
332573
+
332574
+ const RETRY_DEBUG_INTERVAL_MS = 60 * 1000;
332575
+ const loggedEvents = new Set();
332576
+ function writeEventIfNew(itemPath, counter, next, maxRetry = 5) {
332577
+ const key = `${itemPath}-retry-${counter}`;
332578
+ if (loggedEvents.has(key))
332579
+ return;
332580
+ loggedEvents.add(key);
332581
+ resolveRetryType(itemPath)
332582
+ .then((type) => {
332583
+ const nextStr = next ?? 'none';
332584
+ const line = `${itemPath} - ${type} - retry ${counter + 1}/${maxRetry} - next: ${nextStr}\n`;
332585
+ return new Promise((ok, ko) => {
332586
+ external_fs_.appendFile('/tmp/retries', line, (err) => {
332587
+ if (err)
332588
+ ko(`Error appending to /tmp/retries: ${err}`);
332589
+ else
332590
+ ok();
332591
+ });
332592
+ });
332593
+ })
332594
+ .catch(() => {
332595
+ operator_src_logger.warn(`Failed to resolve retry type for ${itemPath}`);
332596
+ });
332597
+ }
332598
+ function initRetryDebug(retryWatchers, maxRetry) {
332599
+ loggedEvents.clear();
332600
+ try {
332601
+ external_fs_.writeFileSync('/tmp/retries', '');
332602
+ }
332603
+ catch {
332604
+ operator_src_logger.warn('Failed to clear /tmp/retries');
332605
+ }
332606
+ let running = false;
332607
+ setInterval(() => {
332608
+ if (running)
332609
+ return;
332610
+ running = true;
332611
+ writeRetryDebug(retryWatchers, maxRetry)
332612
+ .then(() => {
332613
+ running = false;
332614
+ })
332615
+ .catch((err) => {
332616
+ operator_src_logger.error(`PANIC cannot evaluate the retry debug!!!: ${err}`);
332617
+ running = false;
332618
+ });
332619
+ }, RETRY_DEBUG_INTERVAL_MS);
332620
+ }
332621
+ async function writeRetryDebug(retryWatchers, maxRetry) {
332622
+ let output = '';
332623
+ for (const watcher of Object.values(retryWatchers)) {
332624
+ const type = await resolveRetryType(watcher.itemPath);
332625
+ const nextStr = watcher.retry
332626
+ ? 'pending'
332627
+ : (watcher.nextRetryAt ?? 'unknown');
332628
+ output += `${watcher.itemPath} - ${type} - retry ${watcher.retryCounter + 1}/${maxRetry} - next: ${nextStr}\n`;
332629
+ }
332630
+ return new Promise((ok, ko) => {
332631
+ external_fs_.writeFile('/tmp/retries', output, (err) => {
332632
+ if (err)
332633
+ ko(`Error writing /tmp/retries: ${err}`);
332634
+ else
332635
+ ok();
332636
+ });
332637
+ });
332638
+ }
332639
+ async function resolveRetryType(itemPath) {
332640
+ try {
332641
+ const item = await ctl_getItemByItemPath(itemPath);
332642
+ const errorCondition = item.status?.conditions?.find((c) => c.type === 'ERROR' && c.status === 'True');
332643
+ return retryOpForReason(errorCondition?.reason) || 'RETRY';
332644
+ }
332645
+ catch {
332646
+ return 'RETRY';
332647
+ }
332648
+ }
332649
+
332518
332650
  ;// CONCATENATED MODULE: ../operator/src/retry.ts
332519
332651
 
332520
332652
 
332653
+
332521
332654
  // Retries now use exponential backoff, starting at 5 minutes
332522
332655
  // and doubling each time, up to the maximum number of retries
332523
- // configured by MAXRETRY.
332524
- const NEXT_RETRY_MS = 1000 * 60 * 5;
332525
- const MAXRETRY = 5;
332656
+ // configured by OPERATOR_MAX_RETRY (getMaxRetry()).
332657
+ //
332658
+ // Both values can be overridden via environment variables for testing:
332659
+ // OPERATOR_NEXT_RETRY_MS — base delay in ms (default: 300000 = 5 min)
332660
+ // OPERATOR_MAX_RETRY — max retry attempts (default: 5)
332661
+ function getNextRetryMs() {
332662
+ const env = process.env.OPERATOR_NEXT_RETRY_MS;
332663
+ if (env) {
332664
+ const n = Number.parseInt(env, 10);
332665
+ if (Number.isFinite(n) && n > 0)
332666
+ return n;
332667
+ }
332668
+ return 1000 * 60 * 5;
332669
+ }
332670
+ function getMaxRetry() {
332671
+ const env = process.env.OPERATOR_MAX_RETRY;
332672
+ if (env) {
332673
+ const n = Number.parseInt(env, 10);
332674
+ if (Number.isFinite(n) && n > 0)
332675
+ return n;
332676
+ }
332677
+ return 5;
332678
+ }
332526
332679
  function nextRetryMs(currCounter) {
332527
- return NEXT_RETRY_MS * Math.pow(2, currCounter);
332680
+ return getNextRetryMs() * Math.pow(2, currCounter);
332528
332681
  }
332529
332682
  const retryWatchers = {};
332530
332683
  async function initRetry(enqueue) {
332684
+ initRetryDebug(retryWatchers, getMaxRetry());
332531
332685
  void retry_loop(enqueue);
332532
332686
  return {
332533
332687
  errorReconciling(itemPath) {
@@ -332551,23 +332705,29 @@ function retry(itemPath) {
332551
332705
  retry: false,
332552
332706
  retryCounter: 0,
332553
332707
  nextRetry: null,
332708
+ nextRetryAt: null,
332554
332709
  };
332555
332710
  }
332556
332711
  const currCounter = retryWatchers[itemPath].retryCounter;
332557
- const delayMs = NEXT_RETRY_MS * Math.pow(2, currCounter);
332558
- if (currCounter >= MAXRETRY) {
332559
- operator_src_logger.debug(`Failed to process item '${itemPath}'. Retry limit (${MAXRETRY}) reached. No further retries will be attempted.`);
332712
+ const maxRetry = getMaxRetry();
332713
+ const delayMs = nextRetryMs(currCounter);
332714
+ if (currCounter >= maxRetry) {
332715
+ writeEventIfNew(itemPath, currCounter, null, maxRetry);
332716
+ operator_src_logger.debug(`Failed to process item '${itemPath}'. Retry limit (${maxRetry}) reached. No further retries will be attempted.`);
332560
332717
  removeFromRetry(itemPath);
332561
332718
  return;
332562
332719
  }
332563
- operator_src_logger.debug(`Failed to process item '${itemPath}'. Retrying in '${delayMs / 1000 / 60}' minutes. Remaining retries: '${MAXRETRY - currCounter - 1}'.`);
332720
+ operator_src_logger.debug(`Failed to process item '${itemPath}'. Retrying in '${delayMs / 1000 / 60}' minutes. Remaining retries: '${maxRetry - currCounter - 1}'.`);
332564
332721
  retryWatchers[itemPath].retry = false;
332565
332722
  if (retryWatchers[itemPath].nextRetry) {
332566
332723
  clearTimeout(retryWatchers[itemPath].nextRetry);
332567
332724
  }
332725
+ retryWatchers[itemPath].nextRetryAt = new Date(Date.now() + delayMs).toISOString();
332568
332726
  retryWatchers[itemPath].nextRetry = setTimeout(() => {
332569
- if (itemPath in retryWatchers)
332727
+ if (itemPath in retryWatchers) {
332570
332728
  retryWatchers[itemPath].retry = true;
332729
+ retryWatchers[itemPath].nextRetryAt = null;
332730
+ }
332571
332731
  }, delayMs);
332572
332732
  }
332573
332733
  function removeFromRetry(itemPath) {
@@ -332579,7 +332739,8 @@ function removeFromRetry(itemPath) {
332579
332739
  async function retry_loop(enqueueIfNeeded) {
332580
332740
  while (1) {
332581
332741
  await retry_fWait();
332582
- const needRetryWatchItem = Object.values(retryWatchers).filter((watcher) => watcher.retryCounter < MAXRETRY && watcher.retry);
332742
+ const maxRetry = getMaxRetry();
332743
+ const needRetryWatchItem = Object.values(retryWatchers).filter((watcher) => watcher.retryCounter < maxRetry && watcher.retry);
332583
332744
  for (const watcher of needRetryWatchItem) {
332584
332745
  const item = await getItemIfNeededRetry(watcher);
332585
332746
  if (item !== null) {
@@ -332606,7 +332767,7 @@ async function getItemIfNeededRetry(watcher) {
332606
332767
  return null;
332607
332768
  }
332608
332769
  else {
332609
- console.error(e);
332770
+ operator_src_logger.warn(`Unexpected error in retry check for '${watcher.itemPath}': ${e}`);
332610
332771
  }
332611
332772
  return null;
332612
332773
  }
@@ -332891,7 +333052,7 @@ function enqueue(pluralKind, workItem, queue, compute, syncCtl, retryCtl) {
332891
333052
  const resolvedExitCode = exitCode !== undefined ? exitCode : /\berror\b/i.test(output) ? 1 : 0;
332892
333053
  const retryCount = result?.status?.retryCount ?? 0;
332893
333054
  const backoffCounter = Math.max(retryCount - 1, 0);
332894
- const nextRetryTime = resolvedExitCode === 0 || backoffCounter >= MAXRETRY
333055
+ const nextRetryTime = resolvedExitCode === 0 || backoffCounter >= getMaxRetry()
332895
333056
  ? undefined
332896
333057
  : new Date(Date.now() + nextRetryMs(backoffCounter)).toISOString();
332897
333058
  await updateRetryStatusInCR(pluralKind, item.metadata.namespace, item.metadata.name, retryCount, nextRetryTime);
@@ -332906,6 +333067,7 @@ function enqueue(pluralKind, workItem, queue, compute, syncCtl, retryCtl) {
332906
333067
  itemPath: () => informer_itemPath(pluralKind, workItem.item),
332907
333068
  error: () => retryCtl.errorReconciling(informer_itemPath(pluralKind, workItem.item)),
332908
333069
  success: () => retryCtl.successReconciling(informer_itemPath(pluralKind, workItem.item)),
333070
+ removeFromRetry: () => retryCtl.successReconciling(informer_itemPath(pluralKind, workItem.item)),
332909
333071
  recommendedTimeout: () => {
332910
333072
  const customTimeoutAnnotation = catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('test-custom-timeout');
332911
333073
  let customTimeout = null;
@@ -332925,7 +333087,8 @@ function enqueue(pluralKind, workItem, queue, compute, syncCtl, retryCtl) {
332925
333087
  }
332926
333088
  // only for delete operations
332927
333089
  if (operation !== OperationType.MARKED_TO_DELETION) {
332928
- if (operation === OperationType.RETRY) {
333090
+ if (operation === OperationType.RETRY ||
333091
+ operation === OperationType.RETRY_SYNC) {
332929
333092
  // is the retry a delete operation?
332930
333093
  if (!('deletionTimestamp' in workItem.item.metadata)) {
332931
333094
  return false;
@@ -332961,13 +333124,15 @@ function enqueue(pluralKind, workItem, queue, compute, syncCtl, retryCtl) {
332961
333124
  operation === OperationType.UPDATED ||
332962
333125
  operation === OperationType.SYNC ||
332963
333126
  operation === OperationType.CREATED ||
332964
- operation === OperationType.RETRY;
333127
+ operation === OperationType.RETRY ||
333128
+ operation === OperationType.RETRY_SYNC;
332965
333129
  await setSyncStatus(workItem.handler.itemPath(), operation, 'False', 'Sync process started');
332966
333130
  for await (const transition of compute(item, operation, handler)) {
332967
333131
  yield transition;
332968
333132
  }
332969
333133
  if (needsUpdateSyncConditions) {
332970
- if (operation === OperationType.SYNC) {
333134
+ if (operation === OperationType.SYNC ||
333135
+ operation === OperationType.RETRY_SYNC) {
332971
333136
  // Fetch the CR once and reuse for both hasSyncFailed check and ERROR guard
332972
333137
  const currentItem = await ctl_getItemByItemPath(workItem.handler.itemPath());
332973
333138
  const syncStatus = await getSyncStatus(workItem.handler.itemPath(), currentItem);
@@ -332982,7 +333147,10 @@ function enqueue(pluralKind, workItem, queue, compute, syncCtl, retryCtl) {
332982
333147
  return;
332983
333148
  }
332984
333149
  }
332985
- await setSyncStatus(workItem.handler.itemPath(), operation, operation === OperationType.SYNC ? 'True' : 'False', 'Sync process finished');
333150
+ await setSyncStatus(workItem.handler.itemPath(), operation, operation === OperationType.SYNC ||
333151
+ operation === OperationType.RETRY_SYNC
333152
+ ? 'True'
333153
+ : 'False', 'Sync process finished');
332986
333154
  void syncCtl.updateItem(informer_itemPath(pluralKind, item));
332987
333155
  }
332988
333156
  else {
@@ -333044,18 +333212,21 @@ async function inform(pluralKind, item, op, lastWorkItem = null) {
333044
333212
  return workItem;
333045
333213
  }
333046
333214
  return null;
333047
- case 'onRetry':
333215
+ case 'onRetry': {
333048
333216
  if (workItem !== null && workItem.workStatus !== WorkStatus.FINISHED) {
333049
333217
  return null;
333050
333218
  }
333219
+ const errorCondition = item.status?.conditions?.find((c) => c.type === 'ERROR' && c.status === 'True');
333220
+ const retryOp = retryOpForReason(errorCondition?.reason);
333051
333221
  workItem = {
333052
- operation: OperationType.RETRY,
333222
+ operation: retryOp,
333053
333223
  item,
333054
333224
  workStatus: WorkStatus.PENDING,
333055
333225
  onDelete: function () { },
333056
333226
  upsertTime: Date.now(),
333057
333227
  };
333058
333228
  return workItem;
333229
+ }
333059
333230
  case 'onAdd':
333060
333231
  needed = await needsProvisioningOnCreateOrUpdate(item);
333061
333232
  if (needed.needs) {
@@ -333637,7 +333808,8 @@ class DeferredSchedulingBookkeeper {
333637
333808
  const op = item.operation;
333638
333809
  if (op === OperationType.MARKED_TO_DELETION)
333639
333810
  return true;
333640
- if (op === OperationType.RETRY && item.item?.metadata?.deletionTimestamp)
333811
+ if ((op === OperationType.RETRY || op === OperationType.RETRY_SYNC) &&
333812
+ item.item?.metadata?.deletionTimestamp)
333641
333813
  return true;
333642
333814
  return false;
333643
333815
  }
@@ -333913,6 +334085,7 @@ async function writeDiagnosticSnapshot(queue, maxSlots) {
333913
334085
  const envTfmMirrorRefreshInterval = process.env.TFM_MIRROR_REFRESH_INTERVAL || '900';
333914
334086
  const envBackendProvider = process.env.BACKEND_PROVIDER_NAME || 'kubernetes-provider';
333915
334087
  const envGithubAppId = process.env.GITHUB_APP_ID || '';
334088
+ const envTfmSkipGitConfig = process.env.TFM_SKIP_GIT_CONFIG || 'false';
333916
334089
  // Build YAML output
333917
334090
  let output = '';
333918
334091
  output += `timestamp: "${now}"\n`;
@@ -333925,6 +334098,7 @@ async function writeDiagnosticSnapshot(queue, maxSlots) {
333925
334098
  output += ` TFM_MIRROR_REFRESH_INTERVAL: ${envTfmMirrorRefreshInterval}\n`;
333926
334099
  output += ` BACKEND_PROVIDER_NAME: ${envBackendProvider}\n`;
333927
334100
  output += ` GITHUB_APP_ID: ${envGithubAppId}\n`;
334101
+ output += ` TFM_SKIP_GIT_CONFIG: ${envTfmSkipGitConfig}\n`;
333928
334102
  output += 'queue:\n';
333929
334103
  output += ` total: ${queue.length}\n`;
333930
334104
  output += ` pending: ${pending}\n`;
@@ -334683,6 +334857,7 @@ const WEIGHTS = {
334683
334857
  UPDATED: 10,
334684
334858
  CREATED: 9,
334685
334859
  RETRY: 8,
334860
+ RETRY_SYNC: 8,
334686
334861
  MARKED_TO_DELETION: 6,
334687
334862
  SYNC: 1,
334688
334863
  NOTHING: 0,
@@ -335689,16 +335864,26 @@ async function gitFetchPrune(mirrorPath) {
335689
335864
  });
335690
335865
  }
335691
335866
  /**
335692
- * Single package-wide GitHub authentication config writer for repo mirrors and remote workflows.
335693
335867
  * Writes the required url rewriting stanza to /home/node/.gitconfig based on the current org's GitHub App token.
335694
335868
  * This is the ONLY allowed implementation of project git-auth per package specs.
335869
+ *
335870
+ * When TFM_SKIP_GIT_CONFIG=true is set, the function removes any existing
335871
+ * /home/node/.gitconfig and returns early without writing a new one. This is
335872
+ * used in dev/test environments where no GitHub App credentials are available
335873
+ * (e.g. local dev, smoke tests using prefapp/tfm mirrors).
335695
335874
  */
335696
335875
  async function configGit() {
335876
+ const gitconfigPath = '/home/node/.gitconfig';
335877
+ if (process.env.TFM_SKIP_GIT_CONFIG === 'true') {
335878
+ if (external_fs_.existsSync(gitconfigPath)) {
335879
+ external_fs_.rmSync(gitconfigPath);
335880
+ }
335881
+ return;
335882
+ }
335697
335883
  // Import github dynamically to avoid Jest ESM issues when not specifically running this function
335698
335884
  // (see CONSTITUTION and RULES: must not change test machinery)
335699
335885
  const githubModule = await Promise.resolve(/* import() */).then(__nccwpck_require__.bind(__nccwpck_require__, 99029));
335700
335886
  const github = githubModule.default || githubModule;
335701
- const gitconfigPath = '/home/node/.gitconfig';
335702
335887
  if (external_fs_.existsSync(gitconfigPath)) {
335703
335888
  external_fs_.rmSync(gitconfigPath);
335704
335889
  }
@@ -337221,8 +337406,8 @@ function policyAllowsOp(policy, op, item) {
337221
337406
  msg = `A RETRY operation is not allowed on a resource with a deletionTimestamp. It means
337222
337407
  that the resource is being deleted and it is not possible to retry the operation with policy: ${policy}.
337223
337408
 
337224
- To fix this issue, you must first delete the "firestatr.dev/finalizer" from finalizers array in the resource manifest,
337225
- it will be automatically deleted by kubernetes. Terraform will not execute any operation on the resource.
337409
+ To fix this issue, you must first delete the "firestartr.dev/finalizer" from finalizers array in the resource manifest,
337410
+ it will be automatically deleted by Kubernetes. Terraform will not execute any operation on the resource.
337226
337411
  `;
337227
337412
  return { allowed: false, msg };
337228
337413
  }
@@ -337230,6 +337415,19 @@ it will be automatically deleted by kubernetes. Terraform will not execute any o
337230
337415
  return { allowed: true, msg };
337231
337416
  }
337232
337417
  }
337418
+ if (op === OperationType.RETRY_SYNC.toString() &&
337419
+ foundPolicy?.allowedOps.includes(OperationType.SYNC.toString())) {
337420
+ if ('deletionTimestamp' in item.metadata && 'full-control' !== policy) {
337421
+ msg = `A RETRY_SYNC operation is not allowed on a resource with a deletionTimestamp. It means
337422
+ that the resource is being deleted and it is not possible to retry the operation with policy: ${policy}.
337423
+
337424
+ To fix this issue, you must first delete the "firestartr.dev/finalizer" from finalizers array in the resource manifest,
337425
+ it will be automatically deleted by Kubernetes. Terraform will not execute any operation on the resource.
337426
+ `;
337427
+ return { allowed: false, msg };
337428
+ }
337429
+ return { allowed: true, msg };
337430
+ }
337233
337431
  if (!foundPolicy) {
337234
337432
  msg = `Policy ${policy} not found`;
337235
337433
  return { allowed: false, msg };
@@ -337432,6 +337630,7 @@ function processOperation(item, op, handler) {
337432
337630
  case OperationType.MARKED_TO_DELETION:
337433
337631
  return process_operation_markedToDeletion(item, op, handler);
337434
337632
  case OperationType.RETRY:
337633
+ case OperationType.RETRY_SYNC:
337435
337634
  return process_operation_retry(item, op, handler);
337436
337635
  case OperationType.NOTHING:
337437
337636
  return process_operation_nothing(item, op, handler);
@@ -337449,11 +337648,26 @@ async function* process_operation_observe(item, op, handler) {
337449
337648
  yield transition;
337450
337649
  }
337451
337650
  }
337452
- async function* doPlanJSONFormat(item, op, handler, setResult = function (_r) { }) {
337651
+ async function* doPlanJSONFormat(item, op, handler, setResult = function (_r) { }, emitSyncErrorCondition = true) {
337453
337652
  let error = false;
337454
337653
  let deps;
337455
337654
  let terraformExecutionStarted = false;
337456
337655
  const sessionId = generateSessionId();
337656
+ if (op !== OperationType.RETRY && op !== OperationType.RETRY_SYNC) {
337657
+ try {
337658
+ await handler.writeTerraformOutputInTfResult(item, '', 0);
337659
+ }
337660
+ catch (e) {
337661
+ operator_src_logger.warn(`Failed to clear Terraform output: ${e}`);
337662
+ }
337663
+ try {
337664
+ if (handler.removeFromRetry)
337665
+ handler.removeFromRetry();
337666
+ }
337667
+ catch (e) {
337668
+ operator_src_logger.warn(`Failed to clear retry watcher: ${e}`);
337669
+ }
337670
+ }
337457
337671
  try {
337458
337672
  yield {
337459
337673
  item,
@@ -337582,17 +337796,22 @@ async function* doPlanJSONFormat(item, op, handler, setResult = function (_r) {
337582
337796
  }
337583
337797
  }
337584
337798
  if (error) {
337585
- if (op === OperationType.SYNC) {
337586
- // if there is an error on a sync we never put the state on error
337587
- // it would be problematic because the RETRY op kicks in
337588
- if (error) {
337799
+ if (op === OperationType.SYNC || op === OperationType.RETRY_SYNC) {
337800
+ if (emitSyncErrorCondition) {
337589
337801
  yield {
337590
337802
  item,
337591
337803
  reason: op,
337592
- type: 'SYNCHRONIZED',
337804
+ type: 'ERROR',
337593
337805
  status: 'True',
337594
337806
  message: SYNC_DEFAULT_ERROR_MESSAGE,
337595
337807
  };
337808
+ yield {
337809
+ item,
337810
+ reason: op,
337811
+ type: 'SYNCHRONIZED',
337812
+ status: 'False',
337813
+ message: SYNC_DEFAULT_ERROR_MESSAGE,
337814
+ };
337596
337815
  yield {
337597
337816
  item,
337598
337817
  reason: op,
@@ -337614,6 +337833,29 @@ async function* doPlanJSONFormat(item, op, handler, setResult = function (_r) {
337614
337833
  status: 'False',
337615
337834
  message: 'doPlanJSONFormat',
337616
337835
  };
337836
+ }
337837
+ else {
337838
+ yield {
337839
+ item,
337840
+ reason: op,
337841
+ type: 'SYNCHRONIZED',
337842
+ status: 'True',
337843
+ message: SYNC_DEFAULT_ERROR_MESSAGE,
337844
+ };
337845
+ yield {
337846
+ item,
337847
+ reason: op,
337848
+ type: 'PROVISIONED',
337849
+ status: 'True',
337850
+ message: 'doPlanJSONFormat',
337851
+ };
337852
+ yield {
337853
+ item,
337854
+ reason: op,
337855
+ type: 'PLANNING',
337856
+ status: 'False',
337857
+ message: 'doPlanJSONFormat',
337858
+ };
337617
337859
  yield {
337618
337860
  item,
337619
337861
  reason: op,
@@ -337656,9 +337898,16 @@ async function* doPlanJSONFormat(item, op, handler, setResult = function (_r) {
337656
337898
  }
337657
337899
  }
337658
337900
  else {
337659
- if (op === OperationType.SYNC) {
337901
+ handler.success();
337902
+ if (op === OperationType.SYNC || op === OperationType.RETRY_SYNC) {
337660
337903
  setResult('SYNC_SUCCESS');
337661
337904
  }
337905
+ try {
337906
+ await handler.writeTerraformOutputInTfResult(item, '', 0);
337907
+ }
337908
+ catch (e) {
337909
+ operator_src_logger.warn(`Failed to clear Terraform output: ${e}`);
337910
+ }
337662
337911
  }
337663
337912
  }
337664
337913
  }
@@ -337688,6 +337937,13 @@ async function* process_operation_retry(item, op, handler) {
337688
337937
  yield transition;
337689
337938
  }
337690
337939
  }
337940
+ else if (op === OperationType.RETRY_SYNC) {
337941
+ const policy = getPolicy(item, 'firestartr.dev/policy');
337942
+ const syncPolicy = getPolicy(item, 'firestartr.dev/sync-policy');
337943
+ for await (const transition of process_operation_sync(item, OperationType.RETRY_SYNC, handler, syncPolicy, policy)) {
337944
+ yield transition;
337945
+ }
337946
+ }
337691
337947
  else {
337692
337948
  for await (const transition of doApply(item, op, handler)) {
337693
337949
  yield transition;
@@ -337704,7 +337960,7 @@ async function* process_operation_sync(item, op, handler, syncPolicy, generalPol
337704
337960
  let doResult = '';
337705
337961
  if (!syncPolicy) {
337706
337962
  operator_src_logger.debug(`The Terraform processor is only observing item '${item.kind}/${item.metadata.name}' because no sync policy was found for operation '${op}'.`);
337707
- yield* doPlanJSONFormat(item, op, handler);
337963
+ yield* doPlanJSONFormat(item, op, handler, undefined, false);
337708
337964
  return;
337709
337965
  }
337710
337966
  else if (!catalog_common/* default.policies.policiesAreCompatible */.Z.policies.policiesAreCompatible(syncPolicy, generalPolicy)) {
@@ -337749,6 +338005,9 @@ async function* process_operation_markedToDeletion(item, op, handler) {
337749
338005
  let terraformExecutionStarted = false;
337750
338006
  const sessionId = generateSessionId();
337751
338007
  try {
338008
+ if (op === OperationType.MARKED_TO_DELETION) {
338009
+ await handler.writeTerraformOutputInTfResult(item, '', 0);
338010
+ }
337752
338011
  const type = 'DELETING';
337753
338012
  yield {
337754
338013
  item,
@@ -337898,6 +338157,21 @@ async function* doApply(item, op, handler) {
337898
338157
  let deps;
337899
338158
  let terraformExecutionStarted = false;
337900
338159
  const sessionId = generateSessionId();
338160
+ if (op !== OperationType.RETRY && op !== OperationType.RETRY_SYNC) {
338161
+ try {
338162
+ await handler.writeTerraformOutputInTfResult(item, '', 0);
338163
+ }
338164
+ catch (e) {
338165
+ operator_src_logger.warn(`Failed to clear Terraform output: ${e}`);
338166
+ }
338167
+ try {
338168
+ if (handler.removeFromRetry)
338169
+ handler.removeFromRetry();
338170
+ }
338171
+ catch (e) {
338172
+ operator_src_logger.warn(`Failed to clear retry watcher: ${e}`);
338173
+ }
338174
+ }
337901
338175
  try {
337902
338176
  yield {
337903
338177
  item,
@@ -342152,6 +342426,7 @@ function process_operation_processOperation(item, op, handler) {
342152
342426
  case OperationType.MARKED_TO_DELETION:
342153
342427
  return gh_process_operation_markedToDeletion(item, op, handler);
342154
342428
  case OperationType.RETRY:
342429
+ case OperationType.RETRY_SYNC:
342155
342430
  return gh_process_operation_retry(item, op, handler);
342156
342431
  case OperationType.NOTHING:
342157
342432
  return gh_process_operation_nothing(item, op, handler);
@@ -342188,6 +342463,11 @@ async function* gh_process_operation_retry(item, op, handler) {
342188
342463
  yield transition;
342189
342464
  }
342190
342465
  }
342466
+ else if (op === OperationType.RETRY_SYNC) {
342467
+ for await (const transition of gh_process_operation_sync(item, OperationType.RETRY_SYNC, handler)) {
342468
+ yield transition;
342469
+ }
342470
+ }
342191
342471
  else {
342192
342472
  for await (const transition of process_operation_doApply(item, op, handler)) {
342193
342473
  yield transition;
@@ -342340,6 +342620,14 @@ async function* process_operation_doApply(item, op, handler) {
342340
342620
  let checkRunCtl;
342341
342621
  let checkRunTFCtl;
342342
342622
  let error = false;
342623
+ if (op !== OperationType.RETRY && op !== OperationType.RETRY_SYNC) {
342624
+ try {
342625
+ await handler.writeTerraformOutputInTfResult(item, '', 0);
342626
+ }
342627
+ catch (e) {
342628
+ operator_src_logger.warn(`Failed to reset retry count: ${e instanceof Error ? e.stack || e.message : JSON.stringify(e)}`);
342629
+ }
342630
+ }
342343
342631
  try {
342344
342632
  yield {
342345
342633
  item,
@@ -342373,6 +342661,7 @@ async function* process_operation_doApply(item, op, handler) {
342373
342661
  if (op === OperationType.UPDATED ||
342374
342662
  op === OperationType.RENAMED ||
342375
342663
  op === OperationType.RETRY ||
342664
+ op === OperationType.RETRY_SYNC ||
342376
342665
  op === OperationType.SYNC) {
342377
342666
  opts['update'] = true;
342378
342667
  }
@@ -521630,7 +521919,7 @@ const crsStatusSubcommand = {
521630
521919
  };
521631
521920
 
521632
521921
  ;// CONCATENATED MODULE: ./package.json
521633
- const package_namespaceObject = JSON.parse('{"i8":"2.8.0-snapshot-variant-cloning-test-1"}');
521922
+ const package_namespaceObject = JSON.parse('{"i8":"2.8.0-snapshot-variant-cloning-2"}');
521634
521923
  ;// CONCATENATED MODULE: ../../package.json
521635
521924
  const package_namespaceObject_1 = {"i8":"2.7.1"};
521636
521925
  ;// CONCATENATED MODULE: ./src/subcommands/index.ts
@@ -1238,10 +1238,6 @@ declare const schemas: {
1238
1238
  description: string;
1239
1239
  type: string;
1240
1240
  properties: {
1241
- name: {
1242
- type: string;
1243
- description: string;
1244
- };
1245
1241
  values: {
1246
1242
  type: string;
1247
1243
  additionalProperties: boolean;
@@ -1320,6 +1316,7 @@ declare const schemas: {
1320
1316
  properties: {
1321
1317
  name: {
1322
1318
  type: string;
1319
+ maxLength: number;
1323
1320
  description: string;
1324
1321
  };
1325
1322
  overrides: {
@@ -143,10 +143,6 @@ export declare const TerraformSchemas: {
143
143
  description: string;
144
144
  type: string;
145
145
  properties: {
146
- name: {
147
- type: string;
148
- description: string;
149
- };
150
146
  values: {
151
147
  type: string;
152
148
  additionalProperties: boolean;
@@ -225,6 +221,7 @@ export declare const TerraformSchemas: {
225
221
  properties: {
226
222
  name: {
227
223
  type: string;
224
+ maxLength: number;
228
225
  description: string;
229
226
  };
230
227
  overrides: {
@@ -143,10 +143,6 @@ declare const _default: {
143
143
  description: string;
144
144
  type: string;
145
145
  properties: {
146
- name: {
147
- type: string;
148
- description: string;
149
- };
150
146
  values: {
151
147
  type: string;
152
148
  additionalProperties: boolean;
@@ -225,6 +221,7 @@ declare const _default: {
225
221
  properties: {
226
222
  name: {
227
223
  type: string;
224
+ maxLength: number;
228
225
  description: string;
229
226
  };
230
227
  overrides: {
@@ -22,8 +22,10 @@ export declare enum OperationType {
22
22
  SYNC = "SYNC",
23
23
  MARKED_TO_DELETION = "MARKED_TO_DELETION",
24
24
  NOTHING = "NOTHING",
25
- RETRY = "RETRY"
25
+ RETRY = "RETRY",
26
+ RETRY_SYNC = "RETRY_SYNC"
26
27
  }
28
+ export declare function retryOpForReason(reason: string | undefined): OperationType;
27
29
  export declare enum WorkStatus {
28
30
  PENDING = "PENDING",
29
31
  PROCESSING = "PROCESSING",
@@ -65,6 +67,7 @@ export type WorkItemHandler = {
65
67
  itemPath: ItemPathFn;
66
68
  error: ErrorFn;
67
69
  success: SuccessFn;
70
+ removeFromRetry?: () => void;
68
71
  isBlocked?: boolean;
69
72
  isPicked?: boolean;
70
73
  needsBlocking?: (item: any, operation: OperationType) => boolean;
@@ -6,3 +6,17 @@ export declare function processOperation(item: any, op: OperationType, handler:
6
6
  status: string;
7
7
  message: string;
8
8
  }, void, unknown>;
9
+ export declare function retry(item: any, op: OperationType, handler: any): AsyncGenerator<{
10
+ item: any;
11
+ reason: OperationType;
12
+ type: string;
13
+ status: string;
14
+ message: string;
15
+ }, void, unknown>;
16
+ export declare function sync(item: any, op: OperationType, handler: any): AsyncGenerator<{
17
+ item: any;
18
+ reason: OperationType;
19
+ type: string;
20
+ status: string;
21
+ message: string;
22
+ }, void, unknown>;
@@ -1,5 +1,4 @@
1
- export declare const NEXT_RETRY_MS: number;
2
- export declare const MAXRETRY = 5;
1
+ export declare function getMaxRetry(): number;
3
2
  export declare function nextRetryMs(currCounter: number): number;
4
3
  export declare function initRetry(enqueue: Function): Promise<{
5
4
  errorReconciling(itemPath: string): void;
@@ -0,0 +1,11 @@
1
+ type RetryWatcher = {
2
+ itemPath: string;
3
+ retryCounter: number;
4
+ retry: boolean;
5
+ nextRetryAt: string | null;
6
+ };
7
+ export declare function writeEventIfNew(itemPath: string, counter: number, next: string | null, maxRetry?: number): void;
8
+ export declare function initRetryDebug(retryWatchers: {
9
+ [key: string]: RetryWatcher;
10
+ }, maxRetry: number): void;
11
+ export {};
@@ -8,3 +8,6 @@ export declare function syncer(enqueue: Function): Promise<{
8
8
  deleteItem(itemPath: string): void;
9
9
  }>;
10
10
  export declare function loop(enqueueIfNeeded: Function, api: any): Promise<void>;
11
+ export declare function getItemIfNeededSync(watcher: any, watchers?: {
12
+ [key: string]: SyncWatcher;
13
+ }): Promise<any>;
@@ -7,6 +7,27 @@ export declare function processOperation(item: any, op: OperationType, handler:
7
7
  status: string;
8
8
  message: any;
9
9
  }, void, unknown>;
10
+ export declare function doPlanJSONFormat(item: any, op: OperationType, handler: any, setResult?: (_r: string) => void, emitSyncErrorCondition?: boolean): AsyncGenerator<{
11
+ item: any;
12
+ reason: OperationType;
13
+ type: string;
14
+ status: string;
15
+ message: any;
16
+ }, void, unknown>;
17
+ export declare function retry(item: any, op: OperationType, handler: any): AsyncGenerator<{
18
+ item: any;
19
+ reason: OperationType;
20
+ type: string;
21
+ status: string;
22
+ message: any;
23
+ }, void, unknown>;
24
+ export declare function sync(item: any, op: OperationType, handler: any, syncPolicy: string, generalPolicy: string): AsyncGenerator<{
25
+ item: any;
26
+ reason: OperationType;
27
+ type: string;
28
+ status: string;
29
+ message: any;
30
+ }, void, unknown>;
10
31
  /**
11
32
  *
12
33
  * @param {any} item - CR to be applied
@@ -38,8 +38,12 @@ export declare function gitRemoteUpdate(mirrorPath: string): Promise<void>;
38
38
  */
39
39
  export declare function gitFetchPrune(mirrorPath: string): Promise<void>;
40
40
  /**
41
- * Single package-wide GitHub authentication config writer for repo mirrors and remote workflows.
42
41
  * Writes the required url rewriting stanza to /home/node/.gitconfig based on the current org's GitHub App token.
43
42
  * This is the ONLY allowed implementation of project git-auth per package specs.
43
+ *
44
+ * When TFM_SKIP_GIT_CONFIG=true is set, the function removes any existing
45
+ * /home/node/.gitconfig and returns early without writing a new one. This is
46
+ * used in dev/test environments where no GitHub App credentials are available
47
+ * (e.g. local dev, smoke tests using prefapp/tfm mirrors).
44
48
  */
45
49
  export declare function configGit(): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firestartr/cli",
3
- "version": "2.8.0-snapshot-variant-cloning-test-1",
3
+ "version": "2.8.0-snapshot-variant-cloning-2",
4
4
  "private": false,
5
5
  "description": "Commandline tool",
6
6
  "main": "build/main.js",