Skip to content

Commit 9491b67

Browse files
authored
Merge pull request #2 from antongolub/master
feat: add execasync CLI flag to make execa calls be always synchronous
2 parents e63aa0d + c2cc713 commit 9491b67

File tree

4 files changed

+63
-2
lines changed

4 files changed

+63
-2
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ The integration with semantic release is pretty janky — this is a quick summar
120120
- Had to duplicate the internal cosmiconfig setup from semantic release to get this working :(
121121
4. I found Git getting itself into weird states because e.g. `git tag` is done asynchronously
122122
- To get around this I had to stagger package publishing so they were done one at a time (which slows things down)
123-
- I think calls to `execa()` in semantic release should be replaced with `execa.sync()` to ensure Git's internal state is atomic.
123+
- I think calls to `execa()` in semantic release should be replaced with `execa.sync()` to ensure Git's internal state is atomic. For an experiment, you may add `--execasync` CLI flag that makes all calls synchronous through [ritm-hook](https://github.com/elastic/require-in-the-middle).
124124

125125
### Git tags
126126

bin/cli.js

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
#!/usr/bin/env node
22

3+
// Execa hook.
4+
if (require("yargs").argv.execasync) {
5+
require("../lib/execaHook").hook();
6+
}
7+
38
// Imports.
49
const getWorkspacesYarn = require("../lib/getWorkspacesYarn");
510
const multiSemanticRelease = require("../lib/multiSemanticRelease");

lib/execaHook.js

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// NOTE this workaround forces execa calls to be always sync
2+
// Discussion: https://github.com/semantic-release/semantic-release/issues/193#issuecomment-462063871
3+
4+
const execa = require("execa");
5+
const ritm = require("require-in-the-middle");
6+
7+
let interceptor;
8+
9+
const uncache = () => delete require.cache[require.resolve("execa")];
10+
11+
const getExecaSyncPromisified = () =>
12+
Object.assign((...args) => {
13+
const result = new Promise((resolve, reject) => {
14+
try {
15+
resolve(execa.sync(...args));
16+
} catch (e) {
17+
reject(e);
18+
}
19+
});
20+
21+
result.stdout = new String("");
22+
result.stderr = new String("");
23+
result.stdout.pipe = () => {};
24+
result.stderr.pipe = () => {};
25+
26+
return result;
27+
}, execa);
28+
29+
const hook = () => {
30+
if (interceptor) {
31+
return;
32+
}
33+
34+
const execaHooked = getExecaSyncPromisified();
35+
36+
interceptor = ritm(["execa"], () => execaHooked);
37+
uncache();
38+
39+
console.log('"execa" hooked');
40+
};
41+
42+
const unhook = () => {
43+
if (interceptor) {
44+
interceptor.unhook();
45+
interceptor = null;
46+
uncache();
47+
48+
console.log('"execa" unhooked');
49+
}
50+
};
51+
52+
module.exports = {
53+
hook,
54+
unhook
55+
};

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747
"semver": "^5.6.0",
4848
"signale": "^1.2.0",
4949
"stream-buffers": "^3.0.2",
50-
"tempy": "^0.2.1"
50+
"tempy": "^0.2.1",
51+
"yargs": "^13.2.2"
5152
},
5253
"devDependencies": {
5354
"@commitlint/config-conventional": "^7.3.1",

0 commit comments

Comments
 (0)