@opencrvs/create-countryconfig 2.1.0-rc.982e0ae → 2.1.0-rc.9a83eed

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 +133 -2
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -13,6 +13,7 @@
13
13
 
14
14
  const path = require('path')
15
15
  const fs = require('fs')
16
+ const { execSync } = require('child_process')
16
17
  const readline = require('readline/promises')
17
18
  const degit = require('degit').default
18
19
 
@@ -21,6 +22,14 @@ const CORE_REPOSITORY = 'opencrvs/opencrvs-core'
21
22
  const COUNTRYCONFIG_TEMPLATE_REPOSITORY_SUBPATH =
22
23
  'packages/countryconfig-template'
23
24
 
25
+ const CORE_REPO_URL = 'https://github.com/' + CORE_REPOSITORY + '.git'
26
+ const INFRASTRUCTURE_REPO_URL =
27
+ 'https://github.com/' + INFRASTRUCTURE_REPOSITORY + '.git'
28
+
29
+ const { version } = JSON.parse(
30
+ fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8')
31
+ )
32
+
24
33
  function joinValues(values, separator) {
25
34
  return values
26
35
  .filter((value) => !!value)
@@ -28,6 +37,125 @@ function joinValues(values, separator) {
28
37
  .trim()
29
38
  }
30
39
 
40
+ function tagExists(repoUrl, tag) {
41
+ try {
42
+ execSync(
43
+ 'git ls-remote --exit-code --tags ' + repoUrl + ' refs/tags/' + tag,
44
+ { stdio: 'pipe' }
45
+ )
46
+ return true
47
+ } catch (err) {
48
+ return false
49
+ }
50
+ }
51
+
52
+ function branchExists(repoUrl, branch) {
53
+ try {
54
+ execSync(
55
+ 'git ls-remote --exit-code --heads ' + repoUrl + ' refs/heads/' + branch,
56
+ { stdio: 'pipe' }
57
+ )
58
+ return true
59
+ } catch (err) {
60
+ return false
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Release tags (e.g. "v2.1.0"), highest first. Delegates the version-aware
66
+ * ordering to git itself rather than hand-parsing semver, then filters down
67
+ * to strict "vX.Y.Z" tags - `--sort=-version:refname` alone still leaves in
68
+ * non-release refs (e.g. "vtesting", "v2.0.0-beta") and peeled annotated-tag
69
+ * lines ("refs/tags/v2.0.0^{}").
70
+ */
71
+ function listReleaseTags(repoUrl) {
72
+ const output = execSync(
73
+ 'git ls-remote --tags --sort=-version:refname ' + repoUrl,
74
+ { encoding: 'utf-8' }
75
+ )
76
+
77
+ return output
78
+ .split('\n')
79
+ .map((line) => line.split('\t')[1])
80
+ .filter(Boolean)
81
+ .map((ref) => ref.replace('refs/tags/', ''))
82
+ .filter((tag) => /^v\d+\.\d+\.\d+$/.test(tag))
83
+ }
84
+
85
+ /**
86
+ * The highest release tag present in *both* repositories - used as the
87
+ * fallback when the version-specific tag can't be found in one or both, so
88
+ * scaffolding still lands on a real, matched release rather than develop.
89
+ */
90
+ function getLatestCommonReleaseTag() {
91
+ const infrastructureTags = new Set(listReleaseTags(INFRASTRUCTURE_REPO_URL))
92
+ return (
93
+ listReleaseTags(CORE_REPO_URL).find((tag) => infrastructureTags.has(tag)) ||
94
+ null
95
+ )
96
+ }
97
+
98
+ /**
99
+ * A prerelease-shaped own version (e.g. "2.1.0-rc.f5ea803", what npm resolves
100
+ * `@next` to - a build published from every push to a branch) never has a
101
+ * matching release tag, so it's resolved as a branch instead. Its base
102
+ * version (stripped of the "-rc.<sha>" suffix) tells apart two different
103
+ * situations: an RC for a version already being stabilized on its own
104
+ * "release/X.Y.Z" branch (e.g. "2.0.1-rc.*" while a patch release is in
105
+ * progress) versus an RC for a version that hasn't been branched off yet and
106
+ * only exists on develop (e.g. "2.1.0-rc.*" while that release branch hasn't
107
+ * been cut). Scaffold from the release branch when it exists in both
108
+ * repositories, otherwise fall back to develop.
109
+ *
110
+ * Otherwise, the own "X.Y.Z" version - whether resolved via npm's `latest`
111
+ * dist-tag (bare invocation) or an explicit `@X.Y.Z` pin - scaffolds from the
112
+ * matching "vX.Y.Z" tag when it exists in both repositories. If it doesn't
113
+ * (e.g. `latest` lagging behind the repos, or a pin that predates one repo's
114
+ * tagging), fall back to the highest release tag common to both, rather than
115
+ * a mismatched pairing of one tagged repo at that version and another repo
116
+ * at a different release. Exits with an error if no matching release tag
117
+ * exists in both repositories.
118
+ */
119
+ function resolveRef() {
120
+ if (version.includes('-')) {
121
+ const releaseBranch = 'release/' + version.split('-')[0]
122
+ if (
123
+ branchExists(CORE_REPO_URL, releaseBranch) &&
124
+ branchExists(INFRASTRUCTURE_REPO_URL, releaseBranch)
125
+ ) {
126
+ return releaseBranch
127
+ }
128
+ return 'develop'
129
+ }
130
+
131
+ const tag = 'v' + version
132
+ if (
133
+ tagExists(CORE_REPO_URL, tag) &&
134
+ tagExists(INFRASTRUCTURE_REPO_URL, tag)
135
+ ) {
136
+ return tag
137
+ }
138
+
139
+ const latestCommonTag = getLatestCommonReleaseTag()
140
+ if (latestCommonTag) {
141
+ console.warn(
142
+ '\nWarning: tag "' +
143
+ tag +
144
+ '" was not found in both repositories; falling back to the latest ' +
145
+ 'available release, ' +
146
+ latestCommonTag +
147
+ '.'
148
+ )
149
+ return latestCommonTag
150
+ }
151
+
152
+ console.error(
153
+ '\nError: no matching release tag was found in both the core and ' +
154
+ 'infrastructure repositories.'
155
+ )
156
+ process.exit(1)
157
+ }
158
+
31
159
  /**
32
160
  * Clones a repository from GitHub to a target directory.
33
161
  *
@@ -271,6 +399,8 @@ async function main() {
271
399
  ensureTargetDirectoryDoesNotExist(countryconfigDirName)
272
400
  ensureTargetDirectoryDoesNotExist(infrastructureDirName)
273
401
 
402
+ const ref = resolveRef()
403
+
274
404
  // Gather all answers up front so the operator isn't interrupted mid-clone.
275
405
  const organisation = await promptOrganisation()
276
406
  const countryCode = await promptCountryCode()
@@ -280,7 +410,8 @@ async function main() {
280
410
  await cloneRepository(
281
411
  {
282
412
  repository: CORE_REPOSITORY,
283
- repositorySubPath: COUNTRYCONFIG_TEMPLATE_REPOSITORY_SUBPATH
413
+ repositorySubPath: COUNTRYCONFIG_TEMPLATE_REPOSITORY_SUBPATH,
414
+ branch: ref
284
415
  },
285
416
  countryconfigTargetPath
286
417
  )
@@ -293,7 +424,7 @@ async function main() {
293
424
 
294
425
  try {
295
426
  await cloneRepository(
296
- { repository: INFRASTRUCTURE_REPOSITORY },
427
+ { repository: INFRASTRUCTURE_REPOSITORY, branch: ref },
297
428
  infrastructureTargetPath
298
429
  )
299
430
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencrvs/create-countryconfig",
3
- "version": "2.1.0-rc.982e0ae",
3
+ "version": "2.1.0-rc.9a83eed",
4
4
  "description": "Scaffold a new OpenCRVS country configuration",
5
5
  "bin": {
6
6
  "create-countryconfig": "./index.js"