fix(ci): preserve pnpm links in packed probes
This commit is contained in:
@@ -3,15 +3,12 @@
|
|||||||
import { spawnSync } from 'node:child_process'
|
import { spawnSync } from 'node:child_process'
|
||||||
import {
|
import {
|
||||||
copyFileSync,
|
copyFileSync,
|
||||||
existsSync,
|
|
||||||
globSync,
|
globSync,
|
||||||
mkdirSync,
|
mkdirSync,
|
||||||
mkdtempSync,
|
mkdtempSync,
|
||||||
readFileSync,
|
readFileSync,
|
||||||
rmSync,
|
rmSync,
|
||||||
symlinkSync,
|
|
||||||
} from 'node:fs'
|
} from 'node:fs'
|
||||||
import { tmpdir } from 'node:os'
|
|
||||||
import { dirname, resolve } from 'node:path'
|
import { dirname, resolve } from 'node:path'
|
||||||
import { pathToFileURL } from 'node:url'
|
import { pathToFileURL } from 'node:url'
|
||||||
|
|
||||||
@@ -19,7 +16,6 @@ const root = resolve(import.meta.dirname, '..')
|
|||||||
const loaderUrl = pathToFileURL(resolve(root, 'vendor/loader/lib/index.js')).href
|
const loaderUrl = pathToFileURL(resolve(root, 'vendor/loader/lib/index.js')).href
|
||||||
const failures = []
|
const failures = []
|
||||||
const manifests = globSync('packages/*/*/package.json', { cwd: root }).sort()
|
const manifests = globSync('packages/*/*/package.json', { cwd: root }).sort()
|
||||||
const stagingRoot = mkdtempSync(resolve(tmpdir(), 'dsh-built-package-invariants-'))
|
|
||||||
const packArgs = ['pack', '--dry-run', '--json', '--ignore-scripts']
|
const packArgs = ['pack', '--dry-run', '--json', '--ignore-scripts']
|
||||||
// Windows cannot spawn npm's .cmd shim directly; setup-node installs this JS
|
// Windows cannot spawn npm's .cmd shim directly; setup-node installs this JS
|
||||||
// entrypoint beside node.exe, so the probe stays shell-free on every runner.
|
// entrypoint beside node.exe, so the probe stays shell-free on every runner.
|
||||||
@@ -27,38 +23,41 @@ const npmInvocation = process.platform === 'win32'
|
|||||||
? [process.execPath, [resolve(dirname(process.execPath), 'node_modules/npm/bin/npm-cli.js'), ...packArgs]]
|
? [process.execPath, [resolve(dirname(process.execPath), 'node_modules/npm/bin/npm-cli.js'), ...packArgs]]
|
||||||
: ['npm', packArgs]
|
: ['npm', packArgs]
|
||||||
|
|
||||||
try {
|
for (const manifestPath of manifests) {
|
||||||
for (const [index, manifestPath] of manifests.entries()) {
|
const packageDir = dirname(resolve(root, manifestPath))
|
||||||
const packageDir = dirname(resolve(root, manifestPath))
|
const manifest = JSON.parse(readFileSync(resolve(root, manifestPath), 'utf8'))
|
||||||
const manifest = JSON.parse(readFileSync(resolve(root, manifestPath), 'utf8'))
|
const packageName = manifest.name
|
||||||
const packageName = manifest.name
|
if (typeof packageName !== 'string' || packageName.length === 0) {
|
||||||
if (typeof packageName !== 'string' || packageName.length === 0) {
|
failures.push(`${manifestPath}: missing package name`)
|
||||||
failures.push(`${manifestPath}: missing package name`)
|
continue
|
||||||
continue
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const pack = spawnSync(npmInvocation[0], npmInvocation[1], {
|
const pack = spawnSync(npmInvocation[0], npmInvocation[1], {
|
||||||
cwd: packageDir,
|
cwd: packageDir,
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
})
|
})
|
||||||
if (pack.status !== 0) {
|
if (pack.status !== 0) {
|
||||||
const detail = pack.error?.message
|
const detail = pack.error?.message
|
||||||
?? (pack.stderr.trim() || pack.stdout.trim() || `npm pack exited ${pack.status}`)
|
?? (pack.stderr.trim() || pack.stdout.trim() || `npm pack exited ${pack.status}`)
|
||||||
failures.push(`${packageName}: ${detail}`)
|
failures.push(`${packageName}: ${detail}`)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let files
|
let files
|
||||||
try {
|
try {
|
||||||
const result = JSON.parse(pack.stdout)
|
const result = JSON.parse(pack.stdout)
|
||||||
files = result[0]?.files
|
files = result[0]?.files
|
||||||
if (!Array.isArray(files)) throw new Error('npm pack returned no file inventory')
|
if (!Array.isArray(files)) throw new Error('npm pack returned no file inventory')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
failures.push(`${packageName}: cannot parse npm pack inventory: ${String(error)}`)
|
failures.push(`${packageName}: cannot parse npm pack inventory: ${String(error)}`)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const stagedPackageDir = resolve(stagingRoot, String(index))
|
// Keep the packed view below its owning package so Node reaches the real
|
||||||
|
// pnpm dependency links. Junctioning node_modules elsewhere breaks pnpm's
|
||||||
|
// relative workspace links on Windows.
|
||||||
|
const stagedPackageDir = mkdtempSync(resolve(packageDir, '.dsh-packed-invariant-'))
|
||||||
|
try {
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
if (typeof file.path !== 'string'
|
if (typeof file.path !== 'string'
|
||||||
|| (file.path !== 'package.json' && !file.path.startsWith('lib/'))) continue
|
|| (file.path !== 'package.json' && !file.path.startsWith('lib/'))) continue
|
||||||
@@ -66,14 +65,6 @@ try {
|
|||||||
mkdirSync(dirname(target), { recursive: true })
|
mkdirSync(dirname(target), { recursive: true })
|
||||||
copyFileSync(resolve(packageDir, file.path), target)
|
copyFileSync(resolve(packageDir, file.path), target)
|
||||||
}
|
}
|
||||||
const packageNodeModules = resolve(packageDir, 'node_modules')
|
|
||||||
if (existsSync(packageNodeModules)) {
|
|
||||||
symlinkSync(
|
|
||||||
packageNodeModules,
|
|
||||||
resolve(stagedPackageDir, 'node_modules'),
|
|
||||||
process.platform === 'win32' ? 'junction' : 'dir',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const probe = `
|
const probe = `
|
||||||
const companion = await import(${JSON.stringify(`${packageName}/invariant`)});
|
const companion = await import(${JSON.stringify(`${packageName}/invariant`)});
|
||||||
@@ -92,13 +83,14 @@ try {
|
|||||||
cwd: stagedPackageDir,
|
cwd: stagedPackageDir,
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
})
|
})
|
||||||
if (result.status === 0) continue
|
if (result.status !== 0) {
|
||||||
const detail = result.error?.message
|
const detail = result.error?.message
|
||||||
?? (result.stderr.trim() || result.stdout.trim() || `node exited ${result.status}`)
|
?? (result.stderr.trim() || result.stdout.trim() || `node exited ${result.status}`)
|
||||||
failures.push(`${packageName}: ${detail}`)
|
failures.push(`${packageName}: ${detail}`)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
rmSync(stagedPackageDir, { recursive: true, force: true })
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
rmSync(stagingRoot, { recursive: true, force: true })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (failures.length > 0) {
|
if (failures.length > 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user