@opencrvs/create-countryconfig 2.0.1-rc.fed4de8 → 2.0.2-rc.1248069

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.
Files changed (2) hide show
  1. package/index.js +177 -14
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -17,8 +17,142 @@ const fs = require('fs')
17
17
 
18
18
  const COUNTRYCONFIG_REPO_URL =
19
19
  'https://github.com/opencrvs/opencrvs-countryconfig.git'
20
- const INFRASTRUCTURE_REPO_URL =
21
- 'https://github.com/opencrvs/infrastructure.git'
20
+ const INFRASTRUCTURE_REPO_URL = 'https://github.com/opencrvs/infrastructure.git'
21
+
22
+ const { version } = JSON.parse(
23
+ fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8')
24
+ )
25
+
26
+ function tagExists(repoUrl, tag) {
27
+ try {
28
+ execSync(
29
+ 'git ls-remote --exit-code --tags ' + repoUrl + ' refs/tags/' + tag,
30
+ {
31
+ stdio: 'pipe'
32
+ }
33
+ )
34
+ return true
35
+ } catch (err) {
36
+ return false
37
+ }
38
+ }
39
+
40
+ function branchExists(repoUrl, branch) {
41
+ try {
42
+ execSync(
43
+ 'git ls-remote --exit-code --heads ' + repoUrl + ' refs/heads/' + branch,
44
+ {
45
+ stdio: 'pipe'
46
+ }
47
+ )
48
+ return true
49
+ } catch (err) {
50
+ return false
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Release tags (e.g. "v2.1.0"), highest first. Delegates the version-aware
56
+ * ordering to git itself rather than hand-parsing semver, then filters down
57
+ * to strict "vX.Y.Z" tags - `--sort=-version:refname` alone still leaves in
58
+ * non-release refs (e.g. "vtesting", "v2.0.0-beta") and peeled annotated-tag
59
+ * lines ("refs/tags/v2.0.0^{}").
60
+ */
61
+ function listReleaseTags(repoUrl) {
62
+ const output = execSync(
63
+ 'git ls-remote --tags --sort=-version:refname ' + repoUrl,
64
+ { encoding: 'utf-8' }
65
+ )
66
+
67
+ return output
68
+ .split('\n')
69
+ .map((line) => line.split('\t')[1])
70
+ .filter(Boolean)
71
+ .map((ref) => ref.replace('refs/tags/', ''))
72
+ .filter((tag) => /^v\d+\.\d+\.\d+$/.test(tag))
73
+ }
74
+
75
+ /**
76
+ * The highest release tag present in *both* repositories - used as the
77
+ * fallback when the version-specific tag can't be found in one or both, so
78
+ * scaffolding still lands on a real, matched release rather than develop.
79
+ */
80
+ function getLatestCommonReleaseTag() {
81
+ const infrastructureTags = new Set(listReleaseTags(INFRASTRUCTURE_REPO_URL))
82
+ return (
83
+ listReleaseTags(COUNTRYCONFIG_REPO_URL).find((tag) =>
84
+ infrastructureTags.has(tag)
85
+ ) || null
86
+ )
87
+ }
88
+
89
+ /**
90
+ * A prerelease-shaped own version (e.g. "2.1.0-rc.f5ea803", what npm resolves
91
+ * `@next` to - a build published from every push to a branch) never has a
92
+ * matching release tag, so it's resolved as a branch instead. Its base
93
+ * version (stripped of the "-rc.<sha>" suffix) tells apart two different
94
+ * situations: an RC for a version already being stabilized on its own
95
+ * "release/X.Y.Z" branch (e.g. "2.0.1-rc.*" while a patch release is in
96
+ * progress) versus an RC for a version that hasn't been branched off yet and
97
+ * only exists on develop (e.g. "2.1.0-rc.*" while that release branch hasn't
98
+ * been cut). Scaffold from the release branch when it exists in both
99
+ * repositories, otherwise fall back to develop.
100
+ *
101
+ * Otherwise, the own "X.Y.Z" version - whether resolved via npm's `latest`
102
+ * dist-tag (bare invocation) or an explicit `@X.Y.Z` pin - scaffolds from the
103
+ * matching "vX.Y.Z" tag when it exists in both repositories. If it doesn't
104
+ * (e.g. `latest` lagging behind the repos, or a pin that predates one repo's
105
+ * tagging), fall back to the highest release tag common to both, rather than
106
+ * a mismatched pairing of one tagged repo at that version and another repo
107
+ * at a different release. Exits with an error if no matching release tag
108
+ * exists in both repositories.
109
+ */
110
+ function resolveRef() {
111
+ if (version.includes('-')) {
112
+ const releaseBranch = 'release/' + version.split('-')[0]
113
+ if (
114
+ branchExists(COUNTRYCONFIG_REPO_URL, releaseBranch) &&
115
+ branchExists(INFRASTRUCTURE_REPO_URL, releaseBranch)
116
+ ) {
117
+ return releaseBranch
118
+ }
119
+ return 'develop'
120
+ }
121
+
122
+ const tag = 'v' + version
123
+ if (
124
+ tagExists(COUNTRYCONFIG_REPO_URL, tag) &&
125
+ tagExists(INFRASTRUCTURE_REPO_URL, tag)
126
+ ) {
127
+ return tag
128
+ }
129
+
130
+ const latestCommonTag = getLatestCommonReleaseTag()
131
+ if (latestCommonTag) {
132
+ console.warn(
133
+ '\nWarning: tag "' +
134
+ tag +
135
+ '" was not found in both repositories; falling back to the latest ' +
136
+ 'available release, ' +
137
+ latestCommonTag +
138
+ '.'
139
+ )
140
+ return latestCommonTag
141
+ }
142
+
143
+ console.error(
144
+ '\nError: no matching release tag was found in both the country config and ' +
145
+ 'infrastructure repositories.'
146
+ )
147
+ process.exit(1)
148
+ }
149
+
150
+ function cloneRepository(repoUrl, ref, targetDir) {
151
+ execSync(
152
+ 'git clone --depth 1 --branch ' + ref + ' ' + repoUrl + ' ' + targetDir,
153
+ { stdio: 'inherit' }
154
+ )
155
+ }
22
156
 
23
157
  const projectName = process.argv[2]
24
158
 
@@ -33,31 +167,48 @@ const countryconfigDirName = projectName + '-countryconfig'
33
167
  const infrastructureDirName = projectName + '-infrastructure'
34
168
 
35
169
  const countryconfigTargetDir = path.resolve(process.cwd(), countryconfigDirName)
36
- const infrastructureTargetDir = path.resolve(process.cwd(), infrastructureDirName)
170
+ const infrastructureTargetDir = path.resolve(
171
+ process.cwd(),
172
+ infrastructureDirName
173
+ )
37
174
 
38
175
  if (fs.existsSync(countryconfigTargetDir)) {
39
- console.error('Error: Directory "' + countryconfigDirName + '" already exists.')
176
+ console.error(
177
+ 'Error: Directory "' + countryconfigDirName + '" already exists.'
178
+ )
40
179
  process.exit(1)
41
180
  }
42
181
 
43
182
  if (fs.existsSync(infrastructureTargetDir)) {
44
- console.error('Error: Directory "' + infrastructureDirName + '" already exists.')
183
+ console.error(
184
+ 'Error: Directory "' + infrastructureDirName + '" already exists.'
185
+ )
45
186
  process.exit(1)
46
187
  }
47
188
 
48
- console.log('\nScaffolding OpenCRVS country config in ./' + countryconfigDirName + '...\n')
189
+ const ref = resolveRef()
190
+
191
+ console.log(
192
+ '\nScaffolding OpenCRVS country config in ./' + countryconfigDirName + '...\n'
193
+ )
49
194
 
50
195
  try {
51
- execSync('git clone --depth 1 ' + COUNTRYCONFIG_REPO_URL + ' ' + countryconfigDirName, { stdio: 'inherit' })
196
+ cloneRepository(COUNTRYCONFIG_REPO_URL, ref, countryconfigDirName)
52
197
  } catch (err) {
53
198
  console.error('Failed to clone the country config repository:', err.message)
54
199
  process.exit(1)
55
200
  }
56
201
 
57
202
  try {
58
- fs.rmSync(path.join(countryconfigTargetDir, '.git'), { recursive: true, force: true })
203
+ fs.rmSync(path.join(countryconfigTargetDir, '.git'), {
204
+ recursive: true,
205
+ force: true
206
+ })
59
207
  } catch (err) {
60
- console.error('Failed to remove .git directory from country config:', err.message)
208
+ console.error(
209
+ 'Failed to remove .git directory from country config:',
210
+ err.message
211
+ )
61
212
  process.exit(1)
62
213
  }
63
214
 
@@ -72,22 +223,34 @@ if (fs.existsSync(pkgPath)) {
72
223
  process.exit(1)
73
224
  }
74
225
  } else {
75
- console.warn('Warning: No package.json found in the cloned country config repository. Project name was not updated.')
226
+ console.warn(
227
+ 'Warning: No package.json found in the cloned country config repository. Project name was not updated.'
228
+ )
76
229
  }
77
230
 
78
- console.log('\nScaffolding OpenCRVS infrastructure in ./' + infrastructureDirName + '...\n')
231
+ console.log(
232
+ '\nScaffolding OpenCRVS infrastructure in ./' +
233
+ infrastructureDirName +
234
+ '...\n'
235
+ )
79
236
 
80
237
  try {
81
- execSync('git clone --depth 1 ' + INFRASTRUCTURE_REPO_URL + ' ' + infrastructureDirName, { stdio: 'inherit' })
238
+ cloneRepository(INFRASTRUCTURE_REPO_URL, ref, infrastructureDirName)
82
239
  } catch (err) {
83
240
  console.error('Failed to clone the infrastructure repository:', err.message)
84
241
  process.exit(1)
85
242
  }
86
243
 
87
244
  try {
88
- fs.rmSync(path.join(infrastructureTargetDir, '.git'), { recursive: true, force: true })
245
+ fs.rmSync(path.join(infrastructureTargetDir, '.git'), {
246
+ recursive: true,
247
+ force: true
248
+ })
89
249
  } catch (err) {
90
- console.error('Failed to remove .git directory from infrastructure:', err.message)
250
+ console.error(
251
+ 'Failed to remove .git directory from infrastructure:',
252
+ err.message
253
+ )
91
254
  process.exit(1)
92
255
  }
93
256
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencrvs/create-countryconfig",
3
- "version": "2.0.1-rc.fed4de8",
3
+ "version": "2.0.2-rc.1248069",
4
4
  "description": "Scaffold a new OpenCRVS country configuration",
5
5
  "bin": {
6
6
  "create-countryconfig": "./index.js"