Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support loading multiple patches. #474

Merged
merged 41 commits into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
1c0cfbe
augment parseNameAndVersion
ds300 Jun 19, 2023
2ec3191
initial support for applying patch sequence
ds300 Jun 19, 2023
f5d7e06
clean up old patch file stuff
ds300 Jun 19, 2023
1a188cb
add npm install to script
ds300 Jun 19, 2023
ef7efca
fix main.yml
ds300 Jun 19, 2023
2ac6424
fix package loop breaking, do some renaming
ds300 Jun 22, 2023
f956f95
patch sequence appending and updating
ds300 Jun 24, 2023
d5e6a0a
update snapshots to be ordered by time
ds300 Jun 24, 2023
7a846dc
remove parens in function
ds300 Jun 24, 2023
efcecd1
force usage of bash
ds300 Jun 26, 2023
42e62be
use function instead of alias
ds300 Jun 26, 2023
4be83bb
update integration test template
ds300 Jun 26, 2023
23c591c
add canary version number
ds300 Jun 26, 2023
52f0eef
don't recommend --create-issue with --append
ds300 Jul 3, 2023
8da5bd2
comment about --rebase
ds300 Jul 3, 2023
6855cc7
new canary release
ds300 Jul 3, 2023
2b86e1f
fix numPatchesAfterCreate
ds300 Jul 9, 2023
1bb87b6
improve apply-multiple-patches
ds300 Jul 9, 2023
e956cfe
make patch sequence application idempotent
ds300 Jul 10, 2023
dd4de6a
bump canary version
ds300 Jul 10, 2023
2fbccfa
use stable stringify for state file
ds300 Jul 12, 2023
950e0b2
fix runIntegrationTest
ds300 Jul 12, 2023
e941f97
add support for --reverse
ds300 Jul 12, 2023
9bfcf30
fix --reverse behavior
ds300 Jul 12, 2023
1f27349
add rebase command to undo patches
ds300 Jul 13, 2023
d9d613d
extract out patch application for a single package
ds300 Jul 13, 2023
ec0e69c
rebase continue behavior
ds300 Jul 13, 2023
1c9104c
add initial rebase tests
ds300 Jul 14, 2023
df30019
bump canary version
ds300 Jul 14, 2023
d68b6af
fix tests
ds300 Jul 14, 2023
a3f3a62
bump canary version
ds300 Jul 14, 2023
e653491
todo
ds300 Jul 14, 2023
c26a1ae
fix fast-forwarding, test --rebase 0
ds300 Jul 19, 2023
984a6c3
add log for empty diff while updating existing patch during rebase
ds300 Jul 19, 2023
a45d600
handle edge cases
ds300 Jul 19, 2023
3cae2de
bump canary version
ds300 Jul 19, 2023
e80899e
add docs for multiple patches
ds300 Jul 19, 2023
1981d42
update snapshots
ds300 Jul 20, 2023
cced41a
add --partial option
ds300 Jul 27, 2023
dbc3cd9
update snapshots
ds300 Jul 27, 2023
3ba21d8
update package.json
ds300 Jul 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
on: [push, pull_request]
on:
pull_request:
push:
branches: [master]
name: Test
jobs:
test:
Expand Down
131 changes: 121 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,15 @@ files.

### yarn v2+

