mirror of
https://github.com/pnpm/pnpm.git
synced 2026-04-29 03:26:25 -04:00
feat: add musl support to node runtime (#10664)
The lockfile now includes musl Linux builds (sourced from unofficial-builds.nodejs.org) alongside the standard glibc variants, so that `node@runtime:` works out of the box on Alpine Linux and other musl-based distributions. `env use` can download node.js artifacts for systems that use musl.
This commit is contained in:
7
.changeset/env-cross-platform-musl.md
Normal file
7
.changeset/env-cross-platform-musl.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@pnpm/node.fetcher": minor
|
||||
"@pnpm/plugin-commands-env": minor
|
||||
"pnpm": minor
|
||||
---
|
||||
|
||||
On systems using the musl C library (e.g. Alpine Linux), `pnpm env` now automatically downloads the musl variant of Node.js from [unofficial-builds.nodejs.org](https://unofficial-builds.nodejs.org).
|
||||
6
.changeset/node-runtime-musl-support.md
Normal file
6
.changeset/node-runtime-musl-support.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/node.resolver": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Include musl Linux variants when resolving `node@runtime:` dependencies. The lockfile now includes musl builds (from `unofficial-builds.nodejs.org`) alongside the standard glibc variants, so that `node@runtime:` works out of the box on Alpine Linux and other musl-based distributions.
|
||||
1
env/node.fetcher/package.json
vendored
1
env/node.fetcher/package.json
vendored
@@ -35,7 +35,6 @@
|
||||
"dependencies": {
|
||||
"@pnpm/create-cafs-store": "workspace:*",
|
||||
"@pnpm/crypto.shasums-file": "workspace:*",
|
||||
"@pnpm/error": "workspace:*",
|
||||
"@pnpm/fetching-types": "workspace:*",
|
||||
"@pnpm/fetching.binary-fetcher": "workspace:*",
|
||||
"@pnpm/node.resolver": "workspace:*",
|
||||
|
||||
67
env/node.fetcher/src/index.ts
vendored
67
env/node.fetcher/src/index.ts
vendored
@@ -1,5 +1,4 @@
|
||||
import path from 'path'
|
||||
import { PnpmError } from '@pnpm/error'
|
||||
import { fetchShasumsFileRaw, pickFileChecksumFromShasumsFile } from '@pnpm/crypto.shasums-file'
|
||||
import {
|
||||
type FetchFromRegistry,
|
||||
@@ -8,18 +7,22 @@ import {
|
||||
import { createCafsStore } from '@pnpm/create-cafs-store'
|
||||
import { type Cafs } from '@pnpm/cafs-types'
|
||||
import { createTarballFetcher } from '@pnpm/tarball-fetcher'
|
||||
import { getNodeArtifactAddress } from '@pnpm/node.resolver'
|
||||
import {
|
||||
getNodeArtifactAddress,
|
||||
DEFAULT_NODE_MIRROR_BASE_URL,
|
||||
UNOFFICIAL_NODE_MIRROR_BASE_URL,
|
||||
} from '@pnpm/node.resolver'
|
||||
import { downloadAndUnpackZip } from '@pnpm/fetching.binary-fetcher'
|
||||
import { isNonGlibcLinux } from 'detect-libc'
|
||||
|
||||
// Constants
|
||||
const DEFAULT_NODE_MIRROR_BASE_URL = 'https://nodejs.org/download/release/'
|
||||
|
||||
export interface FetchNodeOptionsToDir {
|
||||
storeDir: string
|
||||
fetchTimeout?: number
|
||||
nodeMirrorBaseUrl?: string
|
||||
retry?: RetryTimeoutOptions
|
||||
// Overrides for testing
|
||||
platform?: string
|
||||
arch?: string
|
||||
}
|
||||
|
||||
export interface FetchNodeOptions {
|
||||
@@ -44,7 +47,7 @@ interface NodeArtifactInfo {
|
||||
* @param version - Node.js version to install
|
||||
* @param targetDir - Directory where Node.js should be installed
|
||||
* @param opts - Configuration options for the fetch operation
|
||||
* @throws {PnpmError} When system uses MUSL libc, integrity verification fails, or download fails
|
||||
* @throws {PnpmError} When integrity verification fails or download fails
|
||||
*/
|
||||
export async function fetchNode (
|
||||
fetch: FetchFromRegistry,
|
||||
@@ -52,10 +55,26 @@ export async function fetchNode (
|
||||
targetDir: string,
|
||||
opts: FetchNodeOptionsToDir
|
||||
): Promise<void> {
|
||||
await validateSystemCompatibility()
|
||||
const platform = opts.platform ?? process.platform
|
||||
const arch = opts.arch ?? process.arch
|
||||
// On a native musl Linux system, automatically use the musl variant so that
|
||||
// pnpm env works out of the box on Alpine Linux and similar distributions.
|
||||
let libc: string | undefined
|
||||
if (platform === 'linux' && await isNonGlibcLinux()) {
|
||||
libc = 'musl'
|
||||
}
|
||||
|
||||
const nodeMirrorBaseUrl = opts.nodeMirrorBaseUrl ?? DEFAULT_NODE_MIRROR_BASE_URL
|
||||
const artifactInfo = await getNodeArtifactInfo(fetch, version, { nodeMirrorBaseUrl })
|
||||
const isMusl = libc === 'musl'
|
||||
const nodeMirrorBaseUrl = opts.nodeMirrorBaseUrl ?? (isMusl
|
||||
? UNOFFICIAL_NODE_MIRROR_BASE_URL
|
||||
: DEFAULT_NODE_MIRROR_BASE_URL)
|
||||
|
||||
const artifactInfo = await getNodeArtifactInfo(fetch, version, {
|
||||
nodeMirrorBaseUrl,
|
||||
platform,
|
||||
arch,
|
||||
libc,
|
||||
})
|
||||
|
||||
if (artifactInfo.isZip) {
|
||||
await downloadAndUnpackZip(fetch, artifactInfo, targetDir)
|
||||
@@ -65,26 +84,12 @@ export async function fetchNode (
|
||||
await downloadAndUnpackTarballToDir(fetch, artifactInfo, targetDir, opts)
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the current system is compatible with Node.js installation.
|
||||
*
|
||||
* @throws {PnpmError} When system uses MUSL libc
|
||||
*/
|
||||
async function validateSystemCompatibility (): Promise<void> {
|
||||
if (await isNonGlibcLinux()) {
|
||||
throw new PnpmError(
|
||||
'MUSL',
|
||||
'The current system uses the "MUSL" C standard library. Node.js currently has prebuilt artifacts only for the "glibc" libc, so we can install Node.js only for glibc'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets Node.js artifact information including URL, integrity, and file type.
|
||||
*
|
||||
* @param fetch - Function to fetch resources from registry
|
||||
* @param version - Node.js version
|
||||
* @param nodeMirrorBaseUrl - Base URL for Node.js mirror
|
||||
* @param opts - Options including nodeMirrorBaseUrl, platform, arch, and libc
|
||||
* @returns Promise resolving to artifact information
|
||||
* @throws {PnpmError} When integrity file cannot be fetched or parsed
|
||||
*/
|
||||
@@ -94,21 +99,28 @@ async function getNodeArtifactInfo (
|
||||
opts: {
|
||||
nodeMirrorBaseUrl: string
|
||||
integrities?: Record<string, string>
|
||||
platform: string
|
||||
arch: string
|
||||
libc?: string
|
||||
}
|
||||
): Promise<NodeArtifactInfo> {
|
||||
const isMusl = opts.libc === 'musl'
|
||||
|
||||
const tarball = getNodeArtifactAddress({
|
||||
version,
|
||||
baseUrl: opts.nodeMirrorBaseUrl,
|
||||
platform: process.platform,
|
||||
arch: process.arch,
|
||||
platform: opts.platform,
|
||||
arch: opts.arch,
|
||||
libc: opts.libc,
|
||||
})
|
||||
|
||||
const tarballFileName = `${tarball.basename}${tarball.extname}`
|
||||
const shasumsFileUrl = `${tarball.dirname}/SHASUMS256.txt`
|
||||
const url = `${tarball.dirname}/${tarballFileName}`
|
||||
|
||||
const integrityKey = isMusl ? `${opts.platform}-${opts.arch}-musl` : `${opts.platform}-${opts.arch}`
|
||||
const integrity = opts.integrities
|
||||
? opts.integrities[`${process.platform}-${process.arch}`]
|
||||
? opts.integrities[integrityKey]
|
||||
: await loadArtifactIntegrity(fetch, tarballFileName, shasumsFileUrl)
|
||||
|
||||
return {
|
||||
@@ -125,7 +137,6 @@ async function getNodeArtifactInfo (
|
||||
* @param fetch - Function to fetch resources from registry
|
||||
* @param fileName - Name of the file to find integrity for
|
||||
* @param shasumsUrl - URL of the SHASUMS256.txt file
|
||||
* @param options - Optional configuration for integrity verification
|
||||
* @returns Promise resolving to the integrity hash in base64 format
|
||||
* @throws {PnpmError} When integrity file cannot be fetched or parsed
|
||||
*/
|
||||
|
||||
39
env/node.fetcher/test/node.test.ts
vendored
39
env/node.fetcher/test/node.test.ts
vendored
@@ -13,7 +13,18 @@ jest.unstable_mockModule('detect-libc', () => ({
|
||||
const { fetchNode } = await import('@pnpm/node.fetcher')
|
||||
const { isNonGlibcLinux } = await import('detect-libc')
|
||||
|
||||
// A stable fake hex digest used as placeholder sha256 in mock SHASUMS256.txt files.
|
||||
// Any non-zero value works; the tarball content won't match, so integrity will
|
||||
// fail — but all URL assertions run before that happens.
|
||||
const FAKE_SHA256 = '5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef'
|
||||
|
||||
const fetchMock = jest.fn(async (url: string) => {
|
||||
if (url.endsWith('SHASUMS256.txt')) {
|
||||
// Return a minimal SHASUMS file covering the artifacts used in tests.
|
||||
return new Response(
|
||||
`${FAKE_SHA256} node-v22.0.0-linux-x64-musl.tar.gz\n`
|
||||
)
|
||||
}
|
||||
if (url.endsWith('.zip')) {
|
||||
// The Windows code path for pnpm's node bootstrapping expects a subdir
|
||||
// within the .zip file.
|
||||
@@ -62,15 +73,27 @@ test.skip('install Node using the default node mirror', async () => {
|
||||
}
|
||||
})
|
||||
|
||||
test('install Node using a custom node mirror #2', async () => {
|
||||
|
||||
test('auto-detects musl on non-glibc Linux and uses unofficial-builds mirror', async () => {
|
||||
jest.mocked(isNonGlibcLinux).mockReturnValue(Promise.resolve(true))
|
||||
tempDir()
|
||||
|
||||
const opts: FetchNodeOptions = {
|
||||
storeDir: path.resolve('store'),
|
||||
}
|
||||
|
||||
// The function will throw because the downloaded tarball content won't match
|
||||
// the fake sha256 we put in the SHASUMS256.txt mock, but all fetch calls are
|
||||
// recorded before the integrity check, so we can assert the correct URLs.
|
||||
await expect(
|
||||
fetchNode(fetchMock, '16.4.0', path.resolve('node'), opts)
|
||||
).rejects.toThrow('The current system uses the "MUSL" C standard library. Node.js currently has prebuilt artifacts only for the "glibc" libc, so we can install Node.js only for glibc')
|
||||
})
|
||||
fetchNode(fetchMock, '22.0.0', path.resolve('node'), {
|
||||
storeDir: path.resolve('store'),
|
||||
platform: 'linux',
|
||||
arch: 'x64',
|
||||
retry: { retries: 0 },
|
||||
})
|
||||
).rejects.toThrow()
|
||||
|
||||
const shasumsUrl = fetchMock.mock.calls[0][0] as string
|
||||
expect(shasumsUrl).toContain('unofficial-builds.nodejs.org')
|
||||
|
||||
const tarballUrl = fetchMock.mock.calls[1][0] as string
|
||||
expect(tarballUrl).toContain('unofficial-builds.nodejs.org')
|
||||
expect(tarballUrl).toContain('node-v22.0.0-linux-x64-musl.tar.gz')
|
||||
})
|
||||
3
env/node.fetcher/tsconfig.json
vendored
3
env/node.fetcher/tsconfig.json
vendored
@@ -24,9 +24,6 @@
|
||||
{
|
||||
"path": "../../network/fetching-types"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/error"
|
||||
},
|
||||
{
|
||||
"path": "../../store/cafs-types"
|
||||
},
|
||||
|
||||
@@ -11,6 +11,7 @@ export interface GetNodeArtifactAddressOptions {
|
||||
baseUrl: string
|
||||
platform: string
|
||||
arch: string
|
||||
libc?: string
|
||||
}
|
||||
|
||||
export function getNodeArtifactAddress ({
|
||||
@@ -18,13 +19,15 @@ export function getNodeArtifactAddress ({
|
||||
baseUrl,
|
||||
platform,
|
||||
arch,
|
||||
libc,
|
||||
}: GetNodeArtifactAddressOptions): NodeArtifactAddress {
|
||||
const isWindowsPlatform = platform === 'win32'
|
||||
const normalizedPlatform = isWindowsPlatform ? 'win' : platform
|
||||
const normalizedArch = getNormalizedArch(platform, arch, version)
|
||||
const archSuffix = libc === 'musl' ? '-musl' : ''
|
||||
return {
|
||||
dirname: `${baseUrl}v${version}`,
|
||||
basename: `node-v${version}-${normalizedPlatform}-${normalizedArch}`,
|
||||
basename: `node-v${version}-${normalizedPlatform}-${normalizedArch}${archSuffix}`,
|
||||
extname: isWindowsPlatform ? '.zip' : '.tar.gz',
|
||||
}
|
||||
}
|
||||
|
||||
50
env/node.resolver/src/index.ts
vendored
50
env/node.resolver/src/index.ts
vendored
@@ -5,6 +5,7 @@ import { type FetchFromRegistry } from '@pnpm/fetching-types'
|
||||
import {
|
||||
type BinaryResolution,
|
||||
type PlatformAssetResolution,
|
||||
type PlatformAssetTarget,
|
||||
type ResolveOptions,
|
||||
type ResolveResult,
|
||||
type VariationsResolution,
|
||||
@@ -19,6 +20,9 @@ import { getNodeArtifactAddress } from './getNodeArtifactAddress.js'
|
||||
|
||||
export { getNodeMirror, parseEnvSpecifier, getNodeArtifactAddress }
|
||||
|
||||
export const DEFAULT_NODE_MIRROR_BASE_URL = 'https://nodejs.org/download/release/'
|
||||
export const UNOFFICIAL_NODE_MIRROR_BASE_URL = 'https://unofficial-builds.nodejs.org/download/release/'
|
||||
|
||||
export interface NodeRuntimeResolveResult extends ResolveResult {
|
||||
resolution: VariationsResolution
|
||||
resolvedVia: 'nodejs.org'
|
||||
@@ -70,24 +74,56 @@ export async function resolveNodeRuntime (
|
||||
}
|
||||
|
||||
async function readNodeAssets (fetch: FetchFromRegistry, nodeMirrorBaseUrl: string, version: string): Promise<PlatformAssetResolution[]> {
|
||||
const assets = await readNodeAssetsFromMirror(fetch, { nodeMirrorBaseUrl, version, muslOnly: false })
|
||||
|
||||
// When using the default mirror, also fetch musl variants from unofficial-builds.nodejs.org,
|
||||
// since musl builds are not available on the official mirror.
|
||||
if (nodeMirrorBaseUrl === DEFAULT_NODE_MIRROR_BASE_URL) {
|
||||
try {
|
||||
const muslAssets = await readNodeAssetsFromMirror(fetch, { nodeMirrorBaseUrl: UNOFFICIAL_NODE_MIRROR_BASE_URL, version, muslOnly: true })
|
||||
assets.push(...muslAssets)
|
||||
} catch {
|
||||
// Musl variants may not be available for all Node.js versions (e.g. very old ones)
|
||||
}
|
||||
}
|
||||
|
||||
return assets
|
||||
}
|
||||
|
||||
async function readNodeAssetsFromMirror (
|
||||
fetch: FetchFromRegistry,
|
||||
opts: {
|
||||
nodeMirrorBaseUrl: string
|
||||
version: string
|
||||
muslOnly: boolean
|
||||
}
|
||||
): Promise<PlatformAssetResolution[]> {
|
||||
const { nodeMirrorBaseUrl, version, muslOnly } = opts
|
||||
const integritiesFileUrl = `${nodeMirrorBaseUrl}v${version}/SHASUMS256.txt`
|
||||
const shasumsFileItems = await fetchShasumsFile(fetch, integritiesFileUrl)
|
||||
const escaped = version.replace(/\\/g, '\\\\').replace(/\./g, '\\.')
|
||||
const pattern = new RegExp(`^node-v${escaped}-([^-.]+)-([^.]+)\\.(?:tar\\.gz|zip)$`)
|
||||
// The second capture group uses [^.-]+ to stop at a dash, so that the optional
|
||||
// third group can capture the '-musl' suffix separately (e.g. 'x64' + '-musl').
|
||||
const pattern = new RegExp(`^node-v${escaped}-([^-.]+)-([^.-]+)(-musl)?\\.(?:tar\\.gz|zip)$`)
|
||||
const assets: PlatformAssetResolution[] = []
|
||||
for (const { integrity, fileName } of shasumsFileItems) {
|
||||
const match = pattern.exec(fileName)
|
||||
if (!match) continue
|
||||
|
||||
let [, platform, arch] = match
|
||||
let [, platform, arch, muslSuffix] = match
|
||||
if (platform === 'win') {
|
||||
platform = 'win32'
|
||||
}
|
||||
const isMusl = muslSuffix != null
|
||||
if (muslOnly && !isMusl) continue
|
||||
|
||||
const libc = isMusl ? 'musl' : undefined
|
||||
const address = getNodeArtifactAddress({
|
||||
version,
|
||||
baseUrl: nodeMirrorBaseUrl,
|
||||
platform,
|
||||
arch,
|
||||
libc,
|
||||
})
|
||||
const url = `${address.dirname}/${address.basename}${address.extname}`
|
||||
const resolution: BinaryResolution = {
|
||||
@@ -100,11 +136,13 @@ async function readNodeAssets (fetch: FetchFromRegistry, nodeMirrorBaseUrl: stri
|
||||
if (resolution.archive === 'zip') {
|
||||
resolution.prefix = address.basename
|
||||
}
|
||||
const target: PlatformAssetTarget = {
|
||||
os: platform,
|
||||
cpu: arch,
|
||||
...(libc != null && { libc }),
|
||||
}
|
||||
assets.push({
|
||||
targets: [{
|
||||
os: platform,
|
||||
cpu: arch,
|
||||
}],
|
||||
targets: [target],
|
||||
resolution,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -64,3 +64,17 @@ test.each([
|
||||
arch,
|
||||
})).toStrictEqual(tarball)
|
||||
})
|
||||
|
||||
test('getNodeArtifactAddress with libc=musl appends -musl suffix to arch', () => {
|
||||
expect(getNodeArtifactAddress({
|
||||
version: '22.0.0',
|
||||
baseUrl: 'https://unofficial-builds.nodejs.org/download/release/',
|
||||
platform: 'linux',
|
||||
arch: 'x64',
|
||||
libc: 'musl',
|
||||
})).toStrictEqual({
|
||||
basename: 'node-v22.0.0-linux-x64-musl',
|
||||
dirname: 'https://unofficial-builds.nodejs.org/download/release/v22.0.0',
|
||||
extname: '.tar.gz',
|
||||
})
|
||||
})
|
||||
|
||||
1
env/plugin-commands-env/test/node.test.ts
vendored
1
env/plugin-commands-env/test/node.test.ts
vendored
@@ -24,6 +24,7 @@ const fetchMock = jest.fn(async (url: string) => {
|
||||
5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef node-v16.4.0-darwin-arm64.tar.gz
|
||||
5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef node-v16.4.0-linux-arm64.tar.gz
|
||||
5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef node-v16.4.0-linux-x64.tar.gz
|
||||
5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef node-v16.4.0-linux-x64-musl.tar.gz
|
||||
a08f3386090e6511772b949d41970b75a6b71d28abb551dff9854ceb1929dae1 node-v16.4.0-win-x64.zip
|
||||
5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef node-v18.0.0-rc.3-darwin-arm64.tar.gz
|
||||
5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef node-v18.0.0-rc.3-linux-arm64.tar.gz
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { LOCKFILE_VERSION, WANTED_LOCKFILE } from '@pnpm/constants'
|
||||
import { type VariationsResolution } from '@pnpm/resolver-base'
|
||||
import { prepareEmpty } from '@pnpm/prepare'
|
||||
import { addDependenciesToPackage, install } from '@pnpm/core'
|
||||
import { getIntegrity } from '@pnpm/registry-mock'
|
||||
@@ -8,7 +9,8 @@ import { sync as rimraf } from '@zkochan/rimraf'
|
||||
import { sync as writeYamlFile } from 'write-yaml-file'
|
||||
import { testDefaults } from '../utils/index.js'
|
||||
|
||||
const RESOLUTIONS = [
|
||||
// The standard glibc variants from nodejs.org/download/release/
|
||||
const GLIBC_RESOLUTIONS = [
|
||||
{
|
||||
targets: [
|
||||
{
|
||||
@@ -185,7 +187,9 @@ test('installing Node.js runtime', async () => {
|
||||
|
||||
project.isExecutable('.bin/node')
|
||||
expect(fs.readlinkSync('node_modules/node')).toContain(path.join('links', '@', 'node', '22.0.0'))
|
||||
expect(project.readLockfile()).toStrictEqual({
|
||||
|
||||
const lockfile = project.readLockfile()
|
||||
expect(lockfile).toStrictEqual({
|
||||
settings: {
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
@@ -206,7 +210,9 @@ test('installing Node.js runtime', async () => {
|
||||
hasBin: true,
|
||||
resolution: {
|
||||
type: 'variations',
|
||||
variants: RESOLUTIONS,
|
||||
// Musl variants from unofficial-builds.nodejs.org are appended alongside
|
||||
// the standard glibc variants, so use arrayContaining to allow them.
|
||||
variants: expect.arrayContaining(GLIBC_RESOLUTIONS),
|
||||
},
|
||||
version: '22.0.0',
|
||||
},
|
||||
@@ -215,6 +221,14 @@ test('installing Node.js runtime', async () => {
|
||||
'node@runtime:22.0.0': {},
|
||||
},
|
||||
})
|
||||
// Verify that musl variants are present for linux x64 and arm64.
|
||||
const variants = (lockfile.packages['node@runtime:22.0.0'].resolution as VariationsResolution).variants
|
||||
expect(variants).toContainEqual(expect.objectContaining({
|
||||
targets: [{ os: 'linux', cpu: 'x64', libc: 'musl' }],
|
||||
resolution: expect.objectContaining({
|
||||
url: expect.stringContaining('unofficial-builds.nodejs.org'),
|
||||
}),
|
||||
}))
|
||||
|
||||
// Verify that package.json is created
|
||||
expect(fs.existsSync(path.resolve('node_modules/node/package.json'))).toBeTruthy()
|
||||
@@ -254,7 +268,7 @@ test('installing Node.js runtime', async () => {
|
||||
hasBin: true,
|
||||
resolution: {
|
||||
type: 'variations',
|
||||
variants: RESOLUTIONS,
|
||||
variants: expect.arrayContaining(GLIBC_RESOLUTIONS),
|
||||
},
|
||||
version: '22.0.0',
|
||||
},
|
||||
@@ -309,7 +323,7 @@ test('installing Node.js runtime fails if integrity check fails', async () => {
|
||||
hasBin: true,
|
||||
resolution: {
|
||||
type: 'variations',
|
||||
variants: RESOLUTIONS.map((resolutionVariant) => ({
|
||||
variants: GLIBC_RESOLUTIONS.map((resolutionVariant) => ({
|
||||
...resolutionVariant,
|
||||
resolution: {
|
||||
...resolutionVariant.resolution,
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -2275,9 +2275,6 @@ importers:
|
||||
'@pnpm/crypto.shasums-file':
|
||||
specifier: workspace:*
|
||||
version: link:../../crypto/shasums-file
|
||||
'@pnpm/error':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/error
|
||||
'@pnpm/fetching-types':
|
||||
specifier: workspace:*
|
||||
version: link:../../network/fetching-types
|
||||
|
||||
Reference in New Issue
Block a user