Skip to content

Commit bcafc18

Browse files
authored
feat: add allow-empty option to staged command (#8)
1 parent 59c51f2 commit bcafc18

2 files changed

Lines changed: 103 additions & 3 deletions

File tree

packages/rstack/src/staged.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
1+
import { parseArgs } from 'node:util';
12
import { loadRstackConfig } from './config.js';
23

34
const stagedHelpMessage = `Rstack v${RSTACK_VERSION}
45
56
Usage:
6-
$ rs staged
7+
$ rs staged [options]
78
89
Runs lint-staged with tasks from define.staged in rstack.config.
910
1011
Options:
11-
-h, --help Display this help message`;
12+
--allow-empty Allow empty commits when tasks revert all staged changes
13+
-h, --help Display this help message`;
1214

1315
export async function runStagedCLI(args: string[]): Promise<void> {
14-
if (args.length === 1 && (args[0] === '-h' || args[0] === '--help')) {
16+
const { values } = parseArgs({
17+
args,
18+
options: {
19+
'allow-empty': { type: 'boolean' },
20+
allowEmpty: { type: 'boolean' },
21+
help: { type: 'boolean', short: 'h' },
22+
},
23+
allowPositionals: false,
24+
strict: true,
25+
});
26+
27+
if (values.help) {
1528
console.log(stagedHelpMessage);
1629
return;
1730
}
@@ -29,6 +42,7 @@ export async function runStagedCLI(args: string[]): Promise<void> {
2942
'lint-staged'
3043
);
3144
const success = await lintStaged({
45+
allowEmpty: values['allow-empty'] ?? values.allowEmpty ?? false,
3246
config: stagedConfig,
3347
});
3448
if (!success) {
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { execFileSync } from 'node:child_process';
2+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
3+
import path from 'node:path';
4+
import { test } from '#test-helpers';
5+
6+
const git = (cwd: string, args: string[]): void => {
7+
execFileSync('git', args, { cwd, stdio: 'ignore' });
8+
};
9+
10+
const createGitFixture = async (): Promise<string> => {
11+
const cwd = await mkdtemp(path.join(import.meta.dirname, 'fixture-'));
12+
13+
await Promise.all([
14+
writeFile(
15+
path.join(cwd, 'rstack.config.ts'),
16+
`import { define } from 'rstack';
17+
18+
define.staged({ '*.txt': 'node revert.mjs' });
19+
`,
20+
),
21+
writeFile(
22+
path.join(cwd, 'revert.mjs'),
23+
`import { writeFileSync } from 'node:fs';
24+
25+
for (const file of process.argv.slice(2)) {
26+
writeFileSync(file, 'initial\\n');
27+
}
28+
`,
29+
),
30+
writeFile(path.join(cwd, 'file.txt'), 'initial\n'),
31+
]);
32+
33+
git(cwd, ['init', '--quiet']);
34+
git(cwd, ['add', '.']);
35+
git(cwd, [
36+
'-c',
37+
'user.name=Rstack Test',
38+
'-c',
39+
'user.email=rstack@example.com',
40+
'commit',
41+
'--quiet',
42+
'-m',
43+
'initial',
44+
]);
45+
46+
await writeFile(path.join(cwd, 'file.txt'), 'changed\n');
47+
git(cwd, ['add', 'file.txt']);
48+
49+
return cwd;
50+
};
51+
52+
const withGitFixture = async (callback: (cwd: string) => Promise<void> | void): Promise<void> => {
53+
const cwd = await createGitFixture();
54+
55+
try {
56+
await callback(cwd);
57+
} finally {
58+
await rm(cwd, { recursive: true, force: true });
59+
}
60+
};
61+
62+
test('should display the staged help message', ({ execCli, expect }) => {
63+
const output = execCli('staged --help');
64+
65+
expect(output).toContain('Rstack v');
66+
expect(output).toContain('Usage:\n $ rs staged [options]');
67+
expect(output).toContain('Runs lint-staged with tasks from define.staged in rstack.config.');
68+
expect(output).toContain('--allow-empty');
69+
expect(output).toContain('-h, --help');
70+
});
71+
72+
test('should reject unknown staged options', ({ execCli, expect }) => {
73+
expect(() => execCli('staged --unknown')).toThrow();
74+
});
75+
76+
test('should prevent an empty commit by default', async ({ execCli, expect }) => {
77+
await withGitFixture((cwd) => {
78+
expect(() => execCli('staged', { cwd })).toThrow();
79+
});
80+
});
81+
82+
test(`should allow an empty commit with --allow-empty`, async ({ execCli }) => {
83+
await withGitFixture((cwd) => {
84+
execCli(`staged --allow-empty`, { cwd });
85+
});
86+
});

0 commit comments

Comments
 (0)