@shazhou/proman-core 0.9.0 → 0.9.1
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/CHANGELOG.md +18 -0
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +6 -1
- package/dist/utils/smoke-test.d.ts +11 -1
- package/dist/utils/smoke-test.d.ts.map +1 -1
- package/dist/utils/smoke-test.js +32 -7
- package/package.json +1 -1
- package/src/commands/publish.ts +6 -1
- package/src/utils/smoke-test.ts +45 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.1 — 2026-06-13
|
|
4
|
+
|
|
5
|
+
- Update release workflow for monorepo and fix smoke test workspace deps
|
|
6
|
+
|
|
7
|
+
**release.yaml v2**: Updated for monorepo structure — uses `proman bump` and
|
|
8
|
+
`proman publish` instead of raw `npm version`/`pnpm publish`. Preflight checks
|
|
9
|
+
all packages' versions on npm. Publisher verifies `workspace:*` was resolved
|
|
10
|
+
correctly after publish.
|
|
11
|
+
|
|
12
|
+
**smoke-test**: `smokeTestTarball` now accepts `workspacePackages` map and
|
|
13
|
+
symlinks workspace dependencies into extracted tarball's `node_modules/`,
|
|
14
|
+
fixing smoke test failure for packages with workspace deps (e.g. CLI → core).
|
|
15
|
+
|
|
16
|
+
**smoke-test parse fix**: Extract `.tgz` filename from pnpm pack verbose output
|
|
17
|
+
via regex instead of treating entire stdout as filename.
|
|
18
|
+
|
|
19
|
+
**docs**: Renamed `lint` → `check` across all documentation and pre-push hook.
|
|
20
|
+
|
|
3
21
|
## 0.9.0 — 2026-06-13
|
|
4
22
|
|
|
5
23
|
- Refactor proman into a monorepo with `@shazhou/proman-core` and `@shazhou/proman` packages.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC3D,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,OAAO,EACb,MAAM,iBAAiB,CAAA;AAGxB,YAAY,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,SAAS,CAAA;IACf,aAAa,CAAC,EAAE,gBAAgB,CAAA;IAChC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAoBD;;;GAGG;AACH,wBAAsB,OAAO,CAAC,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC3D,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,OAAO,EACb,MAAM,iBAAiB,CAAA;AAGxB,YAAY,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,SAAS,CAAA;IACf,aAAa,CAAC,EAAE,gBAAgB,CAAA;IAChC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAoBD;;;GAGG;AACH,wBAAsB,OAAO,CAAC,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4HtE"}
|
package/dist/commands/publish.js
CHANGED
|
@@ -75,7 +75,12 @@ export async function publish(opts = {}) {
|
|
|
75
75
|
}
|
|
76
76
|
// Smoke test: validate tarball before publishing
|
|
77
77
|
try {
|
|
78
|
-
|
|
78
|
+
// Build workspace package map for symlink resolution
|
|
79
|
+
const workspacePackages = {};
|
|
80
|
+
for (const pkg of cfg.packages) {
|
|
81
|
+
workspacePackages[pkg.name] = resolve(cwd, pkg.path);
|
|
82
|
+
}
|
|
83
|
+
await smokeTestTarball(pkgDir, spawn, workspacePackages);
|
|
79
84
|
}
|
|
80
85
|
catch (err) {
|
|
81
86
|
const message = err.message;
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import type { SpawnFn } from './npm.js';
|
|
2
|
+
/**
|
|
3
|
+
* Map of workspace package names → absolute paths on disk.
|
|
4
|
+
* Used to symlink workspace dependencies into the smoke test directory
|
|
5
|
+
* so bin commands can resolve them without npm install.
|
|
6
|
+
*/
|
|
7
|
+
export type WorkspacePackages = Record<string, string>;
|
|
2
8
|
/**
|
|
3
9
|
* Smoke test a package tarball by extracting it and running bin commands.
|
|
4
10
|
* Validates that the packaged artifact actually works before publishing.
|
|
11
|
+
*
|
|
12
|
+
* @param workspacePackages - Map of workspace package names to their absolute
|
|
13
|
+
* paths. When provided, workspace dependencies are symlinked into the
|
|
14
|
+
* extracted tarball's node_modules so bin commands can resolve them.
|
|
5
15
|
*/
|
|
6
|
-
export declare function smokeTestTarball(pkgDir: string, spawn: SpawnFn): Promise<void>;
|
|
16
|
+
export declare function smokeTestTarball(pkgDir: string, spawn: SpawnFn, workspacePackages?: WorkspacePackages): Promise<void>;
|
|
7
17
|
//# sourceMappingURL=smoke-test.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smoke-test.d.ts","sourceRoot":"","sources":["../../src/utils/smoke-test.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"smoke-test.d.ts","sourceRoot":"","sources":["../../src/utils/smoke-test.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AASvC;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAEtD;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,EACd,iBAAiB,CAAC,EAAE,iBAAiB,GACpC,OAAO,CAAC,IAAI,CAAC,CAqFf"}
|
package/dist/utils/smoke-test.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import { readFile, rm } from 'node:fs/promises';
|
|
1
|
+
import { mkdir, readFile, rm, symlink } from 'node:fs/promises';
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
/**
|
|
5
5
|
* Smoke test a package tarball by extracting it and running bin commands.
|
|
6
6
|
* Validates that the packaged artifact actually works before publishing.
|
|
7
|
+
*
|
|
8
|
+
* @param workspacePackages - Map of workspace package names to their absolute
|
|
9
|
+
* paths. When provided, workspace dependencies are symlinked into the
|
|
10
|
+
* extracted tarball's node_modules so bin commands can resolve them.
|
|
7
11
|
*/
|
|
8
|
-
export async function smokeTestTarball(pkgDir, spawn) {
|
|
12
|
+
export async function smokeTestTarball(pkgDir, spawn, workspacePackages) {
|
|
9
13
|
// Read package.json to check for bin entries
|
|
10
14
|
const pkgJsonPath = join(pkgDir, 'package.json');
|
|
11
15
|
const pkgJsonText = await readFile(pkgJsonPath, 'utf8');
|
|
@@ -25,10 +29,13 @@ export async function smokeTestTarball(pkgDir, spawn) {
|
|
|
25
29
|
if (packResult.code !== 0) {
|
|
26
30
|
throw new Error(`pnpm pack failed: ${packResult.stderr || packResult.stdout}`);
|
|
27
31
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
// pnpm pack outputs verbose info (📦, file list, etc.)
|
|
33
|
+
// Extract the .tgz filename from the output
|
|
34
|
+
const tgzMatch = packResult.stdout.match(/[\w@.-]+\.tgz/);
|
|
35
|
+
if (!tgzMatch) {
|
|
36
|
+
throw new Error(`pnpm pack did not return tarball filename. Output: ${packResult.stdout}`);
|
|
31
37
|
}
|
|
38
|
+
const tarballName = tgzMatch[0];
|
|
32
39
|
// Step 2: Extract tarball to temp directory
|
|
33
40
|
const { mkdtemp } = await import('node:fs/promises');
|
|
34
41
|
const testDir = await mkdtemp(join(tmpdir(), 'proman-smoke-'));
|
|
@@ -41,7 +48,25 @@ export async function smokeTestTarball(pkgDir, spawn) {
|
|
|
41
48
|
}
|
|
42
49
|
// pnpm pack creates a 'package/' directory inside the tarball
|
|
43
50
|
const extractedPkgDir = join(testDir, 'package');
|
|
44
|
-
// Step 3:
|
|
51
|
+
// Step 3: Symlink workspace dependencies into node_modules
|
|
52
|
+
if (workspacePackages) {
|
|
53
|
+
const deps = pkgJson.dependencies ?? {};
|
|
54
|
+
const nodeModulesDir = join(extractedPkgDir, 'node_modules');
|
|
55
|
+
for (const [depName, depPath] of Object.entries(workspacePackages)) {
|
|
56
|
+
if (depName in deps) {
|
|
57
|
+
// Handle scoped packages: @scope/name → node_modules/@scope/name
|
|
58
|
+
const segments = depName.split('/');
|
|
59
|
+
if (segments.length === 2) {
|
|
60
|
+
await mkdir(join(nodeModulesDir, segments[0]), { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
await mkdir(nodeModulesDir, { recursive: true });
|
|
64
|
+
}
|
|
65
|
+
await symlink(depPath, join(nodeModulesDir, depName), 'dir');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Step 4: Test each bin entry
|
|
45
70
|
for (const [binName, binPath] of Object.entries(binEntries)) {
|
|
46
71
|
const binFullPath = join(extractedPkgDir, binPath);
|
|
47
72
|
const binTestResult = await spawn(['node', binFullPath, '--version'], extractedPkgDir);
|
|
@@ -52,7 +77,7 @@ export async function smokeTestTarball(pkgDir, spawn) {
|
|
|
52
77
|
}
|
|
53
78
|
}
|
|
54
79
|
finally {
|
|
55
|
-
// Step
|
|
80
|
+
// Step 5: Always clean up temp directory and tarball
|
|
56
81
|
await rm(testDir, { recursive: true, force: true });
|
|
57
82
|
await rm(join(pkgDir, tarballName), { force: true });
|
|
58
83
|
}
|
package/package.json
CHANGED
package/src/commands/publish.ts
CHANGED
|
@@ -113,7 +113,12 @@ export async function publish(opts: PublishOptions = {}): Promise<void> {
|
|
|
113
113
|
|
|
114
114
|
// Smoke test: validate tarball before publishing
|
|
115
115
|
try {
|
|
116
|
-
|
|
116
|
+
// Build workspace package map for symlink resolution
|
|
117
|
+
const workspacePackages: Record<string, string> = {}
|
|
118
|
+
for (const pkg of cfg.packages) {
|
|
119
|
+
workspacePackages[pkg.name] = resolve(cwd, pkg.path)
|
|
120
|
+
}
|
|
121
|
+
await smokeTestTarball(pkgDir, spawn, workspacePackages)
|
|
117
122
|
} catch (err) {
|
|
118
123
|
const message = (err as Error).message
|
|
119
124
|
const published = publishablePackages.slice(0, i).map((p) => p.name)
|
package/src/utils/smoke-test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFile, rm } from 'node:fs/promises'
|
|
1
|
+
import { mkdir, readFile, rm, symlink } from 'node:fs/promises'
|
|
2
2
|
import { tmpdir } from 'node:os'
|
|
3
3
|
import { join } from 'node:path'
|
|
4
4
|
import type { SpawnFn } from './npm.js'
|
|
@@ -7,13 +7,29 @@ type PackageJson = {
|
|
|
7
7
|
name: string
|
|
8
8
|
version: string
|
|
9
9
|
bin?: string | Record<string, string>
|
|
10
|
+
dependencies?: Record<string, string>
|
|
10
11
|
}
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Map of workspace package names → absolute paths on disk.
|
|
15
|
+
* Used to symlink workspace dependencies into the smoke test directory
|
|
16
|
+
* so bin commands can resolve them without npm install.
|
|
17
|
+
*/
|
|
18
|
+
export type WorkspacePackages = Record<string, string>
|
|
19
|
+
|
|
12
20
|
/**
|
|
13
21
|
* Smoke test a package tarball by extracting it and running bin commands.
|
|
14
22
|
* Validates that the packaged artifact actually works before publishing.
|
|
23
|
+
*
|
|
24
|
+
* @param workspacePackages - Map of workspace package names to their absolute
|
|
25
|
+
* paths. When provided, workspace dependencies are symlinked into the
|
|
26
|
+
* extracted tarball's node_modules so bin commands can resolve them.
|
|
15
27
|
*/
|
|
16
|
-
export async function smokeTestTarball(
|
|
28
|
+
export async function smokeTestTarball(
|
|
29
|
+
pkgDir: string,
|
|
30
|
+
spawn: SpawnFn,
|
|
31
|
+
workspacePackages?: WorkspacePackages,
|
|
32
|
+
): Promise<void> {
|
|
17
33
|
// Read package.json to check for bin entries
|
|
18
34
|
const pkgJsonPath = join(pkgDir, 'package.json')
|
|
19
35
|
const pkgJsonText = await readFile(pkgJsonPath, 'utf8')
|
|
@@ -39,10 +55,13 @@ export async function smokeTestTarball(pkgDir: string, spawn: SpawnFn): Promise<
|
|
|
39
55
|
throw new Error(`pnpm pack failed: ${packResult.stderr || packResult.stdout}`)
|
|
40
56
|
}
|
|
41
57
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
58
|
+
// pnpm pack outputs verbose info (📦, file list, etc.)
|
|
59
|
+
// Extract the .tgz filename from the output
|
|
60
|
+
const tgzMatch = packResult.stdout.match(/[\w@.-]+\.tgz/)
|
|
61
|
+
if (!tgzMatch) {
|
|
62
|
+
throw new Error(`pnpm pack did not return tarball filename. Output: ${packResult.stdout}`)
|
|
45
63
|
}
|
|
64
|
+
const tarballName = tgzMatch[0]
|
|
46
65
|
|
|
47
66
|
// Step 2: Extract tarball to temp directory
|
|
48
67
|
const { mkdtemp } = await import('node:fs/promises')
|
|
@@ -59,7 +78,26 @@ export async function smokeTestTarball(pkgDir: string, spawn: SpawnFn): Promise<
|
|
|
59
78
|
// pnpm pack creates a 'package/' directory inside the tarball
|
|
60
79
|
const extractedPkgDir = join(testDir, 'package')
|
|
61
80
|
|
|
62
|
-
// Step 3:
|
|
81
|
+
// Step 3: Symlink workspace dependencies into node_modules
|
|
82
|
+
if (workspacePackages) {
|
|
83
|
+
const deps = pkgJson.dependencies ?? {}
|
|
84
|
+
const nodeModulesDir = join(extractedPkgDir, 'node_modules')
|
|
85
|
+
|
|
86
|
+
for (const [depName, depPath] of Object.entries(workspacePackages)) {
|
|
87
|
+
if (depName in deps) {
|
|
88
|
+
// Handle scoped packages: @scope/name → node_modules/@scope/name
|
|
89
|
+
const segments = depName.split('/')
|
|
90
|
+
if (segments.length === 2) {
|
|
91
|
+
await mkdir(join(nodeModulesDir, segments[0] as string), { recursive: true })
|
|
92
|
+
} else {
|
|
93
|
+
await mkdir(nodeModulesDir, { recursive: true })
|
|
94
|
+
}
|
|
95
|
+
await symlink(depPath, join(nodeModulesDir, depName), 'dir')
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Step 4: Test each bin entry
|
|
63
101
|
for (const [binName, binPath] of Object.entries(binEntries)) {
|
|
64
102
|
const binFullPath = join(extractedPkgDir, binPath)
|
|
65
103
|
const binTestResult = await spawn(['node', binFullPath, '--version'], extractedPkgDir)
|
|
@@ -72,7 +110,7 @@ export async function smokeTestTarball(pkgDir: string, spawn: SpawnFn): Promise<
|
|
|
72
110
|
}
|
|
73
111
|
}
|
|
74
112
|
} finally {
|
|
75
|
-
// Step
|
|
113
|
+
// Step 5: Always clean up temp directory and tarball
|
|
76
114
|
await rm(testDir, { recursive: true, force: true })
|
|
77
115
|
await rm(join(pkgDir, tarballName), { force: true })
|
|
78
116
|
}
|