@aidc-toolkit/dev 0.9.19-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.
- package/README.md +1 -1
- package/config/publish.json +51 -19
- package/copy-workflows.json +4 -0
- package/dev.iml +3 -1
- package/dist/eslint-config-template.d.ts.map +1 -1
- package/dist/eslint-config-template.js +1 -0
- package/dist/eslint-config-template.js.map +1 -1
- package/package.json +3 -3
- package/src/eslint-config-template.ts +1 -0
- package/src/publish/configuration.ts +318 -0
- package/src/publish/logger.ts +18 -7
- package/src/publish/publish-alpha.ts +54 -27
- package/src/publish/publish-beta.ts +96 -28
- package/src/publish/publish.ts +341 -377
- package/src/publish/type-helper.ts +23 -0
|
@@ -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
|
|
62
|
+
let anyExternalUpdates = false;
|
|
63
|
+
|
|
64
|
+
const repositoryState = this.repositoryState;
|
|
65
|
+
const packageConfiguration = repositoryState.packageConfiguration;
|
|
38
66
|
|
|
39
|
-
// Check for external
|
|
40
|
-
for (const currentDependencies of [
|
|
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 [
|
|
70
|
+
for (const [dependencyPackageName, version] of Object.entries(currentDependencies)) {
|
|
43
71
|
// Ignore organization dependencies.
|
|
44
|
-
if (this.dependencyRepositoryName(
|
|
45
|
-
const [latestVersion] = this.run(true, true, "npm", "view",
|
|
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 ${
|
|
76
|
+
logger.info(`Dependency ${dependencyPackageName}@${version} ${!this._updateAll ? "pending update" : "updating"} to version ${latestVersion}.`);
|
|
49
77
|
|
|
50
78
|
if (this._updateAll) {
|
|
51
|
-
currentDependencies[
|
|
79
|
+
currentDependencies[dependencyPackageName] = `^${latestVersion}`;
|
|
52
80
|
|
|
53
|
-
|
|
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 (
|
|
89
|
+
if (anyExternalUpdates) {
|
|
62
90
|
// Save the dependency updates; this will be detected by call to anyChanges().
|
|
63
91
|
this.savePackageConfiguration();
|
|
64
92
|
}
|
|
@@ -67,28 +95,24 @@ 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", ...
|
|
98
|
+
this.run(false, false, "npm", "update", ...repositoryState.npmPlatformArgs);
|
|
71
99
|
}
|
|
72
100
|
|
|
73
|
-
const anyChanges = this.anyChanges(
|
|
101
|
+
const anyChanges = this.anyChanges(repositoryState.phaseDateTime, true) || repositoryState.anyDependenciesUpdated;
|
|
74
102
|
|
|
75
103
|
if (anyChanges) {
|
|
76
|
-
const switchToAlpha =
|
|
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,
|
|
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
|
-
this.run(false, false, "npm", "set", this.atOrganizationRegistry, "--location", "project");
|
|
111
|
+
this.run(false, false, "npm", "config", "set", this.atOrganizationRegistry, "--location", "project");
|
|
84
112
|
}
|
|
85
113
|
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
logger.debug(`Updating organization dependencies [${updateOrganizationDependencies.join(", ")}]`);
|
|
90
|
-
|
|
91
|
-
this.run(false, false, "npm", "update", ...updateOrganizationDependencies, ...this.npmPlatformArgs);
|
|
114
|
+
if (repositoryState.anyDependenciesUpdated && (switchToAlpha || !this._updateAll)) {
|
|
115
|
+
this.updateOrganizationDependencies();
|
|
92
116
|
}
|
|
93
117
|
}
|
|
94
118
|
|
|
@@ -99,10 +123,11 @@ class PublishAlpha extends Publish {
|
|
|
99
123
|
this.run(false, false, "npm", "run", "build:dev", "--if-present");
|
|
100
124
|
|
|
101
125
|
if (anyChanges) {
|
|
102
|
-
const
|
|
126
|
+
const now = new Date();
|
|
127
|
+
const nowISOString = now.toISOString();
|
|
103
128
|
|
|
104
129
|
// Nothing further required if this repository is not a dependency of others.
|
|
105
|
-
if (
|
|
130
|
+
if (repositoryState.repository.dependencyType !== "none") {
|
|
106
131
|
if (!this.dryRun) {
|
|
107
132
|
// Backup the package configuration file.
|
|
108
133
|
fs.renameSync(PACKAGE_CONFIGURATION_PATH, BACKUP_PACKAGE_CONFIGURATION_PATH);
|
|
@@ -117,9 +142,9 @@ class PublishAlpha extends Publish {
|
|
|
117
142
|
|
|
118
143
|
// Unpublish all prior alpha versions.
|
|
119
144
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Output is a JSON array.
|
|
120
|
-
for (const version of JSON.parse(this.run(true, true, "npm", "view",
|
|
121
|
-
if (/^\d+.\d+.\d+-alpha.\d+$/.test(version) && version !==
|
|
122
|
-
this.run(false, false, "npm", "unpublish", `${
|
|
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}`);
|
|
123
148
|
}
|
|
124
149
|
}
|
|
125
150
|
} finally {
|
|
@@ -133,7 +158,9 @@ class PublishAlpha extends Publish {
|
|
|
133
158
|
|
|
134
159
|
this.commitUpdatedPackageVersion(PACKAGE_CONFIGURATION_PATH, PACKAGE_LOCK_CONFIGURATION_PATH);
|
|
135
160
|
|
|
136
|
-
this.
|
|
161
|
+
this.updatePhaseState({
|
|
162
|
+
dateTime: now
|
|
163
|
+
});
|
|
137
164
|
}
|
|
138
165
|
}
|
|
139
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
|
|
|
@@ -35,7 +36,7 @@ interface WorkflowConfiguration {
|
|
|
35
36
|
* Push branches.
|
|
36
37
|
*/
|
|
37
38
|
branches?: string[];
|
|
38
|
-
};
|
|
39
|
+
} | null;
|
|
39
40
|
|
|
40
41
|
/**
|
|
41
42
|
* Release trigger.
|
|
@@ -45,14 +46,14 @@ interface WorkflowConfiguration {
|
|
|
45
46
|
* Release types.
|
|
46
47
|
*/
|
|
47
48
|
types?: string[];
|
|
48
|
-
};
|
|
49
|
+
} | null;
|
|
49
50
|
};
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
/**
|
|
53
54
|
* Publish steps.
|
|
54
55
|
*/
|
|
55
|
-
type Step = "
|
|
56
|
+
type Step = "update" | "build" | "commit" | "tag" | "push" | "workflow (push)" | "release" | "workflow (release)" | "complete";
|
|
56
57
|
|
|
57
58
|
/**
|
|
58
59
|
* Publish beta versions.
|
|
@@ -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
|
-
|
|
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.
|
|
150
|
+
this.updatePhaseState({
|
|
151
|
+
step
|
|
152
|
+
});
|
|
102
153
|
|
|
103
154
|
await stepRunner();
|
|
104
155
|
|
|
105
|
-
this.
|
|
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,34 +222,42 @@ 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 (
|
|
174
|
-
|
|
228
|
+
if (repositoryState.preReleaseIdentifier !== "beta") {
|
|
229
|
+
repositoryState.phaseState.step = undefined;
|
|
175
230
|
}
|
|
176
231
|
|
|
177
|
-
if (
|
|
178
|
-
if (this.anyChanges(
|
|
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
|
|
|
182
237
|
publish = true;
|
|
183
238
|
|
|
184
239
|
this.updatePackageVersion(undefined, undefined, undefined, "beta");
|
|
240
|
+
|
|
241
|
+
// Revert to default registry for organization.
|
|
242
|
+
this.run(false, false, "npm", "config", "delete", this.atOrganizationRegistry, "--location", "project");
|
|
185
243
|
} else {
|
|
186
|
-
|
|
187
|
-
|
|
244
|
+
const step = repositoryState.phaseState.step;
|
|
245
|
+
const startingPublication = step === undefined;
|
|
246
|
+
|
|
247
|
+
// Step is defined and not "complete" if previous attempt failed at that step.
|
|
248
|
+
publish = !startingPublication && step !== "complete";
|
|
188
249
|
|
|
189
250
|
// Ignore changes after publication process has started.
|
|
190
|
-
if (
|
|
191
|
-
throw new Error("
|
|
251
|
+
if (startingPublication && this.anyChanges(repositoryState.repository.phaseStates.alpha?.dateTime, false)) {
|
|
252
|
+
throw new Error("Repository has changed since last alpha published");
|
|
192
253
|
}
|
|
193
254
|
}
|
|
194
255
|
|
|
195
256
|
if (publish) {
|
|
196
|
-
const tag = `v${
|
|
257
|
+
const tag = `v${repositoryState.packageConfiguration.version}`;
|
|
197
258
|
|
|
198
|
-
if (
|
|
199
|
-
logger.debug(`Repository failed at step "${
|
|
259
|
+
if (repositoryState.phaseState.step !== undefined) {
|
|
260
|
+
logger.debug(`Repository failed at step "${repositoryState.phaseState.step}" on prior run`);
|
|
200
261
|
}
|
|
201
262
|
|
|
202
263
|
const workflowsPath = ".github/workflows/";
|
|
@@ -211,13 +272,13 @@ class PublishBeta extends Publish {
|
|
|
211
272
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Workflow configuration format is known.
|
|
212
273
|
const workflowOn = (yamlParse(fs.readFileSync(path.resolve(workflowsPath, workflowFile)).toString()) as WorkflowConfiguration).on;
|
|
213
274
|
|
|
214
|
-
if (workflowOn.push !== undefined && (workflowOn.push
|
|
275
|
+
if (workflowOn.push !== undefined && (workflowOn.push?.branches === undefined || workflowOn.push.branches.includes("v*"))) {
|
|
215
276
|
logger.debug("Repository has push workflow");
|
|
216
277
|
|
|
217
278
|
hasPushWorkflow = true;
|
|
218
279
|
}
|
|
219
280
|
|
|
220
|
-
if (workflowOn.release !== undefined && (workflowOn.release
|
|
281
|
+
if (workflowOn.release !== undefined && (workflowOn.release?.types === undefined || workflowOn.release.types.includes("published"))) {
|
|
221
282
|
logger.debug("Repository has release workflow");
|
|
222
283
|
|
|
223
284
|
hasReleaseWorkflow = true;
|
|
@@ -225,12 +286,15 @@ class PublishBeta extends Publish {
|
|
|
225
286
|
}
|
|
226
287
|
}
|
|
227
288
|
|
|
228
|
-
await this.runStep("
|
|
229
|
-
this.
|
|
289
|
+
await this.runStep("update", () => {
|
|
290
|
+
this.updateOrganizationDependencies();
|
|
230
291
|
});
|
|
231
292
|
|
|
232
293
|
await this.runStep("build", () => {
|
|
233
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");
|
|
234
298
|
});
|
|
235
299
|
|
|
236
300
|
await this.runStep("commit", () => {
|
|
@@ -242,7 +306,7 @@ class PublishBeta extends Publish {
|
|
|
242
306
|
});
|
|
243
307
|
|
|
244
308
|
await this.runStep("push", () => {
|
|
245
|
-
this.run(false, false, "git", "push", "--atomic", "origin",
|
|
309
|
+
this.run(false, false, "git", "push", "--atomic", "origin", repositoryState.branch, tag);
|
|
246
310
|
});
|
|
247
311
|
|
|
248
312
|
if (hasPushWorkflow) {
|
|
@@ -257,7 +321,7 @@ class PublishBeta extends Publish {
|
|
|
257
321
|
} else {
|
|
258
322
|
await this._octokit.rest.repos.createRelease({
|
|
259
323
|
owner: this.configuration.organization,
|
|
260
|
-
repo:
|
|
324
|
+
repo: repositoryState.repositoryName,
|
|
261
325
|
tag_name: tag,
|
|
262
326
|
name: `Release ${tag}`,
|
|
263
327
|
prerelease: true
|
|
@@ -271,8 +335,11 @@ class PublishBeta extends Publish {
|
|
|
271
335
|
});
|
|
272
336
|
}
|
|
273
337
|
|
|
274
|
-
this.
|
|
275
|
-
|
|
338
|
+
this.updatePhaseState({
|
|
339
|
+
dateTime: new Date(),
|
|
340
|
+
tag,
|
|
341
|
+
step: "complete"
|
|
342
|
+
});
|
|
276
343
|
}
|
|
277
344
|
}
|
|
278
345
|
|
|
@@ -282,7 +349,8 @@ class PublishBeta extends Publish {
|
|
|
282
349
|
protected override finalizeAll(): void {
|
|
283
350
|
// Publication complete; reset steps to undefined for next run.
|
|
284
351
|
for (const repository of Object.values(this.configuration.repositories)) {
|
|
285
|
-
|
|
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;
|
|
286
354
|
}
|
|
287
355
|
}
|
|
288
356
|
}
|