@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 === '
|
|
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 === '
|
|
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 === '
|
|
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 === '
|
|
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
|
-
|
|
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
|
-
//
|
|
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.
|
|
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>;
|