yarn 2+ have native support for patching dependencies via [`yarn patch`](https://yarnpkg.com/cli/patch).
You do not need to use patch-package on these projects.
yarn 2+ have native support for patching dependencies via
[`yarn patch`](https://yarnpkg.com/cli/patch). You do not need to use
patch-package on these projects.

### pnpm

pnpm has native support for patching dependencies via [`pnpm patch`](https://pnpm.io/cli/patch).
You do not need to use patch-package on these projects.
pnpm has native support for patching dependencies via
[`pnpm patch`](https://pnpm.io/cli/patch). You do not need to use patch-package
on these projects.

### Heroku

Expand All @@ -88,30 +90,38 @@ details.
Otherwise if you update a patch then the change may not be reflected on
subsequent CI runs.


### CircleCI
Create a hash of your patches before loading/saving your cache. If using a Linux machine, run `md5sum patches/* > patches.hash`. If running on a macOS machine, use `md5 patches/* > patches.hash`

Create a hash of your patches before loading/saving your cache. If using a Linux
machine, run `md5sum patches/* > patches.hash`. If running on a macOS machine,
use `md5 patches/* > patches.hash`

```yaml
- run:
name: patch-package hash
command: md5sum patches/* > patches.hash
```

Then, update your hash key to include a checksum of that file:

```yaml
- restore_cache:
key: app-node_modules-v1-{{ checksum "yarn.lock" }}-{{ checksum "patches.hash" }}
```
key:
app-node_modules-v1-{{ checksum "yarn.lock" }}-{{ checksum "patches.hash"
}}
```

As well as the save_cache

```yaml
- save_cache:
key: app-node_modules-v1-{{ checksum "yarn.lock" }}-{{ checksum "patches.hash" }}
key:
app-node_modules-v1-{{ checksum "yarn.lock" }}-{{ checksum "patches.hash"
}}
paths:
- ./node_modules
```


## Usage

### Making patches
Expand Down Expand Up @@ -248,6 +258,107 @@ to
This will allow those patch files to be safely ignored when
`NODE_ENV=production`.

### Creating multiple patches for the same package

_💡 This is an advanced feature and is not recommended unless you really, really
need it._

Let's say you have a patch for react-native called

- `patches/react-native+0.72.0.patch`

If you want to add another patch file to `react-native`, you can use the
`--append` flag while supplying a name for the patch.

Just make you changes inside `node_modules/react-native` then run e.g.

npx patch-package react-native --append 'fix-touchable-opacity'

This will create a new patch file while renaming the old patch file so that you
now have:

- `patches/react-native+0.72.0+001+initial.patch`
- `patches/react-native+0.72.0+002+fix-touchable-opacity.patch`

The patches are ordered in a sequence, so that they can build on each other if
necessary. **Think of these as commits in a git history**.

#### Updating a sequenced patch file

If the patch file is the last one in the sequence, you can just make your
changes inside e.g. `node_modules/react-native` and then run

npx patch-package react-native

This will update the last patch file in the sequence.

If the patch file is not the last one in the sequence **you need to use the
`--rebase` feature** to un-apply the succeeding patch files first.

Using the example above, let's say you want to update the `001+initial` patch
but leave the other patch alone. You can run

npx patch-package react-native --rebase patches/react-native+0.72.0+001+initial.patch

This will undo the `002-fix-touchable-opacity` patch file. You can then make
your changes and run

npx patch-package react-native

to finish the rebase by updating the `001+initial` patch file and re-apply the
`002-fix-touchable-opacity` patch file, leaving you with all patches applied and
up-to-date.

#### Inserting a new patch file in the middle of an existing sequence

Using the above example, let's say you want to insert a new patch file between
the `001+initial` and `002+fix-touchable-opacity` patch files. You can run

npx patch-package react-native --rebase patches/react-native+0.72.0+001+initial.patch

This will undo the `002-fix-touchable-opacity` patch file. You can then make any
changes you want to insert in a new patch file and run

npx patch-package react-native --append 'fix-console-warnings'

This will create a new patch file while renaming any successive patches to
maintain the sequence order, leaving you with

- `patches/react-native+0.72.0+001+initial.patch`
- `patches/react-native+0.72.0+002+fix-console-warnings.patch`
- `patches/react-native+0.72.0+003+fix-touchable-opacity.patch`

To insert a new patch file at the start of the sequence, you can run

npx patch-package react-native --rebase 0

Which will un-apply all patch files in the sequence. Then follow the process
above to create a new patch file numbered `001`.

#### Deleting a sequenced patch file

To delete a sequenced patch file, just delete it, then remove and reinstall your
`node_modules` folder.

If you deleted one of the patch files other than the last one, you don't need to
update the sequence numbers in the successive patch file names, but you might
want to do so to keep things tidy.

#### Partially applying a broken patch file

Normally patch application is atomic per patch file. i.e. if a patch file
contains an error anywhere then none of the changes in the patch file will be
applied and saved to disk.

This can be problematic if you have a patch with many changes and you want to
keep some of them and update others.

In this case you can use the `--partial` option. Patch-package will apply as
many of the changes as it can and then leave it to you to fix the rest.

Any errors encountered will be written to a file `./patch-package-errors.log` to
help you keep track of what needs fixing.

## Benefits of patching over forking

- Sometimes forks need extra build steps, e.g. with react-native for Android.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Test append-patches: 00: basic patch file 1`] = `
"SNAPSHOT: basic patch file
left-pad+1.3.0.patch
END SNAPSHOT"
`;

exports[`Test append-patches: 01: after appending a patch file 1`] = `
"SNAPSHOT: after appending a patch file
left-pad+1.3.0+001+initial.patch
left-pad+1.3.0+002+MillionDollars.patch
END SNAPSHOT"
`;

exports[`Test append-patches: 02: the second patch file should go from patch-package to a million dollars 1`] = `
"SNAPSHOT: the second patch file should go from patch-package to a million dollars
diff --git a/node_modules/left-pad/index.js b/node_modules/left-pad/index.js
index a409e14..73d2a7c 100644
--- a/node_modules/left-pad/index.js
+++ b/node_modules/left-pad/index.js
@@ -3,7 +3,7 @@
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://www.wtfpl.net/ for more details. */
-'use patch-package';
+'use a million dollars';
module.exports = leftPad;
var cache = [
END SNAPSHOT"
`;

exports[`Test append-patches: 03: creating a first patch file with --append 1`] = `
"SNAPSHOT: creating a first patch file with --append
left-pad+1.3.0+001+FirstPatch.patch
END SNAPSHOT"
`;

exports[`Test append-patches: 04: the squashed patch file should go from use strict to a million dollars 1`] = `
"SNAPSHOT: the squashed patch file should go from use strict to a million dollars
diff --git a/node_modules/left-pad/index.js b/node_modules/left-pad/index.js
index e90aec3..73d2a7c 100644
--- a/node_modules/left-pad/index.js
+++ b/node_modules/left-pad/index.js
@@ -3,7 +3,7 @@
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://www.wtfpl.net/ for more details. */
-'use strict';
+'use a million dollars';
module.exports = leftPad;
var cache = [
END SNAPSHOT"
`;

exports[`Test append-patches: 05: after appending a billion dollars 1`] = `
"SNAPSHOT: after appending a billion dollars
left-pad+1.3.0+001+FirstPatch.patch
left-pad+1.3.0+002+BillionDollars.patch
END SNAPSHOT"
`;

exports[`Test append-patches: 06: after updating the appended patch file to a TRILLION dollars 1`] = `
"SNAPSHOT: after updating the appended patch file to a TRILLION dollars
diff --git a/node_modules/left-pad/index.js b/node_modules/left-pad/index.js
index 73d2a7c..f53ea10 100644
--- a/node_modules/left-pad/index.js
+++ b/node_modules/left-pad/index.js
@@ -3,7 +3,7 @@
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://www.wtfpl.net/ for more details. */
-'use a million dollars';
+'use a trillion dollars';
module.exports = leftPad;
var cache = [
END SNAPSHOT"
`;

exports[`Test append-patches: 07: patch-package fails when a patch in the sequence is invalid 1`] = `
"SNAPSHOT: patch-package fails when a patch in the sequence is invalid
patch-package 0.0.0
• Creating temporary folder
• Installing left-pad@1.3.0 with npm
• Diffing your files with clean files
Failed to apply patch left-pad+1.3.0+001+FirstPatch.patch to left-pad
END SNAPSHOT"
`;

exports[`Test append-patches: 08: --append is not compatible with --create-issue 1`] = `
"SNAPSHOT: --append is not compatible with --create-issue
patch-package 0.0.0
--create-issue is not compatible with --append.
END SNAPSHOT"
`;
84 changes: 84 additions & 0 deletions integration-tests/append-patches/append-patches.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/bin/bash
# make sure errors stop the script
set -e

npm install

echo "add patch-package"
npm add $1

function patch-package {
./node_modules/.bin/patch-package "$@"
}

function replace {
npx replace "$1" "$2" node_modules/left-pad/index.js
}

echo "making an initial patch file does not add a sequence number to the file by default"
replace 'use strict' 'use patch-package'

patch-package left-pad

echo "SNAPSHOT: basic patch file"
ls patches
echo "END SNAPSHOT"

echo "using --apend creates a patch file with a sequence number and updates the original patch file"

replace 'use patch-package' 'use a million dollars'

patch-package left-pad --append 'MillionDollars'

echo "SNAPSHOT: after appending a patch file"
ls patches
echo "END SNAPSHOT"

echo "SNAPSHOT: the second patch file should go from patch-package to a million dollars"
cat patches/left-pad*MillionDollars.patch
echo "END SNAPSHOT"

echo "we can squash the patches together by deleting the patch files"
rm patches/left-pad*patch

patch-package left-pad --append 'FirstPatch'

echo "SNAPSHOT: creating a first patch file with --append"
ls patches
echo "END SNAPSHOT"

echo "SNAPSHOT: the squashed patch file should go from use strict to a million dollars"
cat patches/left-pad*FirstPatch.patch
echo "END SNAPSHOT"

echo "i can update an appended patch file"

replace 'use a million dollars' 'use a billion dollars'

patch-package left-pad --append 'BillionDollars'

echo "SNAPSHOT: after appending a billion dollars"
ls patches
echo "END SNAPSHOT"

replace 'use a billion dollars' 'use a trillion dollars'
patch-package left-pad

echo "SNAPSHOT: after updating the appended patch file to a TRILLION dollars"
cat patches/left-pad*BillionDollars.patch
echo "END SNAPSHOT"

echo "if one of the patches in the sequence is invalid, the sequence is not applied"
npx replace 'use strict' 'use bananas' patches/*FirstPatch.patch

echo "SNAPSHOT: patch-package fails when a patch in the sequence is invalid"
if patch-package left-pad --append 'Bananas' ; then
exit 1
fi
echo "END SNAPSHOT"

echo "SNAPSHOT: --append is not compatible with --create-issue"
if patch-package left-pad --append 'Bananas' --create-issue ; then
exit 1
fi
echo "END SNAPSHOT"
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { runIntegrationTest } from "../runIntegrationTest"
runIntegrationTest({
projectName: "delete-old-patch-files",
shouldProduceSnapshots: false,
projectName: "append-patches",
shouldProduceSnapshots: true,
})