@smoothbricks/cli 0.1.1 → 0.3.0
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 +161 -32
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +110 -10
- package/dist/devenv/index.d.ts +10 -0
- package/dist/devenv/index.d.ts.map +1 -0
- package/dist/devenv/index.js +27 -0
- package/dist/generate/index.d.ts +20 -0
- package/dist/generate/index.d.ts.map +1 -0
- package/dist/generate/index.js +47 -0
- package/dist/lib/cli-package.d.ts +4 -0
- package/dist/lib/cli-package.d.ts.map +1 -0
- package/dist/lib/cli-package.js +15 -0
- package/dist/lib/run.d.ts +6 -0
- package/dist/lib/run.d.ts.map +1 -1
- package/dist/lib/run.js +32 -0
- package/dist/lib/workspace.d.ts +25 -1
- package/dist/lib/workspace.d.ts.map +1 -1
- package/dist/lib/workspace.js +79 -17
- package/dist/monorepo/commit-msg.d.ts +8 -1
- package/dist/monorepo/commit-msg.d.ts.map +1 -1
- package/dist/monorepo/commit-msg.js +85 -7
- package/dist/monorepo/index.d.ts +19 -2
- package/dist/monorepo/index.d.ts.map +1 -1
- package/dist/monorepo/index.js +104 -16
- package/dist/monorepo/lockfile.d.ts.map +1 -1
- package/dist/monorepo/lockfile.js +9 -0
- package/dist/monorepo/managed-files.js +1 -1
- package/dist/monorepo/nx-sync.d.ts +2 -1
- package/dist/monorepo/nx-sync.d.ts.map +1 -1
- package/dist/monorepo/nx-sync.js +8 -2
- package/dist/monorepo/package-hygiene.d.ts +6 -2
- package/dist/monorepo/package-hygiene.d.ts.map +1 -1
- package/dist/monorepo/package-hygiene.js +12 -4
- package/dist/monorepo/package-policy.d.ts +13 -4
- package/dist/monorepo/package-policy.d.ts.map +1 -1
- package/dist/monorepo/package-policy.js +208 -113
- package/dist/monorepo/packed-package.d.ts +3 -0
- package/dist/monorepo/packed-package.d.ts.map +1 -1
- package/dist/monorepo/packed-package.js +68 -36
- package/dist/monorepo/packs/index.d.ts +20 -1
- package/dist/monorepo/packs/index.d.ts.map +1 -1
- package/dist/monorepo/packs/index.js +238 -19
- package/dist/monorepo/publish-workflow.d.ts +0 -4
- package/dist/monorepo/publish-workflow.d.ts.map +1 -1
- package/dist/monorepo/publish-workflow.js +7 -15
- package/dist/monorepo/tool-validation.d.ts +22 -0
- package/dist/monorepo/tool-validation.d.ts.map +1 -0
- package/dist/monorepo/tool-validation.js +399 -0
- package/dist/nx/index.d.ts +25 -0
- package/dist/nx/index.d.ts.map +1 -0
- package/dist/nx/index.js +112 -0
- package/dist/release/bootstrap-npm-packages.d.ts +19 -0
- package/dist/release/bootstrap-npm-packages.d.ts.map +1 -0
- package/dist/release/bootstrap-npm-packages.js +58 -0
- package/dist/release/candidates.d.ts +11 -0
- package/dist/release/candidates.d.ts.map +1 -0
- package/dist/release/candidates.js +181 -0
- package/dist/release/core.d.ts +4 -1
- package/dist/release/core.d.ts.map +1 -1
- package/dist/release/core.js +76 -9
- package/dist/release/github-release.d.ts +1 -0
- package/dist/release/github-release.d.ts.map +1 -1
- package/dist/release/github-release.js +3 -3
- package/dist/release/index.d.ts +32 -1
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +488 -64
- package/dist/release/npm-auth.d.ts +0 -1
- package/dist/release/npm-auth.d.ts.map +1 -1
- package/dist/release/npm-auth.js +4 -16
- package/dist/release/orchestration.d.ts +11 -2
- package/dist/release/orchestration.d.ts.map +1 -1
- package/dist/release/orchestration.js +41 -3
- package/dist/release/publish-plan.js +1 -1
- package/managed/raw/git-format-staged.yml +54 -0
- package/managed/raw/tooling/git-hooks/commit-msg.sh +1 -1
- package/managed/templates/github/actions/setup-devenv/action.yml +1 -7
- package/managed/templates/github/workflows/ci.yml +4 -2
- package/package.json +15 -8
- package/src/cli.ts +153 -22
- package/src/devenv/index.test.ts +49 -0
- package/src/devenv/index.ts +38 -0
- package/src/generate/index.ts +92 -0
- package/src/lib/cli-package.ts +18 -0
- package/src/lib/run.ts +44 -0
- package/src/lib/workspace.ts +112 -17
- package/src/monorepo/__tests__/publish-workflow.test.ts +16 -9
- package/src/monorepo/commit-msg.test.ts +45 -0
- package/src/monorepo/commit-msg.ts +107 -7
- package/src/monorepo/index.ts +142 -16
- package/src/monorepo/lockfile.ts +9 -0
- package/src/monorepo/managed-files.ts +1 -1
- package/src/monorepo/nx-sync.ts +9 -2
- package/src/monorepo/package-hygiene.test.ts +34 -0
- package/src/monorepo/package-hygiene.ts +26 -4
- package/src/monorepo/package-policy.test.ts +1130 -0
- package/src/monorepo/package-policy.ts +237 -114
- package/src/monorepo/packed-package.ts +89 -37
- package/src/monorepo/packs/index.test.ts +189 -0
- package/src/monorepo/packs/index.ts +311 -20
- package/src/monorepo/publish-workflow.ts +10 -19
- package/src/monorepo/setup-test-tracing.test.ts +120 -0
- package/src/monorepo/tool-validation.test.ts +261 -0
- package/src/monorepo/tool-validation.ts +462 -0
- package/src/nx/index.test.ts +73 -0
- package/src/nx/index.ts +139 -0
- package/src/release/__tests__/bootstrap-npm-packages.test.ts +127 -0
- package/src/release/__tests__/candidates.test.ts +262 -0
- package/src/release/__tests__/core-properties.test.ts +6 -6
- package/src/release/__tests__/core-scenarios.test.ts +27 -20
- package/src/release/__tests__/core.test.ts +52 -5
- package/src/release/__tests__/fixture-repo.test.ts +90 -31
- package/src/release/__tests__/github-release.test.ts +22 -24
- package/src/release/__tests__/helpers/fixture-repo.ts +1 -0
- package/src/release/__tests__/npm-auth.test.ts +12 -21
- package/src/release/__tests__/orchestration.test.ts +142 -12
- package/src/release/__tests__/publish-plan.test.ts +9 -3
- package/src/release/__tests__/retag-unpublished.test.ts +10 -10
- package/src/release/__tests__/trust-publisher.test.ts +165 -0
- package/src/release/bootstrap-npm-packages.ts +88 -0
- package/src/release/candidates.ts +225 -0
- package/src/release/core.ts +96 -10
- package/src/release/github-release.ts +3 -3
- package/src/release/index.ts +658 -74
- package/src/release/npm-auth.ts +4 -33
- package/src/release/orchestration.ts +60 -5
- package/src/release/publish-plan.ts +1 -1
- package/dist/nx-version-actions.cjs +0 -25
- package/dist/nx-version-actions.d.cts +0 -6
- package/dist/nx-version-actions.d.cts.map +0 -1
- package/managed/raw/.git-format-staged.yml +0 -47
- package/src/nx-version-actions.cts +0 -36
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { isRecord } from '../lib/json.js';
|
|
2
|
+
import type { ReleasePackageInfo } from './core.js';
|
|
3
|
+
import { releaseTag } from './core.js';
|
|
4
|
+
|
|
5
|
+
export interface AutoReleaseCandidateShell {
|
|
6
|
+
gitRefExists(ref: string): Promise<boolean>;
|
|
7
|
+
packageChangedFilesSince(ref: string, packagePath: string): Promise<string[]>;
|
|
8
|
+
packageJsonAtRef(ref: string, packagePath: string): Promise<Record<string, unknown> | null>;
|
|
9
|
+
currentPackageJson(packagePath: string): Promise<Record<string, unknown> | null>;
|
|
10
|
+
packageBuildInputPatterns(projectName: string, packagePath: string): Promise<string[]>;
|
|
11
|
+
packageHasHistory(packagePath: string): Promise<boolean>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const releasableManifestKeys = [
|
|
15
|
+
'author',
|
|
16
|
+
'bin',
|
|
17
|
+
'browser',
|
|
18
|
+
'bugs',
|
|
19
|
+
'cpu',
|
|
20
|
+
'dependencies',
|
|
21
|
+
'description',
|
|
22
|
+
'engines',
|
|
23
|
+
'exports',
|
|
24
|
+
'files',
|
|
25
|
+
'funding',
|
|
26
|
+
'homepage',
|
|
27
|
+
'imports',
|
|
28
|
+
'keywords',
|
|
29
|
+
'license',
|
|
30
|
+
'main',
|
|
31
|
+
'module',
|
|
32
|
+
'name',
|
|
33
|
+
'optionalDependencies',
|
|
34
|
+
'os',
|
|
35
|
+
'peerDependencies',
|
|
36
|
+
'peerDependenciesMeta',
|
|
37
|
+
'publishConfig',
|
|
38
|
+
'repository',
|
|
39
|
+
'sideEffects',
|
|
40
|
+
'types',
|
|
41
|
+
'typesVersions',
|
|
42
|
+
] as const;
|
|
43
|
+
|
|
44
|
+
export async function autoReleaseCandidatePackages<Package extends ReleasePackageInfo>(
|
|
45
|
+
shell: AutoReleaseCandidateShell,
|
|
46
|
+
packages: Package[],
|
|
47
|
+
): Promise<Package[]> {
|
|
48
|
+
const candidates: Package[] = [];
|
|
49
|
+
for (const pkg of packages) {
|
|
50
|
+
if (await isAutoReleaseCandidate(shell, pkg)) {
|
|
51
|
+
candidates.push(pkg);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return candidates;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function isAutoReleaseCandidate<Package extends ReleasePackageInfo>(
|
|
58
|
+
shell: AutoReleaseCandidateShell,
|
|
59
|
+
pkg: Package,
|
|
60
|
+
): Promise<boolean> {
|
|
61
|
+
const tagRef = `refs/tags/${releaseTag(pkg)}`;
|
|
62
|
+
if (await shell.gitRefExists(tagRef)) {
|
|
63
|
+
return packageHasReleasableChangesSince(shell, tagRef, pkg);
|
|
64
|
+
}
|
|
65
|
+
return !pkg.version.includes('-') && shell.packageHasHistory(pkg.path);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function packageHasReleasableChangesSince<Package extends ReleasePackageInfo>(
|
|
69
|
+
shell: AutoReleaseCandidateShell,
|
|
70
|
+
ref: string,
|
|
71
|
+
pkg: Package,
|
|
72
|
+
): Promise<boolean> {
|
|
73
|
+
const changedFiles = await shell.packageChangedFilesSince(ref, pkg.path);
|
|
74
|
+
if (changedFiles.length === 0) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
const currentManifest = await shell.currentPackageJson(pkg.path);
|
|
78
|
+
const buildInputPatterns = await shell.packageBuildInputPatterns(pkg.projectName, pkg.path);
|
|
79
|
+
for (const changedFile of changedFiles) {
|
|
80
|
+
if (changedFile === 'package.json') {
|
|
81
|
+
const previousManifest = await shell.packageJsonAtRef(ref, pkg.path);
|
|
82
|
+
if (!previousManifest || !currentManifest || releasableManifestChanged(previousManifest, currentManifest)) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (isReleasablePackagePath(changedFile, currentManifest, buildInputPatterns)) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function releasableManifestChanged(
|
|
95
|
+
previousManifest: Record<string, unknown>,
|
|
96
|
+
currentManifest: Record<string, unknown>,
|
|
97
|
+
): boolean {
|
|
98
|
+
for (const key of releasableManifestKeys) {
|
|
99
|
+
if (!stableJsonEqual(previousManifest[key], currentManifest[key])) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isReleasablePackagePath(
|
|
107
|
+
path: string,
|
|
108
|
+
manifest: Record<string, unknown> | null,
|
|
109
|
+
buildInputPatterns: string[],
|
|
110
|
+
): boolean {
|
|
111
|
+
return (
|
|
112
|
+
isBuildInputPath(path, buildInputPatterns) || isPackageMetadataPath(path) || isManifestFilesPath(path, manifest)
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function isBuildInputPath(path: string, patterns: string[]): boolean {
|
|
117
|
+
if (isReleaseIgnoredBuildInputPath(path)) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
let matched = false;
|
|
121
|
+
for (const pattern of patterns) {
|
|
122
|
+
const excluded = pattern.startsWith('!');
|
|
123
|
+
const rawPattern = excluded ? pattern.slice(1) : pattern;
|
|
124
|
+
if (matchesBuildInputPattern(path, rawPattern)) {
|
|
125
|
+
matched = !excluded;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return matched;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function matchesBuildInputPattern(path: string, pattern: string): boolean {
|
|
132
|
+
const normalized = pattern.replace(/^\.\//, '').replace(/\/$/, '');
|
|
133
|
+
if (!normalized) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
return globPatternToRegExp(normalized).test(path);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function globPatternToRegExp(pattern: string): RegExp {
|
|
140
|
+
let source = '^';
|
|
141
|
+
for (let index = 0; index < pattern.length; index += 1) {
|
|
142
|
+
const char = pattern[index];
|
|
143
|
+
if (char === '*') {
|
|
144
|
+
if (pattern[index + 1] === '*') {
|
|
145
|
+
if (pattern[index + 2] === '/') {
|
|
146
|
+
source += '(?:.*/)?';
|
|
147
|
+
index += 2;
|
|
148
|
+
} else {
|
|
149
|
+
source += '.*';
|
|
150
|
+
index += 1;
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
source += '[^/]*';
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
source += escapeRegExpChar(char);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return new RegExp(`${source}$`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function escapeRegExpChar(char: string | undefined): string {
|
|
163
|
+
if (!char) {
|
|
164
|
+
return '';
|
|
165
|
+
}
|
|
166
|
+
return /[\\^$+?.()|[\]{}]/.test(char) ? `\\${char}` : char;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function isReleaseIgnoredBuildInputPath(path: string): boolean {
|
|
170
|
+
return (
|
|
171
|
+
path === 'package.json' ||
|
|
172
|
+
path === 'tsconfig.test.json' ||
|
|
173
|
+
path.includes('/__tests__/') ||
|
|
174
|
+
path.endsWith('.test.ts') ||
|
|
175
|
+
path.endsWith('.test.tsx') ||
|
|
176
|
+
path.endsWith('.spec.ts') ||
|
|
177
|
+
path.endsWith('.spec.tsx')
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function isPackageMetadataPath(path: string): boolean {
|
|
182
|
+
return /^(README|LICENSE|CHANGELOG)(\.|$)/.test(path);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function isManifestFilesPath(path: string, manifest: Record<string, unknown> | null): boolean {
|
|
186
|
+
const files = manifest?.files;
|
|
187
|
+
if (!Array.isArray(files)) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
for (const entry of files) {
|
|
191
|
+
if (typeof entry !== 'string' || entry.length === 0 || entry.startsWith('!')) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (matchesManifestFilesEntry(path, entry)) {
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function matchesManifestFilesEntry(path: string, entry: string): boolean {
|
|
202
|
+
const normalized = entry.replace(/^\.\//, '').replace(/\/$/, '');
|
|
203
|
+
if (!normalized || normalized.includes('*')) {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
return path === normalized || path.startsWith(`${normalized}/`);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function stableJsonEqual(left: unknown, right: unknown): boolean {
|
|
210
|
+
return JSON.stringify(stableJson(left)) === JSON.stringify(stableJson(right));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function stableJson(value: unknown): unknown {
|
|
214
|
+
if (Array.isArray(value)) {
|
|
215
|
+
return value.map(stableJson);
|
|
216
|
+
}
|
|
217
|
+
if (isRecord(value)) {
|
|
218
|
+
const normalized: Record<string, unknown> = {};
|
|
219
|
+
for (const key of Object.keys(value).sort()) {
|
|
220
|
+
normalized[key] = stableJson(value[key]);
|
|
221
|
+
}
|
|
222
|
+
return normalized;
|
|
223
|
+
}
|
|
224
|
+
return value;
|
|
225
|
+
}
|
package/src/release/core.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export interface ReleasePackageInfo {
|
|
2
2
|
name: string;
|
|
3
|
+
projectName: string;
|
|
3
4
|
path: string;
|
|
4
5
|
version: string;
|
|
5
6
|
}
|
|
@@ -43,10 +44,18 @@ export interface ReleasePlanningShell {
|
|
|
43
44
|
durableTagState(pkg: ReleasePackageInfo, tag: string): Promise<DurableTagState>;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
export function releaseTag(pkg: Pick<ReleasePackageInfo, '
|
|
47
|
+
export function releaseTag(pkg: Pick<ReleasePackageInfo, 'projectName' | 'version'>): string {
|
|
48
|
+
return `${pkg.projectName}@${pkg.version}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function legacyReleaseTag(pkg: Pick<ReleasePackageInfo, 'name' | 'version'>): string {
|
|
47
52
|
return `${pkg.name}@${pkg.version}`;
|
|
48
53
|
}
|
|
49
54
|
|
|
55
|
+
export function releaseTagAliases(pkg: Pick<ReleasePackageInfo, 'name' | 'projectName' | 'version'>): string[] {
|
|
56
|
+
return [...new Set([releaseTag(pkg), legacyReleaseTag(pkg)])];
|
|
57
|
+
}
|
|
58
|
+
|
|
50
59
|
export function npmDistTagForVersion(version: string): string {
|
|
51
60
|
return version.includes('-') ? 'next' : 'latest';
|
|
52
61
|
}
|
|
@@ -56,7 +65,7 @@ export function releasePackageForTag<Package extends Omit<ReleasePackageInfo, 'v
|
|
|
56
65
|
tag: string,
|
|
57
66
|
): { pkg: Package; version: string } | null {
|
|
58
67
|
for (const pkg of packages) {
|
|
59
|
-
const prefix = `${pkg.
|
|
68
|
+
const prefix = `${pkg.projectName}@`;
|
|
60
69
|
if (tag.startsWith(prefix)) {
|
|
61
70
|
const version = tag.slice(prefix.length);
|
|
62
71
|
if (!version) {
|
|
@@ -84,13 +93,14 @@ export async function collectOwnedReleaseTagRecords<Package extends Omit<Release
|
|
|
84
93
|
ref: string,
|
|
85
94
|
shell: ReleasePlanningShell,
|
|
86
95
|
): Promise<Array<ReleaseTagRecord<Package & { version: string }>>> {
|
|
87
|
-
const
|
|
88
|
-
|
|
96
|
+
const candidates: Array<{
|
|
97
|
+
tag: GitReleaseTagInfo;
|
|
98
|
+
pkg: Package & { version: string };
|
|
99
|
+
}> = [];
|
|
100
|
+
const durableStates = new BoundedPromiseRunner(8);
|
|
101
|
+
|
|
89
102
|
for (const tag of await shell.listReleaseTagsByCreatorDate()) {
|
|
90
103
|
const match = releasePackageForTag(packages, tag.name);
|
|
91
|
-
if (match && completedPackages.has(match.pkg.name)) {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
104
|
if (!match || !(await shell.isAncestor(tag.sha, ref))) {
|
|
95
105
|
continue;
|
|
96
106
|
}
|
|
@@ -103,15 +113,91 @@ export async function collectOwnedReleaseTagRecords<Package extends Omit<Release
|
|
|
103
113
|
);
|
|
104
114
|
}
|
|
105
115
|
const pkg = { ...match.pkg, version: match.version };
|
|
106
|
-
|
|
107
|
-
|
|
116
|
+
candidates.push({ tag, pkg });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const records: Array<ReleaseTagRecord<Package & { version: string }>> = [];
|
|
120
|
+
const completedPackages = new Set<string>();
|
|
121
|
+
const activePackages = new Set<string>();
|
|
122
|
+
const states = new Map<number, Promise<DurableTagState>>();
|
|
123
|
+
|
|
124
|
+
// Run durable-state checks concurrently across packages, but do not query an
|
|
125
|
+
// older tag for the same package until its newer tag proves incomplete.
|
|
126
|
+
const scheduleFrom = (startIndex: number) => {
|
|
127
|
+
for (let index = startIndex; index < candidates.length; index += 1) {
|
|
128
|
+
if (states.size >= 8) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const candidate = candidates[index];
|
|
132
|
+
if (!candidate || states.has(index) || completedPackages.has(candidate.pkg.name)) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (activePackages.has(candidate.pkg.name)) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
activePackages.add(candidate.pkg.name);
|
|
139
|
+
states.set(
|
|
140
|
+
index,
|
|
141
|
+
durableStates.run(() => shell.durableTagState(candidate.pkg, candidate.tag.name)),
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
for (const candidate of candidates) {
|
|
147
|
+
const index = candidates.indexOf(candidate);
|
|
148
|
+
scheduleFrom(index);
|
|
149
|
+
if (completedPackages.has(candidate.pkg.name)) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const state = await states.get(index);
|
|
153
|
+
if (!state) {
|
|
154
|
+
throw new Error(`Release tag ${candidate.tag.name} lost durable state planning.`);
|
|
155
|
+
}
|
|
156
|
+
activePackages.delete(candidate.pkg.name);
|
|
157
|
+
states.delete(index);
|
|
158
|
+
records.push(
|
|
159
|
+
classifyReleaseTag(
|
|
160
|
+
{ tag: candidate.tag.name, sha: candidate.tag.sha, timestamp: candidate.tag.timestamp, pkg: candidate.pkg },
|
|
161
|
+
state,
|
|
162
|
+
),
|
|
163
|
+
);
|
|
108
164
|
if (state.npmPublished && state.githubReleaseExists) {
|
|
109
|
-
completedPackages.add(pkg.name);
|
|
165
|
+
completedPackages.add(candidate.pkg.name);
|
|
110
166
|
}
|
|
111
167
|
}
|
|
112
168
|
return records;
|
|
113
169
|
}
|
|
114
170
|
|
|
171
|
+
class BoundedPromiseRunner {
|
|
172
|
+
private active = 0;
|
|
173
|
+
private readonly waiting: Array<() => void> = [];
|
|
174
|
+
|
|
175
|
+
constructor(private readonly limit: number) {}
|
|
176
|
+
|
|
177
|
+
async run<T>(operation: () => Promise<T>): Promise<T> {
|
|
178
|
+
await this.acquire();
|
|
179
|
+
try {
|
|
180
|
+
return await operation();
|
|
181
|
+
} finally {
|
|
182
|
+
this.release();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private async acquire(): Promise<void> {
|
|
187
|
+
if (this.active < this.limit) {
|
|
188
|
+
this.active += 1;
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
await new Promise<void>((resolve) => this.waiting.push(resolve));
|
|
192
|
+
this.active += 1;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private release(): void {
|
|
196
|
+
this.active -= 1;
|
|
197
|
+
this.waiting.shift()?.();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
115
201
|
export function groupReleaseTargets<Package extends ReleasePackageInfo>(
|
|
116
202
|
records: ReleaseTagRecord<Package>[],
|
|
117
203
|
): ReleaseTarget<Package>[] {
|
|
@@ -39,7 +39,7 @@ export async function renderNxProjectChangelogContents(input: RenderNxProjectCha
|
|
|
39
39
|
nxRenderOnlyReleaseConfig,
|
|
40
40
|
false,
|
|
41
41
|
)(nxProjectChangelogArgs(input.pkg, input.previousTag, input.dryRun));
|
|
42
|
-
return projectChangelogContents(result, input.pkg.
|
|
42
|
+
return projectChangelogContents(result, input.pkg.projectName);
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -65,7 +65,7 @@ export async function createOrUpdateGithubRelease(
|
|
|
65
65
|
export function nxProjectChangelogArgs(pkg: ReleasePackageInfo, previousTag: string | null, dryRun: boolean) {
|
|
66
66
|
const base = {
|
|
67
67
|
version: pkg.version,
|
|
68
|
-
projects: [pkg.
|
|
68
|
+
projects: [pkg.projectName],
|
|
69
69
|
gitCommit: false,
|
|
70
70
|
gitTag: false,
|
|
71
71
|
gitPush: false,
|
|
@@ -112,7 +112,7 @@ function isPrereleaseVersion(version: string): boolean {
|
|
|
112
112
|
return version.includes('-');
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
async function withNxWorkspaceRoot<T>(root: string, run: () => Promise<T>): Promise<T> {
|
|
115
|
+
export async function withNxWorkspaceRoot<T>(root: string, run: () => Promise<T>): Promise<T> {
|
|
116
116
|
const workspaceRootModule = await import('nx/src/utils/workspace-root.js');
|
|
117
117
|
const previousWorkspaceRoot = workspaceRootModule.workspaceRoot;
|
|
118
118
|
const previousEnvWorkspaceRoot = process.env.NX_WORKSPACE_ROOT_PATH;
|