@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
package/src/publish/publish.ts
CHANGED
|
@@ -1,151 +1,130 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
|
-
import * as path from "node:path";
|
|
4
3
|
import * as process from "node:process";
|
|
5
|
-
import
|
|
6
|
-
|
|
4
|
+
import {
|
|
5
|
+
type Configuration,
|
|
6
|
+
loadConfiguration,
|
|
7
|
+
type Phase,
|
|
8
|
+
type PhaseState,
|
|
9
|
+
type Repository,
|
|
10
|
+
saveConfiguration,
|
|
11
|
+
SHARED_CONFIGURATION_PATH
|
|
12
|
+
} from "./configuration.js";
|
|
7
13
|
import { logger, setLogLevel } from "./logger.js";
|
|
8
|
-
import {
|
|
14
|
+
import { pick } from "./type-helper.js";
|
|
9
15
|
|
|
10
|
-
const
|
|
11
|
-
const LOCAL_CONFIGURATION_PATH = "config/publish.local.json";
|
|
16
|
+
export const PACKAGE_CONFIGURATION_PATH = "package.json";
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
const SHARED_CONFIGURATION_FULL_PATH = path.resolve(SHARED_CONFIGURATION_PATH);
|
|
15
|
-
const LOCAL_CONFIGURATION_FULL_PATH = path.resolve(LOCAL_CONFIGURATION_PATH);
|
|
18
|
+
export const PACKAGE_LOCK_CONFIGURATION_PATH = "package-lock.json";
|
|
16
19
|
|
|
17
20
|
/**
|
|
18
|
-
*
|
|
21
|
+
* Configuration layout of package.json (relevant attributes only).
|
|
19
22
|
*/
|
|
20
|
-
export interface
|
|
23
|
+
export interface PackageConfiguration {
|
|
21
24
|
/**
|
|
22
|
-
*
|
|
25
|
+
* Name.
|
|
23
26
|
*/
|
|
24
|
-
|
|
27
|
+
readonly name: string;
|
|
25
28
|
|
|
26
29
|
/**
|
|
27
|
-
*
|
|
30
|
+
* Version.
|
|
28
31
|
*/
|
|
29
|
-
|
|
32
|
+
version: string;
|
|
30
33
|
|
|
31
34
|
/**
|
|
32
|
-
*
|
|
35
|
+
* Development dependencies.
|
|
33
36
|
*/
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* CPU architecture of native modules to install.
|
|
37
|
-
*/
|
|
38
|
-
cpu: string;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* OS of native modules to install.
|
|
42
|
-
*/
|
|
43
|
-
os: string;
|
|
44
|
-
};
|
|
37
|
+
readonly devDependencies?: Record<string, string>;
|
|
45
38
|
|
|
46
39
|
/**
|
|
47
|
-
*
|
|
40
|
+
* Dependencies.
|
|
48
41
|
*/
|
|
49
|
-
|
|
42
|
+
readonly dependencies?: Record<string, string>;
|
|
43
|
+
}
|
|
50
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Repository state, derived from package configuration and updated during publishing.
|
|
47
|
+
*/
|
|
48
|
+
interface RepositoryState {
|
|
51
49
|
/**
|
|
52
|
-
*
|
|
50
|
+
* Repository name from configuration.
|
|
53
51
|
*/
|
|
54
|
-
|
|
52
|
+
readonly repositoryName: string;
|
|
55
53
|
|
|
56
54
|
/**
|
|
57
|
-
*
|
|
55
|
+
* Repository from configuration.
|
|
58
56
|
*/
|
|
59
|
-
|
|
57
|
+
repository: Repository;
|
|
60
58
|
|
|
61
59
|
/**
|
|
62
|
-
*
|
|
60
|
+
* Phase state.
|
|
63
61
|
*/
|
|
64
|
-
|
|
62
|
+
phaseState: PhaseState;
|
|
65
63
|
|
|
66
64
|
/**
|
|
67
|
-
*
|
|
65
|
+
* Phase date/time or undefined if phase never before published.
|
|
68
66
|
*/
|
|
69
|
-
|
|
67
|
+
phaseDateTime: Date | undefined;
|
|
70
68
|
|
|
71
69
|
/**
|
|
72
|
-
*
|
|
70
|
+
* NPM platform arguments if any.
|
|
73
71
|
*/
|
|
74
|
-
|
|
72
|
+
readonly npmPlatformArgs: readonly string[];
|
|
75
73
|
|
|
76
74
|
/**
|
|
77
|
-
*
|
|
75
|
+
* Branch.
|
|
78
76
|
*/
|
|
79
|
-
|
|
80
|
-
}
|
|
77
|
+
readonly branch: string;
|
|
81
78
|
|
|
82
|
-
/**
|
|
83
|
-
* Configuration layout of merged publish.json and publish.local.json.
|
|
84
|
-
*/
|
|
85
|
-
export interface Configuration {
|
|
86
79
|
/**
|
|
87
|
-
*
|
|
80
|
+
* Package configuration.
|
|
88
81
|
*/
|
|
89
|
-
|
|
82
|
+
readonly packageConfiguration: PackageConfiguration;
|
|
90
83
|
|
|
91
84
|
/**
|
|
92
|
-
*
|
|
85
|
+
* Major version.
|
|
93
86
|
*/
|
|
94
|
-
|
|
87
|
+
majorVersion: number;
|
|
95
88
|
|
|
96
89
|
/**
|
|
97
|
-
*
|
|
90
|
+
* Minor version.
|
|
98
91
|
*/
|
|
99
|
-
|
|
92
|
+
minorVersion: number;
|
|
100
93
|
|
|
101
94
|
/**
|
|
102
|
-
*
|
|
95
|
+
* Patch version.
|
|
103
96
|
*/
|
|
104
|
-
|
|
105
|
-
}
|
|
97
|
+
patchVersion: number;
|
|
106
98
|
|
|
107
|
-
export const PACKAGE_CONFIGURATION_PATH = "package.json";
|
|
108
|
-
|
|
109
|
-
export const PACKAGE_LOCK_CONFIGURATION_PATH = "package-lock.json";
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Configuration layout of package.json (relevant attributes only).
|
|
113
|
-
*/
|
|
114
|
-
export interface PackageConfiguration {
|
|
115
99
|
/**
|
|
116
|
-
*
|
|
100
|
+
* Pre-release identifier or null if none.
|
|
117
101
|
*/
|
|
118
|
-
|
|
102
|
+
preReleaseIdentifier: string | null;
|
|
119
103
|
|
|
120
104
|
/**
|
|
121
|
-
*
|
|
105
|
+
* Dependency package names extracted directly from package configuration.
|
|
122
106
|
*/
|
|
123
|
-
|
|
107
|
+
readonly dependencyPackageNames: readonly string[];
|
|
124
108
|
|
|
125
109
|
/**
|
|
126
|
-
*
|
|
110
|
+
* All dependency package names in publication order.
|
|
127
111
|
*/
|
|
128
|
-
|
|
112
|
+
readonly allDependencyPackageNames: readonly string[];
|
|
129
113
|
|
|
130
114
|
/**
|
|
131
|
-
*
|
|
115
|
+
* True if any dependencies have been updated.
|
|
132
116
|
*/
|
|
133
|
-
|
|
117
|
+
readonly anyDependenciesUpdated: boolean;
|
|
134
118
|
}
|
|
135
119
|
|
|
136
|
-
/**
|
|
137
|
-
* Release type.
|
|
138
|
-
*/
|
|
139
|
-
type ReleaseType = "alpha" | "beta" | "production";
|
|
140
|
-
|
|
141
120
|
/**
|
|
142
121
|
* Publish base class.
|
|
143
122
|
*/
|
|
144
123
|
export abstract class Publish {
|
|
145
124
|
/**
|
|
146
|
-
*
|
|
125
|
+
* Phase.
|
|
147
126
|
*/
|
|
148
|
-
private readonly
|
|
127
|
+
private readonly _phase: Phase;
|
|
149
128
|
|
|
150
129
|
/**
|
|
151
130
|
* If true, outputs what would be run rather than running it.
|
|
@@ -168,65 +147,14 @@ export abstract class Publish {
|
|
|
168
147
|
private readonly _atOrganizationRegistry: string;
|
|
169
148
|
|
|
170
149
|
/**
|
|
171
|
-
*
|
|
150
|
+
* Repository states, keyed on repository name.
|
|
172
151
|
*/
|
|
173
|
-
private readonly
|
|
152
|
+
private readonly _repositoryStates: Record<string, Readonly<RepositoryState>>;
|
|
174
153
|
|
|
175
154
|
/**
|
|
176
|
-
* Current repository
|
|
155
|
+
* Current repository state.
|
|
177
156
|
*/
|
|
178
|
-
private
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Current repository.
|
|
182
|
-
*/
|
|
183
|
-
private _repository!: Repository;
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* NPM platform arguments if any.
|
|
187
|
-
*/
|
|
188
|
-
private _npmPlatformArgs!: string[];
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Branch.
|
|
192
|
-
*/
|
|
193
|
-
private _branch!: string;
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Package configuration.
|
|
197
|
-
*/
|
|
198
|
-
private _packageConfiguration!: PackageConfiguration;
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Major version.
|
|
202
|
-
*/
|
|
203
|
-
private _majorVersion!: number;
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Minor version.
|
|
207
|
-
*/
|
|
208
|
-
private _minorVersion!: number;
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Patch version.
|
|
212
|
-
*/
|
|
213
|
-
private _patchVersion!: number;
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Pre-release identifier or null if none.
|
|
217
|
-
*/
|
|
218
|
-
private _preReleaseIdentifier!: string | null;
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Dependencies that belong to the organization, keyed on repository name; null if additional (not included in
|
|
222
|
-
* package configuration).
|
|
223
|
-
*/
|
|
224
|
-
private _organizationDependencies!: Record<string, string | null>;
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* True if any organization dependency has been updated.
|
|
228
|
-
*/
|
|
229
|
-
private _organizationDependenciesUpdated!: boolean;
|
|
157
|
+
private _repositoryState: RepositoryState | undefined;
|
|
230
158
|
|
|
231
159
|
/**
|
|
232
160
|
* Constructor.
|
|
@@ -237,36 +165,29 @@ export abstract class Publish {
|
|
|
237
165
|
* @param dryRun
|
|
238
166
|
* If true, outputs what would be run rather than running it.
|
|
239
167
|
*/
|
|
240
|
-
protected constructor(releaseType:
|
|
241
|
-
this.
|
|
168
|
+
protected constructor(releaseType: Phase, dryRun: boolean) {
|
|
169
|
+
this._phase = releaseType;
|
|
242
170
|
this._dryRun = dryRun;
|
|
243
171
|
|
|
244
|
-
|
|
245
|
-
this._configuration = {
|
|
246
|
-
...omit(sharedConfigurationJSON, "repositories"),
|
|
247
|
-
...omit(localConfigurationJSON, "repositories"),
|
|
248
|
-
repositories: Object.fromEntries(Object.entries(sharedConfigurationJSON.repositories).map(([repositoryName, repository]) => [repositoryName, {
|
|
249
|
-
...repository,
|
|
250
|
-
...((localConfigurationJSON.repositories as Record<string, Partial<Repository> | undefined>)[repositoryName] ?? {})
|
|
251
|
-
}]))
|
|
252
|
-
};
|
|
172
|
+
this._configuration = loadConfiguration();
|
|
253
173
|
|
|
254
174
|
this._atOrganization = `@${this.configuration.organization}`;
|
|
255
175
|
|
|
256
|
-
this._atOrganizationRegistry = `${this.atOrganization}:registry
|
|
257
|
-
|
|
258
|
-
this._allOrganizationDependencies = {};
|
|
176
|
+
this._atOrganizationRegistry = `${this.atOrganization}:registry${releaseType === "alpha" ? `=${this.configuration.alphaRegistry}` : ""}`;
|
|
259
177
|
|
|
260
178
|
if (this._configuration.logLevel !== undefined) {
|
|
261
179
|
setLogLevel(this._configuration.logLevel);
|
|
262
180
|
}
|
|
181
|
+
|
|
182
|
+
this._repositoryStates = {};
|
|
183
|
+
this._repositoryState = undefined;
|
|
263
184
|
}
|
|
264
185
|
|
|
265
186
|
/**
|
|
266
|
-
* Get the
|
|
187
|
+
* Get the phase.
|
|
267
188
|
*/
|
|
268
|
-
protected get
|
|
269
|
-
return this.
|
|
189
|
+
protected get phase(): Phase {
|
|
190
|
+
return this._phase;
|
|
270
191
|
}
|
|
271
192
|
|
|
272
193
|
/**
|
|
@@ -298,88 +219,83 @@ export abstract class Publish {
|
|
|
298
219
|
}
|
|
299
220
|
|
|
300
221
|
/**
|
|
301
|
-
* Get
|
|
302
|
-
*/
|
|
303
|
-
protected get allOrganizationDependencies(): Record<string, Record<string, string | null>> {
|
|
304
|
-
return this._allOrganizationDependencies;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Get the current repository name.
|
|
309
|
-
*/
|
|
310
|
-
protected get repositoryName(): string {
|
|
311
|
-
return this._repositoryName;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* Get the current repository.
|
|
222
|
+
* Get the repository states, keyed on repository name.
|
|
316
223
|
*/
|
|
317
|
-
protected get
|
|
318
|
-
return this.
|
|
224
|
+
protected get repositoryStates(): Record<string, Readonly<RepositoryState>> {
|
|
225
|
+
return this._repositoryStates;
|
|
319
226
|
}
|
|
320
227
|
|
|
321
228
|
/**
|
|
322
|
-
* Get the
|
|
229
|
+
* Get the current repository state.
|
|
323
230
|
*/
|
|
324
|
-
get
|
|
325
|
-
|
|
326
|
-
|
|
231
|
+
protected get repositoryState(): RepositoryState {
|
|
232
|
+
// Repository state should be accessed only during active publication.
|
|
233
|
+
if (this._repositoryState === undefined) {
|
|
234
|
+
throw new Error("Repository state not defined");
|
|
235
|
+
}
|
|
327
236
|
|
|
328
|
-
|
|
329
|
-
* Get the branch.
|
|
330
|
-
*/
|
|
331
|
-
protected get branch(): string {
|
|
332
|
-
return this._branch;
|
|
237
|
+
return this._repositoryState;
|
|
333
238
|
}
|
|
334
239
|
|
|
335
240
|
/**
|
|
336
|
-
* Get the
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
*
|
|
241
|
+
* Get the dependency version for a dependency repository.
|
|
242
|
+
*
|
|
243
|
+
* @param dependencyRepositoryName
|
|
244
|
+
* Dependency repository name.
|
|
245
|
+
*
|
|
246
|
+
* @param dependencyRepository
|
|
247
|
+
* Dependency repository.
|
|
248
|
+
*
|
|
249
|
+
* @returns
|
|
250
|
+
* Dependency version.
|
|
344
251
|
*/
|
|
345
|
-
protected
|
|
346
|
-
return this._majorVersion;
|
|
347
|
-
}
|
|
252
|
+
protected abstract dependencyVersionFor(dependencyRepositoryName: string, dependencyRepository: Repository): string;
|
|
348
253
|
|
|
349
254
|
/**
|
|
350
|
-
*
|
|
255
|
+
* Determine the latest date/time or undefined if all undefined.
|
|
256
|
+
*
|
|
257
|
+
* @param initialDateTime
|
|
258
|
+
* Initial date/time.
|
|
259
|
+
*
|
|
260
|
+
* @param additionalDateTimes
|
|
261
|
+
* Additional date/times.
|
|
262
|
+
*
|
|
263
|
+
* @returns
|
|
264
|
+
* Latest date/time.
|
|
351
265
|
*/
|
|
352
|
-
protected
|
|
353
|
-
|
|
354
|
-
}
|
|
266
|
+
protected latestDateTime(initialDateTime: Date, ...additionalDateTimes: Array<Date | undefined>): Date {
|
|
267
|
+
let latestDateTime = initialDateTime;
|
|
355
268
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
269
|
+
for (const dateTime of additionalDateTimes) {
|
|
270
|
+
if (dateTime !== undefined && latestDateTime.getTime() < dateTime.getTime()) {
|
|
271
|
+
latestDateTime = dateTime;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
362
274
|
|
|
363
|
-
|
|
364
|
-
* Get the pre-release identifier.
|
|
365
|
-
*/
|
|
366
|
-
protected get preReleaseIdentifier(): string | null {
|
|
367
|
-
return this._preReleaseIdentifier;
|
|
275
|
+
return latestDateTime;
|
|
368
276
|
}
|
|
369
277
|
|
|
370
278
|
/**
|
|
371
|
-
* Get
|
|
279
|
+
* Get the phase date/time for a repository.
|
|
280
|
+
*
|
|
281
|
+
* @param repository
|
|
282
|
+
* Repository.
|
|
283
|
+
*
|
|
284
|
+
* @param phaseDateTime
|
|
285
|
+
* Initial phase date/time.
|
|
286
|
+
*
|
|
287
|
+
* @returns
|
|
288
|
+
* Phase date/time or undefined if phase never before published.
|
|
372
289
|
*/
|
|
373
|
-
protected
|
|
374
|
-
return this._organizationDependencies;
|
|
375
|
-
}
|
|
290
|
+
protected abstract getPhaseDateTime(repository: Repository, phaseDateTime: Date): Date;
|
|
376
291
|
|
|
377
292
|
/**
|
|
378
|
-
* Determine if
|
|
293
|
+
* Determine if branch is valid for the phase.
|
|
294
|
+
*
|
|
295
|
+
* @returns
|
|
296
|
+
* True if branch is valid for the phase.
|
|
379
297
|
*/
|
|
380
|
-
protected
|
|
381
|
-
return this._organizationDependenciesUpdated;
|
|
382
|
-
}
|
|
298
|
+
protected abstract isValidBranch(): boolean;
|
|
383
299
|
|
|
384
300
|
/**
|
|
385
301
|
* Run a command and optionally capture its output.
|
|
@@ -457,22 +373,61 @@ export abstract class Publish {
|
|
|
457
373
|
return parsedDependency.length === 2 && parsedDependency[0] === this.atOrganization ? parsedDependency[1] : null;
|
|
458
374
|
}
|
|
459
375
|
|
|
376
|
+
/**
|
|
377
|
+
* Determine if an organization dependency has been updated.
|
|
378
|
+
*
|
|
379
|
+
* @param phaseDateTime
|
|
380
|
+
* Phase date/time of the current repository.
|
|
381
|
+
*
|
|
382
|
+
* @param dependencyRepositoryName
|
|
383
|
+
* Dependency repository name.
|
|
384
|
+
*
|
|
385
|
+
* @param isAdditional
|
|
386
|
+
* True if this is an additional dependency.
|
|
387
|
+
*
|
|
388
|
+
* @returns
|
|
389
|
+
* True if organization dependency has been updated.
|
|
390
|
+
*/
|
|
391
|
+
private isOrganizationDependencyUpdated(phaseDateTime: Date, dependencyRepositoryName: string, isAdditional: boolean): boolean {
|
|
392
|
+
const dependencyString = !isAdditional ? "Dependency" : "Additional dependency";
|
|
393
|
+
|
|
394
|
+
// If dependency repository state exists, so does dependency repository.
|
|
395
|
+
if (!(dependencyRepositoryName in this.repositoryStates)) {
|
|
396
|
+
throw new Error(`${dependencyString} repository ${dependencyRepositoryName} not yet published`);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const dependencyRepository = this.configuration.repositories[dependencyRepositoryName];
|
|
400
|
+
const dependencyPhaseState = dependencyRepository.phaseStates[this.phase];
|
|
401
|
+
|
|
402
|
+
if (dependencyPhaseState === undefined) {
|
|
403
|
+
throw new Error(`*** Internal error *** ${dependencyString} ${dependencyRepositoryName} does not have state for ${this.phase} phase`);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const isUpdated = phaseDateTime.getTime() < this.getPhaseDateTime(dependencyRepository, dependencyPhaseState.dateTime).getTime();
|
|
407
|
+
|
|
408
|
+
if (isUpdated) {
|
|
409
|
+
logger.trace(`Dependency repository ${dependencyRepositoryName} updated`);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return isUpdated;
|
|
413
|
+
}
|
|
414
|
+
|
|
460
415
|
/**
|
|
461
416
|
* Determine if there have been any changes to the current repository.
|
|
462
417
|
*
|
|
463
|
-
* @param
|
|
464
|
-
*
|
|
418
|
+
* @param phaseDateTime
|
|
419
|
+
* Phase date/time to check against or undefined if phase never before published.
|
|
465
420
|
*
|
|
466
421
|
* @param ignoreGitHub
|
|
467
422
|
* If true, ignore .github directory.
|
|
468
423
|
*
|
|
469
424
|
* @returns
|
|
470
|
-
* True if there
|
|
425
|
+
* True if there have been any changes since the phase date/time.
|
|
471
426
|
*/
|
|
472
|
-
protected anyChanges(
|
|
427
|
+
protected anyChanges(phaseDateTime: Date | undefined, ignoreGitHub: boolean): boolean {
|
|
473
428
|
let anyChanges: boolean;
|
|
474
429
|
|
|
475
|
-
const excludePaths = this.repository.excludePaths ?? [];
|
|
430
|
+
const excludePaths = this.repositoryState.repository.excludePaths ?? [];
|
|
476
431
|
|
|
477
432
|
const changedFilesSet = new Set<string>();
|
|
478
433
|
|
|
@@ -511,13 +466,14 @@ export abstract class Publish {
|
|
|
511
466
|
}
|
|
512
467
|
}
|
|
513
468
|
|
|
514
|
-
if (this.
|
|
469
|
+
if (this.phase !== "alpha" && this.run(true, true, "git", "fetch", "--porcelain", "--dry-run").length !== 0) {
|
|
515
470
|
throw new Error("Remote repository has outstanding changes");
|
|
516
471
|
}
|
|
517
472
|
|
|
518
|
-
|
|
473
|
+
// Phase date/time is undefined if never before published.
|
|
474
|
+
if (phaseDateTime !== undefined) {
|
|
519
475
|
// Get all files committed since last published.
|
|
520
|
-
for (const line of this.run(true, true, "git", "log", "--since",
|
|
476
|
+
for (const line of this.run(true, true, "git", "log", "--since", phaseDateTime.toISOString(), "--name-status", "--pretty=oneline")) {
|
|
521
477
|
// Header starts with 40-character SHA.
|
|
522
478
|
if (/^[0-9a-f]{40} /.test(line)) {
|
|
523
479
|
logger.debug(`Commit SHA ${line.substring(0, 40)}`);
|
|
@@ -532,10 +488,7 @@ export abstract class Publish {
|
|
|
532
488
|
const output = this.run(true, true, "git", "status", "--porcelain");
|
|
533
489
|
|
|
534
490
|
if (output.length !== 0) {
|
|
535
|
-
|
|
536
|
-
if (this.releaseType !== "alpha") {
|
|
537
|
-
throw new Error("Repository has uncommitted changes");
|
|
538
|
-
}
|
|
491
|
+
const committedCount = changedFilesSet.size;
|
|
539
492
|
|
|
540
493
|
logger.debug("Uncommitted");
|
|
541
494
|
|
|
@@ -546,9 +499,14 @@ export abstract class Publish {
|
|
|
546
499
|
|
|
547
500
|
processChangedFile(status, file, newFile);
|
|
548
501
|
}
|
|
502
|
+
|
|
503
|
+
// Beta or production publication requires that repository be fully committed except for excluded paths.
|
|
504
|
+
if (this.phase !== "alpha" && changedFilesSet.size !== committedCount) {
|
|
505
|
+
throw new Error("Repository has uncommitted changes");
|
|
506
|
+
}
|
|
549
507
|
}
|
|
550
508
|
|
|
551
|
-
const lastPublishedDateTime = new Date(
|
|
509
|
+
const lastPublishedDateTime = new Date(phaseDateTime);
|
|
552
510
|
|
|
553
511
|
anyChanges = false;
|
|
554
512
|
|
|
@@ -564,17 +522,11 @@ export abstract class Publish {
|
|
|
564
522
|
}
|
|
565
523
|
}
|
|
566
524
|
|
|
567
|
-
if (!anyChanges && this.organizationDependenciesUpdated) {
|
|
568
|
-
logger.info("Organization dependencies updated");
|
|
569
|
-
|
|
570
|
-
anyChanges = true;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
525
|
if (!anyChanges) {
|
|
574
526
|
logger.info("No changes");
|
|
575
527
|
}
|
|
576
528
|
} else {
|
|
577
|
-
logger.info("
|
|
529
|
+
logger.info("Never published");
|
|
578
530
|
|
|
579
531
|
// No last published, so there must have been changes.
|
|
580
532
|
anyChanges = true;
|
|
@@ -620,10 +572,12 @@ export abstract class Publish {
|
|
|
620
572
|
* Save package configuration.
|
|
621
573
|
*/
|
|
622
574
|
protected savePackageConfiguration(): void {
|
|
575
|
+
const packageConfiguration = this.repositoryState.packageConfiguration;
|
|
576
|
+
|
|
623
577
|
if (this.dryRun) {
|
|
624
|
-
logger.info(`Dry run: Saving package configuration\n${JSON.stringify(pick(
|
|
578
|
+
logger.info(`Dry run: Saving package configuration\n${JSON.stringify(pick(packageConfiguration, "name", "version", "devDependencies", "dependencies"), null, 2)}\n`);
|
|
625
579
|
} else {
|
|
626
|
-
fs.writeFileSync(PACKAGE_CONFIGURATION_PATH, `${JSON.stringify(
|
|
580
|
+
fs.writeFileSync(PACKAGE_CONFIGURATION_PATH, `${JSON.stringify(packageConfiguration, null, 2)}\n`);
|
|
627
581
|
}
|
|
628
582
|
}
|
|
629
583
|
|
|
@@ -643,27 +597,40 @@ export abstract class Publish {
|
|
|
643
597
|
* Pre-release identifier or undefined if no change.
|
|
644
598
|
*/
|
|
645
599
|
protected updatePackageVersion(majorVersion: number | undefined, minorVersion: number | undefined, patchVersion: number | undefined, preReleaseIdentifier: string | null | undefined): void {
|
|
600
|
+
const repositoryState = this.repositoryState;
|
|
601
|
+
|
|
646
602
|
if (majorVersion !== undefined) {
|
|
647
|
-
|
|
603
|
+
repositoryState.majorVersion = majorVersion;
|
|
648
604
|
}
|
|
649
605
|
|
|
650
606
|
if (minorVersion !== undefined) {
|
|
651
|
-
|
|
607
|
+
repositoryState.minorVersion = minorVersion;
|
|
652
608
|
}
|
|
653
609
|
|
|
654
610
|
if (patchVersion !== undefined) {
|
|
655
|
-
|
|
611
|
+
repositoryState.patchVersion = patchVersion;
|
|
656
612
|
}
|
|
657
613
|
|
|
658
614
|
if (preReleaseIdentifier !== undefined) {
|
|
659
|
-
|
|
615
|
+
repositoryState.preReleaseIdentifier = preReleaseIdentifier;
|
|
660
616
|
}
|
|
661
617
|
|
|
662
|
-
|
|
618
|
+
repositoryState.packageConfiguration.version = `${repositoryState.majorVersion}.${repositoryState.minorVersion}.${repositoryState.patchVersion}${repositoryState.preReleaseIdentifier !== null ? `-${repositoryState.preReleaseIdentifier}` : ""}`;
|
|
663
619
|
|
|
664
620
|
this.savePackageConfiguration();
|
|
665
621
|
}
|
|
666
622
|
|
|
623
|
+
/**
|
|
624
|
+
* Update organization dependencies.
|
|
625
|
+
*/
|
|
626
|
+
protected updateOrganizationDependencies(): void {
|
|
627
|
+
const repositoryState = this.repositoryState;
|
|
628
|
+
|
|
629
|
+
logger.debug(`Updating organization dependencies [${repositoryState.allDependencyPackageNames.join(", ")}]`);
|
|
630
|
+
|
|
631
|
+
this.run(false, false, "npm", "update", ...repositoryState.allDependencyPackageNames, ...this.repositoryState.npmPlatformArgs);
|
|
632
|
+
}
|
|
633
|
+
|
|
667
634
|
/**
|
|
668
635
|
* Commit changes resulting from updating the package version.
|
|
669
636
|
*
|
|
@@ -671,40 +638,40 @@ export abstract class Publish {
|
|
|
671
638
|
* Files to commit; if none, defaults to "--all".
|
|
672
639
|
*/
|
|
673
640
|
protected commitUpdatedPackageVersion(...files: string[]): void {
|
|
674
|
-
this.commitModified(`Updated to version ${this.packageConfiguration.version}.`, ...files);
|
|
641
|
+
this.commitModified(`Updated to version ${this.repositoryState.packageConfiguration.version}.`, ...files);
|
|
675
642
|
}
|
|
676
643
|
|
|
677
644
|
/**
|
|
678
|
-
*
|
|
645
|
+
* Update the phase state. This will replace the phase state object in the repository and repository state and may
|
|
646
|
+
* update the phase date/time in the repository state.
|
|
647
|
+
*
|
|
648
|
+
* @param phaseState
|
|
649
|
+
* Partial phases state. Only those properties provided will be updated.
|
|
679
650
|
*/
|
|
680
|
-
protected
|
|
681
|
-
const
|
|
682
|
-
const saveLocalRepositories: Record<string, Pick<Repository, "platform" | "lastAlphaPublished">> = {};
|
|
651
|
+
protected updatePhaseState(phaseState: Partial<PhaseState>): void {
|
|
652
|
+
const repositoryState = this.repositoryState;
|
|
683
653
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
const saveSharedConfigurationJSON = JSON.stringify({
|
|
690
|
-
...omit(this.configuration, "logLevel", "alphaRegistry", "repositories"),
|
|
691
|
-
repositories: saveSharedRepositories
|
|
692
|
-
}, null, 2);
|
|
654
|
+
const updatedPhaseState = {
|
|
655
|
+
...this.repositoryState.phaseState,
|
|
656
|
+
...phaseState
|
|
657
|
+
};
|
|
693
658
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
repositories: saveLocalRepositories
|
|
697
|
-
}, null, 2);
|
|
659
|
+
repositoryState.repository.phaseStates[this.phase] = updatedPhaseState;
|
|
660
|
+
repositoryState.phaseState = updatedPhaseState;
|
|
698
661
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
} else {
|
|
703
|
-
fs.writeFileSync(SHARED_CONFIGURATION_FULL_PATH, saveSharedConfigurationJSON);
|
|
704
|
-
fs.writeFileSync(LOCAL_CONFIGURATION_FULL_PATH, saveLocalConfigurationJSON);
|
|
662
|
+
// Setting the phase date/time overrides the logic of its initial determination.
|
|
663
|
+
if (phaseState.dateTime !== undefined) {
|
|
664
|
+
repositoryState.phaseDateTime = phaseState.dateTime;
|
|
705
665
|
}
|
|
706
666
|
}
|
|
707
667
|
|
|
668
|
+
/**
|
|
669
|
+
* Save the configuration.
|
|
670
|
+
*/
|
|
671
|
+
private saveConfiguration(): void {
|
|
672
|
+
saveConfiguration(this.configuration, this.dryRun);
|
|
673
|
+
}
|
|
674
|
+
|
|
708
675
|
/**
|
|
709
676
|
* Publish current repository.
|
|
710
677
|
*/
|
|
@@ -717,20 +684,6 @@ export abstract class Publish {
|
|
|
717
684
|
const startDirectory = process.cwd();
|
|
718
685
|
|
|
719
686
|
for (const [repositoryName, repository] of Object.entries(this.configuration.repositories)) {
|
|
720
|
-
this._repositoryName = repositoryName;
|
|
721
|
-
this._repository = repository;
|
|
722
|
-
|
|
723
|
-
this._npmPlatformArgs = repository.platform !== undefined ?
|
|
724
|
-
[
|
|
725
|
-
"--cpu",
|
|
726
|
-
repository.platform.cpu,
|
|
727
|
-
"--os",
|
|
728
|
-
repository.platform.os
|
|
729
|
-
] :
|
|
730
|
-
[];
|
|
731
|
-
|
|
732
|
-
this._branch = this.run(true, true, "git", "branch", "--show-current")[0];
|
|
733
|
-
|
|
734
687
|
// All repositories are expected to be children of the parent of this repository.
|
|
735
688
|
const directory = `../${repository.directory ?? repositoryName}`;
|
|
736
689
|
|
|
@@ -739,142 +692,156 @@ export abstract class Publish {
|
|
|
739
692
|
|
|
740
693
|
process.chdir(directory);
|
|
741
694
|
|
|
742
|
-
|
|
743
|
-
this._packageConfiguration = JSON.parse(fs.readFileSync(PACKAGE_CONFIGURATION_PATH).toString()) as PackageConfiguration;
|
|
695
|
+
let phaseState = repository.phaseStates[this.phase];
|
|
744
696
|
|
|
745
|
-
|
|
697
|
+
// Create phase state if necessary.
|
|
698
|
+
if (phaseState === undefined) {
|
|
699
|
+
phaseState = {
|
|
700
|
+
dateTime: new Date(0)
|
|
701
|
+
};
|
|
746
702
|
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
if (parsedVersion === null) {
|
|
750
|
-
throw new Error(`Invalid package version ${version}`);
|
|
703
|
+
repository.phaseStates[this.phase] = phaseState;
|
|
751
704
|
}
|
|
752
705
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
this._patchVersion = Number(parsedVersion[3]);
|
|
756
|
-
this._preReleaseIdentifier = parsedVersion.length === 6 ? parsedVersion[5] : null;
|
|
706
|
+
try {
|
|
707
|
+
const phaseDateTime = this.getPhaseDateTime(repository, phaseState.dateTime);
|
|
757
708
|
|
|
758
|
-
|
|
709
|
+
const npmPlatformArgs = repository.platform !== undefined ?
|
|
710
|
+
[
|
|
711
|
+
"--cpu",
|
|
712
|
+
repository.platform.cpu,
|
|
713
|
+
"--os",
|
|
714
|
+
repository.platform.os
|
|
715
|
+
] :
|
|
716
|
+
[];
|
|
759
717
|
|
|
760
|
-
|
|
761
|
-
throw new Error(`Beta release must be from version branch v${this.majorVersion}.${this.minorVersion}`);
|
|
762
|
-
}
|
|
718
|
+
const branch = this.run(true, true, "git", "branch", "--show-current")[0];
|
|
763
719
|
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
}
|
|
720
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Package configuration format is known.
|
|
721
|
+
const packageConfiguration = JSON.parse(fs.readFileSync(PACKAGE_CONFIGURATION_PATH).toString()) as PackageConfiguration;
|
|
767
722
|
|
|
768
|
-
|
|
723
|
+
const version = packageConfiguration.version;
|
|
769
724
|
|
|
770
|
-
|
|
771
|
-
if (currentDependencies !== undefined) {
|
|
772
|
-
for (const dependency of Object.keys(currentDependencies)) {
|
|
773
|
-
const dependencyRepositoryName = this.dependencyRepositoryName(dependency);
|
|
725
|
+
const parsedVersion = /^(\d+)\.(\d+)\.(\d+)(-(alpha|beta))?$/.exec(version);
|
|
774
726
|
|
|
775
|
-
|
|
776
|
-
|
|
727
|
+
if (parsedVersion === null) {
|
|
728
|
+
throw new Error(`Invalid package version ${version}`);
|
|
729
|
+
}
|
|
777
730
|
|
|
778
|
-
|
|
731
|
+
const majorVersion = Number(parsedVersion[1]);
|
|
732
|
+
const minorVersion = Number(parsedVersion[2]);
|
|
733
|
+
const patchVersion = Number(parsedVersion[3]);
|
|
734
|
+
const preReleaseIdentifier = parsedVersion.length === 6 ? parsedVersion[5] : null;
|
|
779
735
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
currentDependencies[dependency] = this.releaseType;
|
|
783
|
-
} else {
|
|
784
|
-
const dependencyRepository = this.configuration.repositories[dependencyRepositoryName];
|
|
736
|
+
const dependencyPackageNames: string[] = [];
|
|
737
|
+
const allDependencyPackageNames: string[] = [];
|
|
785
738
|
|
|
786
|
-
|
|
739
|
+
let anyDependenciesUpdated = false;
|
|
787
740
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
741
|
+
for (const dependencies of [packageConfiguration.devDependencies ?? {}, packageConfiguration.dependencies ?? {}]) {
|
|
742
|
+
for (const dependencyPackageName of Object.keys(dependencies)) {
|
|
743
|
+
const dependencyRepositoryName = this.dependencyRepositoryName(dependencyPackageName);
|
|
744
|
+
|
|
745
|
+
// Dependency repository name is null if dependency is not within the organization.
|
|
746
|
+
if (dependencyRepositoryName !== null) {
|
|
747
|
+
logger.trace(`Organization dependency ${dependencyPackageName} from package configuration`);
|
|
791
748
|
|
|
792
|
-
|
|
749
|
+
// Check every dependency for logging purposes.
|
|
750
|
+
if (this.isOrganizationDependencyUpdated(phaseDateTime, dependencyRepositoryName, false)) {
|
|
751
|
+
anyDependenciesUpdated = true;
|
|
793
752
|
}
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
753
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
logger.warn(`Additional dependency ${additionalDependency} already exists`);
|
|
803
|
-
} else {
|
|
804
|
-
logger.trace(`Organization dependency from additional dependencies ${additionalDependency}:null`);
|
|
754
|
+
for (const dependencyDependencyPackageName of this.repositoryStates[dependencyRepositoryName].allDependencyPackageNames) {
|
|
755
|
+
if (!allDependencyPackageNames.includes(dependencyDependencyPackageName)) {
|
|
756
|
+
logger.trace(`Organization dependency ${dependencyDependencyPackageName} from dependencies`);
|
|
805
757
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
}
|
|
758
|
+
allDependencyPackageNames.push(dependencyDependencyPackageName);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
810
761
|
|
|
811
|
-
|
|
812
|
-
for (const dependencyRepositoryName of Object.keys(this.organizationDependencies)) {
|
|
813
|
-
const dependencyOrganizationDependencies = this.allOrganizationDependencies[dependencyRepositoryName];
|
|
762
|
+
dependencyPackageNames.push(dependencyPackageName);
|
|
814
763
|
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
logger.trace(`Organization dependency from dependencies ${dependencyDependencyRepositoryName}:${dependencyDependency}`);
|
|
764
|
+
// Current dependency package name goes in last to preserve hierarchy.
|
|
765
|
+
allDependencyPackageNames.push(dependencyPackageName);
|
|
818
766
|
|
|
819
|
-
|
|
767
|
+
// Dependency changes will ultimately be discarded if there are no changes and no updates to repository states.
|
|
768
|
+
dependencies[dependencyPackageName] = this.dependencyVersionFor(dependencyRepositoryName, this.configuration.repositories[dependencyRepositoryName]);
|
|
769
|
+
}
|
|
820
770
|
}
|
|
821
771
|
}
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
// Save organization dependencies for future repositories.
|
|
825
|
-
this.allOrganizationDependencies[repositoryName] = this.organizationDependencies;
|
|
826
772
|
|
|
827
|
-
|
|
773
|
+
if (repository.additionalDependencies !== undefined) {
|
|
774
|
+
const additionalRepositoryNames: string[] = [];
|
|
828
775
|
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
getLastPublished = repository => repository.lastAlphaPublished;
|
|
832
|
-
break;
|
|
833
|
-
|
|
834
|
-
case "beta":
|
|
835
|
-
getLastPublished = repository => repository.lastBetaPublished;
|
|
836
|
-
break;
|
|
837
|
-
|
|
838
|
-
case "production":
|
|
839
|
-
getLastPublished = repository => repository.lastProductionPublished;
|
|
840
|
-
break;
|
|
841
|
-
}
|
|
776
|
+
for (const additionalDependencyRepositoryName of repository.additionalDependencies) {
|
|
777
|
+
const additionalDependencyPackageName = `${this.atOrganization}/${additionalDependencyRepositoryName}`;
|
|
842
778
|
|
|
843
|
-
|
|
779
|
+
if (allDependencyPackageNames.includes(additionalDependencyPackageName) || additionalRepositoryNames.includes(additionalDependencyRepositoryName)) {
|
|
780
|
+
logger.warn(`Additional dependency repository ${additionalDependencyRepositoryName} already a dependency`);
|
|
781
|
+
} else {
|
|
782
|
+
logger.trace(`Organization dependency ${additionalDependencyRepositoryName} from additional dependencies`);
|
|
844
783
|
|
|
845
|
-
|
|
784
|
+
// Check every dependency for logging purposes.
|
|
785
|
+
if (this.isOrganizationDependencyUpdated(phaseDateTime, additionalDependencyRepositoryName, true)) {
|
|
786
|
+
anyDependenciesUpdated = true;
|
|
787
|
+
}
|
|
846
788
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
789
|
+
additionalRepositoryNames.push(additionalDependencyRepositoryName);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
850
793
|
|
|
851
|
-
|
|
852
|
-
|
|
794
|
+
this._repositoryState = {
|
|
795
|
+
repositoryName,
|
|
796
|
+
repository,
|
|
797
|
+
phaseState,
|
|
798
|
+
phaseDateTime,
|
|
799
|
+
npmPlatformArgs,
|
|
800
|
+
branch,
|
|
801
|
+
packageConfiguration,
|
|
802
|
+
majorVersion,
|
|
803
|
+
minorVersion,
|
|
804
|
+
patchVersion,
|
|
805
|
+
preReleaseIdentifier,
|
|
806
|
+
dependencyPackageNames,
|
|
807
|
+
allDependencyPackageNames,
|
|
808
|
+
anyDependenciesUpdated
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
// Save repository state for future repositories.
|
|
812
|
+
this.repositoryStates[repositoryName] = this._repositoryState;
|
|
813
|
+
|
|
814
|
+
if (!this.isValidBranch()) {
|
|
815
|
+
throw new Error(`Branch ${branch} is not valid for ${this.phase} phase`);
|
|
853
816
|
}
|
|
854
817
|
|
|
855
|
-
|
|
856
|
-
logger.info(`Repository ${dependencyRepositoryName} recently published`);
|
|
818
|
+
const parsedBranch = /^v(\d+)\.(\d+)/.exec(branch);
|
|
857
819
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
820
|
+
// If this is a version branch, update the package version if required.
|
|
821
|
+
if (parsedBranch !== null) {
|
|
822
|
+
const branchMajorVersion = Number(parsedBranch[1]);
|
|
823
|
+
const branchMinorVersion = Number(parsedBranch[2]);
|
|
862
824
|
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
825
|
+
// If in a version branch and version doesn't match, update it.
|
|
826
|
+
if (majorVersion !== branchMajorVersion || minorVersion !== branchMinorVersion) {
|
|
827
|
+
if (majorVersion !== branchMajorVersion ? majorVersion !== branchMajorVersion - 1 : minorVersion !== branchMinorVersion - 1) {
|
|
828
|
+
throw new Error(`Invalid transition from ${majorVersion}.${minorVersion} to ${branchMajorVersion}.${branchMinorVersion}`);
|
|
829
|
+
}
|
|
866
830
|
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
this.commitUpdatedPackageVersion(PACKAGE_CONFIGURATION_PATH);
|
|
831
|
+
this.updatePackageVersion(branchMajorVersion, branchMinorVersion, 0, null);
|
|
832
|
+
this.commitUpdatedPackageVersion(PACKAGE_CONFIGURATION_PATH);
|
|
833
|
+
}
|
|
871
834
|
}
|
|
872
|
-
}
|
|
873
835
|
|
|
874
|
-
try {
|
|
875
836
|
// eslint-disable-next-line no-await-in-loop -- Next iteration requires previous to finish.
|
|
876
837
|
await this.publish();
|
|
877
838
|
} finally {
|
|
839
|
+
// Clear repository state to prevent accidental access.
|
|
840
|
+
this._repositoryState = undefined;
|
|
841
|
+
|
|
842
|
+
// Return to the start directory.
|
|
843
|
+
process.chdir(startDirectory);
|
|
844
|
+
|
|
878
845
|
this.saveConfiguration();
|
|
879
846
|
}
|
|
880
847
|
// Non-external repositories may be private and not accessible to all developers.
|
|
@@ -883,15 +850,12 @@ export abstract class Publish {
|
|
|
883
850
|
}
|
|
884
851
|
}
|
|
885
852
|
|
|
886
|
-
// Return to the start directory.
|
|
887
|
-
process.chdir(startDirectory);
|
|
888
|
-
|
|
889
853
|
this.finalizeAll();
|
|
890
854
|
|
|
891
855
|
this.saveConfiguration();
|
|
892
856
|
|
|
893
|
-
if (this.
|
|
894
|
-
this.commitModified(`Published ${this.
|
|
857
|
+
if (this.phase !== "alpha") {
|
|
858
|
+
this.commitModified(`Published ${this.phase} release.`, SHARED_CONFIGURATION_PATH);
|
|
895
859
|
}
|
|
896
860
|
}
|
|
897
861
|
|