Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support yarn v2+ w/wo corepack enabled
Browse files Browse the repository at this point in the history
fix #272
fix #496
close #506
JounQin committed Dec 21, 2023

Verified

This commit was signed with the committer’s verified signature.
JounQin JounQin
1 parent c7c63bf commit ae90c02
Showing 2 changed files with 52 additions and 17 deletions.
31 changes: 22 additions & 9 deletions src/getPackageResolution.ts
Original file line number Diff line number Diff line change
@@ -30,7 +30,14 @@ export function getPackageResolution({
throw new Error("Can't find yarn.lock file")
}
const lockFileString = readFileSync(lockFilePath).toString()
let appLockFile
let appLockFile: Record<
string,
{
version: string
resolution?: string
resolved?: string
}
>
if (lockFileString.includes("yarn lockfile v1")) {
const parsedYarnLockFile = parseYarnLockFile(lockFileString)
if (parsedYarnLockFile.type !== "success") {
@@ -59,7 +66,6 @@ export function getPackageResolution({
)

const resolutions = entries.map(([_, v]) => {
// @ts-ignore
return v.resolved
})

@@ -71,7 +77,7 @@ export function getPackageResolution({

if (new Set(resolutions).size !== 1) {
console.log(
`Ambigious lockfile entries for ${packageDetails.pathSpecifier}. Using version ${installedVersion}`,
`Ambiguous lockfile entries for ${packageDetails.pathSpecifier}. Using version ${installedVersion}`,
)
return installedVersion
}
@@ -80,18 +86,25 @@ export function getPackageResolution({
return resolutions[0]
}

const resolution = entries[0][0].slice(packageDetails.name.length + 1)
const packageName = packageDetails.name

const resolutionVersion = entries[0][1].version

// `@backstage/integration@npm:^1.5.0, @backstage/integration@npm:^1.7.0, @backstage/integration@npm:^1.7.2`
// ->
// `^1.5.0 ^1.7.0 ^1.7.2`
const resolution = entries[0][0]
.replace(new RegExp(packageName + "@", "g"), "")
.replace(/npm:/g, "")
.replace(/,/g, "")

// resolve relative file path
if (resolution.startsWith("file:.")) {
return `file:${resolve(appPath, resolution.slice("file:".length))}`
}

if (resolution.startsWith("npm:")) {
return resolution.replace("npm:", "")
}

return resolution
// add `resolutionVersion` to ensure correct version, `^1.0.0` could resolve latest `v1.3.0`, but `^1.0.0 1.2.1` won't
return resolutionVersion ? resolution + " " + resolutionVersion : resolution
} else {
const lockfile = require(join(
appPath,
38 changes: 30 additions & 8 deletions src/makePatch.ts
Original file line number Diff line number Diff line change
@@ -172,6 +172,8 @@ export function makePatch({
writeFileSync(
tmpRepoPackageJsonPath,
JSON.stringify({
// support `corepack` enabled without `.yarn/releases`
packageManager: appPackageJson.packageManager,
dependencies: {
[packageDetails.name]: getPackageResolution({
packageDetails,
@@ -193,7 +195,14 @@ export function makePatch({
// copy .npmrc/.yarnrc in case packages are hosted in private registry
// copy .yarn directory as well to ensure installations work in yarn 2
// tslint:disable-next-line:align
;[".npmrc", ".yarnrc", ".yarn"].forEach((rcFile) => {
;[
".npmrc",
".yarnrc",
".yarnrc.yml",
// don't include the whole `.yarn` directory which could contain huge `cache`
".yarn/plugins",
".yarn/releases",
].forEach((rcFile) => {
const rcPath = join(appPath, rcFile)
if (existsSync(rcPath)) {
copySync(rcPath, join(tmpRepo.name, rcFile), { dereference: true })
@@ -205,10 +214,19 @@ export function makePatch({
chalk.grey("•"),
`Installing ${packageDetails.name}@${packageVersion} with yarn`,
)
const yarnArgs = ["install"]
const yarnVersionCmd = spawnSafeSync(`yarn`, ["--version"], {
cwd: tmpRepoNpmRoot,
logStdErrOnError: false,
})
const isYarnV1 = yarnVersionCmd.stdout.toString().startsWith("1.")
if (isYarnV1) {
yarnArgs.push("--ignore-engines")
}
try {
// try first without ignoring scripts in case they are required
// this works in 99.99% of cases
spawnSafeSync(`yarn`, ["install", "--ignore-engines"], {
spawnSafeSync(`yarn`, yarnArgs, {
cwd: tmpRepoNpmRoot,
logStdErrOnError: false,
})
@@ -217,7 +235,7 @@ export function makePatch({
// an implicit context which we haven't reproduced
spawnSafeSync(
`yarn`,
["install", "--ignore-engines", "--ignore-scripts"],
[...yarnArgs, isYarnV1 ? "--ignore-scripts" : "--mode=skip-build"],
{
cwd: tmpRepoNpmRoot,
},
@@ -338,9 +356,8 @@ export function makePatch({
try {
parsePatchFile(diffResult.stdout.toString())
} catch (e) {
if (
(e as Error).message.includes("Unexpected file mode string: 120000")
) {
const err = e as Error
if (err.message.includes("Unexpected file mode string: 120000")) {
console.log(`
⛔️ ${chalk.red.bold("ERROR")}
@@ -358,7 +375,7 @@ export function makePatch({
outPath,
gzipSync(
JSON.stringify({
error: { message: e.message, stack: e.stack },
error: { message: err.message, stack: err.stack },
patch: diffResult.stdout.toString(),
}),
),
@@ -544,7 +561,12 @@ export function makePatch({
}
}
} catch (e) {
console.log(e)
const err = e as Error & {
stdout?: Buffer
stderr?: Buffer
}
// try to log more useful error message
console.log(err.stderr?.toString() || err.stdout?.toString() || e)
throw e
} finally {
tmpRepo.removeCallback()

0 comments on commit ae90c02

Please sign in to comment.