@aidc-toolkit/dev 0.9.20-beta → 0.9.21-beta

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.
@@ -1,4 +1,5 @@
1
1
  import * as fs from "node:fs";
2
+ import type { Repository } from "./configuration";
2
3
  import { PACKAGE_CONFIGURATION_PATH, PACKAGE_LOCK_CONFIGURATION_PATH, Publish } from "./publish.js";
3
4
  import { logger } from "./logger.js";
4
5
 
@@ -30,27 +31,54 @@ class PublishAlpha extends Publish {
30
31
  this._updateAll = updateAll;
31
32
  }
32
33
 
34
+ /**
35
+ * @inheritDoc
36
+ */
37
+ protected dependencyVersionFor(): string {
38
+ // Dependency version is always "alpha".
39
+ return "alpha";
40
+ }
41
+
42
+ /**
43
+ * @inheritDoc
44
+ */
45
+ protected getPhaseDateTime(repository: Repository, phaseDateTime: Date): Date {
46
+ // If beta or production has been published since the last alpha, use that instead.
47
+ return this.latestDateTime(phaseDateTime, repository.phaseStates.beta?.dateTime, repository.phaseStates.production?.dateTime);
48
+ }
49
+
50
+ /**
51
+ * @inheritDoc
52
+ */
53
+ protected isValidBranch(): boolean {
54
+ // Any branch is valid for alpha publication.
55
+ return true;
56
+ }
57
+
33
58
  /**
34
59
  * @inheritDoc
35
60
  */
