exec-staged 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +0 -0
- package/dist/lib/stage.d.ts +1 -0
- package/dist/lib/stage.js +30 -13
- package/package.json +26 -23
- package/src/lib/stage.ts +32 -13
package/dist/bin/cli.js
CHANGED
|
File without changes
|
package/dist/lib/stage.d.ts
CHANGED
package/dist/lib/stage.js
CHANGED
|
@@ -4,6 +4,7 @@ import { spawn, spawnSync } from './spawn.js';
|
|
|
4
4
|
import micromatch from 'micromatch';
|
|
5
5
|
import fs from 'node:fs';
|
|
6
6
|
import path from 'node:path';
|
|
7
|
+
import { deregisterExitHandler, registerExitHandler } from 'on-process-exit';
|
|
7
8
|
import semver from 'semver';
|
|
8
9
|
import parseArgsStringToArgv from 'string-argv';
|
|
9
10
|
export class Stage {
|
|
@@ -14,6 +15,7 @@ export class Stage {
|
|
|
14
15
|
mergeStatus = [];
|
|
15
16
|
head;
|
|
16
17
|
_gitDir;
|
|
18
|
+
needsRevert = false;
|
|
17
19
|
get gitDir() {
|
|
18
20
|
return (this._gitDir ??= this.git(['rev-parse', '--absolute-git-dir']));
|
|
19
21
|
}
|
|
@@ -37,6 +39,13 @@ export class Stage {
|
|
|
37
39
|
this.logger.debug(error);
|
|
38
40
|
throw error;
|
|
39
41
|
}
|
|
42
|
+
this.needsRevert = true;
|
|
43
|
+
const exitHandlerId = registerExitHandler(() => {
|
|
44
|
+
if (this.needsRevert) {
|
|
45
|
+
this.needsRevert = false;
|
|
46
|
+
this.revert();
|
|
47
|
+
}
|
|
48
|
+
});
|
|
40
49
|
try {
|
|
41
50
|
await this.run(tasks);
|
|
42
51
|
this.merge();
|
|
@@ -44,6 +53,7 @@ export class Stage {
|
|
|
44
53
|
catch (error) {
|
|
45
54
|
this.logger.debug(error);
|
|
46
55
|
try {
|
|
56
|
+
this.needsRevert = false;
|
|
47
57
|
this.revert();
|
|
48
58
|
}
|
|
49
59
|
catch (error) {
|
|
@@ -51,6 +61,9 @@ export class Stage {
|
|
|
51
61
|
}
|
|
52
62
|
throw error;
|
|
53
63
|
}
|
|
64
|
+
finally {
|
|
65
|
+
deregisterExitHandler(exitHandlerId);
|
|
66
|
+
}
|
|
54
67
|
}
|
|
55
68
|
check() {
|
|
56
69
|
this.logger.log(stageLifecycleMessages.check);
|
|
@@ -70,15 +83,15 @@ export class Stage {
|
|
|
70
83
|
this.logger.log('⚠️ Unsupported git version!');
|
|
71
84
|
throw new Error('unsupported git version');
|
|
72
85
|
}
|
|
73
|
-
let
|
|
86
|
+
let prefix;
|
|
74
87
|
try {
|
|
75
|
-
|
|
88
|
+
prefix = this.git(['rev-parse', '--show-prefix']).trim();
|
|
76
89
|
}
|
|
77
90
|
catch (error) {
|
|
78
91
|
this.logger.log('⚠️ Not a git repository!');
|
|
79
92
|
throw new Error('cwd is not a git repository');
|
|
80
93
|
}
|
|
81
|
-
if (
|
|
94
|
+
if (prefix !== '') {
|
|
82
95
|
this.logger.log('⚠️ Not in git root directory!');
|
|
83
96
|
throw new Error('cwd is not a git repository root directory');
|
|
84
97
|
}
|
|
@@ -237,16 +250,19 @@ export class Stage {
|
|
|
237
250
|
'-m',
|
|
238
251
|
STAGED_CHANGES_COMMIT_MESSAGE,
|
|
239
252
|
]);
|
|
240
|
-
// apply patch containing unstaged changes
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
253
|
+
// apply patch containing unstaged changes.
|
|
254
|
+
// `--allow-empty` could be used here, but it was not added to `git apply`
|
|
255
|
+
// until 2.35.0 (January 2022), so we skip the call when the patch is empty.
|
|
256
|
+
if (fs.statSync(this.patchPath).size > 0) {
|
|
257
|
+
this.git([
|
|
258
|
+
'apply',
|
|
259
|
+
'--recount',
|
|
260
|
+
'--unidiff-zero',
|
|
261
|
+
'--whitespace=nowarn',
|
|
262
|
+
'--3way',
|
|
263
|
+
this.patchPath,
|
|
264
|
+
]);
|
|
265
|
+
}
|
|
250
266
|
// unstaged deletions are not included in the patch and must be handled
|
|
251
267
|
// separately because the patch cannot be applied if such files are
|
|
252
268
|
// modified by tasks; use force: true to handle cases where the file
|
|
@@ -268,6 +284,7 @@ export class Stage {
|
|
|
268
284
|
this.logger.log('⚠️ Error restoring unstaged changes from stash!');
|
|
269
285
|
throw error;
|
|
270
286
|
}
|
|
287
|
+
this.needsRevert = false;
|
|
271
288
|
}
|
|
272
289
|
revert() {
|
|
273
290
|
this.logger.log(stageLifecycleMessages.revert);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "exec-staged",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Run commands against the current git index",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"git",
|
|
@@ -27,33 +27,36 @@
|
|
|
27
27
|
"dist/",
|
|
28
28
|
"src/"
|
|
29
29
|
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "pnpm clean && tsc --build",
|
|
32
|
+
"clean": "rm -rf dist/",
|
|
33
|
+
"prepare": "husky",
|
|
34
|
+
"prepublishOnly": "pnpm build",
|
|
35
|
+
"test": "pnpm build && tsx --test --experimental-test-coverage"
|
|
36
|
+
},
|
|
30
37
|
"dependencies": {
|
|
31
|
-
"commander": "^
|
|
32
|
-
"cosmiconfig": "^9.0.
|
|
33
|
-
"env-paths": "^
|
|
34
|
-
"execa": "^9.6.
|
|
38
|
+
"commander": "^15.0.0",
|
|
39
|
+
"cosmiconfig": "^9.0.2",
|
|
40
|
+
"env-paths": "^4.0.0",
|
|
41
|
+
"execa": "^9.6.1",
|
|
35
42
|
"micromatch": "^4.0.8",
|
|
36
|
-
"on-process-exit": "^1.0
|
|
37
|
-
"semver": "^7.
|
|
43
|
+
"on-process-exit": "^1.1.0",
|
|
44
|
+
"semver": "^7.8.5",
|
|
38
45
|
"string-argv": "^0.3.2"
|
|
39
46
|
},
|
|
40
47
|
"devDependencies": {
|
|
41
|
-
"@trivago/prettier-plugin-sort-imports": "^
|
|
42
|
-
"@tsconfig/node22": "^22.0.
|
|
43
|
-
"@types/micromatch": "^4.0.
|
|
44
|
-
"@types/node": "^22.
|
|
45
|
-
"@types/semver": "^7.7.
|
|
48
|
+
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
|
49
|
+
"@tsconfig/node22": "^22.0.5",
|
|
50
|
+
"@types/micromatch": "^4.0.10",
|
|
51
|
+
"@types/node": "^22.20.0",
|
|
52
|
+
"@types/semver": "^7.7.1",
|
|
46
53
|
"husky": "^9.1.7",
|
|
47
|
-
"knip": "^
|
|
54
|
+
"knip": "^6.17.1",
|
|
48
55
|
"lint-staged": "github:ItsNickBarry/lint-staged#knip",
|
|
49
|
-
"prettier": "^3.
|
|
50
|
-
"prettier-plugin-packagejson": "^
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
"scripts": {
|
|
55
|
-
"build": "pnpm clean && tsc --build",
|
|
56
|
-
"clean": "rm -rf dist/",
|
|
57
|
-
"test": "pnpm build && tsx --test --experimental-test-coverage"
|
|
56
|
+
"prettier": "^3.8.4",
|
|
57
|
+
"prettier-plugin-packagejson": "^3.0.2",
|
|
58
|
+
"release-it": "^20.2.0",
|
|
59
|
+
"tsx": "^4.22.4",
|
|
60
|
+
"typescript": "^6.0.3"
|
|
58
61
|
}
|
|
59
|
-
}
|
|
62
|
+
}
|
package/src/lib/stage.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { spawn, spawnSync } from './spawn.js';
|
|
|
12
12
|
import micromatch from 'micromatch';
|
|
13
13
|
import fs from 'node:fs';
|
|
14
14
|
import path from 'node:path';
|
|
15
|
+
import { deregisterExitHandler, registerExitHandler } from 'on-process-exit';
|
|
15
16
|
import semver from 'semver';
|
|
16
17
|
import parseArgsStringToArgv from 'string-argv';
|
|
17
18
|
|
|
@@ -23,6 +24,7 @@ export class Stage {
|
|
|
23
24
|
private readonly mergeStatus: (typeof MERGE_FILES)[number][] = [];
|
|
24
25
|
private head?: string;
|
|
25
26
|
private _gitDir?: string;
|
|
27
|
+
private needsRevert: boolean = false;
|
|
26
28
|
|
|
27
29
|
private get gitDir(): string {
|
|
28
30
|
return (this._gitDir ??= this.git(['rev-parse', '--absolute-git-dir']));
|
|
@@ -51,6 +53,15 @@ export class Stage {
|
|
|
51
53
|
throw error;
|
|
52
54
|
}
|
|
53
55
|
|
|
56
|
+
this.needsRevert = true;
|
|
57
|
+
|
|
58
|
+
const exitHandlerId = registerExitHandler(() => {
|
|
59
|
+
if (this.needsRevert) {
|
|
60
|
+
this.needsRevert = false;
|
|
61
|
+
this.revert();
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
54
65
|
try {
|
|
55
66
|
await this.run(tasks);
|
|
56
67
|
this.merge();
|
|
@@ -58,12 +69,15 @@ export class Stage {
|
|
|
58
69
|
this.logger.debug(error);
|
|
59
70
|
|
|
60
71
|
try {
|
|
72
|
+
this.needsRevert = false;
|
|
61
73
|
this.revert();
|
|
62
74
|
} catch (error) {
|
|
63
75
|
this.logger.debug(error);
|
|
64
76
|
}
|
|
65
77
|
|
|
66
78
|
throw error;
|
|
79
|
+
} finally {
|
|
80
|
+
deregisterExitHandler(exitHandlerId);
|
|
67
81
|
}
|
|
68
82
|
}
|
|
69
83
|
|
|
@@ -90,16 +104,16 @@ export class Stage {
|
|
|
90
104
|
throw new Error('unsupported git version');
|
|
91
105
|
}
|
|
92
106
|
|
|
93
|
-
let
|
|
107
|
+
let prefix: string;
|
|
94
108
|
|
|
95
109
|
try {
|
|
96
|
-
|
|
110
|
+
prefix = this.git(['rev-parse', '--show-prefix']).trim();
|
|
97
111
|
} catch (error) {
|
|
98
112
|
this.logger.log('⚠️ Not a git repository!');
|
|
99
113
|
throw new Error('cwd is not a git repository');
|
|
100
114
|
}
|
|
101
115
|
|
|
102
|
-
if (
|
|
116
|
+
if (prefix !== '') {
|
|
103
117
|
this.logger.log('⚠️ Not in git root directory!');
|
|
104
118
|
throw new Error('cwd is not a git repository root directory');
|
|
105
119
|
}
|
|
@@ -311,16 +325,19 @@ export class Stage {
|
|
|
311
325
|
STAGED_CHANGES_COMMIT_MESSAGE,
|
|
312
326
|
]);
|
|
313
327
|
|
|
314
|
-
// apply patch containing unstaged changes
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
328
|
+
// apply patch containing unstaged changes.
|
|
329
|
+
// `--allow-empty` could be used here, but it was not added to `git apply`
|
|
330
|
+
// until 2.35.0 (January 2022), so we skip the call when the patch is empty.
|
|
331
|
+
if (fs.statSync(this.patchPath).size > 0) {
|
|
332
|
+
this.git([
|
|
333
|
+
'apply',
|
|
334
|
+
'--recount',
|
|
335
|
+
'--unidiff-zero',
|
|
336
|
+
'--whitespace=nowarn',
|
|
337
|
+
'--3way',
|
|
338
|
+
this.patchPath,
|
|
339
|
+
]);
|
|
340
|
+
}
|
|
324
341
|
|
|
325
342
|
// unstaged deletions are not included in the patch and must be handled
|
|
326
343
|
// separately because the patch cannot be applied if such files are
|
|
@@ -345,6 +362,8 @@ export class Stage {
|
|
|
345
362
|
this.logger.log('⚠️ Error restoring unstaged changes from stash!');
|
|
346
363
|
throw error;
|
|
347
364
|
}
|
|
365
|
+
|
|
366
|
+
this.needsRevert = false;
|
|
348
367
|
}
|
|
349
368
|
|
|
350
369
|
protected revert() {
|