From 067629593409de03d266838c0686d07a3b2a8f3f Mon Sep 17 00:00:00 2001 From: milahu Date: Thu, 18 Mar 2021 18:00:41 +0100 Subject: [PATCH 01/16] make work with pnpm and git, use pnpm-lock.yaml --- integration-tests/runIntegrationTest.ts | 4 +- package.json | 1 + property-based-tests/executeTestCase.ts | 21 ++++---- property-based-tests/testCases.ts | 2 +- src/detectPackageManager.ts | 4 +- src/filterFiles.ts | 6 +-- src/getPackageResolution.ts | 63 +++++++++++++++++++--- src/makePatch.ts | 68 +++++++++++++++++++----- src/packageIsDevDependency.ts | 4 +- src/patch/apply.ts | 2 +- src/patchFs.ts | 2 +- src/spawnSafe.ts | 70 ++++++++++++------------- 12 files changed, 171 insertions(+), 76 deletions(-) diff --git a/integration-tests/runIntegrationTest.ts b/integration-tests/runIntegrationTest.ts index 3e788a2a..26e86df6 100644 --- a/integration-tests/runIntegrationTest.ts +++ b/integration-tests/runIntegrationTest.ts @@ -7,7 +7,7 @@ import { resolveRelativeFileDependencies } from "../src/resolveRelativeFileDepen export const patchPackageTarballPath = resolve( fs .readdirSync(".") - .filter(nm => nm.match(/^patch-package\.test\.\d+\.tgz$/))[0], + .filter((nm) => nm.match(/^patch-package\.test\.\d+\.tgz$/))[0], ) export function runIntegrationTest({ @@ -64,7 +64,7 @@ export function runIntegrationTest({ expect(snapshots && snapshots.length).toBeTruthy() }) if (snapshots) { - snapshots.forEach(snapshot => { + snapshots.forEach((snapshot) => { const snapshotDescriptionMatch = snapshot.match(/SNAPSHOT: (.*)/) if (snapshotDescriptionMatch) { it(snapshotDescriptionMatch[1], () => { diff --git a/package.json b/package.json index bf67ee95..805112fc 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "@types/tmp": "^0.0.34", "husky": "^1.3.1", "jest": "^24.5.0", + "js-yaml": "^4.0.0", "lint-staged": "^8.1.5", "np": "^7.4.0", "prettier": "^2.2.1", diff --git a/property-based-tests/executeTestCase.ts b/property-based-tests/executeTestCase.ts index 87d19a77..fe47f651 100644 --- a/property-based-tests/executeTestCase.ts +++ b/property-based-tests/executeTestCase.ts @@ -24,32 +24,31 @@ jest.mock("fs-extra", () => { setWorkingFiles, getWorkingFiles, ensureDirSync: jest.fn(), - readFileSync: jest.fn(path => getWorkingFiles()[path].contents), + readFileSync: jest.fn((filePath) => getWorkingFiles()[filePath].contents), writeFileSync: jest.fn( - (path: string, contents: string, opts?: { mode?: number }) => { - getWorkingFiles()[path] = { + (filePath: string, contents: string, opts?: { mode?: number }) => { + getWorkingFiles()[filePath] = { contents, mode: opts && typeof opts.mode === "number" ? opts.mode : 0o644, } }, ), - unlinkSync: jest.fn(path => delete getWorkingFiles()[path]), + unlinkSync: jest.fn((filePath) => delete getWorkingFiles()[filePath]), moveSync: jest.fn((from, to) => { getWorkingFiles()[to] = getWorkingFiles()[from] delete getWorkingFiles()[from] }), - statSync: jest.fn(path => getWorkingFiles()[path]), - chmodSync: jest.fn((path, mode) => { - const { contents } = getWorkingFiles()[path] - getWorkingFiles()[path] = { contents, mode } + statSync: jest.fn((filePath) => getWorkingFiles()[filePath]), + chmodSync: jest.fn((filePath, mode) => { + const { contents } = getWorkingFiles()[filePath] + getWorkingFiles()[filePath] = { contents, mode } }), } }) function writeFiles(cwd: string, files: Files): void { const mkdirpSync = require("fs-extra/lib/mkdirs/index.js").mkdirpSync - const writeFileSync = require("fs").writeFileSync - Object.keys(files).forEach(filePath => { + Object.keys(files).forEach((filePath) => { if (!filePath.startsWith(".git/")) { mkdirpSync(path.join(cwd, path.dirname(filePath))) writeFileSync(path.join(cwd, filePath), files[filePath].contents, { @@ -62,7 +61,7 @@ function writeFiles(cwd: string, files: Files): void { function removeLeadingSpaceOnBlankLines(patchFileContents: string): string { return patchFileContents .split("\n") - .map(line => (line === " " ? "" : line)) + .map((line) => (line === " " ? "" : line)) .join("\n") } diff --git a/property-based-tests/testCases.ts b/property-based-tests/testCases.ts index 8fef3bb8..8875f754 100644 --- a/property-based-tests/testCases.ts +++ b/property-based-tests/testCases.ts @@ -121,7 +121,7 @@ function insertLinesIntoFile(file: File): File { function getUniqueFilename(files: Files) { let filename = makeFileName() const ks = Object.keys(files) - while (ks.some(k => k.startsWith(filename))) { + while (ks.some((k) => k.startsWith(filename))) { filename = makeFileName() } return filename diff --git a/src/detectPackageManager.ts b/src/detectPackageManager.ts index 00976527..1be8a810 100644 --- a/src/detectPackageManager.ts +++ b/src/detectPackageManager.ts @@ -4,7 +4,7 @@ import chalk from "chalk" import process from "process" import findWorkspaceRoot from "find-yarn-workspace-root" -export type PackageManager = "yarn" | "npm" | "npm-shrinkwrap" +export type PackageManager = "yarn" | "npm" | "npm-shrinkwrap" | "pnpm" function printNoYarnLockfileError() { console.error(` @@ -64,6 +64,8 @@ export const detectPackageManager = ( } } else if (yarnLockExists || findWorkspaceRoot()) { return "yarn" + } else if (fs.existsSync(join(appRootPath, "pnpm-lock.yaml"))) { + return "pnpm" } else { printNoLockfilesError() process.exit(1) diff --git a/src/filterFiles.ts b/src/filterFiles.ts index 60983b32..c707cd72 100644 --- a/src/filterFiles.ts +++ b/src/filterFiles.ts @@ -8,10 +8,10 @@ export function removeIgnoredFiles( excludePaths: RegExp, ) { klawSync(dir, { nodir: true }) - .map(item => item.path.slice(`${dir}/`.length)) + .map((item) => item.path.slice(`${dir}/`.length)) .filter( - relativePath => + (relativePath) => !relativePath.match(includePaths) || relativePath.match(excludePaths), ) - .forEach(relativePath => removeSync(join(dir, relativePath))) + .forEach((relativePath) => removeSync(join(dir, relativePath))) } diff --git a/src/getPackageResolution.ts b/src/getPackageResolution.ts index 5c8c158b..1a7374cc 100644 --- a/src/getPackageResolution.ts +++ b/src/getPackageResolution.ts @@ -5,6 +5,9 @@ import { readFileSync, existsSync } from "fs-extra" import { parse as parseYarnLockFile } from "@yarnpkg/lockfile" import findWorkspaceRoot from "find-yarn-workspace-root" import { getPackageVersion } from "./getPackageVersion" +import { execSync } from "child_process" + +const isVerbose = true // TODO expose to CLI export function getPackageResolution({ packageDetails, @@ -56,21 +59,69 @@ export function getPackageResolution({ console.warn( `Ambigious lockfile entries for ${packageDetails.pathSpecifier}. Using version ${installedVersion}`, ) - return installedVersion + return { version: installedVersion } } if (resolutions[0]) { - return resolutions[0] + return { version: resolutions[0] } } const resolution = entries[0][0].slice(packageDetails.name.length + 1) // resolve relative file path if (resolution.startsWith("file:.")) { - return `file:${resolve(appPath, resolution.slice("file:".length))}` + return { + version: `file:${resolve(appPath, resolution.slice("file:".length))}`, + } } - - return resolution + return { version: resolution } + } else if (packageManager === "pnpm") { + const lockfile = require("js-yaml").load( + require("fs").readFileSync(join(appPath, "pnpm-lock.yaml"), "utf8"), + ) + let resolvedVersion = + (lockfile.dependencies && lockfile.dependencies[packageDetails.name]) || + (lockfile.devDependencies && + lockfile.devDependencies[packageDetails.name]) + if (resolvedVersion.startsWith("link:")) { + const localPath = resolve(resolvedVersion.slice(5)) + if (isVerbose) { + console.log(`pnpm installed ${packageDetails.name} from ${localPath}`) + } + if (existsSync(localPath + "/.git")) { + // we hope that the originCommit will be available for future downloads + // otherwise our patch will not work ... + // ideally, we would use the last stable release before originCommit from npm or github + function exec(cmd: string) { + return execSync(cmd, { + cwd: localPath, + windowsHide: true, + encoding: "utf8", + }).trim() + } + const originUrl = exec("git remote get-url origin") + const originCommit = exec("git rev-parse origin/HEAD") // npm needs the long commit hash + resolvedVersion = `git+${originUrl}#${originCommit}` + if (isVerbose) { + console.log( + `using ${packageDetails.name} version ${resolvedVersion} from git origin/HEAD in ${localPath}`, + ) + } + return { version: resolvedVersion, originCommit } + } + const pkgJson = localPath + "/package.json" + if (existsSync(pkgJson)) { + resolvedVersion = require(pkgJson).version + console.warn( + `warning: using ${packageDetails.name} version ${resolvedVersion} from ${pkgJson}`, + ) + return { version: resolvedVersion } + } + } + if (isVerbose) { + console.log(`using ${packageDetails.name} version ${resolvedVersion}`) + } + return { version: resolvedVersion } } else { const lockfile = require(join( appPath, @@ -91,7 +142,7 @@ export function getPackageResolution({ entry.dependencies && packageDetails.name in entry.dependencies, ) const pkg = relevantStackEntry.dependencies[packageDetails.name] - return pkg.resolved || pkg.from || pkg.version + return { version: pkg.resolved || pkg.from || pkg.version } } } diff --git a/src/makePatch.ts b/src/makePatch.ts index 13696703..bbd97c03 100644 --- a/src/makePatch.ts +++ b/src/makePatch.ts @@ -10,6 +10,7 @@ import { unlinkSync, mkdirpSync, realpathSync, + renameSync, } from "fs-extra" import { sync as rimraf } from "rimraf" import { copySync } from "fs-extra" @@ -30,6 +31,8 @@ import { openIssueCreationLink, } from "./createIssue" +const isVerbose = true // TODO expose to CLI + function printNoPackageFoundError( packageName: string, packageJsonPath: string, @@ -87,17 +90,19 @@ export function makePatch({ console.info(chalk.grey("•"), "Creating temporary folder") + const resolvedVersion = getPackageResolution({ + packageDetails, + packageManager, + appPath, + }) + // make a blank package.json mkdirpSync(tmpRepoNpmRoot) writeFileSync( tmpRepoPackageJsonPath, JSON.stringify({ dependencies: { - [packageDetails.name]: getPackageResolution({ - packageDetails, - packageManager, - appPath, - }), + [packageDetails.name]: resolvedVersion.version, }, resolutions: resolveRelativeFileDependencies( appPath, @@ -106,9 +111,10 @@ export function makePatch({ }), ) - const packageVersion = getPackageVersion( - join(resolve(packageDetails.path), "package.json"), - ) + // originCommit is more precise than pkg.version + const packageVersion = + resolvedVersion.originCommit || + getPackageVersion(join(resolve(packageDetails.path), "package.json")) // copy .npmrc/.yarnrc in case packages are hosted in private registry // tslint:disable-next-line:align @@ -143,26 +149,42 @@ export function makePatch({ ) } } else { + const npmCmd = packageManager === "pnpm" ? "pnpm" : "npm" console.info( chalk.grey("•"), - `Installing ${packageDetails.name}@${packageVersion} with npm`, + `Installing ${packageDetails.name}@${packageVersion} with ${npmCmd}`, ) try { // try first without ignoring scripts in case they are required // this works in 99.99% of cases - spawnSafeSync(`npm`, ["i", "--force"], { + if (isVerbose) { + console.log(`run "${npmCmd} install --force" in ${tmpRepoNpmRoot}`) + } + spawnSafeSync(npmCmd, ["install", "--force"], { cwd: tmpRepoNpmRoot, logStdErrOnError: false, - stdio: "ignore", + stdio: isVerbose ? "inherit" : "ignore", }) } catch (e) { // try again while ignoring scripts in case the script depends on // an implicit context which we havn't reproduced - spawnSafeSync(`npm`, ["i", "--ignore-scripts", "--force"], { + if (isVerbose) { + console.log( + `run "${npmCmd} install --ignore-scripts --force" in ${tmpRepoNpmRoot}`, + ) + } + spawnSafeSync(npmCmd, ["install", "--ignore-scripts", "--force"], { cwd: tmpRepoNpmRoot, - stdio: "ignore", + stdio: isVerbose ? "inherit" : "ignore", }) } + if (packageManager === "pnpm") { + // workaround for `git diff`: replace symlink with hardlink + const pkgPath = tmpRepoNpmRoot + "/node_modules/" + packageDetails.name + const realPath = realpathSync(pkgPath) + unlinkSync(pkgPath) // rm symlink + renameSync(realPath, pkgPath) + } } const git = (...args: string[]) => @@ -193,8 +215,16 @@ export function makePatch({ // replace package with user's version rimraf(tmpRepoPackagePath) + if (isVerbose) { + console.log(`copy ${realpathSync(packagePath)} to ${tmpRepoPackagePath}`) + } + // pnpm installs packages as symlinks, copySync would copy only the symlink - copySync(realpathSync(packagePath), tmpRepoPackagePath) + copySync(realpathSync(packagePath), tmpRepoPackagePath, { + filter: (path) => { + return path.indexOf("/node_modules/") === -1 + }, + }) // remove nested node_modules just to be safe rimraf(join(tmpRepoPackagePath, "node_modules")) @@ -207,6 +237,13 @@ export function makePatch({ // stage all files git("add", "-f", packageDetails.path) + // TODO allow to add more paths via CLI, to exclude cache files like 'test/stubs*/**' + const ignorePaths = [ + "package-lock.json", + "pnpm-lock.yaml", + // 'test/stubs*/**', + ] + // get diff of changes const diffResult = git( "diff", @@ -214,6 +251,9 @@ export function makePatch({ "--no-color", "--ignore-space-at-eol", "--no-ext-diff", + ...ignorePaths.map( + (path) => `:(exclude,top)${packageDetails.path}/${path}`, + ), ) if (diffResult.stdout.length === 0) { diff --git a/src/packageIsDevDependency.ts b/src/packageIsDevDependency.ts index 2719c9be..330cb83d 100644 --- a/src/packageIsDevDependency.ts +++ b/src/packageIsDevDependency.ts @@ -14,5 +14,7 @@ export function packageIsDevDependency({ return false } const { devDependencies } = require(packageJsonPath) - return Boolean(devDependencies && devDependencies[packageDetails.packageNames[0]]) + return Boolean( + devDependencies && devDependencies[packageDetails.packageNames[0]], + ) } diff --git a/src/patch/apply.ts b/src/patch/apply.ts index c2601bae..0c21b61f 100644 --- a/src/patch/apply.ts +++ b/src/patch/apply.ts @@ -7,7 +7,7 @@ export const executeEffects = ( effects: ParsedPatchFile, { dryRun }: { dryRun: boolean }, ) => { - effects.forEach(eff => { + effects.forEach((eff) => { switch (eff.type) { case "file deletion": if (dryRun) { diff --git a/src/patchFs.ts b/src/patchFs.ts index 9786365e..13d9d49c 100644 --- a/src/patchFs.ts +++ b/src/patchFs.ts @@ -5,7 +5,7 @@ export const getPatchFiles = (patchesDir: string) => { try { return klawSync(patchesDir, { nodir: true }) .map(({ path }) => relative(patchesDir, path)) - .filter(path => path.endsWith(".patch")) + .filter((path) => path.endsWith(".patch")) } catch (e) { return [] } diff --git a/src/spawnSafe.ts b/src/spawnSafe.ts index 3ea042f7..baf7d8a3 100644 --- a/src/spawnSafe.ts +++ b/src/spawnSafe.ts @@ -1,35 +1,35 @@ -import { sync as spawnSync } from "cross-spawn" -import { SpawnOptions } from "child_process" - -export interface SpawnSafeOptions extends SpawnOptions { - throwOnError?: boolean - logStdErrOnError?: boolean - maxBuffer?: number -} - -const defaultOptions: SpawnSafeOptions = { - logStdErrOnError: true, - throwOnError: true, -} - -export const spawnSafeSync = ( - command: string, - args?: string[], - options?: SpawnSafeOptions, -) => { - const mergedOptions = Object.assign({}, defaultOptions, options) - const result = spawnSync(command, args, options) - if (result.error || result.status !== 0) { - if (mergedOptions.logStdErrOnError) { - if (result.stderr) { - console.error(result.stderr.toString()) - } else if (result.error) { - console.error(result.error) - } - } - if (mergedOptions.throwOnError) { - throw result - } - } - return result -} +import { sync as spawnSync } from "cross-spawn" +import { SpawnOptions } from "child_process" + +export interface SpawnSafeOptions extends SpawnOptions { + throwOnError?: boolean + logStdErrOnError?: boolean + maxBuffer?: number +} + +const defaultOptions: SpawnSafeOptions = { + logStdErrOnError: true, + throwOnError: true, +} + +export const spawnSafeSync = ( + command: string, + args?: string[], + options?: SpawnSafeOptions, +) => { + const mergedOptions = Object.assign({}, defaultOptions, options) + const result = spawnSync(command, args, options) + if (result.error || result.status !== 0) { + if (mergedOptions.logStdErrOnError) { + if (result.stderr) { + console.error(result.stderr.toString()) + } else if (result.error) { + console.error(result.error) + } + } + if (mergedOptions.throwOnError) { + throw result + } + } + return result +} From cd5f9875279ad7419322db58a88014e4544a684b Mon Sep 17 00:00:00 2001 From: milahu Date: Thu, 18 Mar 2021 21:25:01 +0100 Subject: [PATCH 02/16] fix bash scripts: enable alias --- .../adding-and-deleting-files/adding-and-deleting-files.sh | 1 + integration-tests/broken-patch-file/broken-patch-file.sh | 1 + integration-tests/collate-errors/collate-errors.sh | 1 + integration-tests/create-issue/create-issue.sh | 1 + integration-tests/custom-patch-dir/custom-patch-dir.sh | 1 + integration-tests/custom-resolutions/custom-resolutions.sh | 1 + .../delete-old-patch-files/delete-old-patch-files.sh | 1 + integration-tests/delete-scripts/delete-scripts.sh | 1 + integration-tests/dev-only-patches/dev-only-patches.sh | 1 + integration-tests/error-on-fail/error-on-fail.sh | 1 + integration-tests/fails-when-no-package/fails-when-no-package.sh | 1 + integration-tests/file-mode-changes/file-mode-changes.sh | 1 + integration-tests/happy-path-npm/happy-path-npm.sh | 1 + integration-tests/happy-path-yarn/happy-path-yarn.sh | 1 + integration-tests/ignore-whitespace/ignore-whitespace.sh | 1 + .../ignores-scripts-when-making-patch.sh | 1 + integration-tests/include-exclude-paths/include-exclude-paths.sh | 1 + .../include-exclude-regex-relativity.sh | 1 + integration-tests/lerna-canary/lerna-canary.sh | 1 + integration-tests/nested-packages/nested-packages.sh | 1 + .../nested-scoped-packages/nested-scoped-packages.sh | 1 + integration-tests/newIntegrationTest.ts | 1 + integration-tests/no-symbolic-links/no-symbolic-links.sh | 1 + integration-tests/package-gets-updated/package-gets-updated.sh | 1 + integration-tests/patch-parse-failure/patch-parse-failure.sh | 1 + integration-tests/reverse-option/reverse-option.sh | 1 + integration-tests/scoped-package/scoped-package.sh | 1 + .../unexpected-patch-creation-failure.sh | 1 + 28 files changed, 28 insertions(+) diff --git a/integration-tests/adding-and-deleting-files/adding-and-deleting-files.sh b/integration-tests/adding-and-deleting-files/adding-and-deleting-files.sh index 7695aaae..0a0b988f 100755 --- a/integration-tests/adding-and-deleting-files/adding-and-deleting-files.sh +++ b/integration-tests/adding-and-deleting-files/adding-and-deleting-files.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "add a file" diff --git a/integration-tests/broken-patch-file/broken-patch-file.sh b/integration-tests/broken-patch-file/broken-patch-file.sh index 33d102a7..c1f2954f 100755 --- a/integration-tests/broken-patch-file/broken-patch-file.sh +++ b/integration-tests/broken-patch-file/broken-patch-file.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package (>&2 echo "SNAPSHOT: patch-package fails when patch file is invalid") diff --git a/integration-tests/collate-errors/collate-errors.sh b/integration-tests/collate-errors/collate-errors.sh index a16b6aeb..6ea560b8 100755 --- a/integration-tests/collate-errors/collate-errors.sh +++ b/integration-tests/collate-errors/collate-errors.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "SNAPSHOT: left-pad, lodash, and zfs apply" diff --git a/integration-tests/create-issue/create-issue.sh b/integration-tests/create-issue/create-issue.sh index 884162ca..d04528e9 100755 --- a/integration-tests/create-issue/create-issue.sh +++ b/integration-tests/create-issue/create-issue.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "modify left-pad" diff --git a/integration-tests/custom-patch-dir/custom-patch-dir.sh b/integration-tests/custom-patch-dir/custom-patch-dir.sh index 6cb70625..f59a39e9 100755 --- a/integration-tests/custom-patch-dir/custom-patch-dir.sh +++ b/integration-tests/custom-patch-dir/custom-patch-dir.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "modify left-pad" diff --git a/integration-tests/custom-resolutions/custom-resolutions.sh b/integration-tests/custom-resolutions/custom-resolutions.sh index 86f9cc81..982d78f1 100755 --- a/integration-tests/custom-resolutions/custom-resolutions.sh +++ b/integration-tests/custom-resolutions/custom-resolutions.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "make changes to dependency/index.js" diff --git a/integration-tests/delete-old-patch-files/delete-old-patch-files.sh b/integration-tests/delete-old-patch-files/delete-old-patch-files.sh index ae6a5400..6a18ff22 100755 --- a/integration-tests/delete-old-patch-files/delete-old-patch-files.sh +++ b/integration-tests/delete-old-patch-files/delete-old-patch-files.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "apply patch-package" diff --git a/integration-tests/delete-scripts/delete-scripts.sh b/integration-tests/delete-scripts/delete-scripts.sh index aaa69e28..543d94d1 100755 --- a/integration-tests/delete-scripts/delete-scripts.sh +++ b/integration-tests/delete-scripts/delete-scripts.sh @@ -2,6 +2,7 @@ set -e echo 'install without error because package.json is sanitized' yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo 'unsnitize package.json' diff --git a/integration-tests/dev-only-patches/dev-only-patches.sh b/integration-tests/dev-only-patches/dev-only-patches.sh index 02b45983..8e261bc8 100755 --- a/integration-tests/dev-only-patches/dev-only-patches.sh +++ b/integration-tests/dev-only-patches/dev-only-patches.sh @@ -6,6 +6,7 @@ export NODE_ENV=production echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "SNAPSHOT: patch-package happily ignores slash because it's a dev dep" diff --git a/integration-tests/error-on-fail/error-on-fail.sh b/integration-tests/error-on-fail/error-on-fail.sh index 137b5601..9e109adf 100755 --- a/integration-tests/error-on-fail/error-on-fail.sh +++ b/integration-tests/error-on-fail/error-on-fail.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package export NODE_ENV="development" diff --git a/integration-tests/fails-when-no-package/fails-when-no-package.sh b/integration-tests/fails-when-no-package/fails-when-no-package.sh index b35f9503..38e7db1e 100755 --- a/integration-tests/fails-when-no-package/fails-when-no-package.sh +++ b/integration-tests/fails-when-no-package/fails-when-no-package.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package (>&2 echo "SNAPSHOT: no package present failure") diff --git a/integration-tests/file-mode-changes/file-mode-changes.sh b/integration-tests/file-mode-changes/file-mode-changes.sh index 2c82d0c5..c77f6168 100755 --- a/integration-tests/file-mode-changes/file-mode-changes.sh +++ b/integration-tests/file-mode-changes/file-mode-changes.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "check file permissions 1" diff --git a/integration-tests/happy-path-npm/happy-path-npm.sh b/integration-tests/happy-path-npm/happy-path-npm.sh index b6e6f98f..72c22ce2 100755 --- a/integration-tests/happy-path-npm/happy-path-npm.sh +++ b/integration-tests/happy-path-npm/happy-path-npm.sh @@ -5,6 +5,7 @@ npm i echo "add patch-package" npm i $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "Add left-pad" diff --git a/integration-tests/happy-path-yarn/happy-path-yarn.sh b/integration-tests/happy-path-yarn/happy-path-yarn.sh index e9e38409..c0b8ffc7 100755 --- a/integration-tests/happy-path-yarn/happy-path-yarn.sh +++ b/integration-tests/happy-path-yarn/happy-path-yarn.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "Add left-pad" diff --git a/integration-tests/ignore-whitespace/ignore-whitespace.sh b/integration-tests/ignore-whitespace/ignore-whitespace.sh index 106788cf..65cfc216 100755 --- a/integration-tests/ignore-whitespace/ignore-whitespace.sh +++ b/integration-tests/ignore-whitespace/ignore-whitespace.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "add random bits of whitespace" diff --git a/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh b/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh index 4f6fe336..24d9d5ec 100755 --- a/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh +++ b/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package npx replace postinstall lol node_modules/naughty-package/postinstall.sh diff --git a/integration-tests/include-exclude-paths/include-exclude-paths.sh b/integration-tests/include-exclude-paths/include-exclude-paths.sh index e7c4e476..dc1f2842 100755 --- a/integration-tests/include-exclude-paths/include-exclude-paths.sh +++ b/integration-tests/include-exclude-paths/include-exclude-paths.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "edit some files" diff --git a/integration-tests/include-exclude-regex-relativity/include-exclude-regex-relativity.sh b/integration-tests/include-exclude-regex-relativity/include-exclude-regex-relativity.sh index 70de62cd..6a5c670b 100755 --- a/integration-tests/include-exclude-regex-relativity/include-exclude-regex-relativity.sh +++ b/integration-tests/include-exclude-regex-relativity/include-exclude-regex-relativity.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "mutate words.js" diff --git a/integration-tests/lerna-canary/lerna-canary.sh b/integration-tests/lerna-canary/lerna-canary.sh index 38704f92..cf63d592 100755 --- a/integration-tests/lerna-canary/lerna-canary.sh +++ b/integration-tests/lerna-canary/lerna-canary.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package # this test makes sure that we can patch packages with build metadata in their version strings e.g. 4.5.6+commitsha diff --git a/integration-tests/nested-packages/nested-packages.sh b/integration-tests/nested-packages/nested-packages.sh index 6c56ad9b..b45df10e 100755 --- a/integration-tests/nested-packages/nested-packages.sh +++ b/integration-tests/nested-packages/nested-packages.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "wrap-ansi=>string-width should not contain patch-package" diff --git a/integration-tests/nested-scoped-packages/nested-scoped-packages.sh b/integration-tests/nested-scoped-packages/nested-scoped-packages.sh index 22307615..899921c8 100755 --- a/integration-tests/nested-scoped-packages/nested-scoped-packages.sh +++ b/integration-tests/nested-scoped-packages/nested-scoped-packages.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "@microsoft/mezzurite-core => @types/angular should not contain patch-package" diff --git a/integration-tests/newIntegrationTest.ts b/integration-tests/newIntegrationTest.ts index 266f9b89..72f6c0da 100644 --- a/integration-tests/newIntegrationTest.ts +++ b/integration-tests/newIntegrationTest.ts @@ -40,6 +40,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package `, { mode: 0o755 }, diff --git a/integration-tests/no-symbolic-links/no-symbolic-links.sh b/integration-tests/no-symbolic-links/no-symbolic-links.sh index 5aa02c60..242399d7 100755 --- a/integration-tests/no-symbolic-links/no-symbolic-links.sh +++ b/integration-tests/no-symbolic-links/no-symbolic-links.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "make symbolic link" diff --git a/integration-tests/package-gets-updated/package-gets-updated.sh b/integration-tests/package-gets-updated/package-gets-updated.sh index 384f9f40..036c1bb7 100755 --- a/integration-tests/package-gets-updated/package-gets-updated.sh +++ b/integration-tests/package-gets-updated/package-gets-updated.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "SNAPSHOT: left-pad should contain patch-package" diff --git a/integration-tests/patch-parse-failure/patch-parse-failure.sh b/integration-tests/patch-parse-failure/patch-parse-failure.sh index 38b2e875..3e8c9ada 100755 --- a/integration-tests/patch-parse-failure/patch-parse-failure.sh +++ b/integration-tests/patch-parse-failure/patch-parse-failure.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package (>&2 echo "SNAPSHOT: patch parse failure message") diff --git a/integration-tests/reverse-option/reverse-option.sh b/integration-tests/reverse-option/reverse-option.sh index 62777c5b..f5b3b87c 100755 --- a/integration-tests/reverse-option/reverse-option.sh +++ b/integration-tests/reverse-option/reverse-option.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "edit a file" diff --git a/integration-tests/scoped-package/scoped-package.sh b/integration-tests/scoped-package/scoped-package.sh index 5e82a76d..577ada19 100755 --- a/integration-tests/scoped-package/scoped-package.sh +++ b/integration-tests/scoped-package/scoped-package.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "SNAPSHOT: left-pad typings should contain patch-package" diff --git a/integration-tests/unexpected-patch-creation-failure/unexpected-patch-creation-failure.sh b/integration-tests/unexpected-patch-creation-failure/unexpected-patch-creation-failure.sh index 15588a57..397216b6 100755 --- a/integration-tests/unexpected-patch-creation-failure/unexpected-patch-creation-failure.sh +++ b/integration-tests/unexpected-patch-creation-failure/unexpected-patch-creation-failure.sh @@ -3,6 +3,7 @@ set -e echo "add patch-package" yarn add $1 +shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "modify left-pad" From 6a24fab7006fe67c2e0b7f7702dbb566773cdd11 Mon Sep 17 00:00:00 2001 From: milahu Date: Thu, 18 Mar 2021 21:28:22 +0100 Subject: [PATCH 03/16] fix makePatch copySync filter --- src/makePatch.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/makePatch.ts b/src/makePatch.ts index bbd97c03..1cd0a165 100644 --- a/src/makePatch.ts +++ b/src/makePatch.ts @@ -220,9 +220,10 @@ export function makePatch({ } // pnpm installs packages as symlinks, copySync would copy only the symlink - copySync(realpathSync(packagePath), tmpRepoPackagePath, { + const srcPath = realpathSync(packagePath) + copySync(srcPath, tmpRepoPackagePath, { filter: (path) => { - return path.indexOf("/node_modules/") === -1 + return !path.startsWith(srcPath + "/node_modules/") }, }) From bef38c1bfa9b5f192dcbef93a903e63a18034f97 Mon Sep 17 00:00:00 2001 From: milahu Date: Thu, 18 Mar 2021 23:29:19 +0100 Subject: [PATCH 04/16] fix: remove tempfiles, named tempfiles --- integration-tests/runIntegrationTest.ts | 7 +++++- property-based-tests/executeTestCase.ts | 8 ++++++- run-tests.sh | 3 +++ src/getPackageResolution.ts | 2 +- src/makePatch.ts | 30 +++++++++++++++++-------- 5 files changed, 38 insertions(+), 12 deletions(-) diff --git a/integration-tests/runIntegrationTest.ts b/integration-tests/runIntegrationTest.ts index 26e86df6..620e6303 100644 --- a/integration-tests/runIntegrationTest.ts +++ b/integration-tests/runIntegrationTest.ts @@ -18,7 +18,10 @@ export function runIntegrationTest({ shouldProduceSnapshots: boolean }) { describe(`Test ${projectName}:`, () => { - const tmpDir = tmp.dirSync({ unsafeCleanup: true }) + const tmpDir = tmp.dirSync({ + unsafeCleanup: true, + prefix: "patch-package.test-integration.", + }) fs.copySync(join(__dirname, projectName), tmpDir.name, { recursive: true, }) @@ -80,5 +83,7 @@ export function runIntegrationTest({ expect(snapshots && snapshots.length).toBeFalsy() }) } + + tmpDir.removeCallback() }) } diff --git a/property-based-tests/executeTestCase.ts b/property-based-tests/executeTestCase.ts index fe47f651..011b923e 100644 --- a/property-based-tests/executeTestCase.ts +++ b/property-based-tests/executeTestCase.ts @@ -82,7 +82,11 @@ export function executeTestCase(testCase: TestCase) { } } - const tmpDir = tmp.dirSync({ unsafeCleanup: true, mode: 0o100777 }) + const tmpDir = tmp.dirSync({ + unsafeCleanup: true, + mode: 0o100777, + prefix: "patch-package.test-property.", + }) spawnSafeSync("git", ["init"], { cwd: tmpDir.name }) @@ -144,4 +148,6 @@ export function executeTestCase(testCase: TestCase) { expect(fs.getWorkingFiles()).toEqual(testCase.cleanFiles) }) }) + + tmpDir.removeCallback() } diff --git a/run-tests.sh b/run-tests.sh index 894d5268..07ca4847 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -10,3 +10,6 @@ yarn version --new-version 0.0.0 --no-git-tag-version --no-commit-hooks yarn pack --filename patch-package.test.$(date +%s).tgz yarn version --new-version $version --no-git-tag-version --no-commit-hooks yarn jest "$@" + +# workaround for https://github.com/yarnpkg/yarn/issues/6685 +rm -rf /tmp/yarn--* || true diff --git a/src/getPackageResolution.ts b/src/getPackageResolution.ts index 1a7374cc..2356eba3 100644 --- a/src/getPackageResolution.ts +++ b/src/getPackageResolution.ts @@ -7,7 +7,7 @@ import findWorkspaceRoot from "find-yarn-workspace-root" import { getPackageVersion } from "./getPackageVersion" import { execSync } from "child_process" -const isVerbose = true // TODO expose to CLI +const isVerbose = false // TODO expose to CLI export function getPackageResolution({ packageDetails, diff --git a/src/makePatch.ts b/src/makePatch.ts index 1cd0a165..eb21ec20 100644 --- a/src/makePatch.ts +++ b/src/makePatch.ts @@ -31,7 +31,7 @@ import { openIssueCreationLink, } from "./createIssue" -const isVerbose = true // TODO expose to CLI +const isVerbose = false // TODO expose to CLI function printNoPackageFoundError( packageName: string, @@ -76,16 +76,26 @@ export function makePatch({ process.exit(1) } - const tmpRepo = dirSync({ unsafeCleanup: true }) - const tmpRepoPackagePath = join(tmpRepo.name, packageDetails.path) - const tmpRepoNpmRoot = tmpRepoPackagePath.slice( - 0, - -`/node_modules/${packageDetails.name}`.length, - ) + const tmpRepo = dirSync({ + unsafeCleanup: true, + prefix: "patch-package.tmpRepo.", + }) - const tmpRepoPackageJsonPath = join(tmpRepoNpmRoot, "package.json") + function cleanup() { + tmpRepo.removeCallback() + } try { + // finally: cleanup() + + const tmpRepoPackagePath = join(tmpRepo.name, packageDetails.path) + const tmpRepoNpmRoot = tmpRepoPackagePath.slice( + 0, + -`/node_modules/${packageDetails.name}`.length, + ) + + const tmpRepoPackageJsonPath = join(tmpRepoNpmRoot, "package.json") + const patchesDir = resolve(join(appPath, patchDir)) console.info(chalk.grey("•"), "Creating temporary folder") @@ -262,6 +272,7 @@ export function makePatch({ `⁉️ Not creating patch file for package '${packagePathSpecifier}'`, ) console.warn(`⁉️ There don't appear to be any changes.`) + cleanup() process.exit(1) return } @@ -313,6 +324,7 @@ export function makePatch({ `) } + cleanup() process.exit(1) return } @@ -352,7 +364,7 @@ export function makePatch({ console.error(e) throw e } finally { - tmpRepo.removeCallback() + cleanup() } } From 5eab211eb0dbbe00b8a0c4ab78ba7fd2e16ca30c Mon Sep 17 00:00:00 2001 From: milahu Date: Thu, 18 Mar 2021 23:41:46 +0100 Subject: [PATCH 05/16] rollback cd5f987 --- .../adding-and-deleting-files/adding-and-deleting-files.sh | 1 - integration-tests/broken-patch-file/broken-patch-file.sh | 1 - integration-tests/collate-errors/collate-errors.sh | 1 - integration-tests/create-issue/create-issue.sh | 1 - integration-tests/custom-patch-dir/custom-patch-dir.sh | 1 - integration-tests/custom-resolutions/custom-resolutions.sh | 1 - .../delete-old-patch-files/delete-old-patch-files.sh | 1 - integration-tests/delete-scripts/delete-scripts.sh | 1 - integration-tests/dev-only-patches/dev-only-patches.sh | 1 - integration-tests/error-on-fail/error-on-fail.sh | 1 - integration-tests/fails-when-no-package/fails-when-no-package.sh | 1 - integration-tests/file-mode-changes/file-mode-changes.sh | 1 - integration-tests/happy-path-npm/happy-path-npm.sh | 1 - integration-tests/happy-path-yarn/happy-path-yarn.sh | 1 - integration-tests/ignore-whitespace/ignore-whitespace.sh | 1 - .../ignores-scripts-when-making-patch.sh | 1 - integration-tests/include-exclude-paths/include-exclude-paths.sh | 1 - .../include-exclude-regex-relativity.sh | 1 - integration-tests/lerna-canary/lerna-canary.sh | 1 - integration-tests/nested-packages/nested-packages.sh | 1 - .../nested-scoped-packages/nested-scoped-packages.sh | 1 - integration-tests/newIntegrationTest.ts | 1 - integration-tests/no-symbolic-links/no-symbolic-links.sh | 1 - integration-tests/package-gets-updated/package-gets-updated.sh | 1 - integration-tests/patch-parse-failure/patch-parse-failure.sh | 1 - integration-tests/reverse-option/reverse-option.sh | 1 - integration-tests/scoped-package/scoped-package.sh | 1 - .../unexpected-patch-creation-failure.sh | 1 - 28 files changed, 28 deletions(-) diff --git a/integration-tests/adding-and-deleting-files/adding-and-deleting-files.sh b/integration-tests/adding-and-deleting-files/adding-and-deleting-files.sh index 0a0b988f..7695aaae 100755 --- a/integration-tests/adding-and-deleting-files/adding-and-deleting-files.sh +++ b/integration-tests/adding-and-deleting-files/adding-and-deleting-files.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "add a file" diff --git a/integration-tests/broken-patch-file/broken-patch-file.sh b/integration-tests/broken-patch-file/broken-patch-file.sh index c1f2954f..33d102a7 100755 --- a/integration-tests/broken-patch-file/broken-patch-file.sh +++ b/integration-tests/broken-patch-file/broken-patch-file.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package (>&2 echo "SNAPSHOT: patch-package fails when patch file is invalid") diff --git a/integration-tests/collate-errors/collate-errors.sh b/integration-tests/collate-errors/collate-errors.sh index 6ea560b8..a16b6aeb 100755 --- a/integration-tests/collate-errors/collate-errors.sh +++ b/integration-tests/collate-errors/collate-errors.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "SNAPSHOT: left-pad, lodash, and zfs apply" diff --git a/integration-tests/create-issue/create-issue.sh b/integration-tests/create-issue/create-issue.sh index d04528e9..884162ca 100755 --- a/integration-tests/create-issue/create-issue.sh +++ b/integration-tests/create-issue/create-issue.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "modify left-pad" diff --git a/integration-tests/custom-patch-dir/custom-patch-dir.sh b/integration-tests/custom-patch-dir/custom-patch-dir.sh index f59a39e9..6cb70625 100755 --- a/integration-tests/custom-patch-dir/custom-patch-dir.sh +++ b/integration-tests/custom-patch-dir/custom-patch-dir.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "modify left-pad" diff --git a/integration-tests/custom-resolutions/custom-resolutions.sh b/integration-tests/custom-resolutions/custom-resolutions.sh index 982d78f1..86f9cc81 100755 --- a/integration-tests/custom-resolutions/custom-resolutions.sh +++ b/integration-tests/custom-resolutions/custom-resolutions.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "make changes to dependency/index.js" diff --git a/integration-tests/delete-old-patch-files/delete-old-patch-files.sh b/integration-tests/delete-old-patch-files/delete-old-patch-files.sh index 6a18ff22..ae6a5400 100755 --- a/integration-tests/delete-old-patch-files/delete-old-patch-files.sh +++ b/integration-tests/delete-old-patch-files/delete-old-patch-files.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "apply patch-package" diff --git a/integration-tests/delete-scripts/delete-scripts.sh b/integration-tests/delete-scripts/delete-scripts.sh index 543d94d1..aaa69e28 100755 --- a/integration-tests/delete-scripts/delete-scripts.sh +++ b/integration-tests/delete-scripts/delete-scripts.sh @@ -2,7 +2,6 @@ set -e echo 'install without error because package.json is sanitized' yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo 'unsnitize package.json' diff --git a/integration-tests/dev-only-patches/dev-only-patches.sh b/integration-tests/dev-only-patches/dev-only-patches.sh index 8e261bc8..02b45983 100755 --- a/integration-tests/dev-only-patches/dev-only-patches.sh +++ b/integration-tests/dev-only-patches/dev-only-patches.sh @@ -6,7 +6,6 @@ export NODE_ENV=production echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "SNAPSHOT: patch-package happily ignores slash because it's a dev dep" diff --git a/integration-tests/error-on-fail/error-on-fail.sh b/integration-tests/error-on-fail/error-on-fail.sh index 9e109adf..137b5601 100755 --- a/integration-tests/error-on-fail/error-on-fail.sh +++ b/integration-tests/error-on-fail/error-on-fail.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package export NODE_ENV="development" diff --git a/integration-tests/fails-when-no-package/fails-when-no-package.sh b/integration-tests/fails-when-no-package/fails-when-no-package.sh index 38e7db1e..b35f9503 100755 --- a/integration-tests/fails-when-no-package/fails-when-no-package.sh +++ b/integration-tests/fails-when-no-package/fails-when-no-package.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package (>&2 echo "SNAPSHOT: no package present failure") diff --git a/integration-tests/file-mode-changes/file-mode-changes.sh b/integration-tests/file-mode-changes/file-mode-changes.sh index c77f6168..2c82d0c5 100755 --- a/integration-tests/file-mode-changes/file-mode-changes.sh +++ b/integration-tests/file-mode-changes/file-mode-changes.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "check file permissions 1" diff --git a/integration-tests/happy-path-npm/happy-path-npm.sh b/integration-tests/happy-path-npm/happy-path-npm.sh index 72c22ce2..b6e6f98f 100755 --- a/integration-tests/happy-path-npm/happy-path-npm.sh +++ b/integration-tests/happy-path-npm/happy-path-npm.sh @@ -5,7 +5,6 @@ npm i echo "add patch-package" npm i $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "Add left-pad" diff --git a/integration-tests/happy-path-yarn/happy-path-yarn.sh b/integration-tests/happy-path-yarn/happy-path-yarn.sh index c0b8ffc7..e9e38409 100755 --- a/integration-tests/happy-path-yarn/happy-path-yarn.sh +++ b/integration-tests/happy-path-yarn/happy-path-yarn.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "Add left-pad" diff --git a/integration-tests/ignore-whitespace/ignore-whitespace.sh b/integration-tests/ignore-whitespace/ignore-whitespace.sh index 65cfc216..106788cf 100755 --- a/integration-tests/ignore-whitespace/ignore-whitespace.sh +++ b/integration-tests/ignore-whitespace/ignore-whitespace.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "add random bits of whitespace" diff --git a/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh b/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh index 24d9d5ec..4f6fe336 100755 --- a/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh +++ b/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package npx replace postinstall lol node_modules/naughty-package/postinstall.sh diff --git a/integration-tests/include-exclude-paths/include-exclude-paths.sh b/integration-tests/include-exclude-paths/include-exclude-paths.sh index dc1f2842..e7c4e476 100755 --- a/integration-tests/include-exclude-paths/include-exclude-paths.sh +++ b/integration-tests/include-exclude-paths/include-exclude-paths.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "edit some files" diff --git a/integration-tests/include-exclude-regex-relativity/include-exclude-regex-relativity.sh b/integration-tests/include-exclude-regex-relativity/include-exclude-regex-relativity.sh index 6a5c670b..70de62cd 100755 --- a/integration-tests/include-exclude-regex-relativity/include-exclude-regex-relativity.sh +++ b/integration-tests/include-exclude-regex-relativity/include-exclude-regex-relativity.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "mutate words.js" diff --git a/integration-tests/lerna-canary/lerna-canary.sh b/integration-tests/lerna-canary/lerna-canary.sh index cf63d592..38704f92 100755 --- a/integration-tests/lerna-canary/lerna-canary.sh +++ b/integration-tests/lerna-canary/lerna-canary.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package # this test makes sure that we can patch packages with build metadata in their version strings e.g. 4.5.6+commitsha diff --git a/integration-tests/nested-packages/nested-packages.sh b/integration-tests/nested-packages/nested-packages.sh index b45df10e..6c56ad9b 100755 --- a/integration-tests/nested-packages/nested-packages.sh +++ b/integration-tests/nested-packages/nested-packages.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "wrap-ansi=>string-width should not contain patch-package" diff --git a/integration-tests/nested-scoped-packages/nested-scoped-packages.sh b/integration-tests/nested-scoped-packages/nested-scoped-packages.sh index 899921c8..22307615 100755 --- a/integration-tests/nested-scoped-packages/nested-scoped-packages.sh +++ b/integration-tests/nested-scoped-packages/nested-scoped-packages.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "@microsoft/mezzurite-core => @types/angular should not contain patch-package" diff --git a/integration-tests/newIntegrationTest.ts b/integration-tests/newIntegrationTest.ts index 72f6c0da..266f9b89 100644 --- a/integration-tests/newIntegrationTest.ts +++ b/integration-tests/newIntegrationTest.ts @@ -40,7 +40,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package `, { mode: 0o755 }, diff --git a/integration-tests/no-symbolic-links/no-symbolic-links.sh b/integration-tests/no-symbolic-links/no-symbolic-links.sh index 242399d7..5aa02c60 100755 --- a/integration-tests/no-symbolic-links/no-symbolic-links.sh +++ b/integration-tests/no-symbolic-links/no-symbolic-links.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "make symbolic link" diff --git a/integration-tests/package-gets-updated/package-gets-updated.sh b/integration-tests/package-gets-updated/package-gets-updated.sh index 036c1bb7..384f9f40 100755 --- a/integration-tests/package-gets-updated/package-gets-updated.sh +++ b/integration-tests/package-gets-updated/package-gets-updated.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "SNAPSHOT: left-pad should contain patch-package" diff --git a/integration-tests/patch-parse-failure/patch-parse-failure.sh b/integration-tests/patch-parse-failure/patch-parse-failure.sh index 3e8c9ada..38b2e875 100755 --- a/integration-tests/patch-parse-failure/patch-parse-failure.sh +++ b/integration-tests/patch-parse-failure/patch-parse-failure.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package (>&2 echo "SNAPSHOT: patch parse failure message") diff --git a/integration-tests/reverse-option/reverse-option.sh b/integration-tests/reverse-option/reverse-option.sh index f5b3b87c..62777c5b 100755 --- a/integration-tests/reverse-option/reverse-option.sh +++ b/integration-tests/reverse-option/reverse-option.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "edit a file" diff --git a/integration-tests/scoped-package/scoped-package.sh b/integration-tests/scoped-package/scoped-package.sh index 577ada19..5e82a76d 100755 --- a/integration-tests/scoped-package/scoped-package.sh +++ b/integration-tests/scoped-package/scoped-package.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "SNAPSHOT: left-pad typings should contain patch-package" diff --git a/integration-tests/unexpected-patch-creation-failure/unexpected-patch-creation-failure.sh b/integration-tests/unexpected-patch-creation-failure/unexpected-patch-creation-failure.sh index 397216b6..15588a57 100755 --- a/integration-tests/unexpected-patch-creation-failure/unexpected-patch-creation-failure.sh +++ b/integration-tests/unexpected-patch-creation-failure/unexpected-patch-creation-failure.sh @@ -3,7 +3,6 @@ set -e echo "add patch-package" yarn add $1 -shopt -s expand_aliases # enable alias alias patch-package=./node_modules/.bin/patch-package echo "modify left-pad" From 8b80357ab2347c94cb2e08fa5c61d19bd415c00c Mon Sep 17 00:00:00 2001 From: milahu Date: Tue, 11 May 2021 22:51:52 +0200 Subject: [PATCH 06/16] add workaround for linked pkgs, add --verbose and --debug cli flags --- src/getPackageResolution.ts | 61 ++++++++++++++++++++++++++++++++++--- src/index.ts | 24 ++++++++++----- src/makePatch.ts | 42 +++++++++++++++++++------ src/nodejsGlobal.d.ts | 6 ++++ tslint.json | 3 +- 5 files changed, 114 insertions(+), 22 deletions(-) create mode 100644 src/nodejsGlobal.d.ts diff --git a/src/getPackageResolution.ts b/src/getPackageResolution.ts index 2356eba3..de54ffc4 100644 --- a/src/getPackageResolution.ts +++ b/src/getPackageResolution.ts @@ -7,16 +7,19 @@ import findWorkspaceRoot from "find-yarn-workspace-root" import { getPackageVersion } from "./getPackageVersion" import { execSync } from "child_process" -const isVerbose = false // TODO expose to CLI +const isVerbose = global.patchPackageIsVerbose +const isDebug = global.patchPackageIsDebug export function getPackageResolution({ packageDetails, packageManager, appPath, + appPackageJson, }: { packageDetails: PackageDetails packageManager: PackageManager appPath: string + appPackageJson: any }) { if (packageManager === "yarn") { let lockFilePath = "yarn.lock" @@ -76,17 +79,63 @@ export function getPackageResolution({ } return { version: resolution } } else if (packageManager === "pnpm") { + // WORKAROUND for pnpm bug? pnpm-lock.yaml says version 1.2.3 for linked packages, not link:../../path/to/package + const declaredVersion = + (appPackageJson.dependencies && + appPackageJson.dependencies[packageDetails.name]) || + (appPackageJson.devDependencies && + appPackageJson.devDependencies[packageDetails.name]) + if (isDebug) { + console.log( + `patch-package/getPackageResolution: declaredVersion = ${declaredVersion}`, + ) + } + const lockfile = require("js-yaml").load( require("fs").readFileSync(join(appPath, "pnpm-lock.yaml"), "utf8"), ) + if (isDebug) { + console.log(`patch-package/getPackageResolution: appPath = ${appPath}`) + console.log(`patch-package/getPackageResolution: packageDetails:`) + console.dir(packageDetails) + console.log( + `patch-package/getPackageResolution: packageDetails.name = ${packageDetails.name}`, + ) + console.log( + `patch-package/getPackageResolution: lockfile.dependencies[packageDetails.name] = ${ + lockfile.dependencies[packageDetails.name] + }`, + ) + console.log( + `patch-package/getPackageResolution: lockfile.devDependencies[packageDetails.name] = ${ + lockfile.devDependencies[packageDetails.name] + }`, + ) + } let resolvedVersion = (lockfile.dependencies && lockfile.dependencies[packageDetails.name]) || (lockfile.devDependencies && lockfile.devDependencies[packageDetails.name]) + if (declaredVersion.startsWith("link:")) { + // WORKAROUND + if (isDebug) { + console.log( + `patch-package/getPackageResolution: using declaredVersion ${declaredVersion}, not resolvedVersion ${resolvedVersion}`, + ) + } + resolvedVersion = declaredVersion + } + if (isDebug) { + console.log( + `patch-package/getPackageResolution: resolvedVersion = ${resolvedVersion}`, + ) + } if (resolvedVersion.startsWith("link:")) { const localPath = resolve(resolvedVersion.slice(5)) if (isVerbose) { - console.log(`pnpm installed ${packageDetails.name} from ${localPath}`) + console.log( + `patch-package/getPackageResolution: pnpm installed ${packageDetails.name} from ${localPath}`, + ) } if (existsSync(localPath + "/.git")) { // we hope that the originCommit will be available for future downloads @@ -100,11 +149,12 @@ export function getPackageResolution({ }).trim() } const originUrl = exec("git remote get-url origin") + // TODO what if the upstream repo is not called "origin"? const originCommit = exec("git rev-parse origin/HEAD") // npm needs the long commit hash resolvedVersion = `git+${originUrl}#${originCommit}` if (isVerbose) { console.log( - `using ${packageDetails.name} version ${resolvedVersion} from git origin/HEAD in ${localPath}`, + `patch-package/getPackageResolution: using ${packageDetails.name} version ${resolvedVersion} from git origin/HEAD in ${localPath}`, ) } return { version: resolvedVersion, originCommit } @@ -119,7 +169,9 @@ export function getPackageResolution({ } } if (isVerbose) { - console.log(`using ${packageDetails.name} version ${resolvedVersion}`) + console.log( + `patch-package/getPackageResolution: using ${packageDetails.name} version ${resolvedVersion}`, + ) } return { version: resolvedVersion } } else { @@ -158,6 +210,7 @@ if (require.main === module) { appPath: process.cwd(), packageDetails, packageManager: detectPackageManager(process.cwd(), null), + appPackageJson: {}, // TODO? }), ) } diff --git a/src/index.ts b/src/index.ts index a4691a28..95aeab39 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,15 +2,8 @@ import chalk from "chalk" import process from "process" import minimist from "minimist" -import { applyPatchesForApp } from "./applyPatches" import { getAppRootPath } from "./getAppRootPath" -import { makePatch } from "./makePatch" -import { makeRegExp } from "./makeRegExp" -import { detectPackageManager } from "./detectPackageManager" import { join } from "./path" -import { normalize, sep } from "path" -import slash = require("slash") -import isCi from "is-ci" const appPath = getAppRootPath() const argv = minimist(process.argv.slice(2), { @@ -33,6 +26,23 @@ console.log( require(join(__dirname, "../package.json")).version, ) +// used in imported modules +const isDebug = (global.patchPackageIsDebug = Boolean(argv.debug)) +global.patchPackageIsVerbose = isDebug || Boolean(argv.verbose) + +if (isDebug) { + console.log(`patch-package/index: argv:`) + console.dir(argv) +} + +import { applyPatchesForApp } from "./applyPatches" +import { makePatch } from "./makePatch" +import { makeRegExp } from "./makeRegExp" +import { detectPackageManager } from "./detectPackageManager" +import { normalize, sep } from "path" +import slash = require("slash") +import isCi from "is-ci" + if (argv.version || argv.v) { // noop } else if (argv.help || argv.h) { diff --git a/src/makePatch.ts b/src/makePatch.ts index eb21ec20..0ee83a7c 100644 --- a/src/makePatch.ts +++ b/src/makePatch.ts @@ -31,7 +31,8 @@ import { openIssueCreationLink, } from "./createIssue" -const isVerbose = false // TODO expose to CLI +const isVerbose = global.patchPackageIsVerbose +const isDebug = global.patchPackageIsDebug function printNoPackageFoundError( packageName: string, @@ -104,6 +105,7 @@ export function makePatch({ packageDetails, packageManager, appPath, + appPackageJson, }) // make a blank package.json @@ -122,10 +124,27 @@ export function makePatch({ ) // originCommit is more precise than pkg.version + if (isDebug) { + console.log( + `patch-package/makePatch: resolvedVersion.originCommit = ${resolvedVersion.originCommit}`, + ) + } const packageVersion = resolvedVersion.originCommit || getPackageVersion(join(resolve(packageDetails.path), "package.json")) + if (isDebug) { + console.log(`patch-package/makePatch: packageVersion = ${packageVersion}`) + console.log( + `patch-package/makePatch: package path = ${packageDetails.path}`, + ) + console.log( + `patch-package/makePatch: package path resolved = ${resolve( + packageDetails.path, + )}`, + ) + } + // copy .npmrc/.yarnrc in case packages are hosted in private registry // tslint:disable-next-line:align ;[".npmrc", ".yarnrc"].forEach((rcFile) => { @@ -168,7 +187,9 @@ export function makePatch({ // try first without ignoring scripts in case they are required // this works in 99.99% of cases if (isVerbose) { - console.log(`run "${npmCmd} install --force" in ${tmpRepoNpmRoot}`) + console.log( + `patch-package/makePatch: run "${npmCmd} install --force" in ${tmpRepoNpmRoot}`, + ) } spawnSafeSync(npmCmd, ["install", "--force"], { cwd: tmpRepoNpmRoot, @@ -180,7 +201,7 @@ export function makePatch({ // an implicit context which we havn't reproduced if (isVerbose) { console.log( - `run "${npmCmd} install --ignore-scripts --force" in ${tmpRepoNpmRoot}`, + `patch-package/makePatch: run "${npmCmd} install --ignore-scripts --force" in ${tmpRepoNpmRoot}`, ) } spawnSafeSync(npmCmd, ["install", "--ignore-scripts", "--force"], { @@ -217,6 +238,7 @@ export function makePatch({ git("config", "--local", "user.email", "patch@pack.age") // remove ignored files first + // use CLI options --exclude and --include removeIgnoredFiles(tmpRepoPackagePath, includePaths, excludePaths) git("add", "-f", packageDetails.path) @@ -226,7 +248,11 @@ export function makePatch({ rimraf(tmpRepoPackagePath) if (isVerbose) { - console.log(`copy ${realpathSync(packagePath)} to ${tmpRepoPackagePath}`) + console.log( + `patch-package/makePatch: copy ${realpathSync( + packagePath, + )} to ${tmpRepoPackagePath}`, + ) } // pnpm installs packages as symlinks, copySync would copy only the symlink @@ -243,17 +269,13 @@ export function makePatch({ rimraf(join(tmpRepoPackagePath, ".git")) // also remove ignored files like before + // use CLI options --exclude and --include removeIgnoredFiles(tmpRepoPackagePath, includePaths, excludePaths) // stage all files git("add", "-f", packageDetails.path) - // TODO allow to add more paths via CLI, to exclude cache files like 'test/stubs*/**' - const ignorePaths = [ - "package-lock.json", - "pnpm-lock.yaml", - // 'test/stubs*/**', - ] + const ignorePaths = ["package-lock.json", "pnpm-lock.yaml"] // get diff of changes const diffResult = git( diff --git a/src/nodejsGlobal.d.ts b/src/nodejsGlobal.d.ts new file mode 100644 index 00000000..fd1fe845 --- /dev/null +++ b/src/nodejsGlobal.d.ts @@ -0,0 +1,6 @@ +declare namespace NodeJS { + interface Global { + patchPackageIsVerbose: boolean + patchPackageIsDebug: boolean + } +} diff --git a/tslint.json b/tslint.json index ea76ddb6..a68d883e 100644 --- a/tslint.json +++ b/tslint.json @@ -17,7 +17,8 @@ "no-trailing-whitespace": [false], "object-literal-key-quotes": [false], "max-line-length": false, - "no-default-export": true + "no-default-export": true, + "no-namespace": false }, "rulesDirectory": [] } From f95a44224237848fc264e620fcbcc15023f6d9c9 Mon Sep 17 00:00:00 2001 From: milahu Date: Wed, 12 May 2021 13:29:40 +0200 Subject: [PATCH 07/16] use declared package version. add header comments to patchfiles --- package.json | 1 + src/getPackageResolution.ts | 11 +++- src/makePatch.ts | 56 ++++++++++++++++++- src/patch/parse.ts | 16 +++++- .../nodejs.global.d.ts} | 0 tslint.json | 3 +- 6 files changed, 78 insertions(+), 9 deletions(-) rename src/{nodejsGlobal.d.ts => types/nodejs.global.d.ts} (100%) diff --git a/package.json b/package.json index 805112fc..8c428c7d 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "open": "^7.4.2", "rimraf": "^2.6.3", "semver": "^5.6.0", + "shlex": "^2.0.2", "slash": "^2.0.0", "tmp": "^0.0.33" }, diff --git a/src/getPackageResolution.ts b/src/getPackageResolution.ts index de54ffc4..71431a6e 100644 --- a/src/getPackageResolution.ts +++ b/src/getPackageResolution.ts @@ -5,9 +5,9 @@ import { readFileSync, existsSync } from "fs-extra" import { parse as parseYarnLockFile } from "@yarnpkg/lockfile" import findWorkspaceRoot from "find-yarn-workspace-root" import { getPackageVersion } from "./getPackageVersion" -import { execSync } from "child_process" +//import { execSync } from "child_process" -const isVerbose = global.patchPackageIsVerbose +//const isVerbose = global.patchPackageIsVerbose const isDebug = global.patchPackageIsDebug export function getPackageResolution({ @@ -91,6 +91,12 @@ export function getPackageResolution({ ) } + // TODO validate: declaredVersion must not be wildcard + return { version: declaredVersion } + + // TODO dont use lockfiles at all? + // package versions should be pinned in /package.json, so it works with all package managers at all times + /* const lockfile = require("js-yaml").load( require("fs").readFileSync(join(appPath, "pnpm-lock.yaml"), "utf8"), ) @@ -174,6 +180,7 @@ export function getPackageResolution({ ) } return { version: resolvedVersion } + */ } else { const lockfile = require(join( appPath, diff --git a/src/makePatch.ts b/src/makePatch.ts index 0ee83a7c..8d0006e3 100644 --- a/src/makePatch.ts +++ b/src/makePatch.ts @@ -25,11 +25,12 @@ import { resolveRelativeFileDependencies } from "./resolveRelativeFileDependenci import { getPackageResolution } from "./getPackageResolution" import { parsePatchFile } from "./patch/parse" import { gzipSync } from "zlib" -import { getPackageVersion } from "./getPackageVersion" +//import { getPackageVersion } from "./getPackageVersion" import { maybePrintIssueCreationPrompt, openIssueCreationLink, } from "./createIssue" +import { quote as shlexQuote } from "shlex" const isVerbose = global.patchPackageIsVerbose const isDebug = global.patchPackageIsDebug @@ -123,15 +124,25 @@ export function makePatch({ }), ) + /* // originCommit is more precise than pkg.version if (isDebug) { console.log( `patch-package/makePatch: resolvedVersion.originCommit = ${resolvedVersion.originCommit}`, ) + console.log( + `patch-package/makePatch: resolvedVersion.version = ${resolvedVersion.version}`, + ) } const packageVersion = resolvedVersion.originCommit || getPackageVersion(join(resolve(packageDetails.path), "package.json")) + */ + + // this is broken when installing from git -> version can be a pseudo-version like 1.0.0-canary + //const packageVersion = getPackageVersion(join(resolve(packageDetails.path), "package.json")) + + const packageVersion = resolvedVersion.version if (isDebug) { console.log(`patch-package/makePatch: packageVersion = ${packageVersion}`) @@ -359,6 +370,36 @@ export function makePatch({ } }) + const patchPackageVersion = require("../package.json").version + + // patchfiles are parsed in patch/parse.ts function parsePatchLines + // -> header comments are ignored + let diffHeader = "" + diffHeader += `# generated by patch-package ${patchPackageVersion} on ${new Date().toLocaleString( + "lt", + )}\n` + diffHeader += `#\n` + const prettyArgv = process.argv.slice() + if (prettyArgv[0].match(/node/)) { + prettyArgv[0] = "npx" + } + if (prettyArgv[1].match(/patch-package/)) { + prettyArgv[1] = "patch-package" + } + diffHeader += `# command:\n` + diffHeader += `# ${prettyArgv.map((a) => shlexQuote(a)).join(" ")}\n` + diffHeader += `#\n` + diffHeader += `# declared package:\n` + diffHeader += `# ${packageDetails.name}: ${resolvedVersion.version}\n` // TODO rename to declaredVersion + if (packageDetails.packageNames.length > 1) { + diffHeader += `#\n` + diffHeader += `# package names:\n` + packageDetails.packageNames.forEach((packageName) => { + diffHeader += `# ${packageName}\n` + }) + } + diffHeader += `#\n` + const patchFileName = createPatchFileName({ packageDetails, packageVersion, @@ -369,7 +410,7 @@ export function makePatch({ // scoped package mkdirSync(dirname(patchPath)) } - writeFileSync(patchPath, diffResult.stdout) + writeFileSync(patchPath, diffHeader + diffResult.stdout) console.log( `${chalk.green("✔")} Created file ${join(patchDir, patchFileName)}\n`, ) @@ -397,9 +438,18 @@ function createPatchFileName({ packageDetails: PackageDetails packageVersion: string }) { + const packageVersionFilename = packageVersion.includes("#") + ? packageVersion.split("#")[1] // extract commit hash + : packageVersion.replace(/\//g, "_") + if (isVerbose) { + console.log( + `patch-package/makePatch: packageVersion ${packageVersion} -> packageVersionFilename ${packageVersionFilename}`, + ) + } + const packageNames = packageDetails.packageNames .map((name) => name.replace(/\//g, "+")) .join("++") - return `${packageNames}+${packageVersion}.patch` + return `${packageNames}+${packageVersionFilename}.patch` } diff --git a/src/patch/parse.ts b/src/patch/parse.ts index 97fb533d..51ff53bd 100644 --- a/src/patch/parse.ts +++ b/src/patch/parse.ts @@ -175,7 +175,16 @@ function parsePatchLines( const line = lines[i] if (state === "parsing header") { - if (line.startsWith("@@")) { + if (line.startsWith("#")) { + // ignore metadata comment line in header + // in the unidiff format, all header lines before `--- a/` are comment lines + // git-diff uses these comment lines to store metadata + // https://stackoverflow.com/questions/18979120 + if (global.patchPackageIsDebug) { + console.log(`patch-package/patch/parse: ignore comment line: ${line}`) + } + continue + } else if (line.startsWith("@@")) { state = "parsing hunks" currentFilePatch.hunks = [] i-- @@ -206,9 +215,10 @@ function parsePatchLines( } else if (line.startsWith("rename to ")) { currentFilePatch.renameTo = line.slice("rename to ".length).trim() } else if (line.startsWith("index ")) { - const match = line.match(/(\w+)\.\.(\w+)/) + const match = line.match(/(\w+)\.\.(\w+)/) // TODO match whole line + //const match = line.match(/^index (\w+)\.\.(\w+)$/) if (!match) { - continue + continue // TODO handle parse error? } currentFilePatch.beforeHash = match[1] currentFilePatch.afterHash = match[2] diff --git a/src/nodejsGlobal.d.ts b/src/types/nodejs.global.d.ts similarity index 100% rename from src/nodejsGlobal.d.ts rename to src/types/nodejs.global.d.ts diff --git a/tslint.json b/tslint.json index a68d883e..e33715fa 100644 --- a/tslint.json +++ b/tslint.json @@ -18,7 +18,8 @@ "object-literal-key-quotes": [false], "max-line-length": false, "no-default-export": true, - "no-namespace": false + "no-namespace": false, + "comment-format": false }, "rulesDirectory": [] } From eaf653879876c3fddf354de4110bfef3c3dbf0f1 Mon Sep 17 00:00:00 2001 From: milahu Date: Wed, 12 May 2021 14:00:46 +0200 Subject: [PATCH 08/16] debug test on github: ignores-scripts-when-making-patch --- .../ignores-scripts-when-making-patch.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh b/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh index 4f6fe336..7ce697e8 100755 --- a/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh +++ b/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh @@ -14,5 +14,10 @@ echo "END SNAPSHOT" (>&2 echo "END SNAPSHOT") echo "SNAPSHOT: a patch file got produced" +[ ! -f patches/naughty-package+1.0.0.patch ] && { + echo "ERROR: file not found: patches/naughty-package+1.0.0.patch" + echo "ls patches/:" + ls patches/ +} cat patches/naughty-package+1.0.0.patch echo "END SNAPSHOT" \ No newline at end of file From bf8e1e7a80ceb17165be5ed0f82f44465d14d7c1 Mon Sep 17 00:00:00 2001 From: milahu Date: Wed, 12 May 2021 16:58:06 +0200 Subject: [PATCH 09/16] replace minimist with dashdash argv parser --- package.json | 4 ++-- src/index.ts | 55 ++++++++++++++++++++++++++++------------------------ 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 8c428c7d..6988685c 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,6 @@ "@types/fs-extra": "^5.0.5", "@types/is-ci": "^1.1.0", "@types/jest": "^24.0.11", - "@types/minimist": "^1.2.0", "@types/node": "^11.11.6", "@types/rimraf": "^2.0.2", "@types/semver": "^5.5.0", @@ -72,14 +71,15 @@ "typescript": "^4.2.2" }, "dependencies": { + "@types/dashdash": "^1.14.0", "@yarnpkg/lockfile": "^1.1.0", "chalk": "^2.4.2", "cross-spawn": "^6.0.5", + "dashdash": "^2.0.0", "find-yarn-workspace-root": "^2.0.0", "fs-extra": "^7.0.1", "is-ci": "^2.0.0", "klaw-sync": "^6.0.0", - "minimist": "^1.2.0", "open": "^7.4.2", "rimraf": "^2.6.3", "semver": "^5.6.0", diff --git a/src/index.ts b/src/index.ts index 95aeab39..9847e0aa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,24 +1,29 @@ import chalk from "chalk" import process from "process" -import minimist from "minimist" +import dashdash from "dashdash" import { getAppRootPath } from "./getAppRootPath" import { join } from "./path" const appPath = getAppRootPath() -const argv = minimist(process.argv.slice(2), { - boolean: [ - "use-yarn", - "case-sensitive-path-filtering", - "reverse", - "help", - "version", - "error-on-fail", - "create-issue", - ], - string: ["patch-dir"], -}) -const packageNames = argv._ + +var dashdashOptions = [ + { name: "use-yarn", type: "bool" }, + { name: "case-sensitive-path-filtering", type: "bool" }, + { name: "reverse", type: "bool" }, + { names: ["help", "h"], type: "bool" }, + { names: ["version", "v"], type: "bool" }, + { name: "error-on-fail", type: "bool" }, + { name: "verbose", type: "bool" }, + { name: "debug", type: "bool" }, + { name: "patch-dir", type: "string" }, + { name: "include", type: "string" }, + { name: "exclude", type: "string" }, +]; + +const argv = dashdash.parse({ options: dashdashOptions }); + +const packageNames = argv._args console.log( chalk.bold("patch-package"), @@ -27,8 +32,8 @@ console.log( ) // used in imported modules -const isDebug = (global.patchPackageIsDebug = Boolean(argv.debug)) -global.patchPackageIsVerbose = isDebug || Boolean(argv.verbose) +const isDebug = global.patchPackageIsDebug = argv.debug +global.patchPackageIsVerbose = isDebug || argv.verbose if (isDebug) { console.log(`patch-package/index: argv:`) @@ -43,12 +48,12 @@ import { normalize, sep } from "path" import slash = require("slash") import isCi from "is-ci" -if (argv.version || argv.v) { +if (argv.version) { // noop -} else if (argv.help || argv.h) { +} else if (argv.help) { printHelp() } else { - const patchDir = slash(normalize((argv["patch-dir"] || "patches") + sep)) + const patchDir = slash(normalize((argv.patch_dir || "patches") + sep)) if (patchDir.startsWith("/")) { throw new Error("--patch-dir must be a relative path") } @@ -57,19 +62,19 @@ if (argv.version || argv.v) { argv.include, "include", /.*/, - argv["case-sensitive-path-filtering"], + argv.case_sensitive_path_filtering, ) const excludePaths = makeRegExp( argv.exclude, "exclude", /package\.json$/, - argv["case-sensitive-path-filtering"], + argv.case_sensitive_path_filtering, ) const packageManager = detectPackageManager( appPath, - argv["use-yarn"] ? "yarn" : null, + argv.use_yarn ? "yarn" : null, ) - const createIssue = argv["create-issue"] + const createIssue = argv.create_issue packageNames.forEach((packagePathSpecifier: string) => { makePatch({ packagePathSpecifier, @@ -83,11 +88,11 @@ if (argv.version || argv.v) { }) } else { console.log("Applying patches...") - const reverse = !!argv["reverse"] + const reverse = argv.reverse // don't want to exit(1) on postinsall locally. // see https://github.com/ds300/patch-package/issues/86 const shouldExitWithError = - !!argv["error-on-fail"] || isCi || process.env.NODE_ENV === "test" + argv.error_on_fail || isCi || process.env.NODE_ENV === "test" applyPatchesForApp({ appPath, reverse, patchDir, shouldExitWithError }) } } From 3ccbfb84bae33ec2655e45d071990c4d697c76f7 Mon Sep 17 00:00:00 2001 From: milahu Date: Wed, 12 May 2021 19:50:38 +0200 Subject: [PATCH 10/16] fix packageVersion for file protocol --- src/index.ts | 5 ++ src/makePatch.ts | 133 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 103 insertions(+), 35 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9847e0aa..a2772799 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,6 +9,7 @@ const appPath = getAppRootPath() var dashdashOptions = [ { name: "use-yarn", type: "bool" }, + { name: "create-issue", type: "bool" }, { name: "case-sensitive-path-filtering", type: "bool" }, { name: "reverse", type: "bool" }, { names: ["help", "h"], type: "bool" }, @@ -74,6 +75,10 @@ if (argv.version) { appPath, argv.use_yarn ? "yarn" : null, ) + if (isDebug) { + console.log(`patch-package/index: packageManager = ${packageManager}`) + } + const createIssue = argv.create_issue packageNames.forEach((packagePathSpecifier: string) => { makePatch({ diff --git a/src/makePatch.ts b/src/makePatch.ts index 8d0006e3..5b1e3463 100644 --- a/src/makePatch.ts +++ b/src/makePatch.ts @@ -1,5 +1,6 @@ import chalk from "chalk" import { join, dirname, resolve } from "./path" +import { basename } from "path" import { spawnSafeSync } from "./spawnSafe" import { PackageManager } from "./detectPackageManager" import { removeIgnoredFiles } from "./filterFiles" @@ -25,7 +26,7 @@ import { resolveRelativeFileDependencies } from "./resolveRelativeFileDependenci import { getPackageResolution } from "./getPackageResolution" import { parsePatchFile } from "./patch/parse" import { gzipSync } from "zlib" -//import { getPackageVersion } from "./getPackageVersion" +import { getPackageVersion } from "./getPackageVersion" import { maybePrintIssueCreationPrompt, openIssueCreationLink, @@ -34,6 +35,7 @@ import { quote as shlexQuote } from "shlex" const isVerbose = global.patchPackageIsVerbose const isDebug = global.patchPackageIsDebug +const isTest = process.env.NODE_ENV == 'test' function printNoPackageFoundError( packageName: string, @@ -73,6 +75,13 @@ export function makePatch({ const packagePath = join(appPath, packageDetails.path) const packageJsonPath = join(packagePath, "package.json") + if (isDebug) { + console.log(`patch-package/makePatch: appPath = ${appPath}`) + console.log(`patch-package/makePatch: packagePath = ${packagePath}`) + console.log(`patch-package/makePatch: appPackageJson:`) + console.dir(appPackageJson) + } + if (!existsSync(packageJsonPath)) { printNoPackageFoundError(packagePathSpecifier, packageJsonPath) process.exit(1) @@ -102,6 +111,12 @@ export function makePatch({ console.info(chalk.grey("•"), "Creating temporary folder") + if (isDebug) { + console.log( + `patch-package/makePatch: tmpRepoNpmRoot = ${tmpRepoNpmRoot}`, + ) + } + const resolvedVersion = getPackageResolution({ packageDetails, packageManager, @@ -124,36 +139,79 @@ export function makePatch({ }), ) - /* + const declaredVersion = (() => { + var v = resolvedVersion.version + // https://docs.npmjs.com/cli/v7/configuring-npm/package-json + // ://[[:]@][:][:][/][# | #semver:] + // pnpm uses link: protocol instead of file: + // TODO add more protocols? + var m = v.match(/^(file|link|http|https|git|git\+https|git\+http|git\+ssh|git\+file|github):(.+)$/) + if (m) { + var protocol = m[1] + var location = m[2] + var isGit = protocol.startsWith('git') + var gitCommit = isGit ? location.split('#').slice(-1)[0] : null + if (isGit && !gitCommit) { + throw new Error(`error: found wildcard git version ${v}. package.json must pin the exact version of ${packageDetails.name} in the format :#`) + } + if (isGit) { + return { full: v, protocol, location, gitCommit } + } + else { + // sample: https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e + // hash is sha1sum of tgz file + // -> use version number from package's package.json + var version = getPackageVersion(join(resolve(packageDetails.path), "package.json")) + if (isVerbose) { + console.log(`patch-package/makePatch: warning: using version ${version} from ${packageDetails.name}/package.json`) + } + return { version } + } + } + if (!v.match(/^[0-9]+\.[0-9]+\.[0-9]+/)) { + throw new Error(`error: found wildcard version. package.json must pin the exact version of ${packageDetails.name} in the format @..`) + } + return { full: v, version: v } + })() + + const packageVersion = ( + declaredVersion.version || declaredVersion.gitCommit || declaredVersion.full + ) + // originCommit is more precise than pkg.version if (isDebug) { - console.log( - `patch-package/makePatch: resolvedVersion.originCommit = ${resolvedVersion.originCommit}`, - ) - console.log( - `patch-package/makePatch: resolvedVersion.version = ${resolvedVersion.version}`, - ) + //console.log(`patch-package/makePatch: resolvedVersion.originCommit = ${resolvedVersion.originCommit}`) + console.log(`patch-package/makePatch: resolvedVersion.version = ${resolvedVersion.version}`) + console.log(`patch-package/makePatch: packageVersion = ${packageVersion}`) } - const packageVersion = - resolvedVersion.originCommit || - getPackageVersion(join(resolve(packageDetails.path), "package.json")) - */ + + //const packageVersion = + // resolvedVersion.originCommit || + // getPackageVersion(join(resolve(packageDetails.path), "package.json")) // this is broken when installing from git -> version can be a pseudo-version like 1.0.0-canary //const packageVersion = getPackageVersion(join(resolve(packageDetails.path), "package.json")) - const packageVersion = resolvedVersion.version + // TODO rename resolvedVersion -> declaredVersion + + // FIXME false positive + // test integration-tests/create-issue/create-issue.test.ts + // -> patching left-pad prompts to submit an issue + // https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e + // hash is sha checksum of tgz file -> just use the version 1.3.0 + /* + const packageVersion = ( + !resolvedVersion.version.match(/^(file:|link:)/) ? resolvedVersion.version : + getPackageVersion(join(resolve(packageDetails.path), "package.json")) + ) + */ if (isDebug) { + console.log(`patch-package/makePatch: resolvedVersion.version = ${resolvedVersion.version}`) + console.log(`patch-package/makePatch: getPackageVersion -> ${getPackageVersion(join(resolve(packageDetails.path), "package.json"))}`) console.log(`patch-package/makePatch: packageVersion = ${packageVersion}`) - console.log( - `patch-package/makePatch: package path = ${packageDetails.path}`, - ) - console.log( - `patch-package/makePatch: package path resolved = ${resolve( - packageDetails.path, - )}`, - ) + console.log(`patch-package/makePatch: package path = ${packageDetails.path}`) + console.log(`patch-package/makePatch: package path resolved = ${resolve(packageDetails.path)}`) } // copy .npmrc/.yarnrc in case packages are hosted in private registry @@ -375,9 +433,11 @@ export function makePatch({ // patchfiles are parsed in patch/parse.ts function parsePatchLines // -> header comments are ignored let diffHeader = "" - diffHeader += `# generated by patch-package ${patchPackageVersion} on ${new Date().toLocaleString( - "lt", - )}\n` + const dateStr = ( + isTest ? '1980-01-01 00:00:00' : // mock date + new Date().toLocaleString("lt") + ) + diffHeader += `# generated by patch-package ${patchPackageVersion} on ${dateStr}\n` diffHeader += `#\n` const prettyArgv = process.argv.slice() if (prettyArgv[0].match(/node/)) { @@ -390,7 +450,18 @@ export function makePatch({ diffHeader += `# ${prettyArgv.map((a) => shlexQuote(a)).join(" ")}\n` diffHeader += `#\n` diffHeader += `# declared package:\n` - diffHeader += `# ${packageDetails.name}: ${resolvedVersion.version}\n` // TODO rename to declaredVersion + // TODO rename resolvedVersion.version to declaredVersion + const declaredPackageStr = ( + isTest ? (() => { + const v = resolvedVersion.version + const b = basename(v) + if (b != v) return `file:/mocked/path/to/${b}` // mock path // TODO keep the relative path? as declared in /package.json. see getPackageResolution "resolve relative file path" + return v + })() : + resolvedVersion.version + ) + diffHeader += `# ${packageDetails.name}: ${declaredPackageStr}\n` + /* redundant. this is visible from command, sample: npx patch-package wrap-ansi/string-width -> packageNames: wrap-ansi, string-width if (packageDetails.packageNames.length > 1) { diffHeader += `#\n` diffHeader += `# package names:\n` @@ -398,6 +469,7 @@ export function makePatch({ diffHeader += `# ${packageName}\n` }) } + */ diffHeader += `#\n` const patchFileName = createPatchFileName({ @@ -438,18 +510,9 @@ function createPatchFileName({ packageDetails: PackageDetails packageVersion: string }) { - const packageVersionFilename = packageVersion.includes("#") - ? packageVersion.split("#")[1] // extract commit hash - : packageVersion.replace(/\//g, "_") - if (isVerbose) { - console.log( - `patch-package/makePatch: packageVersion ${packageVersion} -> packageVersionFilename ${packageVersionFilename}`, - ) - } - const packageNames = packageDetails.packageNames .map((name) => name.replace(/\//g, "+")) .join("++") - return `${packageNames}+${packageVersionFilename}.patch` + return `${packageNames}+${packageVersion}.patch` } From 33736011a2d5036ab9b9a0e6aa386026c3f521ed Mon Sep 17 00:00:00 2001 From: milahu Date: Wed, 12 May 2021 19:51:47 +0200 Subject: [PATCH 11/16] update snapshots: add patch file header comments --- .../__snapshots__/delete-scripts.test.ts.snap | 8 ++++ .../file-mode-changes.test.ts.snap | 8 ++++ .../__snapshots__/happy-path-npm.test.ts.snap | 8 ++++ .../happy-path-yarn.test.ts.snap | 8 ++++ .../ignore-whitespace.test.ts.snap | 8 ++++ ...res-scripts-when-making-patch.test.ts.snap | 8 ++++ .../include-exclude-paths.test.ts.snap | 40 +++++++++++++++++++ .../__snapshots__/lerna-canary.test.ts.snap | 8 ++++ .../nested-packages.test.ts.snap | 8 ++++ 9 files changed, 104 insertions(+) diff --git a/integration-tests/delete-scripts/__snapshots__/delete-scripts.test.ts.snap b/integration-tests/delete-scripts/__snapshots__/delete-scripts.test.ts.snap index 734a41f3..f0ac31dc 100644 --- a/integration-tests/delete-scripts/__snapshots__/delete-scripts.test.ts.snap +++ b/integration-tests/delete-scripts/__snapshots__/delete-scripts.test.ts.snap @@ -2,6 +2,14 @@ exports[`Test delete-scripts: a patch file got produced 1`] = ` "SNAPSHOT: a patch file got produced +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package left-pad +# +# declared package: +# left-pad: file:/mocked/path/to/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e +# diff --git a/node_modules/left-pad/index.js b/node_modules/left-pad/index.js index e90aec3..f2b8b0a 100644 --- a/node_modules/left-pad/index.js diff --git a/integration-tests/file-mode-changes/__snapshots__/file-mode-changes.test.ts.snap b/integration-tests/file-mode-changes/__snapshots__/file-mode-changes.test.ts.snap index 9bffcbf4..2c491ecd 100644 --- a/integration-tests/file-mode-changes/__snapshots__/file-mode-changes.test.ts.snap +++ b/integration-tests/file-mode-changes/__snapshots__/file-mode-changes.test.ts.snap @@ -2,6 +2,14 @@ exports[`Test file-mode-changes: the patch file 1`] = ` "SNAPSHOT: the patch file +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package prettier +# +# declared package: +# prettier: file:/mocked/path/to/prettier-1.16.0.tgz#104dd25f5ee3d0c9d0a6ce4bb40ced8481d51219 +# diff --git a/node_modules/prettier/bin-prettier.js b/node_modules/prettier/bin-prettier.js old mode 100755 new mode 100644 diff --git a/integration-tests/happy-path-npm/__snapshots__/happy-path-npm.test.ts.snap b/integration-tests/happy-path-npm/__snapshots__/happy-path-npm.test.ts.snap index ee54e635..e29cac23 100644 --- a/integration-tests/happy-path-npm/__snapshots__/happy-path-npm.test.ts.snap +++ b/integration-tests/happy-path-npm/__snapshots__/happy-path-npm.test.ts.snap @@ -17,6 +17,14 @@ END SNAPSHOT" exports[`Test happy-path-npm: the patch looks like this 1`] = ` "SNAPSHOT: the patch looks like this +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package left-pad +# +# declared package: +# left-pad: file:/mocked/path/to/left-pad-1.1.3.tgz +# diff --git a/node_modules/left-pad/index.js b/node_modules/left-pad/index.js index 26f73ff..d4cc4af 100644 --- a/node_modules/left-pad/index.js diff --git a/integration-tests/happy-path-yarn/__snapshots__/happy-path-yarn.test.ts.snap b/integration-tests/happy-path-yarn/__snapshots__/happy-path-yarn.test.ts.snap index 0b22e347..39c683ba 100644 --- a/integration-tests/happy-path-yarn/__snapshots__/happy-path-yarn.test.ts.snap +++ b/integration-tests/happy-path-yarn/__snapshots__/happy-path-yarn.test.ts.snap @@ -17,6 +17,14 @@ END SNAPSHOT" exports[`Test happy-path-yarn: the patch looks like this 1`] = ` "SNAPSHOT: the patch looks like this +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package left-pad +# +# declared package: +# left-pad: file:/mocked/path/to/left-pad-1.1.3.tgz#612f61c033f3a9e08e939f1caebeea41b6f3199a +# diff --git a/node_modules/left-pad/index.js b/node_modules/left-pad/index.js index 26f73ff..b083802 100644 --- a/node_modules/left-pad/index.js diff --git a/integration-tests/ignore-whitespace/__snapshots__/ignore-whitespace.test.ts.snap b/integration-tests/ignore-whitespace/__snapshots__/ignore-whitespace.test.ts.snap index e5b5c464..ef3f0866 100644 --- a/integration-tests/ignore-whitespace/__snapshots__/ignore-whitespace.test.ts.snap +++ b/integration-tests/ignore-whitespace/__snapshots__/ignore-whitespace.test.ts.snap @@ -9,6 +9,14 @@ END SNAPSHOT" exports[`Test ignore-whitespace: line a changed 1`] = ` "SNAPSHOT: line a changed +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package alphabet +# +# declared package: +# alphabet: file:/mocked/path/to/alphabet +# diff --git a/node_modules/alphabet/index.js b/node_modules/alphabet/index.js index 7811d3b..454414b 100644 --- a/node_modules/alphabet/index.js diff --git a/integration-tests/ignores-scripts-when-making-patch/__snapshots__/ignores-scripts-when-making-patch.test.ts.snap b/integration-tests/ignores-scripts-when-making-patch/__snapshots__/ignores-scripts-when-making-patch.test.ts.snap index 1c31fe46..0fd38fe7 100644 --- a/integration-tests/ignores-scripts-when-making-patch/__snapshots__/ignores-scripts-when-making-patch.test.ts.snap +++ b/integration-tests/ignores-scripts-when-making-patch/__snapshots__/ignores-scripts-when-making-patch.test.ts.snap @@ -2,6 +2,14 @@ exports[`Test ignores-scripts-when-making-patch: a patch file got produced 1`] = ` "SNAPSHOT: a patch file got produced +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package naughty-package +# +# declared package: +# naughty-package: file:/mocked/path/to/naughty-package +# diff --git a/node_modules/naughty-package/postinstall.sh b/node_modules/naughty-package/postinstall.sh index 3784520..c4af29c 100755 --- a/node_modules/naughty-package/postinstall.sh diff --git a/integration-tests/include-exclude-paths/__snapshots__/include-exclude-paths.test.ts.snap b/integration-tests/include-exclude-paths/__snapshots__/include-exclude-paths.test.ts.snap index d9aeefa1..8f18bb45 100644 --- a/integration-tests/include-exclude-paths/__snapshots__/include-exclude-paths.test.ts.snap +++ b/integration-tests/include-exclude-paths/__snapshots__/include-exclude-paths.test.ts.snap @@ -2,6 +2,14 @@ exports[`Test include-exclude-paths: exclude all but flip 1`] = ` "SNAPSHOT: exclude all but flip +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package lodash --exclude '^(?!.*flip)' +# +# declared package: +# lodash: file:/mocked/path/to/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae +# diff --git a/node_modules/lodash/flip.js b/node_modules/lodash/flip.js index c28dd78..584b377 100644 --- a/node_modules/lodash/flip.js @@ -17,6 +25,14 @@ END SNAPSHOT" exports[`Test include-exclude-paths: modified package.json 1`] = ` "SNAPSHOT: modified package.json +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package lodash --exclude '^$' +# +# declared package: +# lodash: file:/mocked/path/to/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae +# diff --git a/node_modules/lodash/package.json b/node_modules/lodash/package.json index 028960d..7d346f3 100644 --- a/node_modules/lodash/package.json @@ -35,6 +51,14 @@ END SNAPSHOT" exports[`Test include-exclude-paths: no base files 1`] = ` "SNAPSHOT: no base files +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package lodash --exclude base +# +# declared package: +# lodash: file:/mocked/path/to/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae +# diff --git a/node_modules/lodash/flip.js b/node_modules/lodash/flip.js index c28dd78..584b377 100644 --- a/node_modules/lodash/flip.js @@ -64,6 +88,14 @@ END SNAPSHOT" exports[`Test include-exclude-paths: only __.js being deleted 1`] = ` "SNAPSHOT: only __.js being deleted +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package lodash --include __ +# +# declared package: +# lodash: file:/mocked/path/to/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae +# diff --git a/node_modules/lodash/fp/__.js b/node_modules/lodash/fp/__.js deleted file mode 100644 index 4af98de..0000000 @@ -76,6 +108,14 @@ END SNAPSHOT" exports[`Test include-exclude-paths: only base files, no clone files 1`] = ` "SNAPSHOT: only base files, no clone files +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package lodash --include base --exclude clone +# +# declared package: +# lodash: file:/mocked/path/to/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae +# diff --git a/node_modules/lodash/_baseClamp.js b/node_modules/lodash/_baseClamp.js index a1c5692..c52e38e 100644 --- a/node_modules/lodash/_baseClamp.js diff --git a/integration-tests/lerna-canary/__snapshots__/lerna-canary.test.ts.snap b/integration-tests/lerna-canary/__snapshots__/lerna-canary.test.ts.snap index 1dfdf267..56a74428 100644 --- a/integration-tests/lerna-canary/__snapshots__/lerna-canary.test.ts.snap +++ b/integration-tests/lerna-canary/__snapshots__/lerna-canary.test.ts.snap @@ -25,6 +25,14 @@ END SNAPSHOT" exports[`Test lerna-canary: the patch looks like this 1`] = ` "SNAPSHOT: the patch looks like this +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package @parcel/codeframe +# +# declared package: +# @parcel/codeframe: file:/mocked/path/to/codeframe-2.0.0-nightly.137.tgz#b8bfc2ccf223d6a26eaad193fc26c029f7e14d4f +# diff --git a/node_modules/@parcel/codeframe/src/codeframe.js b/node_modules/@parcel/codeframe/src/codeframe.js index 2bf2c1c..ef0695b 100644 --- a/node_modules/@parcel/codeframe/src/codeframe.js diff --git a/integration-tests/nested-packages/__snapshots__/nested-packages.test.ts.snap b/integration-tests/nested-packages/__snapshots__/nested-packages.test.ts.snap index 420488cc..18b3afa8 100644 --- a/integration-tests/nested-packages/__snapshots__/nested-packages.test.ts.snap +++ b/integration-tests/nested-packages/__snapshots__/nested-packages.test.ts.snap @@ -25,6 +25,14 @@ END SNAPSHOT" exports[`Test nested-packages: the patch file contents 1`] = ` "SNAPSHOT: the patch file contents +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package wrap-ansi/string-width +# +# declared package: +# string-width: file:/mocked/path/to/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e +# diff --git a/node_modules/wrap-ansi/node_modules/string-width/index.js b/node_modules/wrap-ansi/node_modules/string-width/index.js index bbc49d2..6407f49 100644 --- a/node_modules/wrap-ansi/node_modules/string-width/index.js From 86d8e11d12261c6c5724e579b309aa9470ed06ac Mon Sep 17 00:00:00 2001 From: milahu Date: Wed, 12 May 2021 19:52:27 +0200 Subject: [PATCH 12/16] rollback eaf6538 --- .../ignores-scripts-when-making-patch.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh b/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh index 7ce697e8..4f6fe336 100755 --- a/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh +++ b/integration-tests/ignores-scripts-when-making-patch/ignores-scripts-when-making-patch.sh @@ -14,10 +14,5 @@ echo "END SNAPSHOT" (>&2 echo "END SNAPSHOT") echo "SNAPSHOT: a patch file got produced" -[ ! -f patches/naughty-package+1.0.0.patch ] && { - echo "ERROR: file not found: patches/naughty-package+1.0.0.patch" - echo "ls patches/:" - ls patches/ -} cat patches/naughty-package+1.0.0.patch echo "END SNAPSHOT" \ No newline at end of file From 7ec0646d9807864c3160da19e09c7bb31caef4ba Mon Sep 17 00:00:00 2001 From: milahu Date: Wed, 12 May 2021 21:11:26 +0200 Subject: [PATCH 13/16] package.json: add prepare script to build on install from git --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6988685c..19c4c506 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,14 @@ "patch-package": "./index.js" }, "scripts": { - "prepublishOnly": "yarn run clean && yarn run build", + "prepublishOnly": "npm run clean && npm run build", "build": "tsc --project tsconfig.build.json", "new-integration-test": "ts-node integration-tests/newIntegrationTest.ts", "clean": "rimraf dist patch-package.test*.tgz", "format": "prettier --no-semi --write --trailing-comma=all src{/**,}/*.ts integration-tests{/**,}/*.ts property-based-tests{/**,}/*.ts", "prepack": "rimraf dist/**/*.test.js", - "test": "./run-tests.sh --runInBand" + "test": "./run-tests.sh --runInBand", + "prepare": "npm run build" }, "husky": { "hooks": { From bc54703b6ec704decaec0a940be82c0b8aff10ed Mon Sep 17 00:00:00 2001 From: Milan Hauth Date: Sun, 2 Jan 2022 15:48:11 +0100 Subject: [PATCH 14/16] typescript: fix error types --- src/applyPatches.ts | 7 ++++--- src/makePatch.ts | 11 ++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/applyPatches.ts b/src/applyPatches.ts index adbe2dc2..c2759c52 100644 --- a/src/applyPatches.ts +++ b/src/applyPatches.ts @@ -189,7 +189,7 @@ export function applyPatchesForApp({ }), ) } - } catch (error) { + } catch (error: any) { if (error instanceof PatchApplicationError) { errors.push(error.message) } else { @@ -379,14 +379,15 @@ function createUnexpectedError({ error, }: { filename: string - error: Error + error: any }) { + var stack = (error instanceof Error) ? error.stack : error return ` ${chalk.red.bold("**ERROR**")} ${chalk.red( `Failed to apply patch file ${chalk.bold(filename)}`, )} -${error.stack} +${stack} ` } diff --git a/src/makePatch.ts b/src/makePatch.ts index 5b1e3463..d59e33fd 100644 --- a/src/makePatch.ts +++ b/src/makePatch.ts @@ -235,7 +235,7 @@ export function makePatch({ cwd: tmpRepoNpmRoot, logStdErrOnError: false, }) - } catch (e) { + } catch (e: any) { // try again while ignoring scripts in case the script depends on // an implicit context which we havn't reproduced spawnSafeSync( @@ -265,7 +265,7 @@ export function makePatch({ logStdErrOnError: false, stdio: isVerbose ? "inherit" : "ignore", }) - } catch (e) { + } catch (e: any) { // try again while ignoring scripts in case the script depends on // an implicit context which we havn't reproduced if (isVerbose) { @@ -370,9 +370,10 @@ export function makePatch({ try { parsePatchFile(diffResult.stdout.toString()) - } catch (e) { + } catch (e: any) { + if (!(e instanceof Error)) return if ( - (e as Error).message.includes("Unexpected file mode string: 120000") + e.message.includes("Unexpected file mode string: 120000") ) { console.error(` ⛔️ ${chalk.red.bold("ERROR")} @@ -495,7 +496,7 @@ export function makePatch({ } else { maybePrintIssueCreationPrompt(packageDetails, packageManager) } - } catch (e) { + } catch (e: any) { console.error(e) throw e } finally { From 950fa9e870f2c4a918061329bca1d3bb10e363b3 Mon Sep 17 00:00:00 2001 From: Milan Hauth Date: Sun, 2 Jan 2022 15:34:22 +0100 Subject: [PATCH 15/16] error -> warning: found wildcard version --- src/makePatch.ts | 58 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/src/makePatch.ts b/src/makePatch.ts index d59e33fd..78f5fb2a 100644 --- a/src/makePatch.ts +++ b/src/makePatch.ts @@ -12,6 +12,10 @@ import { mkdirpSync, realpathSync, renameSync, + /* + lstatSync, + readlinkSync, + */ } from "fs-extra" import { sync as rimraf } from "rimraf" import { copySync } from "fs-extra" @@ -150,9 +154,31 @@ export function makePatch({ var protocol = m[1] var location = m[2] var isGit = protocol.startsWith('git') - var gitCommit = isGit ? location.split('#').slice(-1)[0] : null + var gitCommit = (isGit && location.includes("#")) ? location.split('#').slice(-1)[0] : null + if (isDebug) { + console.dir({ loc: 'get declaredVersion', isGit, gitCommit }); + } if (isGit && !gitCommit) { - throw new Error(`error: found wildcard git version ${v}. package.json must pin the exact version of ${packageDetails.name} in the format :#`) + var error = new Error(`found wildcard git version ${v}. \ +package.json must pin the exact version of ${packageDetails.name} \ +in the format :#. \ +commitHash is the full hash with 40 chars.`) + delete error.stack + throw error + /* too complex + // guess commit hash of installed package + var stats = lstatSync(packageDetails.path) + if (stats.isSymbolicLink()) { + var linkTarget = readlinkSync(packageDetails.path) + if (linkTarget.startsWith(".pnpm")) { + var match = linkTarget.match(/^\.pnpm\/[^/]+@([0-9a-f]{10})_[0-9a-f]{32}\//) + if (match) { + gitCommit = match[1] + if (isDebug) console.log(`parsed gitCommit ${gitCommit} from pnpm symlink`) + } + } + } + */ } if (isGit) { return { full: v, protocol, location, gitCommit } @@ -163,17 +189,32 @@ export function makePatch({ // -> use version number from package's package.json var version = getPackageVersion(join(resolve(packageDetails.path), "package.json")) if (isVerbose) { - console.log(`patch-package/makePatch: warning: using version ${version} from ${packageDetails.name}/package.json`) + console.log(`patch-package/makePatch: using version ${version} from ${packageDetails.name}/package.json`) } return { version } } } - if (!v.match(/^[0-9]+\.[0-9]+\.[0-9]+/)) { - throw new Error(`error: found wildcard version. package.json must pin the exact version of ${packageDetails.name} in the format @..`) + // https://docs.npmjs.com/about-semantic-versioning + if (!v.match(/^[0-9]+\.[0-9]+\.[0-9]+$/)) { + var exactPart = v.match(/^[^~]([0-9]+\.[0-9]+\.[0-9]+)$/) + var exampleVersion = '1.2.3' + if (exactPart) { + exampleVersion = exactPart[1] + } + console.warn(`patch-package/makePatch: warning: found wildcard version. \ +to ensure successful patching, package.json should pin the exact version of ${packageDetails.name} \ +in the format .., for example: "${packageDetails.name}": "${exampleVersion}"`) } return { full: v, version: v } })() + if (isDebug) { + //console.log(`patch-package/makePatch: resolvedVersion.originCommit = ${resolvedVersion.originCommit}`) + console.log(`patch-package/makePatch: declaredVersion.version = ${declaredVersion.version}`) + console.log(`patch-package/makePatch: declaredVersion.gitCommit = ${declaredVersion.gitCommit}`) + console.log(`patch-package/makePatch: declaredVersion.full = ${declaredVersion.full}`) + } + const packageVersion = ( declaredVersion.version || declaredVersion.gitCommit || declaredVersion.full ) @@ -207,9 +248,7 @@ export function makePatch({ */ if (isDebug) { - console.log(`patch-package/makePatch: resolvedVersion.version = ${resolvedVersion.version}`) console.log(`patch-package/makePatch: getPackageVersion -> ${getPackageVersion(join(resolve(packageDetails.path), "package.json"))}`) - console.log(`patch-package/makePatch: packageVersion = ${packageVersion}`) console.log(`patch-package/makePatch: package path = ${packageDetails.path}`) console.log(`patch-package/makePatch: package path resolved = ${resolve(packageDetails.path)}`) } @@ -480,8 +519,7 @@ export function makePatch({ const patchPath = join(patchesDir, patchFileName) if (!existsSync(dirname(patchPath))) { - // scoped package - mkdirSync(dirname(patchPath)) + mkdirSync(dirname(patchPath), { recursive: true }) } writeFileSync(patchPath, diffHeader + diffResult.stdout) console.log( @@ -497,7 +535,7 @@ export function makePatch({ maybePrintIssueCreationPrompt(packageDetails, packageManager) } } catch (e: any) { - console.error(e) + //console.error(e) throw e } finally { cleanup() From 6b85a8bc1562d1482f30c1b65c9f4e91ba657d39 Mon Sep 17 00:00:00 2001 From: Milan Hauth Date: Sun, 2 Jan 2022 16:55:00 +0100 Subject: [PATCH 16/16] rename + bump: @milahu/patch-package-with-pnpm-support 6.4.8 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 19c4c506..c87d76b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "patch-package", - "version": "6.4.7", + "name": "@milahu/patch-package-with-pnpm-support", + "version": "6.4.8", "description": "Fix broken node modules with no fuss", "main": "dist/index.js", "repository": "github:ds300/patch-package",