@neurodevs/meta-node 0.19.10 → 0.19.12

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.
@@ -49,6 +49,10 @@ export default class NpmReleasePropagatorTest extends AbstractPackageTest {
49
49
  protected static async runInstallsReleaseForEachRepoPath() {
50
50
  await this.run()
51
51
 
52
+ const actualCalls = callsToExec.filter((call) =>
53
+ call.command.includes(`yarn add`)
54
+ )
55
+
52
56
  const expectedCalls = [
53
57
  {
54
58
  command: `yarn add ${this.packageName}@${this.packageVersion}`,
@@ -61,7 +65,7 @@ export default class NpmReleasePropagatorTest extends AbstractPackageTest {
61
65
  ]
62
66
 
63
67
  assert.isEqualDeep(
64
- [callsToExec[2], callsToExec[5]],
68
+ actualCalls,
65
69
  expectedCalls,
66
70
  'Did not install release in each repo path!'
67
71
  )
@@ -1,7 +1,6 @@
1
1
  import { exec as execSync } from 'child_process'
2
2
  import { mkdir, readFile, writeFile } from 'fs/promises'
3
3
  import path from 'path'
4
- import { chdir } from 'process'
5
4
  import { promisify } from 'util'
6
5
  import { pathExists } from 'fs-extra'
7
6
  import { parse } from 'jsonc-parser'
@@ -10,7 +9,6 @@ import GitAutocommit from './GitAutocommit.js'
10
9
 
11
10
  export default class NpmAutopackage implements Autopackage {
12
11
  public static Class?: AutopackageConstructor
13
- public static chdir = chdir
14
12
  public static exec = promisify(execSync)
15
13
  public static fetch = fetch
16
14
  public static mkdir = mkdir
@@ -18,8 +16,6 @@ export default class NpmAutopackage implements Autopackage {
18
16
  public static readFile = readFile
19
17
  public static writeFile = writeFile
20
18
 
21
- private installDir: string
22
- private packageName: string
23
19
  private description: string
24
20
  private gitNamespace: string
25
21
  private npmNamespace?: string
@@ -39,6 +35,25 @@ export default class NpmAutopackage implements Autopackage {
39
35
 
40
36
  private shouldOpenVscode = false
41
37
 
38
+ private readonly installDir: string
39
+ private readonly packageName: string
40
+ private readonly packageDir: string
41
+ private readonly packageJsonPath: string
42
+ private readonly gitignorePath: string
43
+ private readonly tasksJsonPath: string
44
+ private readonly settingsJsonPath: string
45
+ private readonly testDirPath: string
46
+ private readonly abstractTestPath: string
47
+
48
+ private readonly abstractPackageTestFile = `import AbstractModuleTest from '@neurodevs/node-tdd'
49
+
50
+ export default abstract class AbstractPackageTest extends AbstractModuleTest {
51
+ protected static async beforeEach() {
52
+ await super.beforeEach()
53
+ }
54
+ }
55
+ `
56
+
42
57
  protected constructor(options: AutopackageOptions) {
43
58
  const {
44
59
  installDir,
@@ -59,6 +74,23 @@ export default class NpmAutopackage implements Autopackage {
59
74
  this.keywords = keywords
60
75
  this.license = license
61
76
  this.author = author
77
+
78
+ this.packageDir = path.join(this.installDir, this.packageName)
79
+ this.packageJsonPath = path.join(this.packageDir, 'package.json')
80
+ this.gitignorePath = path.join(this.packageDir, '.gitignore')
81
+ this.tasksJsonPath = path.join(this.packageDir, '.vscode/tasks.json')
82
+
83
+ this.settingsJsonPath = path.join(
84
+ this.packageDir,
85
+ '.vscode/settings.json'
86
+ )
87
+
88
+ this.testDirPath = path.join(this.packageDir, 'src', '__tests__')
89
+
90
+ this.abstractTestPath = path.join(
91
+ this.testDirPath,
92
+ 'AbstractPackageTest.ts'
93
+ )
62
94
  }
63
95
 
64
96
  public static Create(options: AutopackageOptions) {
@@ -69,11 +101,7 @@ export default class NpmAutopackage implements Autopackage {
69
101
  this.throwIfGithubTokenNotInEnv()
70
102
 
71
103
  await this.createRepoInGithubOrg()
72
-
73
- this.chdirToInstallDir()
74
104
  await this.cloneGitRepo()
75
-
76
- this.chdirToPackageDir()
77
105
  await this.resetMainToOrigin()
78
106
  await this.setCurrentMetaNodeVersion()
79
107
  await this.spruceCreateModule()
@@ -141,16 +169,15 @@ export default class NpmAutopackage implements Autopackage {
141
169
  )
142
170
  }
143
171
 
144
- private chdirToInstallDir() {
145
- this.chdir(this.installDir)
146
- }
147
-
148
172
  private async cloneGitRepo() {
149
173
  const packageDirExists = await this.checkIfPackageDirExists()
150
174
 
151
175
  if (!packageDirExists) {
152
176
  console.log('Cloning git repository...')
153
- await this.exec(`git clone ${this.gitUrl}`)
177
+
178
+ await this.exec(`git clone ${this.gitUrl}`, {
179
+ cwd: this.installDir,
180
+ })
154
181
  this.shouldOpenVscode = true
155
182
  }
156
183
  }
@@ -159,21 +186,16 @@ export default class NpmAutopackage implements Autopackage {
159
186
  return this.pathExists(this.packageDir)
160
187
  }
161
188
 
162
- private get packageDir() {
163
- return this.packageName
164
- }
165
-
166
189
  private get gitUrl() {
167
190
  return `https://github.com/${this.gitNamespace}/${this.packageName}.git`
168
191
  }
169
192
 
170
193
  private async resetMainToOrigin() {
171
- await this.exec('git fetch origin')
172
- await this.exec('git reset --hard origin/main')
173
- }
194
+ await this.exec('git fetch origin', { cwd: this.packageDir })
174
195
 
175
- private chdirToPackageDir() {
176
- this.chdir(this.packageDir)
196
+ await this.exec('git reset --hard origin/main', {
197
+ cwd: this.packageDir,
198
+ })
177
199
  }
178
200
 
179
201
  private async setCurrentMetaNodeVersion() {
@@ -198,6 +220,7 @@ export default class NpmAutopackage implements Autopackage {
198
220
 
199
221
  if (!packageJsonExists) {
200
222
  console.log('Running spruce create.module...')
223
+
201
224
  await this.execSpruceCreateModule()
202
225
  await this.commitCreatePackage()
203
226
  }
@@ -207,11 +230,10 @@ export default class NpmAutopackage implements Autopackage {
207
230
  return this.pathExists(this.packageJsonPath)
208
231
  }
209
232
 
210
- private readonly packageJsonPath = 'package.json'
211
-
212
233
  private async execSpruceCreateModule() {
213
234
  await this.exec(
214
- `spruce create.module --name "${this.packageName}" --destination "." --description "${this.description}"`
235
+ `spruce create.module --name "${this.packageName}" --destination "." --description "${this.description}"`,
236
+ { cwd: this.packageDir }
215
237
  )
216
238
  }
217
239
 
@@ -226,6 +248,7 @@ export default class NpmAutopackage implements Autopackage {
226
248
 
227
249
  if (!this.isPackageUpToDate) {
228
250
  console.log('Updating package.json...')
251
+
229
252
  await this.updatePackageJsonFile()
230
253
  await this.commitUpdatePackageJson()
231
254
  }
@@ -343,8 +366,6 @@ export default class NpmAutopackage implements Autopackage {
343
366
  })
344
367
  }
345
368
 
346
- private readonly gitignorePath = '.gitignore'
347
-
348
369
  private get isGitignoreUpdated() {
349
370
  const lines = this.originalGitignoreFile
350
371
  .split(/\r?\n/)
@@ -371,17 +392,20 @@ export default class NpmAutopackage implements Autopackage {
371
392
 
372
393
  if (!vscodeSettingsExist) {
373
394
  console.log('Setting up VSCode...')
395
+
374
396
  await this.spruceSetupVscode()
375
397
  await this.commitSetupVscode()
376
398
  }
377
399
  }
378
400
 
379
401
  private async checkIfVscodeSettingsExist() {
380
- return this.pathExists(`.vscode/settings.json`)
402
+ return this.pathExists(this.settingsJsonPath)
381
403
  }
382
404
 
383
405
  private async spruceSetupVscode() {
384
- await this.exec('spruce setup.vscode --all true')
406
+ await this.exec('spruce setup.vscode --all true', {
407
+ cwd: this.packageDir,
408
+ })
385
409
  }
386
410
 
387
411
  private async commitSetupVscode() {
@@ -430,8 +454,6 @@ export default class NpmAutopackage implements Autopackage {
430
454
  return parse(raw)
431
455
  }
432
456
 
433
- private readonly tasksJsonPath = '.vscode/tasks.json'
434
-
435
457
  private get updatedTasksJsonFile() {
436
458
  return JSON.stringify(
437
459
  {
@@ -490,7 +512,8 @@ export default class NpmAutopackage implements Autopackage {
490
512
  console.log('Installing default devDependencies...')
491
513
 
492
514
  await this.exec(
493
- 'yarn add -D @neurodevs/generate-id@latest @neurodevs/node-tdd@latest'
515
+ 'yarn add -D @neurodevs/generate-id@latest @neurodevs/node-tdd@latest',
516
+ { cwd: this.packageDir }
494
517
  )
495
518
  await this.commitInstallDevDependencies()
496
519
  }
@@ -498,7 +521,8 @@ export default class NpmAutopackage implements Autopackage {
498
521
 
499
522
  private async getLatestVersion(scopedPackageName: string) {
500
523
  const { stdout } = await this.exec(
501
- `yarn info ${scopedPackageName} version --silent`
524
+ `yarn info ${scopedPackageName} version --silent`,
525
+ { cwd: this.packageDir }
502
526
  )
503
527
  return stdout.trim()
504
528
  }
@@ -531,12 +555,14 @@ export default class NpmAutopackage implements Autopackage {
531
555
  if (!fileExists) {
532
556
  console.log(`Installing ${this.abstractTestPath}...`)
533
557
 
534
- await this.mkdir('src/__tests__', { recursive: true })
558
+ await this.mkdir(this.testDirPath, { recursive: true })
535
559
 
536
560
  await this.writeFile(
537
561
  this.abstractTestPath,
538
562
  this.abstractPackageTestFile,
539
- { encoding: 'utf-8' }
563
+ {
564
+ encoding: 'utf-8',
565
+ }
540
566
  )
541
567
 
542
568
  await this.commitInstallAbstractPackageTest()
@@ -550,17 +576,6 @@ export default class NpmAutopackage implements Autopackage {
550
576
  return doesTsExist || doesTsxExist
551
577
  }
552
578
 
553
- private readonly abstractTestPath = `src/__tests__/AbstractPackageTest.ts`
554
-
555
- private readonly abstractPackageTestFile = `import AbstractModuleTest from '@neurodevs/node-tdd'
556
-
557
- export default abstract class AbstractPackageTest extends AbstractModuleTest {
558
- protected static async beforeEach() {
559
- await super.beforeEach()
560
- }
561
- }
562
- `
563
-
564
579
  private async commitInstallAbstractPackageTest() {
565
580
  await this.GitAutocommit(
566
581
  `patch: install AbstractPackageTest (@neurodevs/meta-node: ${this.metaNodeVersion})`
@@ -569,14 +584,10 @@ export default abstract class AbstractPackageTest extends AbstractModuleTest {
569
584
 
570
585
  private async openVscode() {
571
586
  if (this.shouldOpenVscode) {
572
- await this.exec('code .')
587
+ await this.exec('code .', { cwd: this.packageDir })
573
588
  }
574
589
  }
575
590
 
576
- private get chdir() {
577
- return NpmAutopackage.chdir
578
- }
579
-
580
591
  private get exec() {
581
592
  return NpmAutopackage.exec
582
593
  }
@@ -602,7 +613,7 @@ export default abstract class AbstractPackageTest extends AbstractModuleTest {
602
613
  }
603
614
 
604
615
  private GitAutocommit(commitMessage: string) {
605
- return GitAutocommit.Create(commitMessage)
616
+ return GitAutocommit.Create(commitMessage, this.packageDir)
606
617
  }
607
618
  }
608
619
 
@@ -49,7 +49,7 @@ export default class NpmPropagationCoordinator
49
49
 
50
50
  const repoPaths = await this.determineWhereToPropagate()
51
51
 
52
- const propagator = this.NpmReleaseCoordinator({
52
+ const propagator = this.NpmReleasePropagator({
53
53
  packageName: this.packageName,
54
54
  packageVersion: this.packageVersion,
55
55
  repoPaths,
@@ -121,7 +121,7 @@ export default class NpmPropagationCoordinator
121
121
  return NpmPropagationCoordinator.readFile
122
122
  }
123
123
 
124
- private NpmReleaseCoordinator(options: ReleasePropagatorOptions) {
124
+ private NpmReleasePropagator(options: ReleasePropagatorOptions) {
125
125
  return NpmReleasePropagator.Create(options)
126
126
  }
127
127
  }
@@ -3,7 +3,7 @@ import { readFile } from 'node:fs/promises'
3
3
  import path from 'node:path'
4
4
  import { promisify } from 'node:util'
5
5
 
6
- import { parse, minVersion, gte } from 'semver'
6
+ import semver from 'semver'
7
7
 
8
8
  import GitAutocommit from './GitAutocommit.js'
9
9
 
@@ -17,8 +17,6 @@ export default class NpmReleasePropagator implements ReleasePropagator {
17
17
  private repoPaths: string[]
18
18
  private shouldGitCommit: boolean
19
19
 
20
- private currentRepoPath!: string
21
- private currentPackageJson!: PackageJson
22
20
  private metaNodeVersion!: string
23
21
 
24
22
  protected constructor(options: ReleasePropagatorOptions) {
@@ -41,38 +39,13 @@ export default class NpmReleasePropagator implements ReleasePropagator {
41
39
 
42
40
  public async run() {
43
41
  await this.throwIfUncommittedGitChanges()
42
+ await this.setCurrentMetaNodeVersion()
44
43
 
45
44
  console.info('Starting propagation...\n')
46
45
 
47
- for (const repoPath of this.repoPaths) {
48
- this.currentRepoPath = repoPath
49
-
50
- await this.loadCurrentPackageJson()
51
-
52
- this.throwIfPreviousReleaseNotFound()
53
-
54
- if (this.isUpToDate) {
55
- console.info(`Already up to date, skipping ${repoPath}...`)
56
- continue
57
- }
58
-
59
- console.info(`Propagating to ${repoPath}...`)
60
- await this.installReleaseForCurrentRepo()
61
-
62
- const hasTypeErrors = await this.checkForTypeErrors()
63
-
64
- if (hasTypeErrors) {
65
- console.warn(
66
- `TypeScript compilation errors detected! Rolling back for ${repoPath}...`
67
- )
68
- await this.rollbackInstallation()
69
- continue
70
- }
71
-
72
- if (this.shouldGitCommit) {
73
- await this.gitCommitChanges()
74
- }
75
- }
46
+ await Promise.all(
47
+ this.repoPaths.map((repoPath) => this.runFor(repoPath))
48
+ )
76
49
 
77
50
  console.info('\nPropagation complete!\n')
78
51
  }
@@ -105,62 +78,98 @@ Please commit or stash these changes before running propagation!
105
78
  `
106
79
  }
107
80
 
108
- private async loadCurrentPackageJson() {
109
- const raw = await this.readFile(this.currentPackageJsonPath, 'utf-8')
110
- this.currentPackageJson = JSON.parse(raw)
81
+ private async setCurrentMetaNodeVersion() {
82
+ const globalRoot = await this.exec('yarn global dir')
83
+
84
+ const pkgPath = path.join(
85
+ globalRoot.stdout.trim(),
86
+ 'node_modules',
87
+ '@neurodevs',
88
+ 'meta-node',
89
+ 'package.json'
90
+ )
91
+
92
+ const raw = await this.readFile(pkgPath, { encoding: 'utf-8' })
93
+ const pkg = JSON.parse(raw)
94
+
95
+ this.metaNodeVersion = pkg.version
111
96
  }
112
97
 
113
- private get currentPackageJsonPath() {
114
- return `${this.currentRepoPath}/package.json`
98
+ private async runFor(repoPath: string) {
99
+ const pkg = await this.loadPackageJsonFor(repoPath)
100
+ this.throwIfNoPreviousReleaseFor(pkg)
101
+
102
+ const isUpToDate = this.isUpToDateFor(pkg)
103
+
104
+ if (isUpToDate) {
105
+ console.info(`Already up to date, skipping ${repoPath}...`)
106
+ return
107
+ }
108
+
109
+ console.info(`Propagating to ${repoPath}...`)
110
+ await this.installReleaseFor(repoPath, pkg)
111
+
112
+ const hasTypeErrors = await this.checkTypeErrorsFor(repoPath)
113
+
114
+ if (hasTypeErrors) {
115
+ console.warn(`Type errors detected! Rolling back ${repoPath}...`)
116
+ await this.rollbackInstallationFor(repoPath)
117
+ return
118
+ }
119
+
120
+ if (this.shouldGitCommit) {
121
+ await this.gitCommitChangesFor(repoPath)
122
+ }
115
123
  }
116
124
 
117
- private throwIfPreviousReleaseNotFound() {
118
- if (!(this.dependencyRange || this.devDependencyRange)) {
125
+ private async loadPackageJsonFor(repoPath: string) {
126
+ const raw = await this.readFile(`${repoPath}/package.json`, 'utf-8')
127
+ return JSON.parse(raw)
128
+ }
129
+
130
+ private throwIfNoPreviousReleaseFor(pkg: PackageJson) {
131
+ const isDependency = Boolean(pkg.dependencies?.[this.packageName])
132
+ const isDevDependency = Boolean(pkg.devDependencies?.[this.packageName])
133
+
134
+ if (!(isDependency || isDevDependency)) {
119
135
  throw new Error(
120
136
  `Cannot propagate release for ${this.packageName} because it is not listed in either dependencies or devDependencies! Please install it in the target repository before running propagation.`
121
137
  )
122
138
  }
123
139
  }
124
140
 
125
- private get dependencyRange() {
126
- return this.currentPackageJson?.dependencies?.[this.packageName] ?? ''
127
- }
141
+ private isUpToDateFor(pkg: PackageJson) {
142
+ const target = semver.parse(this.packageVersion)!
128
143
 
129
- private get devDependencyRange() {
130
- return (
131
- this.currentPackageJson?.devDependencies?.[this.packageName] ?? ''
144
+ const dependencyMin = semver.minVersion(
145
+ pkg.dependencies?.[this.packageName] ?? ''
132
146
  )
133
- }
134
-
135
- private get isUpToDate() {
136
- const target = parse(this.packageVersion)
137
147
 
138
- if (!target) {
139
- return false
140
- }
141
-
142
- const depMin = minVersion(this.dependencyRange ?? '')
143
- const devDepMin = minVersion(this.devDependencyRange ?? '')
148
+ const devDependencyMin = semver.minVersion(
149
+ pkg.devDependencies?.[this.packageName] ?? ''
150
+ )
144
151
 
145
152
  return (
146
- (depMin && gte(depMin, target)) ||
147
- (devDepMin && gte(devDepMin, target))
153
+ (dependencyMin && semver.gte(dependencyMin, target)) ||
154
+ (devDependencyMin && semver.gte(devDependencyMin, target))
148
155
  )
149
156
  }
150
157
 
151
- private async installReleaseForCurrentRepo() {
158
+ private async installReleaseFor(repoPath: string, pkg: PackageJson) {
159
+ const isDevDependency = Boolean(pkg.devDependencies?.[this.packageName])
160
+
152
161
  await this.exec(
153
- `yarn add ${this.devDependencyRange ? '-D ' : ''}${this.packageName}@${this.packageVersion}`,
162
+ `yarn add ${isDevDependency ? '-D ' : ''}${this.packageName}@${this.packageVersion}`,
154
163
  {
155
- cwd: this.currentRepoPath,
164
+ cwd: repoPath,
156
165
  }
157
166
  )
158
167
  }
159
168
 
160
- private async checkForTypeErrors() {
169
+ private async checkTypeErrorsFor(repoPath: string) {
161
170
  try {
162
171
  await this.exec(`npx tsc --noEmit`, {
163
- cwd: this.currentRepoPath,
172
+ cwd: repoPath,
164
173
  })
165
174
  return false
166
175
  } catch {
@@ -168,37 +177,19 @@ Please commit or stash these changes before running propagation!
168
177
  }
169
178
  }
170
179
 
171
- private async rollbackInstallation() {
180
+ private async rollbackInstallationFor(repoPath: string) {
172
181
  await this.exec(`git reset --hard && git clean -fd`, {
173
- cwd: this.currentRepoPath,
182
+ cwd: repoPath,
174
183
  })
175
184
  }
176
185
 
177
- private async gitCommitChanges() {
178
- await this.setCurrentMetaNodeVersion()
179
-
186
+ private async gitCommitChangesFor(repoPath: string) {
180
187
  await this.GitAutocommit(
181
- `patch: propagate ${this.packageName}@${this.packageVersion} (@neurodevs/meta-node: ${this.metaNodeVersion})`
188
+ `patch: propagate ${this.packageName}@${this.packageVersion} (@neurodevs/meta-node: ${this.metaNodeVersion})`,
189
+ repoPath
182
190
  )
183
191
  }
184
192
 
185
- private async setCurrentMetaNodeVersion() {
186
- const globalRoot = await this.exec('yarn global dir')
187
-
188
- const pkgPath = path.join(
189
- globalRoot.stdout.trim(),
190
- 'node_modules',
191
- '@neurodevs',
192
- 'meta-node',
193
- 'package.json'
194
- )
195
-
196
- const raw = await this.readFile(pkgPath, { encoding: 'utf-8' })
197
- const pkg = JSON.parse(raw)
198
-
199
- this.metaNodeVersion = pkg.version
200
- }
201
-
202
193
  private get exec() {
203
194
  return NpmReleasePropagator.exec
204
195
  }
@@ -207,8 +198,8 @@ Please commit or stash these changes before running propagation!
207
198
  return NpmReleasePropagator.readFile
208
199
  }
209
200
 
210
- private GitAutocommit(commitMessage: string) {
211
- return GitAutocommit.Create(commitMessage, this.currentRepoPath)
201
+ private GitAutocommit(commitMessage: string, repoPath: string) {
202
+ return GitAutocommit.Create(commitMessage, repoPath)
212
203
  }
213
204
  }
214
205