@hanseltime/template-repo-sync 1.0.1 → 1.2.0
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/README.md +80 -3
- package/docs/merge-plugins/CURRENT_PLUGINS.md +168 -0
- package/docs/merge-plugins/DEVELOPMENT.md +129 -0
- package/docs/merge-plugins/README.md +85 -0
- package/lib/cjs/plugins/json-merge.js +30 -7
- package/lib/cjs/ref-drivers/git-current-ref.d.ts +3 -0
- package/lib/cjs/ref-drivers/git-current-ref.js +12 -0
- package/lib/cjs/ref-drivers/index.d.ts +1 -0
- package/lib/cjs/ref-drivers/index.js +17 -0
- package/lib/cjs/ref-drivers/types.d.ts +10 -0
- package/lib/cjs/ref-drivers/types.js +2 -0
- package/lib/cjs/template-sync.d.ts +10 -0
- package/lib/cjs/template-sync.js +46 -4
- package/lib/cjs/types.d.ts +1 -1
- package/lib/esm/plugins/json-merge.js +30 -7
- package/lib/esm/ref-drivers/git-current-ref.js +12 -0
- package/lib/esm/ref-drivers/index.js +17 -0
- package/lib/esm/ref-drivers/types.js +2 -0
- package/lib/esm/template-sync.js +46 -4
- package/package.json +5 -8
- package/src/plugins/json-merge.spec.ts +86 -0
- package/src/plugins/json-merge.ts +17 -7
- package/src/ref-drivers/git-current-ref.spec.ts +12 -0
- package/src/ref-drivers/git-current-ref.ts +9 -0
- package/src/ref-drivers/index.ts +1 -0
- package/src/ref-drivers/types.ts +10 -0
- package/src/template-sync.spec.ts +121 -0
- package/src/template-sync.ts +48 -6
- package/src/types.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [1.2.0](https://github.com/HanseltimeIndustries/template-repo-sync/compare/v1.1.0...v1.2.0) (2024-03-11)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* adding comment-json support for merges ([c4393aa](https://github.com/HanseltimeIndustries/template-repo-sync/commit/c4393aaa6bf3bb985670f4377f2a370338450618))
|
|
7
|
+
|
|
8
|
+
# [1.1.0](https://github.com/HanseltimeIndustries/template-repo-sync/compare/v1.0.1...v1.1.0) (2024-03-04)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* adding updateRef Option ([b553e65](https://github.com/HanseltimeIndustries/template-repo-sync/commit/b553e65ebce59777ccb80728d540c5734d41cab7))
|
|
14
|
+
|
|
1
15
|
## [1.0.1](https://github.com/HanseltimeIndustries/template-repo-sync/compare/v1.0.0...v1.0.1) (2024-03-03)
|
|
2
16
|
|
|
3
17
|
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Template Sync
|
|
1
|
+
# Template Sync
|
|
2
2
|
|
|
3
3
|
This npm package seeks to provide further granularity for people hoping to maintain a base template repo in github that
|
|
4
4
|
is either imported or used as a literal template repo.
|
|
@@ -13,6 +13,16 @@ best practice development patterns, then we naturally want to have a way to allo
|
|
|
13
13
|
changes, while also having control over things that may be specifically changed due to their need to support something beyond the
|
|
14
14
|
orgnaization standard.
|
|
15
15
|
|
|
16
|
+
- [Template Sync](#template-sync)
|
|
17
|
+
- [How to use this](#how-to-use-this)
|
|
18
|
+
- [Config file](#config-file)
|
|
19
|
+
- [File format](#file-format)
|
|
20
|
+
- [Example 1 - Using a custom plugin](#example-1---using-a-custom-plugin)
|
|
21
|
+
- [Example 2 - Using a custom plugin for some paths](#example-2---using-a-custom-plugin-for-some-paths)
|
|
22
|
+
- [From SHA/Tag directive](#from-shatag-directive)
|
|
23
|
+
- [Programmatic API](#programmatic-api)
|
|
24
|
+
<!-- Created with Markdown All In One VsCode Entension, rerun to update -->
|
|
25
|
+
|
|
16
26
|
# How to use this
|
|
17
27
|
|
|
18
28
|
This repository publishes a github action that can be used for ease of use in github. It also provides itself as an npm package
|
|
@@ -32,6 +42,10 @@ This library will always respect the overrides of the local template sync file i
|
|
|
32
42
|
templates and their repos, will also provide a list of all files whose template sync behavior was either ignored or overridden by the local
|
|
33
43
|
file. In this way, teams should be able to track (with a little extra CI/CD wiring) or at the very least, explicitly acknowledge a deviation.
|
|
34
44
|
|
|
45
|
+
All config files have the ability to write custom merge plugins either in repo or published as packages for larger use.
|
|
46
|
+
|
|
47
|
+
Please see the [plugins](./docs/merge-plugins/) documentation for more information beyond the simple examples in this readme.
|
|
48
|
+
|
|
35
49
|
### File format
|
|
36
50
|
|
|
37
51
|
```typescript
|
|
@@ -61,7 +75,11 @@ export interface Config {
|
|
|
61
75
|
}
|
|
62
76
|
```
|
|
63
77
|
|
|
64
|
-
### Example 1
|
|
78
|
+
### Example 1 - Using a custom plugin
|
|
79
|
+
|
|
80
|
+
In this scenario, you have installed a package that exposes the correct plugin interface for handling .ini file contents in
|
|
81
|
+
your implementing repository and set up this templatesync.local config file. Because of this, we can be assured that .ini files
|
|
82
|
+
in the local repo will be merged using the plugin we specified.
|
|
65
83
|
|
|
66
84
|
```typescript
|
|
67
85
|
{
|
|
@@ -70,7 +88,34 @@ export interface Config {
|
|
|
70
88
|
".ini": {
|
|
71
89
|
// If you are running under pacakge manager like yarn or npm,
|
|
72
90
|
// you can provide a valid pacakge or .js fil from your package to run
|
|
73
|
-
|
|
91
|
+
plugin: 'my-installed-npm-package',
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Example 2 - Using a custom plugin for some paths
|
|
98
|
+
|
|
99
|
+
Just like in example 1, we have installed a plugin that exposes the correct plugin interface. Now though,
|
|
100
|
+
instead of applying that plugin to all '.ini' files, we are saying that, for this particular set of .ini
|
|
101
|
+
files, only the ones in custom-configs/ will use this merge operator.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
{
|
|
105
|
+
|
|
106
|
+
merge: {
|
|
107
|
+
".ini": {
|
|
108
|
+
// If you are running under pacakge manager like yarn or npm,
|
|
109
|
+
// you can provide a valid pacakge or .js fil from your package to run
|
|
110
|
+
plugin: 'my-installed-npm-package',
|
|
111
|
+
rule: [
|
|
112
|
+
{
|
|
113
|
+
glob: 'custom-configs/**',
|
|
114
|
+
options: {
|
|
115
|
+
myPluginParam: 'some parameter',
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
]
|
|
74
119
|
}
|
|
75
120
|
}
|
|
76
121
|
}
|
|
@@ -91,3 +136,35 @@ but it does mean that you will only see the changes to files that are newer than
|
|
|
91
136
|
|
|
92
137
|
As always, you can remove the SHA/Tag from your local config and this will trigger a full sync in the event that you made the wrong
|
|
93
138
|
assumption about merging templates correctly.
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
{
|
|
142
|
+
afterRef: 'git sha',
|
|
143
|
+
merge: {
|
|
144
|
+
".ini": {
|
|
145
|
+
// If you are running under pacakge manager like yarn or npm,
|
|
146
|
+
// you can provide a valid pacakge or .js fil from your package to run
|
|
147
|
+
plugin: 'my-installed-npm-package',
|
|
148
|
+
rule: [
|
|
149
|
+
{
|
|
150
|
+
glob: 'custom-configs/**',
|
|
151
|
+
options: {
|
|
152
|
+
myPluginParam: 'some parameter',
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Programmatic API
|
|
162
|
+
|
|
163
|
+
The programmatic api for this package is centered around `templateSync`. The way the function is written, we try to
|
|
164
|
+
allow escape hatches for other styles of comparison in the form of "TemplateDriver" functions. As part of the current
|
|
165
|
+
implementation, all of these `drivers` represent git actions, but for the sake of expandability, may be set up to evaluate
|
|
166
|
+
things like helm chart renderings (at least that is the hope). If you write a driver, please consider contributing it back.
|
|
167
|
+
|
|
168
|
+
Please see [template-sync](./src/template-sync.ts) for the most up to date options.
|
|
169
|
+
|
|
170
|
+
TODO: we should update use case examples
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Current Merge Plugins
|
|
2
|
+
|
|
3
|
+
This document lists all merge plugins that are provided provided as defaults for certain file extensions.
|
|
4
|
+
These should be found in the [plugins folder](src/plugins)
|
|
5
|
+
|
|
6
|
+
- [Current Merge Plugins](#current-merge-plugins)
|
|
7
|
+
- [Json Merge Plugin](#json-merge-plugin)
|
|
8
|
+
- [Configuration Options:](#configuration-options)
|
|
9
|
+
- [Simple merge spec](#simple-merge-spec)
|
|
10
|
+
- [JsonPath config](#jsonpath-config)
|
|
11
|
+
- [Example](#example)
|
|
12
|
+
- [About Comments](#about-comments)
|
|
13
|
+
|
|
14
|
+
<!-- Created with Markdown All In One VsCode Extension -->
|
|
15
|
+
|
|
16
|
+
## Json Merge Plugin
|
|
17
|
+
|
|
18
|
+
The json merge plugin allows you to configure jsonpath based merges on any .json file.
|
|
19
|
+
|
|
20
|
+
## Configuration Options:
|
|
21
|
+
|
|
22
|
+
### Simple merge spec
|
|
23
|
+
|
|
24
|
+
At it's simplest, you can take advantage of lodash merge behavior by just specifying one of:
|
|
25
|
+
|
|
26
|
+
- overwrite - the template completely overwrites the file
|
|
27
|
+
- merge-template - keys are merged together with the template overwriting any matching keys on local file
|
|
28
|
+
- merge-current - keys are merged together with the local file keeping any keys that match in the template
|
|
29
|
+
|
|
30
|
+
Example config:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"merge": {
|
|
35
|
+
".json": {
|
|
36
|
+
"rules": [
|
|
37
|
+
{
|
|
38
|
+
"glob": "metadata.json",
|
|
39
|
+
"options": "merge-template"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"glob": "template-lock.json",
|
|
43
|
+
"options": "overwrite"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"glob": "package.json",
|
|
47
|
+
"options": "merge-current"
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### JsonPath config
|
|
56
|
+
|
|
57
|
+
If you would like further control over what merges within a .json file, you can actually specify, via way of jsonpath operators,
|
|
58
|
+
the level of merge per field.
|
|
59
|
+
|
|
60
|
+
A few rules:
|
|
61
|
+
|
|
62
|
+
- Once you have provided jsonpath options, only the json path options (or new fields if the option is enabled) will be merged
|
|
63
|
+
- jsonpaths are run from first to last. This means you can layer merges.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
interface Options {
|
|
67
|
+
/**
|
|
68
|
+
* If set to true, this means we won't add new properties from the template
|
|
69
|
+
*/
|
|
70
|
+
ignoreNewProperties?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* If set to true, overwrite will apply undefined values as deleted for the jsonpaths
|
|
73
|
+
* or for values that are supposed to be merged on top of other values
|
|
74
|
+
*/
|
|
75
|
+
missingIsDelete?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Note, if multiple json paths match a rule, we pick the first one in the list that matches
|
|
78
|
+
*/
|
|
79
|
+
paths: /**
|
|
80
|
+
* We only override jsonpaths. Anything not specified is kept the same.
|
|
81
|
+
*/
|
|
82
|
+
[jsonPath: `$.${string}`, options: BaseJsonMergeOptions][];
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
#### Example
|
|
87
|
+
|
|
88
|
+
This
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"merge": {
|
|
93
|
+
".json": {
|
|
94
|
+
"rules": [
|
|
95
|
+
{
|
|
96
|
+
"glob": "metadata.json",
|
|
97
|
+
"options": {
|
|
98
|
+
"ignoreNewProperties": false,
|
|
99
|
+
"missingIsDelete:": true,
|
|
100
|
+
"paths": [
|
|
101
|
+
["$.path", "template-merge"] // if we delete path in the template, it will delete the path
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"glob": "template-lock.json",
|
|
107
|
+
"options": "overwrite"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"glob": "package.json",
|
|
111
|
+
"options": {
|
|
112
|
+
"ignoreNewProperties": false,
|
|
113
|
+
"paths": [
|
|
114
|
+
["$.scripts.*", "template-merge"],
|
|
115
|
+
["$.scripts.specific-script", "template-currrent"] // We end up keeping the current template
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### About Comments
|
|
126
|
+
|
|
127
|
+
There are numerous json files that support comments now; tsconfig.json is a prime example of this. In order to support this,
|
|
128
|
+
this library makes use of comment-json for parsing and stringifying. This means that, minimally, you will not run into errors
|
|
129
|
+
when merging commented json files (and that you can comment on your templatesync config files).
|
|
130
|
+
|
|
131
|
+
One thing to note however, is that only include comments from the template if they are inside of an object that is being merged.
|
|
132
|
+
This is because this plugin has not yet defined a good configuration for merging comments. If you run into a pertinent need for this,
|
|
133
|
+
please feel free to open an issue and potentially contribute a fix in a PR.
|
|
134
|
+
|
|
135
|
+
Example of comment merging:
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
// In template
|
|
139
|
+
|
|
140
|
+
{
|
|
141
|
+
// I have a comment here
|
|
142
|
+
"newField": 44,
|
|
143
|
+
"overridingField": {
|
|
144
|
+
// Comment in here
|
|
145
|
+
"value": "v",
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// In the extending repo
|
|
150
|
+
{
|
|
151
|
+
// My custom comment
|
|
152
|
+
"newField": 88,
|
|
153
|
+
"overridingField": 66
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// After merging with template-merge
|
|
157
|
+
{
|
|
158
|
+
// My custom comment
|
|
159
|
+
"newField": 44,
|
|
160
|
+
"overridingField": {
|
|
161
|
+
// Comment in here
|
|
162
|
+
"value": "v",
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
From the above example, you can see that we specifically keep as many of the comments as possible from the extending repo
|
|
168
|
+
and only the comment that was fully nested inside new value that we were adding was kept.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Plugin Development
|
|
2
|
+
|
|
3
|
+
- [Plugin Development](#plugin-development)
|
|
4
|
+
- [Example: hello \<world\>](#example-hello-world) - [Example one: local file](#example-one-local-file) - [Example two: npm package](#example-two-npm-package)
|
|
5
|
+
<!-- Created with Markdown All In One VsCode Extension -->
|
|
6
|
+
|
|
7
|
+
The templatesync.json and templatesync.local.config files make use of a `"merge"` property where you can
|
|
8
|
+
customize the baseline behavior of ignore or overwrite from template.
|
|
9
|
+
|
|
10
|
+
This library provides a set of typescript types for you to create additional plugins.
|
|
11
|
+
|
|
12
|
+
At the core of it, you need to have a file or npm package that exposes the interface:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
export interface MergePlugin<PluginOptions> {
|
|
16
|
+
/**
|
|
17
|
+
* This method will be called when a file from the template and it's analog in the downstream repo
|
|
18
|
+
* have some differences. The plugin must perform the merge and return the appropriate file contents
|
|
19
|
+
* as a string
|
|
20
|
+
*
|
|
21
|
+
* TODO: we may create a V2 plugin that could deal with large files and not pass around strings in memory,
|
|
22
|
+
* but for now, this is the current implementation
|
|
23
|
+
*
|
|
24
|
+
* @param current - The downstream repo's current file contents
|
|
25
|
+
* @param fromTemplateRepo - the current
|
|
26
|
+
* @param context - an object defining the context around the file and the specific options
|
|
27
|
+
*/
|
|
28
|
+
merge(
|
|
29
|
+
current: string,
|
|
30
|
+
fromTemplateRepo: string,
|
|
31
|
+
context: MergeContext<PluginOptions>,
|
|
32
|
+
): Promise<string>;
|
|
33
|
+
/**
|
|
34
|
+
* Given an options object for the merge, this validates the options object and returns error messages if there is anything wrong.
|
|
35
|
+
* @param options any json value that the user provided - must be validated against the expected options
|
|
36
|
+
*/
|
|
37
|
+
validate(options: unknown): string[] | undefined;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Example: hello \<world>
|
|
42
|
+
|
|
43
|
+
So let's say that we want to have a plugin that will take every file assigned to it, and just write hello {world} instead.
|
|
44
|
+
(Not much of a merge, but so it goes)
|
|
45
|
+
|
|
46
|
+
We will define and export an options object, validate function, and merge function
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// src/hello-plugin.ts
|
|
50
|
+
import { MergePlugin, MergeContext } from '@hanseltime/template-repo-sync'
|
|
51
|
+
|
|
52
|
+
export interface HelloOptions: {
|
|
53
|
+
/** the name of the world we're greeting */
|
|
54
|
+
world: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const validate: MergePlugin<HelloOptions>['validate'] = (options: unknown) => {
|
|
58
|
+
const errors: string[] = [];
|
|
59
|
+
// In our case, we have decided you HAVE to use an object
|
|
60
|
+
if (typeof options !== 'object') {
|
|
61
|
+
errors.push('must provide an object');
|
|
62
|
+
return errors;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// make sure there aren't extra keys
|
|
66
|
+
const { world, ...rest } = options;
|
|
67
|
+
const unknownKeys = Object.keys(rest);
|
|
68
|
+
if (unknownKeys.length > 0 ) {
|
|
69
|
+
errors.push(`Unexpected options keys: ${unknownKeys.join(' ')}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!world) {
|
|
73
|
+
errors.push(`Must provide a valid world value`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return errors
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const merge: MergePlugin<HelloOptions>['merge'] = async (current, fromTemplateRepo, options: HelloOptions) => {
|
|
80
|
+
// Note, we don't use the current with this simple plugin, but we would use the first 2 args normally
|
|
81
|
+
return `Hello ${options.world}`
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
With all of that set up, as long as we have the package available to the pacakge manager running our script, we can use it:
|
|
87
|
+
|
|
88
|
+
### Example one: local file
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"merge": {
|
|
93
|
+
".txt": {
|
|
94
|
+
"plugin": "dist/hello-plugin.js", // Note, we make it point to the compiled .js so you will need to build and commit the file
|
|
95
|
+
"rules": [
|
|
96
|
+
{
|
|
97
|
+
"glob": "**/*",
|
|
98
|
+
"options": {
|
|
99
|
+
"world": "chad"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Example two: npm package
|
|
109
|
+
|
|
110
|
+
Let's assume that you published this as an npm package to @myscope/hello-merge. Once you have install the pacakge to the project, you can
|
|
111
|
+
simply reference the package (assuming that it exposes the required functions as it's index file).
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"merge": {
|
|
116
|
+
".txt": {
|
|
117
|
+
"plugin": "@myscope/hello-merge",
|
|
118
|
+
"rules": [
|
|
119
|
+
{
|
|
120
|
+
"glob": "**/*",
|
|
121
|
+
"options": {
|
|
122
|
+
"world": "chad"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Merge Plugins
|
|
2
|
+
|
|
3
|
+
The templatesync.json and templatesync.local.config files make use of a `"merge"` property where you can
|
|
4
|
+
customize the baseline behavior of just ignoring or overwriting from the template.
|
|
5
|
+
|
|
6
|
+
# Example Use Case
|
|
7
|
+
|
|
8
|
+
One example of this behavior is around an npm package.json. If you were making a template for a particular
|
|
9
|
+
set of boilerplate for an npm package, you would probably provide an example package.json like:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"name": "<fill in your package name",
|
|
14
|
+
"description": "<fill in your package description",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"publish": "our-artifact-script"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"typescript": "^5.0.0",
|
|
22
|
+
"our-artifact-package": "^1.0.0"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
In this scenario, we expect the template user to declare their own `name` and `description`, and add their own
|
|
28
|
+
`scripts` and `devDependencies`. However, we are hoping to make sure that the publish method and and its
|
|
29
|
+
our-artifact-package are kept up-to-date on syncs. Because of this, we would make use of the default json merge
|
|
30
|
+
plugin that is built-in with this library:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"merge": {
|
|
35
|
+
".json": {
|
|
36
|
+
// This uses the default plugin for json merges
|
|
37
|
+
"rules": [
|
|
38
|
+
{
|
|
39
|
+
"glob": "package.json",
|
|
40
|
+
"options": {
|
|
41
|
+
"paths": [
|
|
42
|
+
["$.scripts.publish", "merge-template"], // Any changes to publish are so critical that we want them to sync
|
|
43
|
+
["$.devDependencies", "merge-template"] // Always ensure dev dependency versions for our scripts are updated
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
As a repo maintainer, we can be sure that when people sync from our repo in its current state, the publish script
|
|
54
|
+
and devDependency should be synced from package.json, without anything else!
|
|
55
|
+
|
|
56
|
+
## What if the repo extender is annoyed?
|
|
57
|
+
|
|
58
|
+
If the repo extender already made the decision to update the publish method for a good reason, they may find it
|
|
59
|
+
tedious to constantly get their publish script overwritten and then have to undo it. Due to the local
|
|
60
|
+
config file, they can specify their own merge configuration for the package.json.
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"merge": {
|
|
65
|
+
".json": {
|
|
66
|
+
// This uses the default plugin for json merges
|
|
67
|
+
"rules": [
|
|
68
|
+
{
|
|
69
|
+
"glob": "package.json",
|
|
70
|
+
"options": {
|
|
71
|
+
"paths": [
|
|
72
|
+
["$.devDependencies", "merge-template"] // Always ensure dev dependency versions for our scripts are updated
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
This configuration will now override the template repo's merge and only allow devDependencies to be updated. We report
|
|
83
|
+
this override as part of the output of the sync call, and for things like our
|
|
84
|
+
[github action](https://github.com/HanseltimeIndustries/template-repo-sync-action), we format that output into the PR
|
|
85
|
+
that is opened up when performing a sync.
|
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
27
|
};
|
|
5
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
29
|
exports.merge = exports.validate = void 0;
|
|
7
30
|
const lodash_merge_1 = __importDefault(require("lodash.merge"));
|
|
8
|
-
const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep"));
|
|
9
31
|
const jsonpath_1 = __importDefault(require("jsonpath"));
|
|
10
32
|
const infer_json_indent_1 = require("../formatting/infer-json-indent");
|
|
33
|
+
const commentJSON = __importStar(require("comment-json"));
|
|
11
34
|
function stringOptionError(value) {
|
|
12
35
|
if (value === "overwrite" ||
|
|
13
36
|
value === "merge-template" ||
|
|
@@ -78,18 +101,18 @@ async function merge(current, fromTemplateRepo, context) {
|
|
|
78
101
|
if (context.mergeArguments === "overwrite") {
|
|
79
102
|
return fromTemplateRepo;
|
|
80
103
|
}
|
|
81
|
-
const currentJson =
|
|
82
|
-
const fromTemplateJson =
|
|
104
|
+
const currentJson = commentJSON.parse(current);
|
|
105
|
+
const fromTemplateJson = commentJSON.parse(fromTemplateRepo);
|
|
83
106
|
if (context.mergeArguments === "merge-current") {
|
|
84
107
|
// Performs Lodash Merge with current as the override
|
|
85
|
-
return
|
|
108
|
+
return commentJSON.stringify((0, lodash_merge_1.default)(fromTemplateJson, currentJson), null, (0, infer_json_indent_1.inferJSONIndent)(current));
|
|
86
109
|
}
|
|
87
110
|
if (context.mergeArguments === "merge-template") {
|
|
88
111
|
// Performs Lodash Merge with current as the override
|
|
89
|
-
return
|
|
112
|
+
return commentJSON.stringify((0, lodash_merge_1.default)(currentJson, fromTemplateJson), null, (0, infer_json_indent_1.inferJSONIndent)(current));
|
|
90
113
|
}
|
|
91
114
|
const { missingIsDelete, ignoreNewProperties, paths } = context.mergeArguments;
|
|
92
|
-
const returnJson =
|
|
115
|
+
const returnJson = commentJSON.parse(current);
|
|
93
116
|
paths.forEach((p) => {
|
|
94
117
|
const [jPath, overrideType] = p;
|
|
95
118
|
const fromTemplatePaths = new Map();
|
|
@@ -143,7 +166,7 @@ async function merge(current, fromTemplateRepo, context) {
|
|
|
143
166
|
}
|
|
144
167
|
});
|
|
145
168
|
}
|
|
146
|
-
return
|
|
169
|
+
return commentJSON.stringify(returnJson, null, (0, infer_json_indent_1.inferJSONIndent)(current));
|
|
147
170
|
}
|
|
148
171
|
exports.merge = merge;
|
|
149
172
|
/**
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.gitCurrentRef = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
async function gitCurrentRef(options) {
|
|
6
|
+
return (0, child_process_1.execSync)(`git rev-parse HEAD`, {
|
|
7
|
+
cwd: options.rootDir,
|
|
8
|
+
})
|
|
9
|
+
.toString()
|
|
10
|
+
.trim();
|
|
11
|
+
}
|
|
12
|
+
exports.gitCurrentRef = gitCurrentRef;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./git-current-ref";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./git-current-ref"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A function that operates within the root dir and returns the
|
|
3
|
+
* current ref for its state. This abstracts the idea of getting
|
|
4
|
+
* the current commit sha, so that things like other custom templating
|
|
5
|
+
* frameworks can provide their own ref
|
|
6
|
+
*/
|
|
7
|
+
export type TemplateRefDriverFn = (options: {
|
|
8
|
+
/** The root dir where we want to get the "current" ref */
|
|
9
|
+
rootDir: string;
|
|
10
|
+
}) => Promise<string>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Change } from "diff";
|
|
2
2
|
import { TemplateCloneDriverFn } from "./clone-drivers";
|
|
3
3
|
import { TemplateDiffDriverFn } from "./diff-drivers";
|
|
4
|
+
import { TemplateRefDriverFn } from "./ref-drivers/types";
|
|
4
5
|
export interface TemplateSyncOptions {
|
|
5
6
|
repoUrl: string;
|
|
6
7
|
/**
|
|
@@ -11,6 +12,11 @@ export interface TemplateSyncOptions {
|
|
|
11
12
|
* The repo directory path that we are going to merge toward
|
|
12
13
|
*/
|
|
13
14
|
repoDir: string;
|
|
15
|
+
/**
|
|
16
|
+
* If set to true, template sync will apply the current ref
|
|
17
|
+
* of the template repo to afterRef
|
|
18
|
+
*/
|
|
19
|
+
updateAfterRef?: boolean;
|
|
14
20
|
/**
|
|
15
21
|
* Defaults to using git clone
|
|
16
22
|
*/
|
|
@@ -19,6 +25,10 @@ export interface TemplateSyncOptions {
|
|
|
19
25
|
* Defaults to using git diff
|
|
20
26
|
*/
|
|
21
27
|
diffDriver?: TemplateDiffDriverFn;
|
|
28
|
+
/**
|
|
29
|
+
* Defaults to using git current ref
|
|
30
|
+
*/
|
|
31
|
+
currentRefDriver?: TemplateRefDriverFn;
|
|
22
32
|
}
|
|
23
33
|
export interface TemplateSyncReturn {
|
|
24
34
|
/**
|