36
61
  protected publish(): void {
37
- let anyDependencyUpdates = false;
62
+ let anyExternalUpdates = false;
63
+
64
+ const repositoryState = this.repositoryState;
65
+ const packageConfiguration = repositoryState.packageConfiguration;
38
66
 
39
- // Check for external dependency updates, even if there are no changes.
40
- for (const currentDependencies of [this.packageConfiguration.devDependencies, this.packageConfiguration.dependencies]) {
67
+ // Check for external updates, even if there are no changes.
68
+ for (const currentDependencies of [packageConfiguration.devDependencies, packageConfiguration.dependencies]) {
41
69
  if (currentDependencies !== undefined) {
42
- for (const [dependency, version] of Object.entries(currentDependencies)) {
70
+ for (const [dependencyPackageName, version] of Object.entries(currentDependencies)) {
43
71
  // Ignore organization dependencies.
44
- if (this.dependencyRepositoryName(dependency) === null && version.startsWith("^")) {
45
- const [latestVersion] = this.run(true, true, "npm", "view", dependency, "version");
72
+ if (this.dependencyRepositoryName(dependencyPackageName) === null && version.startsWith("^")) {
73
+ const [latestVersion] = this.run(true, true, "npm", "view", dependencyPackageName, "version");
46
74
 
47
75
  if (latestVersion !== version.substring(1)) {
48
- logger.info(`Dependency ${dependency}@${version} ${!this._updateAll ? "pending update" : "updating"} to version ${latestVersion}.`);
76
+ logger.info(`Dependency ${dependencyPackageName}@${version} ${!this._updateAll ? "pending update" : "updating"} to version ${latestVersion}.`);
49
77
 
50
78
  if (this._updateAll) {
51
- currentDependencies[dependency] = `^${latestVersion}`;
79
+ currentDependencies[dependencyPackageName] = `^${latestVersion}`;
52
80
 
53
- anyDependencyUpdates = true;
81
+ anyExternalUpdates = true;
54
82
  }
55
83
  }
56
84
  }
@@ -58,7 +86,7 @@ class PublishAlpha extends Publish {
58
86
  }
59
87
  }
60
88
 
61
- if (anyDependencyUpdates) {
89
+ if (anyExternalUpdates) {
62
90
  // Save the dependency updates; this will be detected by call to anyChanges().
63
91
  this.savePackageConfiguration();
64
92
  }
@@ -67,23 +95,23 @@ class PublishAlpha extends Publish {
67
95
  logger.debug("Updating all dependencies");
68
96
 
69
97
  // Running this even if there are no dependency updates will update dependencies of dependencies.
70
- this.run(false, false, "npm", "update", ...this.npmPlatformArgs);
98
+ this.run(false, false, "npm", "update", ...repositoryState.npmPlatformArgs);
71
99
  }
72
100
 
73
- const anyChanges = this.anyChanges(this.repository.lastAlphaPublished, true) || this.organizationDependenciesUpdated;
101
+ const anyChanges = this.anyChanges(repositoryState.phaseDateTime, true) || repositoryState.anyDependenciesUpdated;
74
102
 
75
103
  if (anyChanges) {
76
- const switchToAlpha = this.preReleaseIdentifier !== "alpha";
104
+ const switchToAlpha = repositoryState.preReleaseIdentifier !== "alpha";
77
105
 
78
106
  if (switchToAlpha) {
79
107
  // Previous publication was beta or production.
80
- this.updatePackageVersion(undefined, undefined, this.patchVersion + 1, "alpha");
108
+ this.updatePackageVersion(undefined, undefined, repositoryState.patchVersion + 1, "alpha");
81
109
 
82
110
  // Use specified registry for organization until no longer in alpha mode.
83
111
  this.run(false, false, "npm", "config", "set", this.atOrganizationRegistry, "--location", "project");
84
112
  }
85
113
 
86
- if (this.organizationDependenciesUpdated && (switchToAlpha || !this._updateAll)) {
114
+ if (repositoryState.anyDependenciesUpdated && (switchToAlpha || !this._updateAll)) {
87
115
  this.updateOrganizationDependencies();
88
116
  }
89
117
  }
@@ -95,10 +123,11 @@ class PublishAlpha extends Publish {
95
123
  this.run(false, false, "npm", "run", "build:dev", "--if-present");
96
124
 
97
125
  if (anyChanges) {
98
- const nowISOString = new Date().toISOString();
126
+ const now = new Date();
127
+ const nowISOString = now.toISOString();
99
128
 
100
129
  // Nothing further required if this repository is not a dependency of others.
101
- if (this.repository.dependencyType !== "none") {
130
+ if (repositoryState.repository.dependencyType !== "none") {
102
131
  if (!this.dryRun) {
103
132
  // Backup the package configuration file.
104
133
  fs.renameSync(PACKAGE_CONFIGURATION_PATH, BACKUP_PACKAGE_CONFIGURATION_PATH);
@@ -113,9 +142,9 @@ class PublishAlpha extends Publish {
113
142
 
114
143
  // Unpublish all prior alpha versions.
115
144
  // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Output is a JSON array.
116
- for (const version of JSON.parse(this.run(true, true, "npm", "view", this.packageConfiguration.name, "versions", "--json").join("\n")) as string[]) {
117
- if (/^\d+.\d+.\d+-alpha.\d+$/.test(version) && version !== this.packageConfiguration.version) {
118
- this.run(false, false, "npm", "unpublish", `${this.packageConfiguration.name}@${version}`);
145
+ for (const version of JSON.parse(this.run(true, true, "npm", "view", packageConfiguration.name, "versions", "--json").join("\n")) as string[]) {
146
+ if (/^\d+.\d+.\d+-alpha.\d+$/.test(version) && version !== packageConfiguration.version) {
147
+ this.run(false, false, "npm", "unpublish", `${packageConfiguration.name}@${version}`);
119
148
  }
120
149
  }
121
150
  } finally {
@@ -129,7 +158,9 @@ class PublishAlpha extends Publish {
129
158
 
130
159
  this.commitUpdatedPackageVersion(PACKAGE_CONFIGURATION_PATH, PACKAGE_LOCK_CONFIGURATION_PATH);
131
160
 
132
- this.repository.lastAlphaPublished = nowISOString;
161
+ this.updatePhaseState({
162
+ dateTime: now
163
+ });
133
164
  }
134
165
  }
135
166
  }
@@ -4,6 +4,7 @@ import { setTimeout } from "node:timers/promises";
4
4
  import { Octokit } from "octokit";
5
5
  import { parse as yamlParse } from "yaml";
6
6
  import secureConfigurationJSON from "../../config/publish.secure.json";
7
+ import type { Repository } from "./configuration";
7
8
  import { Publish } from "./publish.js";
8
9
  import { logger } from "./logger.js";
9
10
 
@@ -83,6 +84,52 @@ class PublishBeta extends Publish {
83
84
  });
84
85
  }
85
86
 
87
+ /**
88
+ * @inheritDoc
89
+ */
90
+ protected dependencyVersionFor(dependencyRepositoryName: string, dependencyRepository: Repository): string {
91
+ let dependencyVersion: string;
92
+
93
+ switch (dependencyRepository.dependencyType) {
94
+ case "external":
95
+ dependencyVersion = "beta";
96
+ break;
97
+
98
+ case "internal": {
99
+ const betaTag = dependencyRepository.phaseStates.beta?.tag;
100
+
101
+ if (betaTag === undefined) {
102
+ throw new Error(`*** Internal error *** Beta tag not set for ${dependencyRepositoryName}`);
103
+ }
104
+
105
+ dependencyVersion = `${this.configuration.organization}/${dependencyRepositoryName}#${betaTag}`;
106
+ }
107
+ break;
108
+
109
+ default:
110
+ throw new Error(`Invalid dependency type "${dependencyRepository.dependencyType}" for dependency ${dependencyRepositoryName}`);
111
+ }
112
+
113
+ return dependencyVersion;
114
+ }
115
+
116
+ /**
117
+ * @inheritDoc
118
+ */
119
+ protected getPhaseDateTime(repository: Repository, phaseDateTime: Date): Date {
120
+ return this.latestDateTime(phaseDateTime, repository.phaseStates.production?.dateTime);
121
+ }
122
+
123
+ /**
124
+ * @inheritDoc
125
+ */
126
+ protected isValidBranch(): boolean {
127
+ const repositoryState = this.repositoryState;
128
+
129
+ // Branch for beta phase must match version.
130
+ return repositoryState.branch === `v${repositoryState.majorVersion}.${repositoryState.minorVersion}`;
131
+ }
132
+
86
133
  /**
87
134
  * Run a step.
88
135
  *
@@ -95,14 +142,20 @@ class PublishBeta extends Publish {
95
142
  * Callback to execute step.
96
143
  */
97
144
  private async runStep(step: Step, stepRunner: () => (void | Promise<void>)): Promise<void> {
98
- if (this.repository.publishBetaStep === undefined || this.repository.publishBetaStep === step) {
145
+ const phaseStateStep = this.repositoryState.phaseState.step;
146
+
147
+ if (phaseStateStep === undefined || phaseStateStep === step) {
99
148
  logger.debug(`Running step ${step}`);
100
149
 
101
- this.repository.publishBetaStep = step;
150
+ this.updatePhaseState({
151
+ step
152
+ });
102
153
 
103
154
  await stepRunner();
104
155
 
105
- this.repository.publishBetaStep = undefined;
156
+ this.updatePhaseState({
157
+ step: undefined
158
+ });
106
159
  } else {
107
160
  logger.debug(`Skipping step ${step}`);
108
161
  }
@@ -117,7 +170,7 @@ class PublishBeta extends Publish {
117
170
  if (this.dryRun) {
118
171
  logger.info("Dry run: Validate workflow");
119
172
  } else {
120
- const commitSHA = this.run(true, true, "git", "rev-parse", this.branch)[0];
173
+ const commitSHA = this.run(true, true, "git", "rev-parse", this.repositoryState.branch)[0];
121
174
 
122
175
  let completed = false;
123
176
  let queryCount = 0;
@@ -128,7 +181,7 @@ class PublishBeta extends Publish {
128
181
  const response = await setTimeout(2000).then(
129
182
  async () => this._octokit.rest.actions.listWorkflowRunsForRepo({
130
183
  owner: this.configuration.organization,
131
- repo: this.repositoryName,
184
+ repo: this.repositoryState.repositoryName,
132
185
  head_sha: commitSHA
133
186
  })
134
187
  );
@@ -169,13 +222,15 @@ class PublishBeta extends Publish {
169
222
  protected async publish(): Promise<void> {
170
223
  let publish: boolean;
171
224
 
225
+ const repositoryState = this.repositoryState;
226
+
172
227
  // Scrap any incomplete publishing if pre-release identifier is not beta.
173
- if (this.preReleaseIdentifier !== "beta") {
174
- this.repository.publishBetaStep = undefined;
228
+ if (repositoryState.preReleaseIdentifier !== "beta") {
229
+ repositoryState.phaseState.step = undefined;
175
230
  }
176
231
 
177
- if (this.preReleaseIdentifier === "alpha") {
178
- if (this.anyChanges(this.repository.lastAlphaPublished, true)) {
232
+ if (repositoryState.preReleaseIdentifier === "alpha") {
233
+ if (this.anyChanges(repositoryState.repository.phaseStates.alpha?.dateTime, false)) {
179
234
  throw new Error("Repository has changed since last alpha published");
180
235
  }
181
236
 
@@ -186,22 +241,23 @@ class PublishBeta extends Publish {
186
241
  // Revert to default registry for organization.
187
242
  this.run(false, false, "npm", "config", "delete", this.atOrganizationRegistry, "--location", "project");
188
243
  } else {
189
- const startingPublication = this.repository.publishBetaStep === undefined;
244
+ const step = repositoryState.phaseState.step;
245
+ const startingPublication = step === undefined;
190
246
 
191
- // Publish beta step is defined and not "complete" if previous attempt failed at that step.
192
- publish = !startingPublication && this.repository.publishBetaStep !== "complete";
247
+ // Step is defined and not "complete" if previous attempt failed at that step.
248
+ publish = !startingPublication && step !== "complete";
193
249
 
194
250
  // Ignore changes after publication process has started.
195
- if (startingPublication && this.anyChanges(this.repository.lastAlphaPublished, false)) {
196
- throw new Error("Internal error, repository has changed without intermediate alpha publication");
251
+ if (startingPublication && this.anyChanges(repositoryState.repository.phaseStates.alpha?.dateTime, false)) {
252
+ throw new Error("Repository has changed since last alpha published");
197
253
  }
198
254
  }
199
255
 
200
256
  if (publish) {
201
- const tag = `v${this.packageConfiguration.version}`;
257
+ const tag = `v${repositoryState.packageConfiguration.version}`;
202
258
 
203
- if (this.repository.publishBetaStep !== undefined) {
204
- logger.debug(`Repository failed at step "${this.repository.publishBetaStep}" on prior run`);
259
+ if (repositoryState.phaseState.step !== undefined) {
260
+ logger.debug(`Repository failed at step "${repositoryState.phaseState.step}" on prior run`);
205
261
  }
206
262
 
207
263
  const workflowsPath = ".github/workflows/";
@@ -236,6 +292,9 @@ class PublishBeta extends Publish {
236
292
 
237
293
  await this.runStep("build", () => {
238
294
  this.run(false, false, "npm", "run", "build:release", "--if-present");
295
+
296
+ // Run test if present; must be part of build as correcting errors will require rebuild.
297
+ this.run(false, false, "npm", "run", "test", "--if-present");
239
298
  });
240
299
 
241
300
  await this.runStep("commit", () => {
@@ -247,7 +306,7 @@ class PublishBeta extends Publish {
247
306
  });
248
307
 
249
308
  await this.runStep("push", () => {
250
- this.run(false, false, "git", "push", "--atomic", "origin", this.branch, tag);
309
+ this.run(false, false, "git", "push", "--atomic", "origin", repositoryState.branch, tag);
251
310
  });
252
311
 
253
312
  if (hasPushWorkflow) {
@@ -262,7 +321,7 @@ class PublishBeta extends Publish {
262
321
  } else {
263
322
  await this._octokit.rest.repos.createRelease({
264
323
  owner: this.configuration.organization,
265
- repo: this.repositoryName,
324
+ repo: repositoryState.repositoryName,
266
325
  tag_name: tag,
267
326
  name: `Release ${tag}`,
268
327
  prerelease: true
@@ -276,9 +335,11 @@ class PublishBeta extends Publish {
276
335
  });
277
336
  }
278
337
 
279
- this.repository.lastBetaPublished = new Date().toISOString();
280
- this.repository.lastBetaTag = tag;
281
- this.repository.publishBetaStep = "complete";
338
+ this.updatePhaseState({
339
+ dateTime: new Date(),
340
+ tag,
341
+ step: "complete"
342
+ });
282
343
  }
283
344
  }
284
345
 
@@ -288,7 +349,8 @@ class PublishBeta extends Publish {
288
349
  protected override finalizeAll(): void {
289
350
  // Publication complete; reset steps to undefined for next run.
290
351
  for (const repository of Object.values(this.configuration.repositories)) {
291
- repository.publishBetaStep = undefined;
352
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- All beta phase states are defined by this point.
353
+ repository.phaseStates.beta!.step = undefined;
292
354
  }
293
355
  }
294
356
  }