@smoothbricks/cli 0.10.3 → 0.10.4
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 +9 -13
- package/dist/bun/preload.d.ts +13 -0
- package/dist/bun/preload.d.ts.map +1 -0
- package/dist/bun/preload.js +12 -0
- package/dist/cli.js +12 -4
- package/dist/generate/index.d.ts.map +1 -1
- package/dist/generate/index.js +0 -6
- package/dist/github-ci/index.d.ts.map +1 -1
- package/dist/github-ci/index.js +52 -16
- package/dist/github-ci/outputs.d.ts.map +1 -1
- package/dist/github-ci/outputs.js +1 -2
- package/dist/lib/cli-package.js +2 -2
- package/dist/lib/json.d.ts +118 -11
- package/dist/lib/json.d.ts.map +1 -1
- package/dist/lib/json.js +317 -29
- package/dist/lib/workspace.d.ts +7 -14
- package/dist/lib/workspace.d.ts.map +1 -1
- package/dist/lib/workspace.js +76 -82
- package/dist/monorepo/ci-workflow.d.ts +2 -0
- package/dist/monorepo/ci-workflow.d.ts.map +1 -1
- package/dist/monorepo/ci-workflow.js +27 -1
- package/dist/monorepo/git-config.js +2 -2
- package/dist/monorepo/index.d.ts +3 -1
- package/dist/monorepo/index.d.ts.map +1 -1
- package/dist/monorepo/index.js +6 -2
- package/dist/monorepo/lockfile.d.ts +13 -1
- package/dist/monorepo/lockfile.d.ts.map +1 -1
- package/dist/monorepo/lockfile.js +33 -21
- package/dist/monorepo/managed-files.d.ts +11 -0
- package/dist/monorepo/managed-files.d.ts.map +1 -1
- package/dist/monorepo/managed-files.js +52 -32
- package/dist/monorepo/package-policy.d.ts.map +1 -1
- package/dist/monorepo/package-policy.js +52 -45
- package/dist/monorepo/packed-manifest.d.ts +5 -2
- package/dist/monorepo/packed-manifest.d.ts.map +1 -1
- package/dist/monorepo/packed-manifest.js +16 -47
- package/dist/monorepo/packed-package.d.ts.map +1 -1
- package/dist/monorepo/packed-package.js +28 -16
- package/dist/monorepo/packs/index.d.ts.map +1 -1
- package/dist/monorepo/packs/index.js +13 -4
- package/dist/monorepo/publish-workflow.js +3 -1
- package/dist/monorepo/runtime.d.ts +15 -0
- package/dist/monorepo/runtime.d.ts.map +1 -1
- package/dist/monorepo/runtime.js +66 -12
- package/dist/monorepo/tool-validation.d.ts.map +1 -1
- package/dist/monorepo/tool-validation.js +32 -23
- package/dist/monorepo/wrangler.d.ts.map +1 -1
- package/dist/monorepo/wrangler.js +13 -13
- package/dist/nx/index.d.ts +9 -7
- package/dist/nx/index.d.ts.map +1 -1
- package/dist/nx/index.js +48 -31
- package/dist/pr/index.d.ts.map +1 -1
- package/dist/pr/index.js +28 -32
- package/dist/release/candidates.d.ts +3 -2
- package/dist/release/candidates.d.ts.map +1 -1
- package/dist/release/candidates.js +4 -5
- package/dist/release/index.d.ts +1 -0
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +82 -59
- package/dist/wrangler/prepare-env.d.ts +0 -1
- package/dist/wrangler/prepare-env.d.ts.map +1 -1
- package/dist/wrangler/prepare-env.js +100 -51
- package/dist/wrangler/scaffold.d.ts.map +1 -1
- package/dist/wrangler/scaffold.js +12 -12
- package/managed/raw/git-format-staged.yml +19 -1
- package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +2 -1
- package/managed/raw/tooling/direnv/merge-newer-pins.sh +3 -3
- package/managed/raw/tooling/direnv/setup-environment.ts +150 -19
- package/managed/raw/tooling/git-hooks/pre-commit.sh +0 -6
- package/managed/templates/github/actions/cache-node-modules/action.yml +5 -2
- package/managed/templates/github/actions/cache-ttsc-plugins/action.yml +19 -0
- package/managed/templates/github/actions/setup-devenv/action.yml +5 -0
- package/managed/templates/github/workflows/managed-files.yml +80 -0
- package/package.json +15 -4
- package/src/bun/preload.ts +12 -0
- package/src/cli.ts +19 -7
- package/src/generate/index.ts +0 -6
- package/src/github-ci/index.ts +49 -18
- package/src/github-ci/outputs.ts +1 -2
- package/src/lib/cli-package.ts +2 -2
- package/src/lib/json.ts +291 -32
- package/src/lib/workspace.ts +88 -100
- package/src/monorepo/__tests__/ci-workflow.test.ts +3 -3
- package/src/monorepo/ci-workflow.ts +27 -1
- package/src/monorepo/git-config.ts +2 -2
- package/src/monorepo/index.ts +6 -2
- package/src/monorepo/lockfile.test.ts +35 -36
- package/src/monorepo/lockfile.ts +48 -24
- package/src/monorepo/managed-files.test.ts +1 -0
- package/src/monorepo/managed-files.ts +57 -38
- package/src/monorepo/package-policy.test.ts +20 -50
- package/src/monorepo/package-policy.ts +76 -59
- package/src/monorepo/packed-manifest.ts +18 -52
- package/src/monorepo/packed-package.ts +43 -22
- package/src/monorepo/packs/index.ts +13 -4
- package/src/monorepo/publish-workflow.ts +3 -1
- package/src/monorepo/runtime.test.ts +42 -3
- package/src/monorepo/runtime.ts +90 -12
- package/src/monorepo/tool-validation.ts +35 -25
- package/src/monorepo/wrangler.test.ts +11 -15
- package/src/monorepo/wrangler.ts +15 -15
- package/src/nx/index.test.ts +9 -5
- package/src/nx/index.ts +69 -42
- package/src/pr/index.ts +42 -36
- package/src/release/__tests__/candidates.test.ts +5 -4
- package/src/release/__tests__/trust-publisher.test.ts +7 -0
- package/src/release/candidates.ts +10 -17
- package/src/release/index.ts +104 -73
- package/src/wrangler/prepare-env.ts +75 -54
- package/src/wrangler/scaffold.test.ts +9 -12
- package/src/wrangler/scaffold.ts +13 -13
package/src/nx/index.ts
CHANGED
|
@@ -2,7 +2,13 @@ import { existsSync } from 'node:fs';
|
|
|
2
2
|
import { lstat, rm } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { $ } from 'bun';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
type NxDependsOn,
|
|
7
|
+
type NxProjectJson,
|
|
8
|
+
type NxTargetConfig,
|
|
9
|
+
parseNxProjectJsonText,
|
|
10
|
+
parseStringArrayText,
|
|
11
|
+
} from '../lib/json.js';
|
|
6
12
|
import { decode, run } from '../lib/run.js';
|
|
7
13
|
|
|
8
14
|
export interface ProjectTargets {
|
|
@@ -33,100 +39,116 @@ export function nxCacheDirectories(root: string): string[] {
|
|
|
33
39
|
return [join(root, '.nx/cache'), join(root, '.nx/workspace-data'), join(root, 'node_modules/.cache/nx')];
|
|
34
40
|
}
|
|
35
41
|
|
|
36
|
-
export function targetNamesFromNxProjectJson(value:
|
|
37
|
-
const targets =
|
|
42
|
+
export function targetNamesFromNxProjectJson(value: NxProjectJson | null | undefined): string[] {
|
|
43
|
+
const targets = value?.targets;
|
|
38
44
|
return targets ? Object.keys(targets).sort((a, b) => a.localeCompare(b)) : [];
|
|
39
45
|
}
|
|
40
46
|
|
|
41
|
-
export function projectRootFromNxProjectJson(value:
|
|
42
|
-
return
|
|
47
|
+
export function projectRootFromNxProjectJson(value: NxProjectJson | null | undefined): string | undefined {
|
|
48
|
+
return typeof value?.root === 'string' ? value.root : undefined;
|
|
43
49
|
}
|
|
44
50
|
|
|
45
|
-
export function buildDependsOnFromNxProjectJson(value:
|
|
51
|
+
export function buildDependsOnFromNxProjectJson(value: NxProjectJson | null | undefined): string[] | undefined {
|
|
46
52
|
return targetDependenciesFromNxProjectJson(value).get('build');
|
|
47
53
|
}
|
|
48
54
|
|
|
49
|
-
export function targetDependenciesFromNxProjectJson(value:
|
|
50
|
-
const targets =
|
|
55
|
+
export function targetDependenciesFromNxProjectJson(value: NxProjectJson | null | undefined): Map<string, string[]> {
|
|
56
|
+
const targets = value?.targets;
|
|
51
57
|
const dependencies = new Map<string, string[]>();
|
|
52
58
|
if (!targets) {
|
|
53
59
|
return dependencies;
|
|
54
60
|
}
|
|
55
61
|
for (const [targetName, target] of Object.entries(targets)) {
|
|
56
|
-
if (!
|
|
62
|
+
if (!target.dependsOn) {
|
|
57
63
|
continue;
|
|
58
64
|
}
|
|
59
65
|
const entries: string[] = [];
|
|
60
66
|
for (const dependency of target.dependsOn) {
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
const local = localDependsOnTarget(dependency);
|
|
68
|
+
if (local === undefined) {
|
|
69
|
+
if (isInvalidDependsOn(dependency)) {
|
|
70
|
+
throw new Error(`Nx target ${targetName} has an invalid dependsOn entry.`);
|
|
71
|
+
}
|
|
63
72
|
continue;
|
|
64
73
|
}
|
|
65
|
-
|
|
66
|
-
throw new Error(`Nx target ${targetName} has an invalid dependsOn entry.`);
|
|
67
|
-
}
|
|
68
|
-
if (dependency.projects !== undefined && dependency.projects !== 'self') {
|
|
69
|
-
throw new Error(`Nx target ${targetName} uses unsupported cross-project dependsOn for ${dependency.target}.`);
|
|
70
|
-
}
|
|
71
|
-
entries.push(dependency.target);
|
|
74
|
+
entries.push(local);
|
|
72
75
|
}
|
|
73
76
|
dependencies.set(targetName, entries);
|
|
74
77
|
}
|
|
75
78
|
return dependencies;
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
function localDependsOnTarget(dependency: NxDependsOn): string | undefined {
|
|
82
|
+
if (typeof dependency === 'string') {
|
|
83
|
+
return dependency;
|
|
84
|
+
}
|
|
85
|
+
if (typeof dependency.target !== 'string') {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
if (dependency.projects !== undefined && dependency.projects !== 'self') {
|
|
89
|
+
// Target closures are intentionally project-local. Nx schedules explicit
|
|
90
|
+
// cross-project prerequisites itself; treating them as local targets
|
|
91
|
+
// would collect or verify outputs from the wrong project.
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
return dependency.target;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function isInvalidDependsOn(dependency: NxDependsOn): boolean {
|
|
98
|
+
return typeof dependency !== 'string' && typeof dependency.target !== 'string';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function targetExecutorsFromNxProjectJson(value: NxProjectJson | null | undefined): Map<string, string> {
|
|
102
|
+
const targets = value?.targets;
|
|
80
103
|
const executors = new Map<string, string>();
|
|
81
104
|
if (!targets) {
|
|
82
105
|
return executors;
|
|
83
106
|
}
|
|
84
107
|
for (const [targetName, target] of Object.entries(targets)) {
|
|
85
|
-
if (
|
|
108
|
+
if (typeof target.executor === 'string') {
|
|
86
109
|
executors.set(targetName, target.executor);
|
|
87
110
|
}
|
|
88
111
|
}
|
|
89
112
|
return executors;
|
|
90
113
|
}
|
|
91
114
|
|
|
92
|
-
export function targetOutputsFromNxProjectJson(value:
|
|
115
|
+
export function targetOutputsFromNxProjectJson(value: NxProjectJson | null | undefined): Map<string, string[]> {
|
|
93
116
|
return targetStringArraysFromNxProjectJson(value, 'outputs');
|
|
94
117
|
}
|
|
95
118
|
|
|
96
|
-
export function targetScriptsFromNxProjectJson(value:
|
|
97
|
-
const targets =
|
|
119
|
+
export function targetScriptsFromNxProjectJson(value: NxProjectJson | null | undefined): Map<string, string> {
|
|
120
|
+
const targets = value?.targets;
|
|
98
121
|
const scripts = new Map<string, string>();
|
|
99
122
|
if (!targets) {
|
|
100
123
|
return scripts;
|
|
101
124
|
}
|
|
102
125
|
for (const [targetName, target] of Object.entries(targets)) {
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
const options = recordProperty(target, 'options');
|
|
107
|
-
if (typeof options?.script === 'string') {
|
|
108
|
-
scripts.set(targetName, options.script);
|
|
126
|
+
if (typeof target.options?.script === 'string') {
|
|
127
|
+
scripts.set(targetName, target.options.script);
|
|
109
128
|
}
|
|
110
129
|
}
|
|
111
130
|
return scripts;
|
|
112
131
|
}
|
|
113
132
|
|
|
114
|
-
function targetStringArraysFromNxProjectJson(
|
|
115
|
-
|
|
133
|
+
function targetStringArraysFromNxProjectJson(
|
|
134
|
+
value: NxProjectJson | null | undefined,
|
|
135
|
+
property: 'outputs' | 'inputs',
|
|
136
|
+
): Map<string, string[]> {
|
|
137
|
+
const targets = value?.targets;
|
|
116
138
|
const values = new Map<string, string[]>();
|
|
117
139
|
if (!targets) {
|
|
118
140
|
return values;
|
|
119
141
|
}
|
|
120
142
|
for (const [targetName, target] of Object.entries(targets)) {
|
|
121
|
-
if (!isRecord(target)) {
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
143
|
const entries = target[property];
|
|
125
144
|
if (Array.isArray(entries)) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
145
|
+
const strings: string[] = [];
|
|
146
|
+
for (const entry of entries) {
|
|
147
|
+
if (typeof entry === 'string') {
|
|
148
|
+
strings.push(entry);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
values.set(targetName, strings);
|
|
130
152
|
}
|
|
131
153
|
}
|
|
132
154
|
return values;
|
|
@@ -154,8 +176,8 @@ export function projectNamesFromNxShowProjectsOutput(output: string): string[] {
|
|
|
154
176
|
|
|
155
177
|
if (trimmed.startsWith('[')) {
|
|
156
178
|
try {
|
|
157
|
-
const parsed
|
|
158
|
-
if (
|
|
179
|
+
const parsed = parseStringArrayText(trimmed);
|
|
180
|
+
if (parsed) {
|
|
159
181
|
return parsed.sort((a, b) => a.localeCompare(b));
|
|
160
182
|
}
|
|
161
183
|
} catch {
|
|
@@ -220,7 +242,10 @@ async function readNxProjectNames(root: string): Promise<string[]> {
|
|
|
220
242
|
async function readProjectTarget(root: string, project: string): Promise<ProjectTargets> {
|
|
221
243
|
const command = nxShowProjectCommand(project);
|
|
222
244
|
const result = await $`${command.command} ${command.args}`.cwd(root).quiet();
|
|
223
|
-
const parsed
|
|
245
|
+
const parsed = parseNxProjectJsonText(decode(result.stdout));
|
|
246
|
+
if (!parsed) {
|
|
247
|
+
throw new Error(`Unable to inspect Nx project ${project}.`);
|
|
248
|
+
}
|
|
224
249
|
const targetDependencies = targetDependenciesFromNxProjectJson(parsed);
|
|
225
250
|
return {
|
|
226
251
|
project,
|
|
@@ -233,3 +258,5 @@ async function readProjectTarget(root: string, project: string): Promise<Project
|
|
|
233
258
|
targetScripts: targetScriptsFromNxProjectJson(parsed),
|
|
234
259
|
};
|
|
235
260
|
}
|
|
261
|
+
|
|
262
|
+
export type { NxProjectJson, NxTargetConfig };
|
package/src/pr/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
|
+
import typia from 'typia';
|
|
3
4
|
import { formatMarkerHits, scanRefChangedForMarkers } from '../lib/conflict-markers.js';
|
|
4
|
-
import {
|
|
5
|
+
import { readJson } from '../lib/json.js';
|
|
5
6
|
import { run, runResult } from '../lib/run.js';
|
|
6
7
|
|
|
7
8
|
/** 0 = clean/done, 2 = action required (conflicts to resolve), 1 = usage/error. */
|
|
@@ -50,6 +51,29 @@ interface PrResolveState {
|
|
|
50
51
|
startedAt: string;
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
interface GhPrViewJson {
|
|
55
|
+
number: number;
|
|
56
|
+
url: string;
|
|
57
|
+
headRefName: string;
|
|
58
|
+
baseRefName: string;
|
|
59
|
+
isCrossRepository?: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface PrResolveStateJson {
|
|
63
|
+
pr: number;
|
|
64
|
+
url?: string;
|
|
65
|
+
headBranch: string;
|
|
66
|
+
baseBranch: string;
|
|
67
|
+
remote: string;
|
|
68
|
+
crossRepo?: boolean;
|
|
69
|
+
originalBranch?: string;
|
|
70
|
+
originalSha?: string;
|
|
71
|
+
startedAt?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const parseGhPrViewJson = typia.json.createIsParse<GhPrViewJson>();
|
|
75
|
+
const isPrResolveStateJson = typia.createIs<PrResolveStateJson>();
|
|
76
|
+
|
|
53
77
|
/**
|
|
54
78
|
* Agent-first conflict resolution for a GitHub PR.
|
|
55
79
|
*
|
|
@@ -209,25 +233,16 @@ async function prMeta(shell: PrResolveShell, root: string, prArg: string): Promi
|
|
|
209
233
|
if (result.exitCode !== 0) {
|
|
210
234
|
throw new Error(`Could not resolve PR '${prArg}' via gh: ${result.stderr.trim() || `exit ${result.exitCode}`}`);
|
|
211
235
|
}
|
|
212
|
-
const raw
|
|
213
|
-
if (!
|
|
236
|
+
const raw = parseGhPrViewJson(result.stdout);
|
|
237
|
+
if (!raw) {
|
|
214
238
|
throw new Error(`gh pr view returned unexpected JSON for '${prArg}'.`);
|
|
215
239
|
}
|
|
216
|
-
const
|
|
217
|
-
if (
|
|
218
|
-
typeof number !== 'number' ||
|
|
219
|
-
typeof url !== 'string' ||
|
|
220
|
-
typeof headRefName !== 'string' ||
|
|
221
|
-
typeof baseRefName !== 'string'
|
|
222
|
-
) {
|
|
223
|
-
throw new Error(`gh pr view JSON for '${prArg}' is missing expected fields.`);
|
|
224
|
-
}
|
|
225
|
-
const match = /github\.com\/([^/]+\/[^/]+)\/pull\//.exec(url);
|
|
240
|
+
const match = /github\.com\/([^/]+\/[^/]+)\/pull\//.exec(raw.url);
|
|
226
241
|
return {
|
|
227
|
-
number,
|
|
228
|
-
url,
|
|
229
|
-
headBranch: headRefName,
|
|
230
|
-
baseBranch: baseRefName,
|
|
242
|
+
number: raw.number,
|
|
243
|
+
url: raw.url,
|
|
244
|
+
headBranch: raw.headRefName,
|
|
245
|
+
baseBranch: raw.baseRefName,
|
|
231
246
|
crossRepo: raw.isCrossRepository === true,
|
|
232
247
|
nameWithOwner: match ? match[1] : '',
|
|
233
248
|
};
|
|
@@ -326,28 +341,19 @@ function readState(statePath: string): PrResolveState | null {
|
|
|
326
341
|
} catch {
|
|
327
342
|
return null;
|
|
328
343
|
}
|
|
329
|
-
if (!
|
|
330
|
-
return null;
|
|
331
|
-
}
|
|
332
|
-
const { pr, url, headBranch, baseBranch, remote, crossRepo, originalBranch, originalSha, startedAt } = raw;
|
|
333
|
-
if (
|
|
334
|
-
typeof pr !== 'number' ||
|
|
335
|
-
typeof headBranch !== 'string' ||
|
|
336
|
-
typeof baseBranch !== 'string' ||
|
|
337
|
-
typeof remote !== 'string'
|
|
338
|
-
) {
|
|
344
|
+
if (!isPrResolveStateJson(raw)) {
|
|
339
345
|
return null;
|
|
340
346
|
}
|
|
341
347
|
return {
|
|
342
|
-
pr,
|
|
343
|
-
url:
|
|
344
|
-
headBranch,
|
|
345
|
-
baseBranch,
|
|
346
|
-
remote,
|
|
347
|
-
crossRepo: crossRepo === true,
|
|
348
|
-
originalBranch:
|
|
349
|
-
originalSha:
|
|
350
|
-
startedAt:
|
|
348
|
+
pr: raw.pr,
|
|
349
|
+
url: raw.url ?? '',
|
|
350
|
+
headBranch: raw.headBranch,
|
|
351
|
+
baseBranch: raw.baseBranch,
|
|
352
|
+
remote: raw.remote,
|
|
353
|
+
crossRepo: raw.crossRepo === true,
|
|
354
|
+
originalBranch: raw.originalBranch ?? '',
|
|
355
|
+
originalSha: raw.originalSha ?? '',
|
|
356
|
+
startedAt: raw.startedAt ?? '',
|
|
351
357
|
};
|
|
352
358
|
}
|
|
353
359
|
|
|
@@ -2,7 +2,8 @@ import { describe, expect, it } from 'bun:test';
|
|
|
2
2
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { $ } from 'bun';
|
|
5
|
-
import {
|
|
5
|
+
import type { PackageJson } from '../../lib/json.js';
|
|
6
|
+
import { parsePackageJsonText } from '../../lib/json.js';
|
|
6
7
|
import { type AutoReleaseCandidateShell, autoReleaseCandidatePackages } from '../candidates.js';
|
|
7
8
|
import type { ReleasePackageInfo } from '../core.js';
|
|
8
9
|
import { git, tag, withFixtureRepo, writePackage } from './helpers/fixture-repo.js';
|
|
@@ -309,9 +310,9 @@ function gitCandidateShell(
|
|
|
309
310
|
};
|
|
310
311
|
}
|
|
311
312
|
|
|
312
|
-
function parseJsonObject(text: string):
|
|
313
|
-
const parsed =
|
|
314
|
-
if (!
|
|
313
|
+
function parseJsonObject(text: string): PackageJson {
|
|
314
|
+
const parsed = parsePackageJsonText(text);
|
|
315
|
+
if (!parsed) {
|
|
315
316
|
throw new Error('expected JSON object');
|
|
316
317
|
}
|
|
317
318
|
return parsed;
|
|
@@ -179,6 +179,13 @@ describe('trusted publisher setup', () => {
|
|
|
179
179
|
|
|
180
180
|
it('recognizes npm trust access-denied output', () => {
|
|
181
181
|
expect(npmTrustListAccessDenied('{"error":{"code":"E403"}}', '')).toBe(true);
|
|
182
|
+
expect(npmTrustListAccessDenied('', 'npm error code E401')).toBe(true);
|
|
183
|
+
expect(
|
|
184
|
+
npmTrustListAccessDenied(
|
|
185
|
+
'',
|
|
186
|
+
'npm error 401 Unauthorized - GET https://registry.npmjs.org/-/package/@scope%2fpkg/trust - {"success":false,"error":"You must be logged in to publish packages."}',
|
|
187
|
+
),
|
|
188
|
+
).toBe(true);
|
|
182
189
|
expect(npmTrustListAccessDenied('', 'npm error code EOTP')).toBe(false);
|
|
183
190
|
});
|
|
184
191
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { PackageJson } from '../lib/json.js';
|
|
2
2
|
import type { ReleasePackageInfo } from './core.js';
|
|
3
3
|
import { releaseTag } from './core.js';
|
|
4
4
|
|
|
@@ -6,8 +6,8 @@ export interface AutoReleaseCandidateShell {
|
|
|
6
6
|
gitRefExists(ref: string): Promise<boolean>;
|
|
7
7
|
latestStableReleaseRef(projectName: string): Promise<string | null>;
|
|
8
8
|
packageChangedFilesSince(ref: string, packagePath: string): Promise<string[]>;
|
|
9
|
-
packageJsonAtRef(ref: string, packagePath: string): Promise<
|
|
10
|
-
currentPackageJson(packagePath: string): Promise<
|
|
9
|
+
packageJsonAtRef(ref: string, packagePath: string): Promise<PackageJson | null>;
|
|
10
|
+
currentPackageJson(packagePath: string): Promise<PackageJson | null>;
|
|
11
11
|
packageBuildInputPatterns(projectName: string, packagePath: string): Promise<string[]>;
|
|
12
12
|
packageHasHistory(packagePath: string): Promise<boolean>;
|
|
13
13
|
}
|
|
@@ -104,23 +104,16 @@ async function packageHasReleasableChangesSince<Package extends ReleasePackageIn
|
|
|
104
104
|
return false;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
function releasableManifestChanged(
|
|
108
|
-
previousManifest: Record<string, unknown>,
|
|
109
|
-
currentManifest: Record<string, unknown>,
|
|
110
|
-
): boolean {
|
|
107
|
+
function releasableManifestChanged(previousManifest: PackageJson, currentManifest: PackageJson): boolean {
|
|
111
108
|
for (const key of releasableManifestKeys) {
|
|
112
|
-
if (!stableJsonEqual(previousManifest
|
|
109
|
+
if (!stableJsonEqual(Reflect.get(previousManifest, key), Reflect.get(currentManifest, key))) {
|
|
113
110
|
return true;
|
|
114
111
|
}
|
|
115
112
|
}
|
|
116
113
|
return false;
|
|
117
114
|
}
|
|
118
115
|
|
|
119
|
-
function isReleasablePackagePath(
|
|
120
|
-
path: string,
|
|
121
|
-
manifest: Record<string, unknown> | null,
|
|
122
|
-
buildInputPatterns: string[],
|
|
123
|
-
): boolean {
|
|
116
|
+
function isReleasablePackagePath(path: string, manifest: PackageJson | null, buildInputPatterns: string[]): boolean {
|
|
124
117
|
return (
|
|
125
118
|
isBuildInputPath(path, buildInputPatterns) || isPackageMetadataPath(path) || isManifestFilesPath(path, manifest)
|
|
126
119
|
);
|
|
@@ -195,13 +188,13 @@ function isPackageMetadataPath(path: string): boolean {
|
|
|
195
188
|
return /^(README|LICENSE|CHANGELOG)(\.|$)/.test(path);
|
|
196
189
|
}
|
|
197
190
|
|
|
198
|
-
function isManifestFilesPath(path: string, manifest:
|
|
191
|
+
function isManifestFilesPath(path: string, manifest: PackageJson | null): boolean {
|
|
199
192
|
const files = manifest?.files;
|
|
200
193
|
if (!Array.isArray(files)) {
|
|
201
194
|
return false;
|
|
202
195
|
}
|
|
203
196
|
for (const entry of files) {
|
|
204
|
-
if (
|
|
197
|
+
if (entry.length === 0 || entry.startsWith('!')) {
|
|
205
198
|
continue;
|
|
206
199
|
}
|
|
207
200
|
if (matchesManifestFilesEntry(path, entry)) {
|
|
@@ -227,10 +220,10 @@ function stableJson(value: unknown): unknown {
|
|
|
227
220
|
if (Array.isArray(value)) {
|
|
228
221
|
return value.map(stableJson);
|
|
229
222
|
}
|
|
230
|
-
if (
|
|
223
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
231
224
|
const normalized: Record<string, unknown> = {};
|
|
232
225
|
for (const key of Object.keys(value).sort()) {
|
|
233
|
-
normalized[key] = stableJson(value
|
|
226
|
+
normalized[key] = stableJson(Reflect.get(value, key));
|
|
234
227
|
}
|
|
235
228
|
return normalized;
|
|
236
229
|
}
|