@firestartr/cli 2.0.0 → 2.1.0-snapshot-1

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
@@ -367438,12 +367438,12 @@ class RepoGithubDecanter extends GithubDecanter {
367438
367438
  });
367439
367439
  }
367440
367440
  const directWriters = this.data.teamsAndMembers.directMembers
367441
- .filter((member) => member.role === 'push')
367441
+ .filter((member) => member.role === 'write')
367442
367442
  .map((member) => {
367443
367443
  return `user-imported-ref:${member.name}`;
367444
367444
  });
367445
367445
  const outsideWriters = this.data.teamsAndMembers.outsideMembers
367446
- .filter((member) => member.role === 'push')
367446
+ .filter((member) => member.role === 'write')
367447
367447
  .map((member) => {
367448
367448
  return `collaborator:${member.name.toLowerCase()}`;
367449
367449
  });
@@ -367462,12 +367462,12 @@ class RepoGithubDecanter extends GithubDecanter {
367462
367462
  });
367463
367463
  }
367464
367464
  const directReaders = this.data.teamsAndMembers.directMembers
367465
- .filter((member) => member.role === 'pull')
367465
+ .filter((member) => member.role === 'read')
367466
367466
  .map((member) => {
367467
367467
  return `user-imported-ref:${member.name}`;
367468
367468
  });
367469
367469
  const outsideReaders = this.data.teamsAndMembers.outsideMembers
367470
- .filter((member) => member.role === 'pull')
367470
+ .filter((member) => member.role === 'read')
367471
367471
  .map((member) => {
367472
367472
  return `collaborator:${member.name.toLowerCase()}`;
367473
367473
  });
@@ -367502,7 +367502,11 @@ class RepoGithubDecanter extends GithubDecanter {
367502
367502
  };
367503
367503
  });
367504
367504
  this.data['teamsAndMembers']['teams'] = teams;
367505
- this.data['teamsAndMembers']['directMembers'] = directMembers;
367505
+ // GitHub's `affiliation=direct` includes outside collaborators, so we must
367506
+ // exclude them from directMembers to avoid tagging them as user-imported-ref.
367507
+ const outsideMemberNames = new Set(outsideMembers.map((m) => m.name.toLowerCase()));
367508
+ const filteredDirectMembers = directMembers.filter((m) => !outsideMemberNames.has(m.name.toLowerCase()));
367509
+ this.data['teamsAndMembers']['directMembers'] = filteredDirectMembers;
367506
367510
  this.data['teamsAndMembers']['outsideMembers'] = outsideMembers;
367507
367511
  }
