Skip to content

Commit efd88cc

Browse files
authored
Merge pull request #474 from ds300/multiple-patches
Support loading multiple patches.
2 parents 3d407bd + 3ba21d8 commit efd88cc

File tree

133 files changed

+5002
-671
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

133 files changed

+5002
-671
lines changed

.github/workflows/main.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
on: [push, pull_request]
1+
on:
2+
pull_request:
3+
push:
4+
branches: [master]
25
name: Test
36
jobs:
47
test:

README.md

+121-10
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,15 @@ files.
6161

6262
### yarn v2+
6363

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

6768
### pnpm
6869

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

7274
### Heroku
7375

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

91-
9293
### CircleCI
93-
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`
94+
95+
Create a hash of your patches before loading/saving your cache. If using a Linux
96+
machine, run `md5sum patches/* > patches.hash`. If running on a macOS machine,
97+
use `md5 patches/* > patches.hash`
98+
9499
```yaml
95100
- run:
96101
name: patch-package hash
97102
command: md5sum patches/* > patches.hash
98103
```
99104
100105
Then, update your hash key to include a checksum of that file:
106+
101107
```yaml
102108
- restore_cache:
103-
key: app-node_modules-v1-{{ checksum "yarn.lock" }}-{{ checksum "patches.hash" }}
104-
```
109+
key:
110+
app-node_modules-v1-{{ checksum "yarn.lock" }}-{{ checksum "patches.hash"
111+
}}
112+
```
105113
106114
As well as the save_cache
115+
107116
```yaml
108117
- save_cache:
109-
key: app-node_modules-v1-{{ checksum "yarn.lock" }}-{{ checksum "patches.hash" }}
118+
key:
119+
app-node_modules-v1-{{ checksum "yarn.lock" }}-{{ checksum "patches.hash"
120+
}}
110121
paths:
111122
- ./node_modules
112123
```
113124
114-
115125
## Usage
116126
117127
### Making patches
@@ -248,6 +258,107 @@ to
248258
This will allow those patch files to be safely ignored when
249259
`NODE_ENV=production`.
250260

261+
### Creating multiple patches for the same package
262+
263+
_💡 This is an advanced feature and is not recommended unless you really, really
264+
need it._
265+
266+
Let's say you have a patch for react-native called
267+
268+
- `patches/react-native+0.72.0.patch`
269+
270+
If you want to add another patch file to `react-native`, you can use the
271+
`--append` flag while supplying a name for the patch.
272+
273+
Just make you changes inside `node_modules/react-native` then run e.g.
274+
275+
npx patch-package react-native --append 'fix-touchable-opacity'
276+
277+
This will create a new patch file while renaming the old patch file so that you
278+
now have:
279+
280+
- `patches/react-native+0.72.0+001+initial.patch`
281+
- `patches/react-native+0.72.0+002+fix-touchable-opacity.patch`
282+
283+
The patches are ordered in a sequence, so that they can build on each other if
284+
necessary. **Think of these as commits in a git history**.
285+
286+
#### Updating a sequenced patch file
287+
288+
If the patch file is the last one in the sequence, you can just make your
289+
changes inside e.g. `node_modules/react-native` and then run
290+
291+
npx patch-package react-native
292+
293+
This will update the last patch file in the sequence.
294+
295+
If the patch file is not the last one in the sequence **you need to use the
296+
`--rebase` feature** to un-apply the succeeding patch files first.
297+
298+
Using the example above, let's say you want to update the `001+initial` patch
299+
but leave the other patch alone. You can run
300+
301+
npx patch-package react-native --rebase patches/react-native+0.72.0+001+initial.patch
302+
303+
This will undo the `002-fix-touchable-opacity` patch file. You can then make
304+
your changes and run
305+
306+
npx patch-package react-native
307+
308+
to finish the rebase by updating the `001+initial` patch file and re-apply the
309+
`002-fix-touchable-opacity` patch file, leaving you with all patches applied and
310+
up-to-date.
311+
312+
#### Inserting a new patch file in the middle of an existing sequence
313+
314+
Using the above example, let's say you want to insert a new patch file between
315+
the `001+initial` and `002+fix-touchable-opacity` patch files. You can run
316+
317+
npx patch-package react-native --rebase patches/react-native+0.72.0+001+initial.patch
318+
319+
This will undo the `002-fix-touchable-opacity` patch file. You can then make any
320+
changes you want to insert in a new patch file and run
321+
322+
npx patch-package react-native --append 'fix-console-warnings'
323+
324+
This will create a new patch file while renaming any successive patches to
325+
maintain the sequence order, leaving you with
326+
327+
- `patches/react-native+0.72.0+001+initial.patch`
328+
- `patches/react-native+0.72.0+002+fix-console-warnings.patch`
329+
- `patches/react-native+0.72.0+003+fix-touchable-opacity.patch`
330+
331+
To insert a new patch file at the start of the sequence, you can run
332+
333+
npx patch-package react-native --rebase 0
334+
335+
Which will un-apply all patch files in the sequence. Then follow the process
336+
above to create a new patch file numbered `001`.
337+
338+
#### Deleting a sequenced patch file
339+
340+
To delete a sequenced patch file, just delete it, then remove and reinstall your
341+
`node_modules` folder.
342+
343+
If you deleted one of the patch files other than the last one, you don't need to
344+
update the sequence numbers in the successive patch file names, but you might
345+
want to do so to keep things tidy.
346+
347+
#### Partially applying a broken patch file
348+
349+
Normally patch application is atomic per patch file. i.e. if a patch file
350+
contains an error anywhere then none of the changes in the patch file will be
351+
applied and saved to disk.
352+
353+
This can be problematic if you have a patch with many changes and you want to
354+
keep some of them and update others.
355+
356+
In this case you can use the `--partial` option. Patch-package will apply as
357+
many of the changes as it can and then leave it to you to fix the rest.
358+
359+
Any errors encountered will be written to a file `./patch-package-errors.log` to
360+
help you keep track of what needs fixing.
361+
251362
## Benefits of patching over forking
252363

253364
- Sometimes forks need extra build steps, e.g. with react-native for Android.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Test append-patches: 00: basic patch file 1`] = `
4+
"SNAPSHOT: basic patch file
5+
left-pad+1.3.0.patch
6+
END SNAPSHOT"
7+
`;
8+
9+
exports[`Test append-patches: 01: after appending a patch file 1`] = `
10+
"SNAPSHOT: after appending a patch file
11+
left-pad+1.3.0+001+initial.patch
12+
left-pad+1.3.0+002+MillionDollars.patch
13+
END SNAPSHOT"
14+
`;
15+
16+
exports[`Test append-patches: 02: the second patch file should go from patch-package to a million dollars 1`] = `
17+
"SNAPSHOT: the second patch file should go from patch-package to a million dollars
18+
diff --git a/node_modules/left-pad/index.js b/node_modules/left-pad/index.js
19+
index a409e14..73d2a7c 100644
20+
--- a/node_modules/left-pad/index.js
21+
+++ b/node_modules/left-pad/index.js
22+
@@ -3,7 +3,7 @@
23+
* and/or modify it under the terms of the Do What The Fuck You Want
24+
* To Public License, Version 2, as published by Sam Hocevar. See
25+
* http://www.wtfpl.net/ for more details. */
26+
-'use patch-package';
27+
+'use a million dollars';
28+
module.exports = leftPad;
29+
30+
var cache = [
31+
END SNAPSHOT"
32+
`;
33+
34+
exports[`Test append-patches: 03: creating a first patch file with --append 1`] = `
35+
"SNAPSHOT: creating a first patch file with --append
36+
left-pad+1.3.0+001+FirstPatch.patch
37+
END SNAPSHOT"
38+
`;
39+
40+
exports[`Test append-patches: 04: the squashed patch file should go from use strict to a million dollars 1`] = `
41+
"SNAPSHOT: the squashed patch file should go from use strict to a million dollars
42+
diff --git a/node_modules/left-pad/index.js b/node_modules/left-pad/index.js
43+
index e90aec3..73d2a7c 100644
44+
--- a/node_modules/left-pad/index.js
45+
+++ b/node_modules/left-pad/index.js
46+
@@ -3,7 +3,7 @@
47+
* and/or modify it under the terms of the Do What The Fuck You Want
48+
* To Public License, Version 2, as published by Sam Hocevar. See
49+
* http://www.wtfpl.net/ for more details. */
50+
-'use strict';
51+
+'use a million dollars';
52+
module.exports = leftPad;
53+
54+
var cache = [
55+
END SNAPSHOT"
56+
`;
57+
58+
exports[`Test append-patches: 05: after appending a billion dollars 1`] = `
59+
"SNAPSHOT: after appending a billion dollars
60+
left-pad+1.3.0+001+FirstPatch.patch
61+
left-pad+1.3.0+002+BillionDollars.patch
62+
END SNAPSHOT"
63+
`;
64+
65+
exports[`Test append-patches: 06: after updating the appended patch file to a TRILLION dollars 1`] = `
66+
"SNAPSHOT: after updating the appended patch file to a TRILLION dollars
67+
diff --git a/node_modules/left-pad/index.js b/node_modules/left-pad/index.js
68+
index 73d2a7c..f53ea10 100644
69+
--- a/node_modules/left-pad/index.js
70+
+++ b/node_modules/left-pad/index.js
71+
@@ -3,7 +3,7 @@
72+
* and/or modify it under the terms of the Do What The Fuck You Want
73+
* To Public License, Version 2, as published by Sam Hocevar. See
74+
* http://www.wtfpl.net/ for more details. */
75+
-'use a million dollars';
76+
+'use a trillion dollars';
77+
module.exports = leftPad;
78+
79+
var cache = [
80+
END SNAPSHOT"
81+
`;
82+
83+
exports[`Test append-patches: 07: patch-package fails when a patch in the sequence is invalid 1`] = `
84+
"SNAPSHOT: patch-package fails when a patch in the sequence is invalid
85+
patch-package 0.0.0
86+
• Creating temporary folder
87+
• Installing [email protected] with npm
88+
• Diffing your files with clean files
89+
Failed to apply patch left-pad+1.3.0+001+FirstPatch.patch to left-pad
90+
END SNAPSHOT"
91+
`;
92+
93+
exports[`Test append-patches: 08: --append is not compatible with --create-issue 1`] = `
94+
"SNAPSHOT: --append is not compatible with --create-issue
95+
patch-package 0.0.0
96+
--create-issue is not compatible with --append.
97+
END SNAPSHOT"
98+
`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/bin/bash
2+
# make sure errors stop the script
3+
set -e
4+
5+
npm install
6+
7+
echo "add patch-package"
8+
npm add $1
9+
10+
function patch-package {
11+
./node_modules/.bin/patch-package "$@"
12+
}
13+
14+
function replace {
15+
npx replace "$1" "$2" node_modules/left-pad/index.js
16+
}
17+
18+
echo "making an initial patch file does not add a sequence number to the file by default"
19+
replace 'use strict' 'use patch-package'
20+
21+
patch-package left-pad
22+
23+
echo "SNAPSHOT: basic patch file"
24+
ls patches
25+
echo "END SNAPSHOT"
26+
27+
echo "using --apend creates a patch file with a sequence number and updates the original patch file"
28+
29+
replace 'use patch-package' 'use a million dollars'
30+
31+
patch-package left-pad --append 'MillionDollars'
32+
33+
echo "SNAPSHOT: after appending a patch file"
34+
ls patches
35+
echo "END SNAPSHOT"
36+
37+
echo "SNAPSHOT: the second patch file should go from patch-package to a million dollars"
38+
cat patches/left-pad*MillionDollars.patch
39+
echo "END SNAPSHOT"
40+
41+
echo "we can squash the patches together by deleting the patch files"
42+
rm patches/left-pad*patch
43+
44+
patch-package left-pad --append 'FirstPatch'
45+
46+
echo "SNAPSHOT: creating a first patch file with --append"
47+
ls patches
48+
echo "END SNAPSHOT"
49+
50+
echo "SNAPSHOT: the squashed patch file should go from use strict to a million dollars"
51+
cat patches/left-pad*FirstPatch.patch
52+
echo "END SNAPSHOT"
53+
54+
echo "i can update an appended patch file"
55+
56+
replace 'use a million dollars' 'use a billion dollars'
57+
58+
patch-package left-pad --append 'BillionDollars'
59+
60+
echo "SNAPSHOT: after appending a billion dollars"
61+
ls patches
62+
echo "END SNAPSHOT"
63+
64+
replace 'use a billion dollars' 'use a trillion dollars'
65+
patch-package left-pad
66+
67+
echo "SNAPSHOT: after updating the appended patch file to a TRILLION dollars"
68+
cat patches/left-pad*BillionDollars.patch
69+
echo "END SNAPSHOT"
70+
71+
echo "if one of the patches in the sequence is invalid, the sequence is not applied"
72+
npx replace 'use strict' 'use bananas' patches/*FirstPatch.patch
73+
74+
echo "SNAPSHOT: patch-package fails when a patch in the sequence is invalid"
75+
if patch-package left-pad --append 'Bananas' ; then
76+
exit 1
77+
fi
78+
echo "END SNAPSHOT"
79+
80+
echo "SNAPSHOT: --append is not compatible with --create-issue"
81+
if patch-package left-pad --append 'Bananas' --create-issue ; then
82+
exit 1
83+
fi
84+
echo "END SNAPSHOT"
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { runIntegrationTest } from "../runIntegrationTest"
22
runIntegrationTest({
3-
projectName: "delete-old-patch-files",
4-
shouldProduceSnapshots: false,
3+
projectName: "append-patches",
4+
shouldProduceSnapshots: true,
55
})

0 commit comments

Comments
 (0)