@hanseltime/template-repo-sync 2.2.0 → 2.2.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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [2.2.1](https://github.com/HanseltimeIndustries/template-repo-sync/compare/v2.2.0...v2.2.1) (2026-02-22)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * template sync afterRef updates ([21dd335](https://github.com/HanseltimeIndustries/template-repo-sync/commit/21dd335045034d132ad5f6ab7944a81c82b96981))
7
+
1
8
  # [2.2.0](https://github.com/HanseltimeIndustries/template-repo-sync/compare/v2.1.2...v2.2.0) (2026-02-21)
2
9
 
3
10
 
@@ -61,12 +61,29 @@ async function templateSync(options) {
61
61
  const templateSyncConfig = (0, fs_1.existsSync)(cloneConfigPath)
62
62
  ? commentJSON.parse((0, fs_1.readFileSync)(cloneConfigPath).toString())
63
63
  : { ignore: [] };
64
- const localConfigPath = (0, path_1.join)(options.repoDir, `${exports.TEMPLATE_SYNC_LOCAL_CONFIG}.json`);
64
+ const localConfigFile = `${exports.TEMPLATE_SYNC_LOCAL_CONFIG}.json`;
65
+ const localConfigPath = (0, path_1.join)(options.repoDir, localConfigFile);
65
66
  const localTemplateSyncConfig = (0, fs_1.existsSync)(localConfigPath)
66
67
  ? commentJSON.parse((0, fs_1.readFileSync)(localConfigPath).toString())
67
68
  : { ignore: [] };
68
69
  let filesToSync;
70
+ const ref = await currentRefDriver({
71
+ rootDir: tempCloneDir,
72
+ });
69
73
  if (localTemplateSyncConfig.afterRef) {
74
+ if (ref === localTemplateSyncConfig.afterRef) {
75
+ // short circuit if the refs match
76
+ return {
77
+ localSkipFiles: [],
78
+ localFileChanges: {},
79
+ modifiedFiles: {
80
+ added: [],
81
+ modified: [],
82
+ deleted: [],
83
+ total: 0,
84
+ },
85
+ };
86
+ }
70
87
  filesToSync = await diffDriver(tempCloneDir, localTemplateSyncConfig.afterRef);
71
88
  }
72
89
  else {
@@ -114,7 +131,6 @@ async function templateSync(options) {
114
131
  added: actualAdded,
115
132
  modified: actualModified,
116
133
  deleted: actualDeleted,
117
- total: actualAdded.length + actualModified.length + actualDeleted.length,
118
134
  };
119
135
  // apply after ref
120
136
  if (options.updateAfterRef) {
@@ -126,15 +142,22 @@ async function templateSync(options) {
126
142
  const config = commentJSON.parse(configStr);
127
143
  config.afterRef = ref;
128
144
  (0, fs_1.writeFileSync)(localConfigPath, commentJSON.stringify(config, null, (0, formatting_1.inferJSONIndent)(configStr)));
145
+ modifiedFiles.modified.push(localConfigFile);
129
146
  }
130
147
  else {
131
148
  (0, fs_1.writeFileSync)(localConfigPath, commentJSON.stringify({ afterRef: ref }, null, 4));
149
+ modifiedFiles.added.push(localConfigFile);
132
150
  }
133
151
  }
134
152
  return {
135
153
  localSkipFiles: Array.from(localSkipFiles),
136
154
  localFileChanges,
137
- modifiedFiles: modifiedFiles,
155
+ modifiedFiles: {
156
+ ...modifiedFiles,
157
+ total: modifiedFiles.added.length +
158
+ modifiedFiles.deleted.length +
159
+ modifiedFiles.modified.length,
160
+ },
138
161
  };
139
162
  }
140
163
  exports.templateSync = templateSync;
@@ -61,12 +61,29 @@ async function templateSync(options) {
61
61
  const templateSyncConfig = (0, fs_1.existsSync)(cloneConfigPath)
62
62
  ? commentJSON.parse((0, fs_1.readFileSync)(cloneConfigPath).toString())
63
63
  : { ignore: [] };
64
- const localConfigPath = (0, path_1.join)(options.repoDir, `${exports.TEMPLATE_SYNC_LOCAL_CONFIG}.json`);
64
+ const localConfigFile = `${exports.TEMPLATE_SYNC_LOCAL_CONFIG}.json`;
65
+ const localConfigPath = (0, path_1.join)(options.repoDir, localConfigFile);
65
66
  const localTemplateSyncConfig = (0, fs_1.existsSync)(localConfigPath)
66
67
  ? commentJSON.parse((0, fs_1.readFileSync)(localConfigPath).toString())
67
68
  : { ignore: [] };
68
69
  let filesToSync;
70
+ const ref = await currentRefDriver({
71
+ rootDir: tempCloneDir,
72
+ });
69
73
  if (localTemplateSyncConfig.afterRef) {
74
+ if (ref === localTemplateSyncConfig.afterRef) {
75
+ // short circuit if the refs match
76
+ return {
77
+ localSkipFiles: [],
78
+ localFileChanges: {},
79
+ modifiedFiles: {
80
+ added: [],
81
+ modified: [],
82
+ deleted: [],
83
+ total: 0,
84
+ },
85
+ };
86
+ }
70
87
  filesToSync = await diffDriver(tempCloneDir, localTemplateSyncConfig.afterRef);
71
88
  }
72
89
  else {
@@ -114,7 +131,6 @@ async function templateSync(options) {
114
131
  added: actualAdded,
115
132
  modified: actualModified,
116
133
  deleted: actualDeleted,
117
- total: actualAdded.length + actualModified.length + actualDeleted.length,
118
134
  };
119
135
  // apply after ref
120
136
  if (options.updateAfterRef) {
@@ -126,15 +142,22 @@ async function templateSync(options) {
126
142
  const config = commentJSON.parse(configStr);
127
143
  config.afterRef = ref;
128
144
  (0, fs_1.writeFileSync)(localConfigPath, commentJSON.stringify(config, null, (0, formatting_1.inferJSONIndent)(configStr)));
145
+ modifiedFiles.modified.push(localConfigFile);
129
146
  }
130
147
  else {
131
148
  (0, fs_1.writeFileSync)(localConfigPath, commentJSON.stringify({ afterRef: ref }, null, 4));
149
+ modifiedFiles.added.push(localConfigFile);
132
150
  }
133
151
  }
134
152
  return {
135
153
  localSkipFiles: Array.from(localSkipFiles),
136
154
  localFileChanges,
137
- modifiedFiles: modifiedFiles,
155
+ modifiedFiles: {
156
+ ...modifiedFiles,
157
+ total: modifiedFiles.added.length +
158
+ modifiedFiles.deleted.length +
159
+ modifiedFiles.modified.length,
160
+ },
138
161
  };
139
162
  }
140
163
  exports.templateSync = templateSync;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanseltime/template-repo-sync",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "description": "An npm library that enables pluggable, customizable synchronization between template repos",
5
5
  "main": "lib/cjs/index.js",
6
6
  "types": "lib/cjs/index.d.ts",
@@ -292,7 +292,7 @@ describe("templateSync", () => {
292
292
  // We will only update the templated.ts
293
293
  const mockDiffDriver = jest.fn().mockImplementation(async () => ({
294
294
  added: ["src/templated.ts"],
295
- modified: ["src/index.ts"], // Add index.ts so we make sure it is still ignored - due to a bug
295
+ modified: ["src/index.ts"], // Add index.ts so we make sure it is still ignored - see test-fixtures/template/templatesync.json ignores
296
296
  deleted: [],
297
297
  }));
298
298
  const mockCurrentRefDriver = jest
@@ -311,6 +311,12 @@ describe("templateSync", () => {
311
311
 
312
312
  // since there was no override for this file, no changes from the local file
313
313
  expect(result.localFileChanges).toEqual(expect.objectContaining({}));
314
+ expect(result.modifiedFiles).toEqual({
315
+ added: ["src/templated.ts"],
316
+ modified: ["templatesync.local.json"], // Add index.ts so we make sure it is still ignored - due to a bug
317
+ deleted: [],
318
+ total: 2,
319
+ });
314
320
 
315
321
  // Verify the files
316
322
  await fileMatchTemplate(tmpDir, "templatesync.json");
@@ -332,6 +338,73 @@ describe("templateSync", () => {
332
338
  });
333
339
  expect(dummyCheckoutDriver).not.toHaveBeenCalled();
334
340
  });
341
+ it("Does not update the local templatesync if updateAfterRef is true and the ref is the same", async () => {
342
+ // Remove the local sync overrides
343
+ await rm(join(tmpDir, "templatesync.local.json"));
344
+
345
+ const mockLocalConfig = {
346
+ afterRef: "dummySha",
347
+ ignore: [
348
+ // We don't have a need for this in here, but it's an example of keeping things cleaner for our custom plugins
349
+ "plugins/**",
350
+ ],
351
+ };
352
+
353
+ writeFileSync(
354
+ join(tmpDir, "templatesync.local.json"),
355
+ JSON.stringify(mockLocalConfig),
356
+ );
357
+
358
+ // We will only update the templated.ts
359
+ const mockDiffDriver = jest.fn().mockImplementation(async () => ({
360
+ added: ["src/templated.ts"],
361
+ modified: ["src/index.ts"], // Add index.ts so we make sure it is still ignored - see test-fixtures/template/templatesync.json ignores
362
+ deleted: [],
363
+ }));
364
+ const mockCurrentRefDriver = jest
365
+ .fn()
366
+ .mockImplementation(async () => "dummySha");
367
+ const result = await templateSync({
368
+ tmpCloneDir: "stubbed-by-driver",
369
+ cloneDriver: dummyCloneDriver,
370
+ repoUrl: "not-important",
371
+ repoDir: tmpDir,
372
+ updateAfterRef: true,
373
+ diffDriver: mockDiffDriver,
374
+ currentRefDriver: mockCurrentRefDriver,
375
+ checkoutDriver: dummyCheckoutDriver,
376
+ });
377
+
378
+ // Nothing shoudl be reported as changing
379
+ expect(result).toEqual({
380
+ localFileChanges: {},
381
+ localSkipFiles: [],
382
+ modifiedFiles: {
383
+ added: [],
384
+ modified: [],
385
+ deleted: [],
386
+ total: 0,
387
+ },
388
+ });
389
+ // Verify the files
390
+ await fileMatchDownstream(tmpDir, "templatesync.json");
391
+ await fileMatchDownstream(tmpDir, "src/templated.ts");
392
+
393
+ // Expect the none of the diff files to work
394
+ await fileMatchDownstream(tmpDir, "src/index.ts");
395
+ await fileMatchDownstream(tmpDir, "plugins/custom-plugin.js");
396
+ await fileMatchDownstream(tmpDir, "package.json");
397
+
398
+ // Ensure we have updated the local template field
399
+ expect(
400
+ JSON.parse(
401
+ (await readFile(join(tmpDir, "templatesync.local.json"))).toString(),
402
+ ),
403
+ ).toEqual({
404
+ ...mockLocalConfig,
405
+ });
406
+ expect(dummyCheckoutDriver).not.toHaveBeenCalled();
407
+ });
335
408
  it("creates the local templatesync with the current ref if updateAfterRef is true and no local template exists", async () => {
336
409
  // Remove the local sync overrides
337
410
  await rm(join(tmpDir, "templatesync.local.json"));
@@ -356,6 +429,19 @@ describe("templateSync", () => {
356
429
 
357
430
  // since there was no override for this file, no changes from the local file
358
431
  expect(result.localFileChanges).toEqual(expect.objectContaining({}));
432
+ expect(result.modifiedFiles).toEqual({
433
+ added: [
434
+ "package.json",
435
+ "src/index.js",
436
+ "src/templated.js",
437
+ "src/templated.ts",
438
+ "templatesync.json",
439
+ "templatesync.local.json",
440
+ ],
441
+ deleted: [],
442
+ modified: [],
443
+ total: 6,
444
+ });
359
445
 
360
446
  // Verify the files
361
447
  await fileMatchTemplate(tmpDir, "templatesync.json");
@@ -125,10 +125,8 @@ export async function templateSync(
125
125
  ) as unknown as Config)
126
126
  : { ignore: [] };
127
127
 
128
- const localConfigPath = join(
129
- options.repoDir,
130
- `${TEMPLATE_SYNC_LOCAL_CONFIG}.json`,
131
- );
128
+ const localConfigFile = `${TEMPLATE_SYNC_LOCAL_CONFIG}.json`;
129
+ const localConfigPath = join(options.repoDir, localConfigFile);
132
130
  const localTemplateSyncConfig: LocalConfig = existsSync(localConfigPath)
133
131
  ? (commentJSON.parse(
134
132
  readFileSync(localConfigPath).toString(),
@@ -136,7 +134,23 @@ export async function templateSync(
136
134
  : { ignore: [] };
137
135
 
138
136
  let filesToSync: DiffResult;
137
+ const ref = await currentRefDriver({
138
+ rootDir: tempCloneDir,
139
+ });
139
140
  if (localTemplateSyncConfig.afterRef) {
141
+ if (ref === localTemplateSyncConfig.afterRef) {
142
+ // short circuit if the refs match
143
+ return {
144
+ localSkipFiles: [],
145
+ localFileChanges: {},
146
+ modifiedFiles: {
147
+ added: [],
148
+ modified: [],
149
+ deleted: [],
150
+ total: 0,
151
+ },
152
+ };
153
+ }
140
154
  filesToSync = await diffDriver(
141
155
  tempCloneDir,
142
156
  localTemplateSyncConfig.afterRef,
@@ -202,7 +216,6 @@ export async function templateSync(
202
216
  added: actualAdded,
203
217
  modified: actualModified,
204
218
  deleted: actualDeleted,
205
- total: actualAdded.length + actualModified.length + actualDeleted.length,
206
219
  };
207
220
 
208
221
  // apply after ref
@@ -219,17 +232,25 @@ export async function templateSync(
219
232
  localConfigPath,
220
233
  commentJSON.stringify(config, null, inferJSONIndent(configStr)),
221
234
  );
235
+ modifiedFiles.modified.push(localConfigFile);
222
236
  } else {
223
237
  writeFileSync(
224
238
  localConfigPath,
225
239
  commentJSON.stringify({ afterRef: ref }, null, 4),
226
240
  );
241
+ modifiedFiles.added.push(localConfigFile);
227
242
  }
228
243
  }
229
244
 
230
245
  return {
231
246
  localSkipFiles: Array.from(localSkipFiles),
232
247
  localFileChanges,
233
- modifiedFiles: modifiedFiles,
248
+ modifiedFiles: {
249
+ ...modifiedFiles,
250
+ total:
251
+ modifiedFiles.added.length +
252
+ modifiedFiles.deleted.length +
253
+ modifiedFiles.modified.length,
254
+ },
234
255
  };
235
256
  }