@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
|
@@ -1,8 +1,57 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
|
+
import { applyWorkspaceBoundedTestTargetPolicy, checkWorkspaceBoundedTestTargetPolicy, } from '@smoothbricks/nx-plugin/bounded-test-policy';
|
|
3
|
+
import { applyPackageTargetPolicy, checkPackageTargetPolicy, } from '@smoothbricks/nx-plugin/package-target-policy';
|
|
4
|
+
import { applyReleaseConfigPolicy, checkReleaseConfigPolicy, SMOO_NX_RELEASE_TAG_PATTERN, SMOO_NX_VERSION_ACTIONS, } from '@smoothbricks/nx-plugin/release-config-policy';
|
|
5
|
+
import { applyTypecheckTestPolicy, checkTypecheckTestPolicy } from '@smoothbricks/nx-plugin/typecheck-test-policy';
|
|
6
|
+
import { applyWorkspaceConfigPolicy, checkWorkspaceConfigPolicy, } from '@smoothbricks/nx-plugin/workspace-config-policy';
|
|
2
7
|
import { getOrCreateRecord, hasOwnString, isRecord, readJsonObject, recordProperty, requiredJsonObject, setMissingStringProperty, setStringProperty, stringProperty, writeJsonObject, } from '../lib/json.js';
|
|
3
|
-
import { getWorkspacePackages, listPackageJsonRecords, listPublicPackages, packageRepositoryInfo, repositoryInfo, sameRepositoryAfterNormalization, workspaceDependencyFields, } from '../lib/workspace.js';
|
|
4
|
-
export
|
|
5
|
-
|
|
8
|
+
import { getWorkspacePackageManifests, getWorkspacePackages, listPackageJsonRecords, listPublicPackages, packageRepositoryInfo, repositoryInfo, sameRepositoryAfterNormalization, workspaceDependencyFields, } from '../lib/workspace.js';
|
|
9
|
+
export { SMOO_NX_RELEASE_TAG_PATTERN, SMOO_NX_VERSION_ACTIONS };
|
|
10
|
+
const extraCommitScopes = ['release'];
|
|
11
|
+
const rootScriptPolicy = {
|
|
12
|
+
lint: 'nx run-many -t lint',
|
|
13
|
+
'lint:fix': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml --unstaged',
|
|
14
|
+
'format:staged': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml',
|
|
15
|
+
'format:changed': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml --also-unstaged',
|
|
16
|
+
};
|
|
17
|
+
export function applyFixableMonorepoDefaults(root) {
|
|
18
|
+
applyRootScriptDefaults(root);
|
|
19
|
+
applyNxPluginDefaults(root);
|
|
20
|
+
applyNxProjectNameDefaults(root);
|
|
21
|
+
}
|
|
22
|
+
export function applyRootScriptDefaults(root) {
|
|
23
|
+
const rootPackagePath = join(root, 'package.json');
|
|
24
|
+
const rootPackage = readJsonObject(rootPackagePath);
|
|
25
|
+
if (!rootPackage) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const scripts = getOrCreateRecord(rootPackage, 'scripts');
|
|
29
|
+
let changed = false;
|
|
30
|
+
for (const [name, command] of Object.entries(rootScriptPolicy)) {
|
|
31
|
+
changed = setStringProperty(scripts, name, command) || changed;
|
|
32
|
+
}
|
|
33
|
+
const nx = getOrCreateRecord(rootPackage, 'nx');
|
|
34
|
+
if (!Array.isArray(nx.includedScripts) || nx.includedScripts.length !== 0) {
|
|
35
|
+
nx.includedScripts = [];
|
|
36
|
+
changed = true;
|
|
37
|
+
}
|
|
38
|
+
changed = sortRecordInPlace(scripts) || changed;
|
|
39
|
+
if (changed) {
|
|
40
|
+
writeJsonObject(rootPackagePath, rootPackage);
|
|
41
|
+
console.log('updated package.json root smoo scripts');
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.log('unchanged package.json root smoo scripts');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export function applyNxPluginDefaults(root) {
|
|
48
|
+
if (applyWorkspaceConfigPolicy(root)) {
|
|
49
|
+
console.log('updated nx.json smoo plugin config');
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.log('unchanged nx.json smoo plugin config');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
6
55
|
export function applyPublicPackageDefaults(root) {
|
|
7
56
|
const rootPackage = requiredJsonObject(join(root, 'package.json'));
|
|
8
57
|
const rootLicense = stringProperty(rootPackage, 'license');
|
|
@@ -39,7 +88,7 @@ export function applyPublicPackageDefaults(root) {
|
|
|
39
88
|
}
|
|
40
89
|
}
|
|
41
90
|
}
|
|
42
|
-
export function applyWorkspaceDependencyDefaults(root) {
|
|
91
|
+
export function applyWorkspaceDependencyDefaults(root, options = {}) {
|
|
43
92
|
const workspaceNames = new Set(getWorkspacePackages(root).map((pkg) => pkg.name));
|
|
44
93
|
for (const pkg of listPackageJsonRecords(root)) {
|
|
45
94
|
const changed = fixWorkspaceDependencyRanges(pkg.json, workspaceNames);
|
|
@@ -47,49 +96,76 @@ export function applyWorkspaceDependencyDefaults(root) {
|
|
|
47
96
|
writeJsonObject(pkg.packageJsonPath, pkg.json);
|
|
48
97
|
console.log(`updated ${pkg.path}/package.json workspace dependency ranges`);
|
|
49
98
|
}
|
|
50
|
-
else {
|
|
51
|
-
console.log(`unchanged ${pkg.path}/package.json workspace dependency ranges`);
|
|
52
|
-
}
|
|
53
99
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const nxJsonPath = join(root, 'nx.json');
|
|
57
|
-
const nxJson = requiredJsonObject(nxJsonPath);
|
|
58
|
-
let changed = false;
|
|
59
|
-
const release = getOrCreateRecord(nxJson, 'release');
|
|
60
|
-
changed = setStringProperty(release, 'projectsRelationship', 'independent') || changed;
|
|
61
|
-
const version = getOrCreateRecord(release, 'version');
|
|
62
|
-
changed = setStringProperty(version, 'specifierSource', 'conventional-commits') || changed;
|
|
63
|
-
changed = setStringProperty(version, 'currentVersionResolver', 'git-tag') || changed;
|
|
64
|
-
changed = setStringProperty(version, 'fallbackCurrentVersionResolver', 'disk') || changed;
|
|
65
|
-
changed = setStringProperty(version, 'versionActions', SMOO_NX_VERSION_ACTIONS) || changed;
|
|
66
|
-
if (delete version.preVersionCommand) {
|
|
67
|
-
changed = true;
|
|
100
|
+
if (applyPackageTargetPolicy(root, options)) {
|
|
101
|
+
console.log('updated package Nx target policy');
|
|
68
102
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const changelog = getOrCreateRecord(release, 'changelog');
|
|
72
|
-
changed = setBooleanProperty(changelog, 'workspaceChangelog', false) || changed;
|
|
73
|
-
const projectChangelogs = getOrCreateRecord(changelog, 'projectChangelogs');
|
|
74
|
-
changed = setBooleanProperty(projectChangelogs, 'createRelease', false) || changed;
|
|
75
|
-
changed = setBooleanProperty(projectChangelogs, 'file', false) || changed;
|
|
76
|
-
const renderOptions = getOrCreateRecord(projectChangelogs, 'renderOptions');
|
|
77
|
-
if (typeof renderOptions.authors !== 'boolean') {
|
|
78
|
-
renderOptions.authors = true;
|
|
79
|
-
changed = true;
|
|
103
|
+
else {
|
|
104
|
+
console.log('unchanged package Nx target policy');
|
|
80
105
|
}
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
changed = true;
|
|
106
|
+
if (applyTypecheckTestPolicy(root)) {
|
|
107
|
+
console.log('updated tsconfig.test.json policy');
|
|
84
108
|
}
|
|
85
|
-
|
|
86
|
-
|
|
109
|
+
else {
|
|
110
|
+
console.log('unchanged tsconfig.test.json policy');
|
|
111
|
+
}
|
|
112
|
+
if (applyWorkspaceBoundedTestTargetPolicy(root)) {
|
|
113
|
+
console.log('updated package test targets bounded execution policy');
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
console.log('unchanged package test targets bounded execution policy');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
export function applyNxReleaseDefaults(root) {
|
|
120
|
+
if (applyReleaseConfigPolicy(root)) {
|
|
87
121
|
console.log('updated nx.json release config');
|
|
88
122
|
}
|
|
89
123
|
else {
|
|
90
124
|
console.log('unchanged nx.json release config');
|
|
91
125
|
}
|
|
92
126
|
}
|
|
127
|
+
export function applyNxProjectNameDefaults(root) {
|
|
128
|
+
const rootPackage = requiredJsonObject(join(root, 'package.json'));
|
|
129
|
+
const rootName = stringProperty(rootPackage, 'name');
|
|
130
|
+
if (!rootName) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
for (const pkg of getWorkspacePackageManifests(root)) {
|
|
134
|
+
const suggestedName = suggestNxProjectName(rootName, pkg.name);
|
|
135
|
+
if (!suggestedName) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const nx = getOrCreateRecord(pkg.json, 'nx');
|
|
139
|
+
const changed = setStringProperty(nx, 'name', suggestedName);
|
|
140
|
+
if (changed) {
|
|
141
|
+
writeJsonObject(pkg.packageJsonPath, pkg.json);
|
|
142
|
+
console.log(`updated ${pkg.path}/package.json nx.name`);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
console.log(`unchanged ${pkg.path}/package.json nx.name`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
export function listValidCommitScopes(root) {
|
|
150
|
+
return new Set([...listNxProjectNames(root), ...extraCommitScopes]);
|
|
151
|
+
}
|
|
152
|
+
export function listNxProjectNames(root) {
|
|
153
|
+
const rootPackage = readJsonObject(join(root, 'package.json'));
|
|
154
|
+
const rootName = rootPackage ? stringProperty(rootPackage, 'name') : null;
|
|
155
|
+
const names = [];
|
|
156
|
+
for (const pkg of getWorkspacePackageManifests(root)) {
|
|
157
|
+
const nx = recordProperty(pkg.json, 'nx');
|
|
158
|
+
const configuredName = nx ? stringProperty(nx, 'name') : null;
|
|
159
|
+
const suggestedName = rootName ? suggestNxProjectName(rootName, pkg.name) : null;
|
|
160
|
+
if (configuredName) {
|
|
161
|
+
names.push(configuredName);
|
|
162
|
+
}
|
|
163
|
+
else if (suggestedName) {
|
|
164
|
+
names.push(suggestedName);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return names;
|
|
168
|
+
}
|
|
93
169
|
export function validateRootPackagePolicy(root) {
|
|
94
170
|
const rootPackage = readJsonObject(join(root, 'package.json'));
|
|
95
171
|
if (!rootPackage) {
|
|
@@ -109,6 +185,8 @@ export function validateRootPackagePolicy(root) {
|
|
|
109
185
|
console.error('package.json must define repository.url');
|
|
110
186
|
failures++;
|
|
111
187
|
}
|
|
188
|
+
failures += validateRootScripts(rootPackage);
|
|
189
|
+
failures += validateRootNxScriptInference(rootPackage);
|
|
112
190
|
const packageManager = stringProperty(rootPackage, 'packageManager');
|
|
113
191
|
if (!packageManager?.startsWith('bun@')) {
|
|
114
192
|
console.error('package.json packageManager must use bun@<version>');
|
|
@@ -128,83 +206,38 @@ export function validateRootPackagePolicy(root) {
|
|
|
128
206
|
return failures;
|
|
129
207
|
}
|
|
130
208
|
export function validateNxReleaseConfig(root) {
|
|
131
|
-
const nxJson = readJsonObject(join(root, 'nx.json'));
|
|
132
|
-
if (!nxJson) {
|
|
133
|
-
console.error('nx.json not found or invalid');
|
|
134
|
-
return 1;
|
|
135
|
-
}
|
|
136
|
-
const release = recordProperty(nxJson, 'release');
|
|
137
|
-
const version = release ? recordProperty(release, 'version') : null;
|
|
138
|
-
const releaseTag = release ? recordProperty(release, 'releaseTag') : null;
|
|
139
|
-
const changelog = release ? recordProperty(release, 'changelog') : null;
|
|
140
|
-
const projectChangelogs = changelog ? recordProperty(changelog, 'projectChangelogs') : null;
|
|
141
|
-
const renderOptions = projectChangelogs ? recordProperty(projectChangelogs, 'renderOptions') : null;
|
|
142
209
|
let failures = 0;
|
|
143
|
-
|
|
144
|
-
console.error(
|
|
145
|
-
failures++;
|
|
146
|
-
}
|
|
147
|
-
if (release && stringProperty(release, 'projectsRelationship') !== 'independent') {
|
|
148
|
-
console.error('nx.json release.projectsRelationship must be independent');
|
|
149
|
-
failures++;
|
|
150
|
-
}
|
|
151
|
-
if (!version) {
|
|
152
|
-
console.error('nx.json release.version config is missing');
|
|
210
|
+
for (const issue of checkWorkspaceConfigPolicy(root)) {
|
|
211
|
+
console.error(issue.message);
|
|
153
212
|
failures++;
|
|
154
213
|
}
|
|
155
|
-
|
|
156
|
-
console.error(
|
|
214
|
+
for (const issue of checkReleaseConfigPolicy(root)) {
|
|
215
|
+
console.error(issue.message);
|
|
157
216
|
failures++;
|
|
158
217
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
console.error('nx.json release.version.fallbackCurrentVersionResolver must be disk');
|
|
167
|
-
failures++;
|
|
168
|
-
}
|
|
169
|
-
if (version && stringProperty(version, 'versionActions') !== SMOO_NX_VERSION_ACTIONS) {
|
|
170
|
-
console.error(`nx.json release.version.versionActions must be ${SMOO_NX_VERSION_ACTIONS}`);
|
|
171
|
-
failures++;
|
|
172
|
-
}
|
|
173
|
-
if (version && stringProperty(version, 'preVersionCommand')) {
|
|
174
|
-
console.error('nx.json release.version.preVersionCommand must not be defined; smoo builds npm-missing packages before publish');
|
|
175
|
-
failures++;
|
|
176
|
-
}
|
|
177
|
-
if (!releaseTag) {
|
|
178
|
-
console.error('nx.json release.releaseTag config is missing');
|
|
179
|
-
failures++;
|
|
180
|
-
}
|
|
181
|
-
if (releaseTag && stringProperty(releaseTag, 'pattern') !== SMOO_NX_RELEASE_TAG_PATTERN) {
|
|
182
|
-
console.error(`nx.json release.releaseTag.pattern must be ${SMOO_NX_RELEASE_TAG_PATTERN}`);
|
|
183
|
-
failures++;
|
|
184
|
-
}
|
|
185
|
-
if (!changelog) {
|
|
186
|
-
console.error('nx.json release.changelog config is missing');
|
|
187
|
-
failures++;
|
|
188
|
-
}
|
|
189
|
-
if (changelog && changelog.workspaceChangelog !== false) {
|
|
190
|
-
console.error('nx.json release.changelog.workspaceChangelog must be false');
|
|
191
|
-
failures++;
|
|
192
|
-
}
|
|
193
|
-
if (!projectChangelogs) {
|
|
194
|
-
console.error('nx.json release.changelog.projectChangelogs config is missing');
|
|
195
|
-
failures++;
|
|
196
|
-
}
|
|
197
|
-
if (projectChangelogs && projectChangelogs.createRelease !== false) {
|
|
198
|
-
console.error('nx.json release.changelog.projectChangelogs.createRelease must be false');
|
|
199
|
-
failures++;
|
|
218
|
+
return failures;
|
|
219
|
+
}
|
|
220
|
+
export function validateNxProjectNames(root) {
|
|
221
|
+
const rootPackage = readJsonObject(join(root, 'package.json'));
|
|
222
|
+
const rootName = rootPackage ? stringProperty(rootPackage, 'name') : null;
|
|
223
|
+
if (!rootName) {
|
|
224
|
+
return 0;
|
|
200
225
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
226
|
+
let failures = 0;
|
|
227
|
+
for (const pkg of getWorkspacePackageManifests(root)) {
|
|
228
|
+
const suggestedName = suggestNxProjectName(rootName, pkg.name);
|
|
229
|
+
if (!suggestedName) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const nx = recordProperty(pkg.json, 'nx');
|
|
233
|
+
const configuredName = nx ? stringProperty(nx, 'name') : null;
|
|
234
|
+
if (configuredName !== suggestedName) {
|
|
235
|
+
console.error(`${pkg.path}: package.json nx.name must be "${suggestedName}" so fix(${suggestedName}): maps to this project`);
|
|
236
|
+
failures++;
|
|
237
|
+
}
|
|
204
238
|
}
|
|
205
|
-
if (
|
|
206
|
-
console.
|
|
207
|
-
failures++;
|
|
239
|
+
if (failures === 0) {
|
|
240
|
+
console.log('Nx project names are valid.');
|
|
208
241
|
}
|
|
209
242
|
return failures;
|
|
210
243
|
}
|
|
@@ -278,9 +311,9 @@ export function validatePublicPackageMetadata(root) {
|
|
|
278
311
|
}
|
|
279
312
|
return failures;
|
|
280
313
|
}
|
|
281
|
-
export function validateWorkspaceDependencies(root) {
|
|
282
|
-
const workspaceNames = new Set(getWorkspacePackages(root).map((pkg) => pkg.name));
|
|
314
|
+
export function validateWorkspaceDependencies(root, options = {}) {
|
|
283
315
|
let failures = 0;
|
|
316
|
+
const workspaceNames = new Set(getWorkspacePackages(root).map((pkg) => pkg.name));
|
|
284
317
|
for (const pkg of listPackageJsonRecords(root)) {
|
|
285
318
|
for (const field of workspaceDependencyFields) {
|
|
286
319
|
const dependencies = recordProperty(pkg.json, field);
|
|
@@ -295,11 +328,26 @@ export function validateWorkspaceDependencies(root) {
|
|
|
295
328
|
}
|
|
296
329
|
}
|
|
297
330
|
}
|
|
331
|
+
for (const issue of checkPackageTargetPolicy(root, options)) {
|
|
332
|
+
console.error(`${issue.path}: ${issue.message}`);
|
|
333
|
+
failures++;
|
|
334
|
+
}
|
|
335
|
+
for (const issue of checkTypecheckTestPolicy(root)) {
|
|
336
|
+
console.error(`${issue.path}: ${issue.message}`);
|
|
337
|
+
failures++;
|
|
338
|
+
}
|
|
339
|
+
for (const issue of checkWorkspaceBoundedTestTargetPolicy(root)) {
|
|
340
|
+
console.error(`${issue.path}: ${issue.message}`);
|
|
341
|
+
failures++;
|
|
342
|
+
}
|
|
298
343
|
if (failures === 0) {
|
|
299
|
-
console.log('Workspace dependency
|
|
344
|
+
console.log('Workspace dependency policy is valid.');
|
|
300
345
|
}
|
|
301
346
|
return failures;
|
|
302
347
|
}
|
|
348
|
+
// ---------------------------------------------------------------------------
|
|
349
|
+
// Helpers kept in CLI (not Nx-specific)
|
|
350
|
+
// ---------------------------------------------------------------------------
|
|
303
351
|
function fixWorkspaceDependencyRanges(pkg, workspaceNames) {
|
|
304
352
|
let changed = false;
|
|
305
353
|
for (const field of workspaceDependencyFields) {
|
|
@@ -316,11 +364,58 @@ function fixWorkspaceDependencyRanges(pkg, workspaceNames) {
|
|
|
316
364
|
}
|
|
317
365
|
return changed;
|
|
318
366
|
}
|
|
319
|
-
function
|
|
320
|
-
|
|
367
|
+
function validateRootScripts(rootPackage) {
|
|
368
|
+
const scripts = recordProperty(rootPackage, 'scripts');
|
|
369
|
+
let failures = 0;
|
|
370
|
+
for (const [name, command] of Object.entries(rootScriptPolicy)) {
|
|
371
|
+
if (scripts?.[name] !== command) {
|
|
372
|
+
console.error(`package.json scripts.${name} must be ${command}`);
|
|
373
|
+
failures++;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (scripts && !recordKeysAreSorted(scripts)) {
|
|
377
|
+
console.error('package.json scripts must be sorted alphabetically so root command policy stays stable across fixes.');
|
|
378
|
+
failures++;
|
|
379
|
+
}
|
|
380
|
+
return failures;
|
|
381
|
+
}
|
|
382
|
+
function validateRootNxScriptInference(rootPackage) {
|
|
383
|
+
const nx = recordProperty(rootPackage, 'nx');
|
|
384
|
+
if (nx && Array.isArray(nx.includedScripts) && nx.includedScripts.length === 0) {
|
|
385
|
+
return 0;
|
|
386
|
+
}
|
|
387
|
+
console.error('package.json nx.includedScripts must be [] so root scripts do not become recursive Nx targets.');
|
|
388
|
+
return 1;
|
|
389
|
+
}
|
|
390
|
+
function suggestNxProjectName(rootPackageName, packageName) {
|
|
391
|
+
const rootScope = npmScope(rootPackageName);
|
|
392
|
+
if (!rootScope || npmScope(packageName) !== rootScope) {
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
return unscopedPackageName(packageName);
|
|
396
|
+
}
|
|
397
|
+
function npmScope(packageName) {
|
|
398
|
+
const match = /^(@[^/]+)\//.exec(packageName);
|
|
399
|
+
return match?.[1] ?? null;
|
|
400
|
+
}
|
|
401
|
+
function unscopedPackageName(packageName) {
|
|
402
|
+
return packageName.startsWith('@') ? packageName.slice(packageName.indexOf('/') + 1) : packageName;
|
|
403
|
+
}
|
|
404
|
+
function recordKeysAreSorted(record) {
|
|
405
|
+
const keys = Object.keys(record);
|
|
406
|
+
return keys.every((key, index) => index === 0 || keys[index - 1] <= key);
|
|
407
|
+
}
|
|
408
|
+
function sortRecordInPlace(record) {
|
|
409
|
+
if (recordKeysAreSorted(record)) {
|
|
321
410
|
return false;
|
|
322
411
|
}
|
|
323
|
-
record[
|
|
412
|
+
const entries = Object.entries(record).sort(([a], [b]) => a.localeCompare(b));
|
|
413
|
+
for (const key of Object.keys(record)) {
|
|
414
|
+
delete record[key];
|
|
415
|
+
}
|
|
416
|
+
for (const [key, value] of entries) {
|
|
417
|
+
record[key] = value;
|
|
418
|
+
}
|
|
324
419
|
return true;
|
|
325
420
|
}
|
|
326
421
|
function normalizeExportConditionOrder(value) {
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
export declare function validatePackedPublicPackages(root: string): Promise<number>;
|
|
2
|
+
export declare function validatePackedPublicPackagePublint(root: string): Promise<number>;
|
|
3
|
+
export declare function validatePackedPublicPackageManifest(root: string): Promise<number>;
|
|
4
|
+
export declare function validatePackedPublicPackageTypes(root: string): Promise<number>;
|
|
2
5
|
//# sourceMappingURL=packed-package.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packed-package.d.ts","sourceRoot":"","sources":["../../src/monorepo/packed-package.ts"],"names":[],"mappings":"AAUA,wBAAsB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMhF"}
|
|
1
|
+
{"version":3,"file":"packed-package.d.ts","sourceRoot":"","sources":["../../src/monorepo/packed-package.ts"],"names":[],"mappings":"AAUA,wBAAsB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMhF;AAED,wBAAsB,kCAAkC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMtF;AAED,wBAAsB,mCAAmC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMvF;AAED,wBAAsB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMpF"}
|
|
@@ -3,64 +3,96 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { publint } from 'publint';
|
|
4
4
|
import { formatMessage } from 'publint/utils';
|
|
5
5
|
import { isRecord } from '../lib/json.js';
|
|
6
|
-
import { runStatus } from '../lib/run.js';
|
|
6
|
+
import { runResult, runStatus } from '../lib/run.js';
|
|
7
7
|
import { listPublicPackages } from '../lib/workspace.js';
|
|
8
8
|
import { readPackedPackageJson, validatePackedWorkspaceDependencies } from './packed-manifest.js';
|
|
9
9
|
export async function validatePackedPublicPackages(root) {
|
|
10
|
+
return ((await validatePackedPublicPackagePublint(root)) +
|
|
11
|
+
(await validatePackedPublicPackageManifest(root)) +
|
|
12
|
+
(await validatePackedPublicPackageTypes(root)));
|
|
13
|
+
}
|
|
14
|
+
export async function validatePackedPublicPackagePublint(root) {
|
|
10
15
|
let failures = 0;
|
|
11
16
|
for (const pkg of listPublicPackages(root)) {
|
|
12
|
-
failures += await
|
|
17
|
+
failures += await validatePackedPublicPackageTool(root, pkg, validatePublint);
|
|
13
18
|
}
|
|
14
19
|
return failures;
|
|
15
20
|
}
|
|
16
|
-
async function
|
|
21
|
+
export async function validatePackedPublicPackageManifest(root) {
|
|
17
22
|
let failures = 0;
|
|
23
|
+
for (const pkg of listPublicPackages(root)) {
|
|
24
|
+
failures += await validatePackedPublicPackageTool(root, pkg, validatePackedManifest);
|
|
25
|
+
}
|
|
26
|
+
return failures;
|
|
27
|
+
}
|
|
28
|
+
export async function validatePackedPublicPackageTypes(root) {
|
|
29
|
+
let failures = 0;
|
|
30
|
+
for (const pkg of listPublicPackages(root)) {
|
|
31
|
+
failures += await validatePackedPublicPackageTool(root, pkg, validateAttw);
|
|
32
|
+
}
|
|
33
|
+
return failures;
|
|
34
|
+
}
|
|
35
|
+
async function validatePackedPublicPackageTool(root, pkg, validate) {
|
|
18
36
|
const packed = await packPackage(root, pkg);
|
|
19
37
|
try {
|
|
20
|
-
|
|
21
|
-
for (const message of lint.messages) {
|
|
22
|
-
console.error(`${pkg.path}: publint ${message.type} ${message.code}: ${formatMessage(message, lint.pkg)}`);
|
|
23
|
-
failures++;
|
|
24
|
-
}
|
|
25
|
-
const packedPackage = await readPackedPackageJson(root, packed.path, pkg.name);
|
|
26
|
-
for (const message of validatePackedWorkspaceDependencies(root, pkg, packedPackage)) {
|
|
27
|
-
console.error(message);
|
|
28
|
-
failures++;
|
|
29
|
-
}
|
|
30
|
-
const attwArgs = [
|
|
31
|
-
packed.path,
|
|
32
|
-
'--format',
|
|
33
|
-
'ascii',
|
|
34
|
-
'--no-color',
|
|
35
|
-
'--profile',
|
|
36
|
-
'node16',
|
|
37
|
-
'--ignore-rules',
|
|
38
|
-
'cjs-resolves-to-esm',
|
|
39
|
-
...attwExcludedEntrypointArgs(pkg),
|
|
40
|
-
];
|
|
41
|
-
const attwStatus = await runStatus('attw', ['--quiet', ...attwArgs], root, true);
|
|
42
|
-
if (attwStatus !== 0) {
|
|
43
|
-
await runStatus('attw', attwArgs, root);
|
|
44
|
-
console.error(`${pkg.path}: are-the-types-wrong validation failed`);
|
|
45
|
-
failures++;
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
console.log(`${pkg.path}: are-the-types-wrong valid.`);
|
|
49
|
-
}
|
|
38
|
+
return await validate(root, pkg, packed);
|
|
50
39
|
}
|
|
51
40
|
catch (error) {
|
|
52
41
|
const message = error instanceof Error ? error.message : String(error);
|
|
53
42
|
console.error(`${pkg.path}: packed package validation failed: ${message}`);
|
|
54
|
-
|
|
43
|
+
return 1;
|
|
55
44
|
}
|
|
56
45
|
finally {
|
|
57
46
|
unlinkSync(packed.path);
|
|
58
47
|
}
|
|
59
|
-
|
|
60
|
-
|
|
48
|
+
}
|
|
49
|
+
async function validatePublint(_root, pkg, packed) {
|
|
50
|
+
let failures = 0;
|
|
51
|
+
const lint = await publint({ pack: { tarball: packed.arrayBuffer }, level: 'warning', strict: true });
|
|
52
|
+
for (const message of lint.messages) {
|
|
53
|
+
console.error(`${pkg.path}: publint ${message.type} ${message.code}: ${formatMessage(message, lint.pkg)}`);
|
|
54
|
+
failures++;
|
|
55
|
+
}
|
|
56
|
+
return failures;
|
|
57
|
+
}
|
|
58
|
+
async function validatePackedManifest(root, pkg, packed) {
|
|
59
|
+
let failures = 0;
|
|
60
|
+
const packedPackage = await readPackedPackageJson(root, packed.path, pkg.name);
|
|
61
|
+
for (const message of validatePackedWorkspaceDependencies(root, pkg, packedPackage)) {
|
|
62
|
+
console.error(message);
|
|
63
|
+
failures++;
|
|
61
64
|
}
|
|
62
65
|
return failures;
|
|
63
66
|
}
|
|
67
|
+
async function validateAttw(root, pkg, packed) {
|
|
68
|
+
const attwArgs = [
|
|
69
|
+
packed.path,
|
|
70
|
+
'--format',
|
|
71
|
+
'ascii',
|
|
72
|
+
'--no-color',
|
|
73
|
+
'--profile',
|
|
74
|
+
'node16',
|
|
75
|
+
'--ignore-rules',
|
|
76
|
+
'cjs-resolves-to-esm',
|
|
77
|
+
...attwExcludedEntrypointArgs(pkg),
|
|
78
|
+
];
|
|
79
|
+
const attw = await runResult('attw', attwArgs, root);
|
|
80
|
+
if (attw.exitCode === 0) {
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
printAttwOutput(attw.stdout);
|
|
84
|
+
printAttwOutput(attw.stderr);
|
|
85
|
+
console.error(`${pkg.path}: are-the-types-wrong validation failed`);
|
|
86
|
+
return 1;
|
|
87
|
+
}
|
|
88
|
+
function printAttwOutput(output) {
|
|
89
|
+
for (const line of output.split('\n')) {
|
|
90
|
+
if (!line || line.includes('(ignored)')) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
console.error(line);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
64
96
|
function attwExcludedEntrypointArgs(pkg) {
|
|
65
97
|
const excluded = wasmExportEntrypoints(pkg.json.exports);
|
|
66
98
|
return excluded.length === 0 ? [] : ['--exclude-entrypoints', ...excluded];
|
|
@@ -1,10 +1,29 @@
|
|
|
1
1
|
export interface MonorepoContext {
|
|
2
2
|
root: string;
|
|
3
3
|
syncRuntime: boolean;
|
|
4
|
+
verbose?: boolean;
|
|
4
5
|
}
|
|
5
6
|
export interface ValidatePackOptions {
|
|
6
7
|
failFast?: boolean;
|
|
8
|
+
fix?: boolean;
|
|
9
|
+
verbose?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface MonorepoPack {
|
|
12
|
+
name: string;
|
|
13
|
+
init?(ctx: MonorepoContext): Promise<void> | void;
|
|
14
|
+
fixPreBuild?(ctx: MonorepoContext): Promise<void> | void;
|
|
15
|
+
fixPostBuild?(ctx: MonorepoContext): Promise<void> | void;
|
|
16
|
+
validatePreBuild?(ctx: MonorepoContext): Promise<number> | number;
|
|
17
|
+
validatePostBuild?(ctx: MonorepoContext): Promise<number> | number;
|
|
18
|
+
}
|
|
19
|
+
export interface ValidatePackRunHooks {
|
|
20
|
+
packs?: readonly MonorepoPack[];
|
|
21
|
+
runBuild?: (ctx: MonorepoContext, options?: ValidatePackOptions) => Promise<number> | number;
|
|
22
|
+
}
|
|
23
|
+
export interface ValidatePackResult {
|
|
24
|
+
failures: number;
|
|
25
|
+
failedChecks: number;
|
|
7
26
|
}
|
|
8
27
|
export declare function runInitPacks(ctx: MonorepoContext): Promise<void>;
|
|
9
|
-
export declare function runValidatePacks(ctx: MonorepoContext, options?: ValidatePackOptions): Promise<
|
|
28
|
+
export declare function runValidatePacks(ctx: MonorepoContext, options?: ValidatePackOptions, hooks?: ValidatePackRunHooks): Promise<ValidatePackResult>;
|
|
10
29
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/monorepo/packs/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/monorepo/packs/index.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClD,WAAW,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACzD,YAAY,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1D,gBAAgB,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAClE,iBAAiB,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CACpE;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC9F;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAgGD,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAItE;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE,mBAAwB,EACjC,KAAK,GAAE,oBAAyB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CA0B7B"}
|