367508
367512
  async __gatherPages() {
@@ -367906,6 +367910,7 @@ async function reimportGithubGitopsRepository(org, crsPath, configPath, generate
367906
367910
  const collection = new ReimportCollection();
367907
367911
  const importAnnotation = catalog_common.generic.getFirestartrAnnotation('import');
367908
367912
  const reImportAnnotation = catalog_common.generic.getFirestartrAnnotation('needs-re-import');
367913
+ const reconcileAtAnnotation = catalog_common.generic.getFirestartrAnnotation('reconcile-at');
367909
367914
  const crsWithDependenciesToAnnotate = [];
367910
367915
  // we need to perform a search in all the crsPath
367911
367916
  await searchCRs(crsPath, async (cr, filePath) => {
@@ -367922,6 +367927,10 @@ async function reimportGithubGitopsRepository(org, crsPath, configPath, generate
367922
367927
  }
367923
367928
  cr.metadata.annotations[reImportAnnotation] = 'true';
367924
367929
  cr.metadata.annotations[importAnnotation] = 'true';
367930
+ // we set an annotation to trigger the update
367931
+ cr.metadata.annotations[reconcileAtAnnotation] = new Date()
367932
+ .toISOString()
367933
+ .replace(/\.\d{3}Z$/, 'Z'); // exact format: 2026-04-19T20:45:00Z
367925
367934
  // we write the cr back to the file system
367926
367935
  const newContent = catalog_common.io.toYaml(cr);
367927
367936
  await promises_default().writeFile(filePath, newContent, 'utf-8');
@@ -367930,10 +367939,10 @@ async function reimportGithubGitopsRepository(org, crsPath, configPath, generate
367930
367939
  // we need to search for dependencies if proceeds
367931
367940
  if (!collection.IS_SKIP_SET(generatedFilters, 'gh-repo')) {
367932
367941
  importer_src_logger.info(`Searching for dependencies to annotate with ${reImportAnnotation} and ${importAnnotation}`);
367933
- await searchForDependencies(org, crsPath, configPath, generatedFilters, crsWithDependenciesToAnnotate, reImportAnnotation, importAnnotation);
367942
+ await searchForDependencies(org, crsPath, configPath, generatedFilters, crsWithDependenciesToAnnotate, reImportAnnotation, importAnnotation, reconcileAtAnnotation);
367934
367943
  }
367935
367944
  }
367936
- async function searchForDependencies(org, crsPath, configPath, generatedFilters, crsWithDependenciesToAnnotate, reImportAnnotation, importAnnotation) {
367945
+ async function searchForDependencies(org, crsPath, configPath, generatedFilters, crsWithDependenciesToAnnotate, reImportAnnotation, importAnnotation, reconcileAtAnnotation) {
367937
367946
  // we need to perform a search in all the crsPath
367938
367947
  await searchCRs(crsPath, async (cr, filePath) => {
367939
367948
  importer_src_logger.debug(`${JSON.stringify(cr)}`);
@@ -367951,6 +367960,10 @@ async function searchForDependencies(org, crsPath, configPath, generatedFilters,
367951
367960
  }
367952
367961
  cr.metadata.annotations[reImportAnnotation] = 'true';
367953
367962
  cr.metadata.annotations[importAnnotation] = 'true';
367963
+ // we set an annotation to trigger the update
367964
+ cr.metadata.annotations[reconcileAtAnnotation] = new Date()
367965
+ .toISOString()
367966
+ .replace(/\.\d{3}Z$/, 'Z'); // exact format: 2026-04-19T20:45:00Z
367954
367967
  // we write the cr back to the file system
367955
367968
  const newContent = catalog_common.io.toYaml(cr);
367956
367969
  await promises_default().writeFile(filePath, newContent, 'utf-8');
@@ -368988,6 +369001,7 @@ function conditionsSorter(conditions) {
368988
369001
 
368989
369002
 
368990
369003
 
369004
+
368991
369005
  async function upsertInitialStatus(pluralKind, namespace, item) {
368992
369006
  item = await getItemByItemPath(`${namespace}/${pluralKind}/${item.metadata.name}`);
368993
369007
  if (!('status' in item))
@@ -369003,6 +369017,11 @@ async function needsProvisioningOnCreateOrUpdate(cr) {
369003
369017
  operator_src_logger.debug(`The custom resource '${cr.kind}/${cr.metadata.name}' is missing a status and any conditions.`);
369004
369018
  return { needs: true, reason: 'CREATED' };
369005
369019
  }
369020
+ // there is a force by annotation?
369021
+ if (shouldForceReconcileByAnnotation(cr)) {
369022
+ operator_src_logger.debug(`The custom resource '${cr.kind}/${cr.metadata.name}' has a newer '${catalog_common.generic.getFirestartrAnnotation('reconcile-at')}' annotation than the latest condition update time, so a force-reconcile will be triggered.`);
369023
+ return { needs: true, reason: 'FORCE_RECONCILE_ANNOTATION' };
369024
+ }
369006
369025
  // ERROR
369007
369026
  const errCond = getConditionByType(cr.status.conditions, 'ERROR');
369008
369027
  if (errCond && errCond.status === 'True') {
@@ -369038,6 +369057,36 @@ async function needsProvisioningOnCreateOrUpdate(cr) {
369038
369057
  operator_src_logger.debug(`Skipping the provisioning process for custom resource '${cr.kind}/${cr.metadata.name}' because its current state is not handled.`);
369039
369058
  return { needs: false };
369040
369059
  }
369060
+ function shouldForceReconcileByAnnotation(cr) {
369061
+ const annotationType = catalog_common.generic.getFirestartrAnnotation('reconcile-at');
369062
+ const annotationValue = cr.metadata?.annotations?.[annotationType];
369063
+ if (!annotationValue) {
369064
+ return false;
369065
+ }
369066
+ operator_src_logger.debug(`Found annotation '${annotationType}' with value '${annotationValue}' on ${cr.metadata.name}`);
369067
+ const annotationTime = new Date(annotationValue).getTime();
369068
+ if (isNaN(annotationTime)) {
369069
+ operator_src_logger.warn(`Timestamp is invalid for the annotation ${cr.kind}/${cr.metadata?.name || 'unknown'}: ${annotationValue}`);
369070
+ return false;
369071
+ }
369072
+ // Find the most recent timestamp across all conditions
369073
+ let latestConditionTime = 0;
369074
+ for (const condition of cr.status?.conditions || []) {
369075
+ const timeStr = condition.lastUpdateTime || condition.lastTransitionTime;
369076
+ if (timeStr) {
369077
+ const conditionTime = new Date(timeStr).getTime();
369078
+ if (!isNaN(conditionTime) && conditionTime > latestConditionTime) {
369079
+ latestConditionTime = conditionTime;
369080
+ }
369081
+ }
369082
+ }
369083
+ const shouldForce = annotationTime > latestConditionTime;
369084
+ operator_src_logger.debug(`Evaluating force-reconcile for ${cr.metadata.name}: annotation time (${new Date(annotationTime).toISOString()}) vs latest condition time (${new Date(latestConditionTime).toISOString()})`, { metadata: { shouldForce } });
369085
+ if (shouldForce) {
369086
+ operator_src_logger.info(`force-reconcile activated for ${cr.metadata.name} → annotation (${annotationValue}) is newer than latest condition time (${new Date(latestConditionTime).toISOString()})`);
369087
+ }
369088
+ return shouldForce;
369089
+ }
369041
369090
  async function updateSyncTransition(itemPath, reason, lastSyncTime, nextSyncTime, message, status) {
369042
369091
  operator_src_logger.info(`The item at '${itemPath}' transitioned to a new SYNCHRONIZED condition of '${status}'. The reason for the change is '${reason}' with the message: '${message}'.`);
369043
369092
  const k8sItem = await getItemByItemPath(itemPath);
@@ -370716,6 +370765,19 @@ function getQueueMetrics() {
370716
370765
  },
370717
370766
  };
370718
370767
  }
370768
+ // we need to assign weight to the deletion operation
370769
+ // to avoid blockades
370770
+ // https://github.com/prefapp/gitops-k8s/issues/1864
370771
+ // ghrepo feat | grss -> ghrepo -> ghgroup -> membership
370772
+ const DELETION_WEIGHTS = {
370773
+ FirestartrGithubRepositoryFeature: 5,
370774
+ FirestartrGithubRepositorySecretsSection: 4,
370775
+ FirestartrGithubRepository: 3,
370776
+ FirestartrGithubGroup: 2,
370777
+ FirestartrGithubMembership: 1,
370778
+ FirestartrTerraformWorkspace: 1,
370779
+ FirestartrGithubOrgWebhook: 1,
370780
+ };
370719
370781
  // Do the kinds need different weights for the operations?
370720
370782
  // We need to discuss this with the team in this issue: https://github.com/prefapp/gitops-k8s/issues/524
370721
370783
  // const KIND_WEIGHTS: any = {
@@ -370785,7 +370847,17 @@ function sortQueue(queue) {
370785
370847
  // If weightA is larger, return -1 (a comes before b)
370786
370848
  return weightB - weightA;
370787
370849
  }
370788
- // --- SECONDARY SORT: By upsertTime (Ascending) ---
370850
+ // in case of deletions we need to
370851
+ // establish a secondary sort by kind
370852
+ if (wa.operation === 'MARKED_TO_DELETION' &&
370853
+ wb.operation === 'MARKED_TO_DELETION') {
370854
+ const deletionWeightA = DELETION_WEIGHTS[wa.item.kind] || 0;
370855
+ const deletionWeightB = DELETION_WEIGHTS[wb.item.kind] || 0;
370856
+ if (deletionWeightA !== deletionWeightB) {
370857
+ return deletionWeightB - deletionWeightA;
370858
+ }
370859
+ }
370860
+ // --- 3rd SORT: By upsertTime (Ascending) ---
370789
370861
  // If weights are equal, sort by the oldest upsertTime (ascending)
370790
370862
  return wa.upsertTime - wb.upsertTime;
370791
370863
  });
@@ -379414,7 +379486,7 @@ const crs_analyzerSubcommand = {
379414
379486
  };
379415
379487
 
379416
379488
  ;// CONCATENATED MODULE: ./package.json
379417
- const package_namespaceObject = {"i8":"2.0.0"};
379489
+ const package_namespaceObject = JSON.parse('{"i8":"2.1.0-snapshot-1"}');
379418
379490
  ;// CONCATENATED MODULE: ../../package.json
379419
379491
  const package_namespaceObject_1 = {"i8":"2.0.0"};
379420
379492
  ;// CONCATENATED MODULE: ./src/subcommands/index.ts
@@ -4,6 +4,7 @@ export type NeedsCreationOrUpdate = {
4
4
  };
5
5
  export declare function upsertInitialStatus(pluralKind: string, namespace: string, item: any): Promise<void>;
6
6
  export declare function needsProvisioningOnCreateOrUpdate(cr: any): Promise<NeedsCreationOrUpdate>;
7
+ export declare function shouldForceReconcileByAnnotation(cr: any): boolean;
7
8
  export declare function updateSyncTransition(itemPath: string, reason: string, lastSyncTime: string, nextSyncTime: string, message: string, status: string): Promise<void>;
8
9
  export declare function writePrioritizedStatus(kind: string, namespace: string, item: any): Promise<void>;
9
10
  export declare function updateTransition(itemPath: string, reason: string, type: string, statusValue: string, message?: string, updateStatusOnly?: boolean): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firestartr/cli",
3
- "version": "2.0.0",
3
+ "version": "2.1.0-snapshot-1",
4
4
  "private": false,
5
5
  "description": "Commandline tool",
6
6
  "main": "build/main.js",