Skip to content

Commit 65f3a82

Browse files
feat: ignore GitOps collations, support TLS (#11)
* docs: document `indexStats` (#3) * feat: support TLS (#6) * docs: improve docs * feat: support TLS connections * docs: document TLS options * feat(options): add `tlsCertificateKeyFilePassword` flag (#8) * feat(options): add `tlsCertificateKeyFilePassword` flag * ci: trigger ci * added logic to ingnore default collations * removed catch * added specs * added includeCollation flag * pull request requested fixes * marked includeCollations as param in docs * fix docs * ci: trigger ci --------- Co-authored-by: alinashklyar <alina.shklyar@codefresh.io>
1 parent 8fb918e commit 65f3a82

File tree

9 files changed

+166
-21
lines changed

9 files changed

+166
-21
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,7 @@ dist
132132
!indexes/**
133133

134134
.DS_Store
135+
136+
#Webstorm
137+
.idea/
138+

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "index-alignment",
3-
"version": "0.2.0-2.8",
3+
"version": "0.3.0-2.8",
44
"main": "dist/index.js",
55
"private": true,
66
"type": "module",

src/compare-dump.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,22 @@ import { readDump } from './read-dump.js';
77
import type { CollectionDiff, CollectionIndexes, CompareOptions, DatabaseDiff, DatabaseIndexes, DbMapRaw, FullDiff } from './types.js';
88
import { getTargetToDumpDb } from './utils.js';
99

10-
const compareCollections = (desired: CollectionIndexes, actual?: CollectionIndexes, dbMap?: DbMapRaw): CollectionDiff => {
10+
const compareCollections = (desired: CollectionIndexes, actual?: CollectionIndexes, dbMap?: DbMapRaw, options?: CompareOptions): CollectionDiff => {
1111
const dumpDbName = getTargetToDumpDb(dbMap).get(desired.databaseName) ?? desired.databaseName;
1212

1313
const missingIndexes = desired.indexes.filter((desiredIndex) => {
1414
// Skip indexes that should be ignored in the dump
15-
if (shouldIgnoreIndexInDump(dumpDbName, desired.collectionName, desiredIndex)) return false;
15+
if (shouldIgnoreIndexInDump(dumpDbName, desired.collectionName, desiredIndex, options)) return false;
1616

17-
const match = actual?.indexes.find(actualIndex => isIndexEqual(desiredIndex, actualIndex));
17+
const match = actual?.indexes.find(actualIndex => isIndexEqual(desiredIndex, actualIndex, options));
1818
return !match;
1919
});
2020

2121
const extraIndexes = actual?.indexes.filter((actualIndex) => {
2222
// Skip indexes that should be ignored in the target
23-
if (shouldIgnoreIndexInTarget(dumpDbName, actual.collectionName, actualIndex)) return false;
23+
if (shouldIgnoreIndexInTarget(dumpDbName, actual.collectionName, actualIndex, options)) return false;
2424

25-
const match = desired.indexes.find(desiredIndex => isIndexEqual(desiredIndex, actualIndex));
25+
const match = desired.indexes.find(desiredIndex => isIndexEqual(desiredIndex, actualIndex, options));
2626
return !match;
2727
});
2828

@@ -33,12 +33,12 @@ const compareCollections = (desired: CollectionIndexes, actual?: CollectionIndex
3333
};
3434
};
3535

36-
const compareDatabases = (desired: DatabaseIndexes, actual?: DatabaseIndexes, dbMap?: DbMapRaw): DatabaseDiff => {
36+
const compareDatabases = (desired: DatabaseIndexes, actual?: DatabaseIndexes, dbMap?: DbMapRaw, options?: CompareOptions): DatabaseDiff => {
3737
const dbDiff: DatabaseDiff = { databaseName: desired.databaseName, collections: {} };
3838

3939
for (const desiredCol of desired.collections) {
4040
const actualCol = actual?.collections.find(actuaCol => actuaCol.collectionName === desiredCol.collectionName);
41-
const collectionResult = compareCollections(desiredCol, actualCol, dbMap);
41+
const collectionResult = compareCollections(desiredCol, actualCol, dbMap, options);
4242
if (collectionResult.missingIndexes || collectionResult.extraIndexes) {
4343
dbDiff.collections[desiredCol.collectionName] = collectionResult;
4444
}
@@ -56,7 +56,7 @@ export const compareDump = async (options: CompareOptions): Promise<FullDiff> =>
5656
const diff: FullDiff = { databases: {} };
5757
for (const desiredDb of desired) {
5858
const actualDb = actual.find(db => db.databaseName === desiredDb.databaseName);
59-
const dbDiff = compareDatabases(desiredDb, actualDb, dbMap);
59+
const dbDiff = compareDatabases(desiredDb, actualDb, dbMap, options);
6060
if (Object.keys(dbDiff.collections).length !== 0) {
6161
diff.databases[desiredDb.databaseName] = dbDiff;
6262
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ program
9494
'Map the databases in the dump with the target databases. We have our own naming convention for the production databases, but it is up to the customers to name their databases',
9595
defaultDbMap,
9696
)
97+
.option('--compareGitopsCollations', 'Compare collations for GitOps product. Only takes effect if --product=gitops', false)
9798
.action(compare);
9899

99100
program

src/is-index-equal.spec.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,96 @@ describe('isIndexEqual', () => {
102102
expect(isIndexEqual(input.a, input.b)).toBe(false);
103103
});
104104
});
105+
106+
it('should return true when keys match and collation is default (for gitops)', () => {
107+
const indexA = {
108+
key: { a: 1 },
109+
collation: {
110+
locale: 'en_US',
111+
caseLevel: false,
112+
caseFirst: 'off',
113+
strength: 1,
114+
numericOrdering: false,
115+
alternate: 'non-ignorable',
116+
maxVariable: 'punct',
117+
normalization: false,
118+
backwards: false,
119+
},
120+
};
121+
122+
const indexB = {
123+
key: { a: 1 },
124+
};
125+
126+
expect(isIndexEqual(indexA, indexB, { product: 'gitops', uri: '' })).toBe(true);
127+
});
128+
129+
it('should return false when keys match and collation is default (for classic)', () => {
130+
const indexA = {
131+
key: { a: 1 },
132+
collation: {
133+
locale: 'en_US',
134+
caseLevel: false,
135+
caseFirst: 'off',
136+
strength: 1,
137+
numericOrdering: false,
138+
alternate: 'non-ignorable',
139+
maxVariable: 'punct',
140+
normalization: false,
141+
backwards: false,
142+
},
143+
};
144+
145+
const indexB = {
146+
key: { a: 1 },
147+
};
148+
149+
expect(isIndexEqual(indexA, indexB, { product: 'classic', uri: '' })).toBe(false);
150+
});
151+
152+
it('should return false when keys match and collation is default but compareGitopsCollations flag is true', () => {
153+
const indexA = {
154+
key: { a: 1 },
155+
collation: {
156+
locale: 'en_US',
157+
caseLevel: false,
158+
caseFirst: 'off',
159+
strength: 1,
160+
numericOrdering: false,
161+
alternate: 'non-ignorable',
162+
maxVariable: 'punct',
163+
normalization: false,
164+
backwards: false,
165+
},
166+
};
167+
168+
const indexB = {
169+
key: { a: 1 },
170+
};
171+
172+
expect(isIndexEqual(indexA, indexB, { product: 'gitops', uri: '', compareGitopsCollations: true })).toBe(false);
173+
});
174+
175+
it('should return false when keys match but collation is not default', () => {
176+
const indexA = {
177+
key: { a: 1 },
178+
collation: {
179+
locale: 'en_US',
180+
caseLevel: false,
181+
caseFirst: 'off',
182+
strength: 2,
183+
numericOrdering: false,
184+
alternate: 'non-ignorable',
185+
maxVariable: 'punct',
186+
normalization: false,
187+
backwards: false,
188+
},
189+
};
190+
191+
const indexB = {
192+
key: { a: 1 },
193+
};
194+
195+
expect(isIndexEqual(indexA, indexB, { product: 'gitops', uri: '' })).toBe(false);
196+
});
105197
});

src/is-index-equal.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
import { deepStrictEqual } from 'node:assert';
2-
import type { Index } from './types.js';
2+
import type { CompareOptions, Index } from './types.js';
3+
import { CollationOptions, Document } from 'mongodb';
4+
5+
/**
6+
* Default collation specified for collections in GitOps product
7+
* (https://github.com/codefresh-io/argo-platform/blob/aa831b539c8434156c323db881ee7d44db87ac13/libs/db/src/helpers/helpers.ts#L81),
8+
* extended with implicit collation options.
9+
*/
10+
const defaultCollation: CollationOptions = {
11+
locale: 'en_US',
12+
caseLevel: false,
13+
caseFirst: 'off',
14+
strength: 1,
15+
numericOrdering: false,
16+
alternate: 'non-ignorable',
17+
maxVariable: 'punct',
18+
normalization: false,
19+
backwards: false,
20+
};
21+
22+
function isDefaultCollation(collation: Document | undefined): boolean {
23+
if (!collation) return false;
24+
return JSON.stringify(collation) === JSON.stringify(defaultCollation);
25+
}
326

427
/**
528
* Compare two indexes to check if they are equal.
@@ -19,13 +42,23 @@ import type { Index } from './types.js';
1942
* that's why we use `deepStrictEqual` ({@link https://nodejs.org/api/assert.html#assertdeepstrictequalactual-expected-message|docs}).
2043
*
2144
* - If both `key` and options (except for `name`) are equal, the indexes are considered equal.
45+
*
46+
* `options.compareGitopsCollations` parameter allows to include collation options in the comparison for gitops.
47+
* This check is temporary disabled by default due to a misalignment between production and on-prem environments.
48+
* ({@link https://codefresh-io.atlassian.net/browse/CR-29948})
2249
*/
23-
export const isIndexEqual = (a: Index, b: Index): boolean => {
50+
export const isIndexEqual = (a: Index, b: Index, options?: CompareOptions): boolean => {
2451
const aKey = a.key;
2552
const aOptions = { ...a, key: undefined, name: undefined };
2653
const bKey = b.key;
2754
const bOptions = { ...b, key: undefined, name: undefined };
2855
const isKeyEqual = JSON.stringify(aKey) === JSON.stringify(bKey);
56+
57+
if (options?.product === 'gitops' && !options?.compareGitopsCollations) {
58+
if (isDefaultCollation(aOptions.collation)) delete aOptions.collation;
59+
if (isDefaultCollation(bOptions.collation)) delete bOptions.collation;
60+
}
61+
2962
try {
3063
deepStrictEqual(aOptions, bOptions);
3164
return isKeyEqual;

src/overrides/should-ignore-index-in-dump.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import { isIndexEqual } from '../is-index-equal.js';
2-
import type { CollectionName, DatabaseName, IgnoreInAllCollections, IgnoreList, Index } from '../types.js';
2+
import type {
3+
CollectionName,
4+
CompareOptions,
5+
DatabaseName,
6+
IgnoreInAllCollections,
7+
IgnoreList,
8+
Index,
9+
} from '../types.js';
310

411
// TODO: Verify unique indexes, they should probably be ignored for now.
512

@@ -212,9 +219,9 @@ const ignoreList: IgnoreList = {
212219
},
213220
};
214221

215-
export const shouldIgnoreIndexInDump = (dumpDbName: DatabaseName, collectionName: CollectionName, dumpIndex: Index): boolean => {
222+
export const shouldIgnoreIndexInDump = (dumpDbName: DatabaseName, collectionName: CollectionName, dumpIndex: Index, options?: CompareOptions): boolean => {
216223
// Check if the index should be ignored in all collections
217-
if (ignoreInAllCollections.some(ignore => isIndexEqual(ignore, dumpIndex))) {
224+
if (ignoreInAllCollections.some(ignore => isIndexEqual(ignore, dumpIndex, options))) {
218225
return true;
219226
}
220227

@@ -226,7 +233,7 @@ export const shouldIgnoreIndexInDump = (dumpDbName: DatabaseName, collectionName
226233
}
227234

228235
// Check if the index is in the ignore list for the specific collection
229-
if (ignoreCollection?.indexes.some(ignore => isIndexEqual(ignore, dumpIndex))) {
236+
if (ignoreCollection?.indexes.some(ignore => isIndexEqual(ignore, dumpIndex, options))) {
230237
return true;
231238
}
232239

@@ -235,7 +242,7 @@ export const shouldIgnoreIndexInDump = (dumpDbName: DatabaseName, collectionName
235242
...dumpIndex,
236243
// eslint-disable-next-line @typescript-eslint/no-explicit-any
237244
expireAfterSeconds: 'ANY' as any,
238-
}))) {
245+
}, options))) {
239246
return true;
240247
}
241248

src/overrides/should-ignore-index-in-target.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import { isIndexEqual } from '../is-index-equal.js';
2-
import type { CollectionName, DatabaseName, IgnoreInAllCollections, IgnoreList, Index } from '../types.js';
2+
import type {
3+
CollectionName,
4+
CompareOptions,
5+
DatabaseName,
6+
IgnoreInAllCollections,
7+
IgnoreList,
8+
Index,
9+
} from '../types.js';
310

411
// TODO: Verify unique indexes, they should probably be ignored for now.
512

@@ -55,9 +62,9 @@ const ignoreList: IgnoreList = {
5562
},
5663
};
5764

58-
export const shouldIgnoreIndexInTarget = (dumpDbName: DatabaseName, collectionName: CollectionName, targetIndex: Index): boolean => {
65+
export const shouldIgnoreIndexInTarget = (dumpDbName: DatabaseName, collectionName: CollectionName, targetIndex: Index, options?: CompareOptions): boolean => {
5966
// Check if the index should be ignored in all collections
60-
if (ignoreInAllCollections.some(ignore => isIndexEqual(ignore, targetIndex))) {
67+
if (ignoreInAllCollections.some(ignore => isIndexEqual(ignore, targetIndex, options))) {
6168
return true;
6269
}
6370

@@ -69,7 +76,7 @@ export const shouldIgnoreIndexInTarget = (dumpDbName: DatabaseName, collectionNa
6976
}
7077

7178
// Check if the index is in the ignore list for the specific collection
72-
if (ignoreCollection?.indexes.some(ignore => isIndexEqual(ignore, targetIndex))) {
79+
if (ignoreCollection?.indexes.some(ignore => isIndexEqual(ignore, targetIndex, options))) {
7380
return true;
7481
}
7582

@@ -78,7 +85,7 @@ export const shouldIgnoreIndexInTarget = (dumpDbName: DatabaseName, collectionNa
7885
...targetIndex,
7986
// eslint-disable-next-line @typescript-eslint/no-explicit-any
8087
expireAfterSeconds: 'ANY' as any,
81-
}))) {
88+
}, options))) {
8289
return true;
8390
}
8491

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export interface CompareOptions extends Partial<MongoClientOptions> {
7272
uri: string;
7373
product: Product;
7474
dbMap?: DbMapRaw;
75+
compareGitopsCollations?: boolean;
7576
}
7677

7778
export interface StatsOptions extends Partial<MongoClientOptions> {

0 commit comments

Comments
 (0)