#!/usr/bin/env node /* * Copyright 2020 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* eslint-disable @backstage/no-undeclared-imports */ import { execFile as execFileCb } from "child_process"; import { resolve as resolvePath, dirname as dirnamePath } from "path"; import { promisify } from "util"; const execFile = promisify(execFileCb); async function findLockFiles() { // Not using relative paths as this should be run inside a workspace folder const projectRoot = resolvePath("."); let files = process.argv.slice(2).filter((arg) => !arg.startsWith("--")); for (const argumentFile of files) { if (!argumentFile.match(/(?:^|[\/\\])yarn.lock$/)) { throw new Error(`Not a yarn.lock file path argument: "${argumentFile}"`); } } if (!files.length) { // List all lock files that are in the root or in an immediate subdirectory files = ["yarn.lock"]; } return files.map((file) => ({ fileRelativeToProjectRoot: file, directoryRelativeToProjectRoot: dirnamePath(file), directoryAbsolute: resolvePath(projectRoot, dirnamePath(file)), })); } async function main() { const lockFiles = await findLockFiles(); let fix = false; for (const arg of process.argv) { if (arg.startsWith("--")) { if (arg === "--fix") { fix = true; } else { throw new Error(`Unknown argument ${arg}`); } } } for (const lockFile of lockFiles) { console.log("Checking lock file", lockFile.fileRelativeToProjectRoot); let stdout; let stderr; let failed; try { const result = await execFile( "yarn", ["dedupe", ...(fix ? [] : ["--check"])], { shell: true, cwd: lockFile.directoryAbsolute, } ); stdout = result.stdout?.trim(); stderr = result.stderr?.trim(); failed = false; } catch (error) { stdout = error.stdout?.trim(); stderr = error.stderr?.trim(); failed = true; } if (stdout) { console.log(stdout); } if (stderr) { console.error(stderr); } if (failed) { if (!fix) { const command = `yarn${ lockFile.directoryRelativeToProjectRoot === "." ? "" : ` --cwd ${lockFile.directoryRelativeToProjectRoot}` } dedupe`; const padding = " ".repeat(Math.max(0, 85 - 6 - command.length)); console.error(""); console.error( "*************************************************************************************" ); console.error( "* You have duplicate versions of some packages in a yarn.lock file. *" ); console.error( "* To solve this, run the following command from the project root and commit all *" ); console.log( "* yarn.lock changes. *" ); console.log( "* *" ); console.log(`* ${command}${padding} *`); console.error( "*************************************************************************************" ); console.error(""); } process.exit(1); } } } main().catch((error) => { console.error(error.stack); process.exit(1); });