From 9efd8106592ffe5243a93357dfcb4f395c1b6a4a Mon Sep 17 00:00:00 2001 From: Mike Donnalley Date: Tue, 2 Jan 2024 12:12:42 -0800 Subject: [PATCH] fix: missing core yarn files (#1229) (#1230) * fix: missing core yarn files (#1229) * fix: missing core yarn files Newer versions of yarn depend on more files than "yarn.lock". As a result, the tarballs need to include these core files to ensure that any future commands against the tarball contents utilize the right version of `yarn`. Example: configuring yarn v4 with a "pinned version" requires the ".yarnrc.yml" file along with the `yarnPath` configuration value. If configured to use a specific version of yarn, Yarn will download required files into a "./.yarn/releases/" directory. In the future, any execution of `yarn` will pick up the `yarnPath` configuration and use the "./.yarn/releases/" directory contents to download and use the specific version of yarn. * fix: yarn root path * chore: satisfy linter --------- Co-authored-by: Eric Swanson --- src/tarballs/build.ts | 47 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/tarballs/build.ts b/src/tarballs/build.ts index 71bc8e49a..409f8b1cf 100644 --- a/src/tarballs/build.ts +++ b/src/tarballs/build.ts @@ -25,6 +25,48 @@ const pack = async (from: string, to: string) => { : await exec(`tar cfJ ${to} ${path.basename(from)}`, {cwd}) } +const isYarnProject = (yarnRootPath: string) => { + const yarnLockFileName = 'yarn.lock' + const rootYarnLockFilePath = path.join(yarnRootPath, yarnLockFileName) + + return existsSync(rootYarnLockFilePath) +} + +const copyCoreYarnFiles = async (yarnRootPath: string, workspacePath: string) => { + // copy yarn dependencies lock file + const yarnLockFileName = 'yarn.lock' + const rootYarnLockFilePath = path.join(yarnRootPath, yarnLockFileName) + const workspaceYarnLockFilePath = path.join(workspacePath, yarnLockFileName) + + if (existsSync(rootYarnLockFilePath)) { + await copy(rootYarnLockFilePath, workspaceYarnLockFilePath) + } + + // copy yarn configuration file + const yarnConfigFileName = '.yarnrc.yml' + const rootYarnConfigFilePath = path.join(yarnRootPath, yarnConfigFileName) + const workspaceYarnConfigFilePath = path.join(workspacePath, yarnConfigFileName) + + if (existsSync(rootYarnConfigFilePath)) { + await copy(rootYarnConfigFilePath, workspaceYarnConfigFilePath) + } + + // copy yarn releases e.g. yarn may be installed via a local config path like "yarnPath" + const yarnReleasesDirectoryRelativePath = './.yarn/releases/' + const rootYarnReleasesDirectoryPath = path.join(yarnRootPath, yarnReleasesDirectoryRelativePath) + const workspaceYarnReleasesDirectoryPath = path.join(workspacePath, yarnReleasesDirectoryRelativePath) + + if (existsSync(rootYarnReleasesDirectoryPath)) { + // create the directory if it does not exist + if (!existsSync(workspaceYarnReleasesDirectoryPath)) { + await mkdir(workspaceYarnReleasesDirectoryPath, {recursive: true}) + } + + // recursively copy all files in the directory + await copy(rootYarnReleasesDirectoryPath, workspaceYarnReleasesDirectoryPath) + } +} + export async function build( c: BuildConfig, options: { @@ -69,8 +111,9 @@ export async function build( const addDependencies = async () => { const yarnRoot = findYarnWorkspaceRoot(c.root) || c.root - if (existsSync(path.join(yarnRoot, 'yarn.lock'))) { - await copy(path.join(yarnRoot, 'yarn.lock'), path.join(c.workspace(), 'yarn.lock')) + + if (isYarnProject(yarnRoot)) { + await copyCoreYarnFiles(yarnRoot, c.workspace()) const {stdout} = await exec('yarn -v') const yarnVersion = stdout.charAt(0)