diff --git a/README.md b/README.md index 7f723f8a..ea10ca64 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,10 @@ Run `patch-package` without arguments to apply all patches in your project. Specify the name for the directory in which the patch files are located +- `--ignore-errors` + + Try to apply all of the patches, even if some of them fail. + #### Notes To apply patches individually, you may use `git`: diff --git a/src/applyPatches.ts b/src/applyPatches.ts index f8eddeeb..d235c5bf 100644 --- a/src/applyPatches.ts +++ b/src/applyPatches.ts @@ -62,7 +62,7 @@ function getInstalledPackageVersion({ ) } - exit() + throw new Error("applyPatches") } const { version } = require(join(packageDir, "package.json")) @@ -78,7 +78,7 @@ function getInstalledPackageVersion({ )}`, ) - exit() + throw new Error("applyPatches") } return result as string @@ -87,10 +87,12 @@ function getInstalledPackageVersion({ export function applyPatchesForApp({ appPath, reverse, + ignoreErrors, patchDir, }: { appPath: string reverse: boolean + ignoreErrors: boolean patchDir: string }): void { const patchesDirectory = join(appPath, patchDir) @@ -101,91 +103,112 @@ export function applyPatchesForApp({ return } - files.forEach(filename => { - const packageDetails = getPackageDetailsFromPatchFilename(filename) + let hasFailed = false + files.forEach((filename, idx) => { + try { + const packageDetails = getPackageDetailsFromPatchFilename(filename) - if (!packageDetails) { - console.warn(`Unrecognized patch file in patches directory ${filename}`) - return - } + if (!packageDetails) { + console.warn(`Unrecognized patch file in patches directory ${filename}`) + return + } - const { - name, - version, - path, - pathSpecifier, - isDevOnly, - patchFilename, - } = packageDetails - - const installedPackageVersion = getInstalledPackageVersion({ - appPath, - path, - pathSpecifier, - isDevOnly: - isDevOnly || - // check for direct-dependents in prod - (process.env.NODE_ENV === "production" && - packageIsDevDependency({ appPath, packageDetails })), - patchFilename, - }) - if (!installedPackageVersion) { - // it's ok we're in production mode and this is a dev only package - console.log( - `Skipping dev-only ${chalk.bold(pathSpecifier)}@${version} ${chalk.blue( - "✔", - )}`, - ) - return - } + const { + name, + version, + path, + pathSpecifier, + isDevOnly, + patchFilename, + } = packageDetails - if ( - applyPatch({ - patchFilePath: resolve(patchesDirectory, filename) as string, - reverse, - packageDetails, - patchDir, + const installedPackageVersion = getInstalledPackageVersion({ + appPath, + path, + pathSpecifier, + isDevOnly: + isDevOnly || + // check for direct-dependents in prod + (process.env.NODE_ENV === "production" && + packageIsDevDependency({ appPath, packageDetails })), + patchFilename, }) - ) { - // yay patch was applied successfully - // print warning if version mismatch - if (installedPackageVersion !== version) { - printVersionMismatchWarning({ - packageName: name, - actualVersion: installedPackageVersion, - originalVersion: version, - pathSpecifier, - path, - }) - } else { + if (!installedPackageVersion) { + // it's ok we're in production mode and this is a dev only package console.log( - `${chalk.bold(pathSpecifier)}@${version} ${chalk.green("✔")}`, + `Skipping dev-only ${chalk.bold( + pathSpecifier, + )}@${version} ${chalk.blue("✔")}`, ) + return } - } else { - // completely failed to apply patch - // TODO: propagate useful error messages from patch application - if (installedPackageVersion === version) { - printBrokenPatchFileError({ - packageName: name, - patchFileName: filename, - pathSpecifier, - path, + + if ( + applyPatch({ + patchFilePath: resolve(patchesDirectory, filename) as string, + reverse, + packageDetails, + patchDir, }) + ) { + // yay patch was applied successfully + // print warning if version mismatch + if (installedPackageVersion !== version) { + printVersionMismatchWarning({ + packageName: name, + actualVersion: installedPackageVersion, + originalVersion: version, + pathSpecifier, + path, + }) + } else { + console.log( + `${chalk.bold(pathSpecifier)}@${version} ${chalk.green("✔")}`, + ) + } } else { - printPatchApplictionFailureError({ - packageName: name, - actualVersion: installedPackageVersion, - originalVersion: version, - patchFileName: filename, - path, - pathSpecifier, - }) + // completely failed to apply patch + // TODO: propagate useful error messages from patch application + if (installedPackageVersion === version) { + printBrokenPatchFileError({ + packageName: name, + patchFileName: filename, + pathSpecifier, + path, + }) + } else { + printPatchApplictionFailureError({ + packageName: name, + actualVersion: installedPackageVersion, + originalVersion: version, + patchFileName: filename, + path, + pathSpecifier, + }) + } + + throw new Error("applyPatches") + } + } catch (err) { + if (err.message !== "applyPatches") { + throw err + } + if (!ignoreErrors) { + exit() + } + hasFailed = true + if (idx < files.length - 1) { + console.warn( + `${chalk.yellow("Warning:")} Option ${chalk.bold( + "--ignore-errors", + )} was set, moving on to next patch.`, + ) } - - exit() } }) + if (hasFailed) { + exit() + } } export function applyPatch({ diff --git a/src/index.ts b/src/index.ts index 6aa117a0..6ab507dd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,6 +16,7 @@ const argv = minimist(process.argv.slice(2), { boolean: [ "use-yarn", "case-sensitive-path-filtering", + "ignore-errors", "reverse", "help", "version", @@ -69,7 +70,8 @@ if (argv.version || argv.v) { } else { console.log("Applying patches...") const reverse = !!argv["reverse"] - applyPatchesForApp({ appPath, reverse, patchDir }) + const ignoreErrors = !!argv["ignore-errors"] + applyPatchesForApp({ appPath, reverse, ignoreErrors, patchDir }) } } @@ -89,6 +91,28 @@ Usage: ./patches/+.patch + Options: + + ${chalk.bold("--patch-dir ")} + + Specify the name for the directory in which the patch files are located. + + ${chalk.bold("--ignore-errors")} + + Try to apply all of the patches, even if some of them fail. + + ${chalk.bold("--reverse")} + + Un-applies all patches. + + Note that this will fail if the patched files have changed since being + patched. In that case, you'll probably need to re-install 'node_modules'. + + This option was added to help people using CircleCI avoid an issue around caching + and patch file updates (https://github.com/ds300/patch-package/issues/37), + but might be useful in other contexts too. + + 2. Creating patch files ======================= @@ -101,32 +125,32 @@ Usage: Options: - ${chalk.bold("--use-yarn")} - - By default, patch-package checks whether you use npm or yarn based on - which lockfile you have. If you have both, it uses npm by default. - Set this option to override that default and always use yarn. + ${chalk.bold("--use-yarn")} - ${chalk.bold("--exclude ")} + By default, patch-package checks whether you use npm or yarn based on + which lockfile you have. If you have both, it uses npm by default. + Set this option to override that default and always use yarn. - Ignore paths matching the regexp when creating patch files. - Paths are relative to the root dir of the package to be patched. + ${chalk.bold("--exclude ")} - Default: 'package\\.json$' + Ignore paths matching the regexp when creating patch files. + Paths are relative to the root dir of the package to be patched. - ${chalk.bold("--include ")} + Default: 'package\\.json$' - Only consider paths matching the regexp when creating patch files. - Paths are relative to the root dir of the package to be patched. + ${chalk.bold("--include ")} - Default '.*' + Only consider paths matching the regexp when creating patch files. + Paths are relative to the root dir of the package to be patched. - ${chalk.bold("--case-sensitive-path-filtering")} + Default '.*' - Make regexps used in --include or --exclude filters case-sensitive. + ${chalk.bold("--case-sensitive-path-filtering")} - ${chalk.bold("--patch-dir")} + Make regexps used in --include or --exclude filters case-sensitive. + + ${chalk.bold("--patch-dir")} - Specify the name for the directory in which to put the patch files. + Specify the name for the directory in which to put the patch files. `) }