@hanseltime/template-repo-sync 2.1.2 → 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 +14 -0
- package/lib/cjs/formatting/sync-results-to-md.js +17 -0
- package/lib/cjs/merge-file.d.ts +2 -1
- package/lib/cjs/template-sync.d.ts +11 -1
- package/lib/cjs/template-sync.js +38 -4
- package/lib/esm/formatting/sync-results-to-md.js +17 -0
- package/lib/esm/template-sync.js +38 -4
- package/package.json +1 -1
- package/src/formatting/__snapshots__/sync-results-to-md.spec.ts.snap +17 -0
- package/src/formatting/sync-results-to-md.spec.ts +6 -0
- package/src/formatting/sync-results-to-md.ts +17 -0
- package/src/merge-file.ts +2 -1
- package/src/template-sync.spec.ts +125 -3
- package/src/template-sync.ts +54 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
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
|
+
|
|
8
|
+
# [2.2.0](https://github.com/HanseltimeIndustries/template-repo-sync/compare/v2.1.2...v2.2.0) (2026-02-21)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add modified files output to track actual sync changes ([050ffd0](https://github.com/HanseltimeIndustries/template-repo-sync/commit/050ffd0ff74195943e60fc8dbf4354191959c0be))
|
|
14
|
+
|
|
1
15
|
## [2.1.2](https://github.com/HanseltimeIndustries/template-repo-sync/compare/v2.1.1...v2.1.2) (2026-02-08)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -21,6 +21,23 @@ ${result.localFileChanges[file].reduce((diffS, change) => {
|
|
|
21
21
|
}, "")}
|
|
22
22
|
\`\`\``;
|
|
23
23
|
}, "")}
|
|
24
|
+
|
|
25
|
+
## Files Modified (${result.modifiedFiles.total})
|
|
26
|
+
|
|
27
|
+
Added:
|
|
28
|
+
${result.modifiedFiles.added.reduce((s, f) => {
|
|
29
|
+
return `${s}\n- ${f}`;
|
|
30
|
+
}, "")}
|
|
31
|
+
|
|
32
|
+
Modified:
|
|
33
|
+
${result.modifiedFiles.modified.reduce((s, f) => {
|
|
34
|
+
return `${s}\n- ${f}`;
|
|
35
|
+
}, "")}
|
|
36
|
+
|
|
37
|
+
Deleted:
|
|
38
|
+
${result.modifiedFiles.deleted.reduce((s, f) => {
|
|
39
|
+
return `${s}\n- ${f}`;
|
|
40
|
+
}, "")}
|
|
24
41
|
`;
|
|
25
42
|
}
|
|
26
43
|
exports.syncResultsToMd = syncResultsToMd;
|
package/lib/cjs/merge-file.d.ts
CHANGED
|
@@ -14,7 +14,8 @@ interface MergeFileReturn {
|
|
|
14
14
|
ignoredDueToLocal: boolean;
|
|
15
15
|
/**
|
|
16
16
|
* Only available if the file wasn't ignored, this is a list of lineDiffs
|
|
17
|
-
* from the
|
|
17
|
+
* from the diff library that were applied to what would've been changed by
|
|
18
|
+
* the base templatesync repo
|
|
18
19
|
*/
|
|
19
20
|
localChanges?: Change[];
|
|
20
21
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Change } from "diff";
|
|
2
2
|
import { TemplateCloneDriverFn } from "./clone-drivers";
|
|
3
|
-
import { TemplateDiffDriverFn } from "./diff-drivers";
|
|
3
|
+
import { DiffResult, TemplateDiffDriverFn } from "./diff-drivers";
|
|
4
4
|
import { TemplateRefDriverFn } from "./ref-drivers/types";
|
|
5
5
|
import { TemplateCheckoutDriverFn } from "./checkout-drivers";
|
|
6
6
|
export interface TemplateSyncOptions {
|
|
@@ -57,6 +57,16 @@ export interface TemplateSyncReturn {
|
|
|
57
57
|
localFileChanges: {
|
|
58
58
|
[filePath: string]: Change[];
|
|
59
59
|
};
|
|
60
|
+
/**
|
|
61
|
+
* A list of all files that are modified by this operation. You can use total to quickly check if
|
|
62
|
+
* there was an actual meaningful change.
|
|
63
|
+
*
|
|
64
|
+
* Please note, ther may be localSkipfiles and total: 0, which indicates there were changes BUT the local template
|
|
65
|
+
* sync file rendered them meaningless.
|
|
66
|
+
*/
|
|
67
|
+
modifiedFiles: DiffResult & {
|
|
68
|
+
total: number;
|
|
69
|
+
};
|
|
60
70
|
}
|
|
61
71
|
export declare const TEMPLATE_SYNC_CONFIG = "templatesync";
|
|
62
72
|
export declare const TEMPLATE_SYNC_LOCAL_CONFIG = "templatesync.local";
|
package/lib/cjs/template-sync.js
CHANGED
|
@@ -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
|
|
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 {
|
|
@@ -83,7 +100,7 @@ async function templateSync(options) {
|
|
|
83
100
|
filesToSync.added = filesToSync.added.filter((f) => !(0, micromatch_1.some)(f, templateSyncConfig.ignore));
|
|
84
101
|
filesToSync.modified = filesToSync.modified.filter((f) => !(0, micromatch_1.some)(f, templateSyncConfig.ignore));
|
|
85
102
|
filesToSync.deleted = filesToSync.deleted.filter((f) => !(0, micromatch_1.some)(f, templateSyncConfig.ignore));
|
|
86
|
-
const localSkipFiles =
|
|
103
|
+
const localSkipFiles = new Set();
|
|
87
104
|
const localFileChanges = {};
|
|
88
105
|
const fileSyncFactory = (op) => {
|
|
89
106
|
return async (f) => {
|
|
@@ -95,7 +112,7 @@ async function templateSync(options) {
|
|
|
95
112
|
fileOperation: op,
|
|
96
113
|
});
|
|
97
114
|
if (result.ignoredDueToLocal) {
|
|
98
|
-
localSkipFiles.
|
|
115
|
+
localSkipFiles.add(f);
|
|
99
116
|
}
|
|
100
117
|
else if (result?.localChanges && result.localChanges.length > 0) {
|
|
101
118
|
localFileChanges[f] = result.localChanges;
|
|
@@ -106,6 +123,15 @@ async function templateSync(options) {
|
|
|
106
123
|
await Promise.all(filesToSync.added.map(fileSyncFactory("added")));
|
|
107
124
|
await Promise.all(filesToSync.modified.map(fileSyncFactory("modified")));
|
|
108
125
|
await Promise.all(filesToSync.deleted.map(fileSyncFactory("deleted")));
|
|
126
|
+
// Report the files that changed in general
|
|
127
|
+
const actualAdded = filesToSync.added.filter((f) => !localSkipFiles.has(f));
|
|
128
|
+
const actualModified = filesToSync.modified.filter((f) => !localSkipFiles.has(f));
|
|
129
|
+
const actualDeleted = filesToSync.deleted.filter((f) => !localSkipFiles.has(f));
|
|
130
|
+
const modifiedFiles = {
|
|
131
|
+
added: actualAdded,
|
|
132
|
+
modified: actualModified,
|
|
133
|
+
deleted: actualDeleted,
|
|
134
|
+
};
|
|
109
135
|
// apply after ref
|
|
110
136
|
if (options.updateAfterRef) {
|
|
111
137
|
const ref = await currentRefDriver({
|
|
@@ -116,14 +142,22 @@ async function templateSync(options) {
|
|
|
116
142
|
const config = commentJSON.parse(configStr);
|
|
117
143
|
config.afterRef = ref;
|
|
118
144
|
(0, fs_1.writeFileSync)(localConfigPath, commentJSON.stringify(config, null, (0, formatting_1.inferJSONIndent)(configStr)));
|
|
145
|
+
modifiedFiles.modified.push(localConfigFile);
|
|
119
146
|
}
|
|
120
147
|
else {
|
|
121
148
|
(0, fs_1.writeFileSync)(localConfigPath, commentJSON.stringify({ afterRef: ref }, null, 4));
|
|
149
|
+
modifiedFiles.added.push(localConfigFile);
|
|
122
150
|
}
|
|
123
151
|
}
|
|
124
152
|
return {
|
|
125
|
-
localSkipFiles,
|
|
153
|
+
localSkipFiles: Array.from(localSkipFiles),
|
|
126
154
|
localFileChanges,
|
|
155
|
+
modifiedFiles: {
|
|
156
|
+
...modifiedFiles,
|
|
157
|
+
total: modifiedFiles.added.length +
|
|
158
|
+
modifiedFiles.deleted.length +
|
|
159
|
+
modifiedFiles.modified.length,
|
|
160
|
+
},
|
|
127
161
|
};
|
|
128
162
|
}
|
|
129
163
|
exports.templateSync = templateSync;
|
|
@@ -21,6 +21,23 @@ ${result.localFileChanges[file].reduce((diffS, change) => {
|
|
|
21
21
|
}, "")}
|
|
22
22
|
\`\`\``;
|
|
23
23
|
}, "")}
|
|
24
|
+
|
|
25
|
+
## Files Modified (${result.modifiedFiles.total})
|
|
26
|
+
|
|
27
|
+
Added:
|
|
28
|
+
${result.modifiedFiles.added.reduce((s, f) => {
|
|
29
|
+
return `${s}\n- ${f}`;
|
|
30
|
+
}, "")}
|
|
31
|
+
|
|
32
|
+
Modified:
|
|
33
|
+
${result.modifiedFiles.modified.reduce((s, f) => {
|
|
34
|
+
return `${s}\n- ${f}`;
|
|
35
|
+
}, "")}
|
|
36
|
+
|
|
37
|
+
Deleted:
|
|
38
|
+
${result.modifiedFiles.deleted.reduce((s, f) => {
|
|
39
|
+
return `${s}\n- ${f}`;
|
|
40
|
+
}, "")}
|
|
24
41
|
`;
|
|
25
42
|
}
|
|
26
43
|
exports.syncResultsToMd = syncResultsToMd;
|
package/lib/esm/template-sync.js
CHANGED
|
@@ -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
|
|
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 {
|
|
@@ -83,7 +100,7 @@ async function templateSync(options) {
|
|
|
83
100
|
filesToSync.added = filesToSync.added.filter((f) => !(0, micromatch_1.some)(f, templateSyncConfig.ignore));
|
|
84
101
|
filesToSync.modified = filesToSync.modified.filter((f) => !(0, micromatch_1.some)(f, templateSyncConfig.ignore));
|
|
85
102
|
filesToSync.deleted = filesToSync.deleted.filter((f) => !(0, micromatch_1.some)(f, templateSyncConfig.ignore));
|
|
86
|
-
const localSkipFiles =
|
|
103
|
+
const localSkipFiles = new Set();
|
|
87
104
|
const localFileChanges = {};
|
|
88
105
|
const fileSyncFactory = (op) => {
|
|
89
106
|
return async (f) => {
|
|
@@ -95,7 +112,7 @@ async function templateSync(options) {
|
|
|
95
112
|
fileOperation: op,
|
|
96
113
|
});
|
|
97
114
|
if (result.ignoredDueToLocal) {
|
|
98
|
-
localSkipFiles.
|
|
115
|
+
localSkipFiles.add(f);
|
|
99
116
|
}
|
|
100
117
|
else if (result?.localChanges && result.localChanges.length > 0) {
|
|
101
118
|
localFileChanges[f] = result.localChanges;
|
|
@@ -106,6 +123,15 @@ async function templateSync(options) {
|
|
|
106
123
|
await Promise.all(filesToSync.added.map(fileSyncFactory("added")));
|
|
107
124
|
await Promise.all(filesToSync.modified.map(fileSyncFactory("modified")));
|
|
108
125
|
await Promise.all(filesToSync.deleted.map(fileSyncFactory("deleted")));
|
|
126
|
+
// Report the files that changed in general
|
|
127
|
+
const actualAdded = filesToSync.added.filter((f) => !localSkipFiles.has(f));
|
|
128
|
+
const actualModified = filesToSync.modified.filter((f) => !localSkipFiles.has(f));
|
|
129
|
+
const actualDeleted = filesToSync.deleted.filter((f) => !localSkipFiles.has(f));
|
|
130
|
+
const modifiedFiles = {
|
|
131
|
+
added: actualAdded,
|
|
132
|
+
modified: actualModified,
|
|
133
|
+
deleted: actualDeleted,
|
|
134
|
+
};
|
|
109
135
|
// apply after ref
|
|
110
136
|
if (options.updateAfterRef) {
|
|
111
137
|
const ref = await currentRefDriver({
|
|
@@ -116,14 +142,22 @@ async function templateSync(options) {
|
|
|
116
142
|
const config = commentJSON.parse(configStr);
|
|
117
143
|
config.afterRef = ref;
|
|
118
144
|
(0, fs_1.writeFileSync)(localConfigPath, commentJSON.stringify(config, null, (0, formatting_1.inferJSONIndent)(configStr)));
|
|
145
|
+
modifiedFiles.modified.push(localConfigFile);
|
|
119
146
|
}
|
|
120
147
|
else {
|
|
121
148
|
(0, fs_1.writeFileSync)(localConfigPath, commentJSON.stringify({ afterRef: ref }, null, 4));
|
|
149
|
+
modifiedFiles.added.push(localConfigFile);
|
|
122
150
|
}
|
|
123
151
|
}
|
|
124
152
|
return {
|
|
125
|
-
localSkipFiles,
|
|
153
|
+
localSkipFiles: Array.from(localSkipFiles),
|
|
126
154
|
localFileChanges,
|
|
155
|
+
modifiedFiles: {
|
|
156
|
+
...modifiedFiles,
|
|
157
|
+
total: modifiedFiles.added.length +
|
|
158
|
+
modifiedFiles.deleted.length +
|
|
159
|
+
modifiedFiles.modified.length,
|
|
160
|
+
},
|
|
127
161
|
};
|
|
128
162
|
}
|
|
129
163
|
exports.templateSync = templateSync;
|
package/package.json
CHANGED
|
@@ -18,5 +18,22 @@ package.json
|
|
|
18
18
|
-your thang
|
|
19
19
|
|
|
20
20
|
\`\`\`
|
|
21
|
+
|
|
22
|
+
## Files Modified (6)
|
|
23
|
+
|
|
24
|
+
Added:
|
|
25
|
+
|
|
26
|
+
- src/something.ts
|
|
27
|
+
- new_settings.toml
|
|
28
|
+
|
|
29
|
+
Modified:
|
|
30
|
+
|
|
31
|
+
- something.txt
|
|
32
|
+
- .env
|
|
33
|
+
|
|
34
|
+
Deleted:
|
|
35
|
+
|
|
36
|
+
- TODO.md
|
|
37
|
+
- throwaway.ts
|
|
21
38
|
"
|
|
22
39
|
`;
|
|
@@ -19,6 +19,12 @@ describe("syncResultsToMd", () => {
|
|
|
19
19
|
},
|
|
20
20
|
],
|
|
21
21
|
},
|
|
22
|
+
modifiedFiles: {
|
|
23
|
+
added: ["src/something.ts", "new_settings.toml"],
|
|
24
|
+
deleted: ["TODO.md", "throwaway.ts"],
|
|
25
|
+
modified: ["something.txt", ".env"],
|
|
26
|
+
total: 6,
|
|
27
|
+
},
|
|
22
28
|
}),
|
|
23
29
|
).toMatchSnapshot();
|
|
24
30
|
});
|
|
@@ -23,6 +23,23 @@ ${result.localFileChanges[file].reduce((diffS, change) => {
|
|
|
23
23
|
}, "")}
|
|
24
24
|
\`\`\``;
|
|
25
25
|
}, "")}
|
|
26
|
+
|
|
27
|
+
## Files Modified (${result.modifiedFiles.total})
|
|
28
|
+
|
|
29
|
+
Added:
|
|
30
|
+
${result.modifiedFiles.added.reduce((s, f) => {
|
|
31
|
+
return `${s}\n- ${f}`;
|
|
32
|
+
}, "")}
|
|
33
|
+
|
|
34
|
+
Modified:
|
|
35
|
+
${result.modifiedFiles.modified.reduce((s, f) => {
|
|
36
|
+
return `${s}\n- ${f}`;
|
|
37
|
+
}, "")}
|
|
38
|
+
|
|
39
|
+
Deleted:
|
|
40
|
+
${result.modifiedFiles.deleted.reduce((s, f) => {
|
|
41
|
+
return `${s}\n- ${f}`;
|
|
42
|
+
}, "")}
|
|
26
43
|
`;
|
|
27
44
|
}
|
|
28
45
|
|
package/src/merge-file.ts
CHANGED
|
@@ -22,7 +22,8 @@ interface MergeFileReturn {
|
|
|
22
22
|
ignoredDueToLocal: boolean;
|
|
23
23
|
/**
|
|
24
24
|
* Only available if the file wasn't ignored, this is a list of lineDiffs
|
|
25
|
-
* from the
|
|
25
|
+
* from the diff library that were applied to what would've been changed by
|
|
26
|
+
* the base templatesync repo
|
|
26
27
|
*/
|
|
27
28
|
localChanges?: Change[];
|
|
28
29
|
}
|
|
@@ -44,6 +44,18 @@ describe("templateSync", () => {
|
|
|
44
44
|
// Expect no changes since there was no local sync file
|
|
45
45
|
localSkipFiles: [],
|
|
46
46
|
localFileChanges: {},
|
|
47
|
+
modifiedFiles: {
|
|
48
|
+
added: [
|
|
49
|
+
"package.json",
|
|
50
|
+
"src/index.js",
|
|
51
|
+
"src/templated.js",
|
|
52
|
+
"src/templated.ts",
|
|
53
|
+
"templatesync.json",
|
|
54
|
+
],
|
|
55
|
+
deleted: [],
|
|
56
|
+
modified: [],
|
|
57
|
+
total: 5,
|
|
58
|
+
},
|
|
47
59
|
});
|
|
48
60
|
|
|
49
61
|
// Verify the files
|
|
@@ -72,6 +84,18 @@ describe("templateSync", () => {
|
|
|
72
84
|
// Expect no changes since there was no local sync file
|
|
73
85
|
localSkipFiles: [],
|
|
74
86
|
localFileChanges: {},
|
|
87
|
+
modifiedFiles: {
|
|
88
|
+
added: [
|
|
89
|
+
"package.json",
|
|
90
|
+
"src/index.js",
|
|
91
|
+
"src/templated.js",
|
|
92
|
+
"src/templated.ts",
|
|
93
|
+
"templatesync.json",
|
|
94
|
+
],
|
|
95
|
+
deleted: [],
|
|
96
|
+
modified: [],
|
|
97
|
+
total: 5,
|
|
98
|
+
},
|
|
75
99
|
});
|
|
76
100
|
|
|
77
101
|
// Verify the files
|
|
@@ -175,6 +199,18 @@ describe("templateSync", () => {
|
|
|
175
199
|
"package.json": expect.arrayContaining([]),
|
|
176
200
|
}),
|
|
177
201
|
);
|
|
202
|
+
// Make sure the result captures the changes
|
|
203
|
+
expect(result.modifiedFiles).toEqual({
|
|
204
|
+
added: [
|
|
205
|
+
"package.json",
|
|
206
|
+
"src/index.js",
|
|
207
|
+
"src/templated.js",
|
|
208
|
+
"templatesync.json",
|
|
209
|
+
],
|
|
210
|
+
deleted: [],
|
|
211
|
+
modified: [],
|
|
212
|
+
total: 4,
|
|
213
|
+
});
|
|
178
214
|
|
|
179
215
|
// Verify the files
|
|
180
216
|
await fileMatchTemplate(tmpDir, "templatesync.json");
|
|
@@ -256,7 +292,7 @@ describe("templateSync", () => {
|
|
|
256
292
|
// We will only update the templated.ts
|
|
257
293
|
const mockDiffDriver = jest.fn().mockImplementation(async () => ({
|
|
258
294
|
added: ["src/templated.ts"],
|
|
259
|
-
modified: ["src/index.ts"], // Add index.ts so we make sure it is still ignored -
|
|
295
|
+
modified: ["src/index.ts"], // Add index.ts so we make sure it is still ignored - see test-fixtures/template/templatesync.json ignores
|
|
260
296
|
deleted: [],
|
|
261
297
|
}));
|
|
262
298
|
const mockCurrentRefDriver = jest
|
|
@@ -273,8 +309,14 @@ describe("templateSync", () => {
|
|
|
273
309
|
checkoutDriver: dummyCheckoutDriver,
|
|
274
310
|
});
|
|
275
311
|
|
|
276
|
-
// since there was no override for this file,
|
|
312
|
+
// since there was no override for this file, no changes from the local file
|
|
277
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
|
+
});
|
|
278
320
|
|
|
279
321
|
// Verify the files
|
|
280
322
|
await fileMatchTemplate(tmpDir, "templatesync.json");
|
|
@@ -296,6 +338,73 @@ describe("templateSync", () => {
|
|
|
296
338
|
});
|
|
297
339
|
expect(dummyCheckoutDriver).not.toHaveBeenCalled();
|
|
298
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
|
+
});
|
|
299
408
|
it("creates the local templatesync with the current ref if updateAfterRef is true and no local template exists", async () => {
|
|
300
409
|
// Remove the local sync overrides
|
|
301
410
|
await rm(join(tmpDir, "templatesync.local.json"));
|
|
@@ -318,8 +427,21 @@ describe("templateSync", () => {
|
|
|
318
427
|
checkoutDriver: dummyCheckoutDriver,
|
|
319
428
|
});
|
|
320
429
|
|
|
321
|
-
// since there was no override for this file,
|
|
430
|
+
// since there was no override for this file, no changes from the local file
|
|
322
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
|
+
});
|
|
323
445
|
|
|
324
446
|
// Verify the files
|
|
325
447
|
await fileMatchTemplate(tmpDir, "templatesync.json");
|
package/src/template-sync.ts
CHANGED
|
@@ -77,6 +77,16 @@ export interface TemplateSyncReturn {
|
|
|
77
77
|
localFileChanges: {
|
|
78
78
|
[filePath: string]: Change[];
|
|
79
79
|
};
|
|
80
|
+
/**
|
|
81
|
+
* A list of all files that are modified by this operation. You can use total to quickly check if
|
|
82
|
+
* there was an actual meaningful change.
|
|
83
|
+
*
|
|
84
|
+
* Please note, ther may be localSkipfiles and total: 0, which indicates there were changes BUT the local template
|
|
85
|
+
* sync file rendered them meaningless.
|
|
86
|
+
*/
|
|
87
|
+
modifiedFiles: DiffResult & {
|
|
88
|
+
total: number;
|
|
89
|
+
};
|
|
80
90
|
}
|
|
81
91
|
|
|
82
92
|
export const TEMPLATE_SYNC_CONFIG = "templatesync";
|
|
@@ -115,10 +125,8 @@ export async function templateSync(
|
|
|
115
125
|
) as unknown as Config)
|
|
116
126
|
: { ignore: [] };
|
|
117
127
|
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
`${TEMPLATE_SYNC_LOCAL_CONFIG}.json`,
|
|
121
|
-
);
|
|
128
|
+
const localConfigFile = `${TEMPLATE_SYNC_LOCAL_CONFIG}.json`;
|
|
129
|
+
const localConfigPath = join(options.repoDir, localConfigFile);
|
|
122
130
|
const localTemplateSyncConfig: LocalConfig = existsSync(localConfigPath)
|
|
123
131
|
? (commentJSON.parse(
|
|
124
132
|
readFileSync(localConfigPath).toString(),
|
|
@@ -126,7 +134,23 @@ export async function templateSync(
|
|
|
126
134
|
: { ignore: [] };
|
|
127
135
|
|
|
128
136
|
let filesToSync: DiffResult;
|
|
137
|
+
const ref = await currentRefDriver({
|
|
138
|
+
rootDir: tempCloneDir,
|
|
139
|
+
});
|
|
129
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
|
+
}
|
|
130
154
|
filesToSync = await diffDriver(
|
|
131
155
|
tempCloneDir,
|
|
132
156
|
localTemplateSyncConfig.afterRef,
|
|
@@ -153,7 +177,7 @@ export async function templateSync(
|
|
|
153
177
|
(f) => !some(f, templateSyncConfig.ignore),
|
|
154
178
|
);
|
|
155
179
|
|
|
156
|
-
const localSkipFiles: string
|
|
180
|
+
const localSkipFiles: Set<string> = new Set();
|
|
157
181
|
const localFileChanges: {
|
|
158
182
|
[filePath: string]: Change[];
|
|
159
183
|
} = {};
|
|
@@ -168,7 +192,7 @@ export async function templateSync(
|
|
|
168
192
|
fileOperation: op,
|
|
169
193
|
});
|
|
170
194
|
if (result.ignoredDueToLocal) {
|
|
171
|
-
localSkipFiles.
|
|
195
|
+
localSkipFiles.add(f);
|
|
172
196
|
} else if (result?.localChanges && result.localChanges.length > 0) {
|
|
173
197
|
localFileChanges[f] = result.localChanges;
|
|
174
198
|
}
|
|
@@ -180,6 +204,20 @@ export async function templateSync(
|
|
|
180
204
|
await Promise.all(filesToSync.modified.map(fileSyncFactory("modified")));
|
|
181
205
|
await Promise.all(filesToSync.deleted.map(fileSyncFactory("deleted")));
|
|
182
206
|
|
|
207
|
+
// Report the files that changed in general
|
|
208
|
+
const actualAdded = filesToSync.added.filter((f) => !localSkipFiles.has(f));
|
|
209
|
+
const actualModified = filesToSync.modified.filter(
|
|
210
|
+
(f) => !localSkipFiles.has(f),
|
|
211
|
+
);
|
|
212
|
+
const actualDeleted = filesToSync.deleted.filter(
|
|
213
|
+
(f) => !localSkipFiles.has(f),
|
|
214
|
+
);
|
|
215
|
+
const modifiedFiles = {
|
|
216
|
+
added: actualAdded,
|
|
217
|
+
modified: actualModified,
|
|
218
|
+
deleted: actualDeleted,
|
|
219
|
+
};
|
|
220
|
+
|
|
183
221
|
// apply after ref
|
|
184
222
|
if (options.updateAfterRef) {
|
|
185
223
|
const ref = await currentRefDriver({
|
|
@@ -194,16 +232,25 @@ export async function templateSync(
|
|
|
194
232
|
localConfigPath,
|
|
195
233
|
commentJSON.stringify(config, null, inferJSONIndent(configStr)),
|
|
196
234
|
);
|
|
235
|
+
modifiedFiles.modified.push(localConfigFile);
|
|
197
236
|
} else {
|
|
198
237
|
writeFileSync(
|
|
199
238
|
localConfigPath,
|
|
200
239
|
commentJSON.stringify({ afterRef: ref }, null, 4),
|
|
201
240
|
);
|
|
241
|
+
modifiedFiles.added.push(localConfigFile);
|
|
202
242
|
}
|
|
203
243
|
}
|
|
204
244
|
|
|
205
245
|
return {
|
|
206
|
-
localSkipFiles,
|
|
246
|
+
localSkipFiles: Array.from(localSkipFiles),
|
|
207
247
|
localFileChanges,
|
|
248
|
+
modifiedFiles: {
|
|
249
|
+
...modifiedFiles,
|
|
250
|
+
total:
|
|
251
|
+
modifiedFiles.added.length +
|
|
252
|
+
modifiedFiles.deleted.length +
|
|
253
|
+
modifiedFiles.modified.length,
|
|
254
|
+
},
|
|
208
255
|
};
|
|
209
256
|
}
|