Skip to content

Commit 0a8b02b

Browse files
committed
feat: add global --yes flag
1 parent 16b8ea5 commit 0a8b02b

10 files changed

Lines changed: 26 additions & 25 deletions

File tree

src/cli-core.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ export function createProgram(config: CLIConfig): CommanderCommand {
515515

516516
const program = new CommanderCommand();
517517
program.name(specs.name).description(specs.description).version(version);
518+
program.option('-y, --yes', 'Skip all confirmation prompts');
518519

519520
registerCommands(config, program, specs.commands);
520521

src/lib/access-keys/delete.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default async function remove(options: Record<string, unknown>) {
2323
: getOption<string>(options, ['format', 'f', 'F'], 'table');
2424

2525
const id = getOption<string>(options, ['id']);
26-
const force = getOption<boolean>(options, ['force']);
26+
const force = getOption<boolean>(options, ['force', 'yes', 'y']);
2727

2828
if (!id) {
2929
printFailure(context, 'Access key ID is required');
@@ -49,7 +49,7 @@ export default async function remove(options: Record<string, unknown>) {
4949
}
5050

5151
if (!force) {
52-
requireInteractive('Use --force to skip confirmation');
52+
requireInteractive('Use --yes to skip confirmation');
5353
const confirmed = await confirm(`Delete access key '${id}'?`);
5454
if (!confirmed) {
5555
console.log('Aborted');

src/lib/buckets/delete.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default async function deleteBucket(options: Record<string, unknown>) {
2020
: getOption<string>(options, ['format', 'f', 'F'], 'table');
2121

2222
const names = getOption<string | string[]>(options, ['name']);
23-
const force = getOption<boolean>(options, ['force']);
23+
const force = getOption<boolean>(options, ['force', 'yes', 'y']);
2424

2525
if (!names) {
2626
printFailure(context, 'Bucket name is required');
@@ -31,7 +31,7 @@ export default async function deleteBucket(options: Record<string, unknown>) {
3131
const config = await getStorageConfig();
3232

3333
if (!force) {
34-
requireInteractive('Use --force to skip confirmation');
34+
requireInteractive('Use --yes to skip confirmation');
3535
const confirmed = await confirm(`Delete ${bucketNames.length} bucket(s)?`);
3636
if (!confirmed) {
3737
console.log('Aborted');

src/lib/iam/policies/delete.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export default async function del(options: Record<string, unknown>) {
2121
printStart(context);
2222

2323
let resource = getOption<string>(options, ['resource']);
24-
const force = getOption<boolean>(options, ['force']);
24+
const force = getOption<boolean>(options, ['force', 'yes', 'y']);
2525

2626
const loginMethod = await getLoginMethod();
2727

@@ -83,7 +83,7 @@ export default async function del(options: Record<string, unknown>) {
8383
}
8484

8585
if (!force) {
86-
requireInteractive('Use --force to skip confirmation');
86+
requireInteractive('Use --yes to skip confirmation');
8787
const confirmed = await confirm(`Delete policy '${resource}'?`);
8888
if (!confirmed) {
8989
console.log('Aborted');

src/lib/iam/users/remove.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export default async function removeUser(options: Record<string, unknown>) {
2222
printStart(context);
2323

2424
const resourceOption = getOption<string | string[]>(options, ['resource']);
25-
const force = getOption<boolean>(options, ['force']);
25+
const force = getOption<boolean>(options, ['force', 'yes', 'y']);
2626

2727
const loginMethod = await getLoginMethod();
2828

@@ -101,7 +101,7 @@ export default async function removeUser(options: Record<string, unknown>) {
101101
}
102102

103103
if (!force) {
104-
requireInteractive('Use --force to skip confirmation');
104+
requireInteractive('Use --yes to skip confirmation');
105105
const confirmed = await confirm(`Remove ${resources.length} user(s)?`);
106106
if (!confirmed) {
107107
console.log('Aborted');

src/lib/iam/users/revoke-invitation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export default async function revokeInvitation(
2424
printStart(context);
2525

2626
const resourceOption = getOption<string | string[]>(options, ['resource']);
27-
const force = getOption<boolean>(options, ['force']);
27+
const force = getOption<boolean>(options, ['force', 'yes', 'y']);
2828

2929
const loginMethod = await getLoginMethod();
3030

@@ -104,7 +104,7 @@ export default async function revokeInvitation(
104104
}
105105

106106
if (!force) {
107-
requireInteractive('Use --force to skip confirmation');
107+
requireInteractive('Use --yes to skip confirmation');
108108
const confirmed = await confirm(
109109
`Revoke ${resources.length} invitation(s)?`
110110
);

src/lib/mv.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ let _jsonMode = false;
1818
export default async function mv(options: Record<string, unknown>) {
1919
const src = getOption<string>(options, ['src']);
2020
const dest = getOption<string>(options, ['dest']);
21-
const force = getOption<boolean>(options, ['force', 'f', 'F']);
21+
const force = getOption<boolean>(options, ['force', 'f', 'F', 'yes', 'y']);
2222
const recursive = !!getOption<boolean>(options, ['recursive', 'r']);
2323
const jsonFlag = getOption<boolean>(options, ['json']);
2424
const format = jsonFlag
@@ -159,7 +159,7 @@ export default async function mv(options: Record<string, unknown>) {
159159

160160
const totalToMove = itemsToMove.length + (hasFolderMarker ? 1 : 0);
161161
if (!force) {
162-
requireInteractive('Use --force to skip confirmation');
162+
requireInteractive('Use --yes to skip confirmation');
163163
const confirmed = await confirm(
164164
`Are you sure you want to move ${totalToMove} object(s)?`
165165
);
@@ -273,7 +273,7 @@ export default async function mv(options: Record<string, unknown>) {
273273
}
274274

275275
if (!force) {
276-
requireInteractive('Use --force to skip confirmation');
276+
requireInteractive('Use --yes to skip confirmation');
277277
const confirmed = await confirm(
278278
`Are you sure you want to move 't3://${srcPath.bucket}/${srcPath.path}'?`
279279
);

src/lib/objects/delete.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export default async function deleteObject(options: Record<string, unknown>) {
2121

2222
const bucket = getOption<string>(options, ['bucket']);
2323
const keys = getOption<string | string[]>(options, ['key']);
24-
const force = getOption<boolean>(options, ['force']);
24+
const force = getOption<boolean>(options, ['force', 'yes', 'y']);
2525

2626
if (!bucket) {
2727
printFailure(context, 'Bucket name is required');
@@ -37,7 +37,7 @@ export default async function deleteObject(options: Record<string, unknown>) {
3737
const keyList = Array.isArray(keys) ? keys : [keys];
3838

3939
if (!force) {
40-
requireInteractive('Use --force to skip confirmation');
40+
requireInteractive('Use --yes to skip confirmation');
4141
const confirmed = await confirm(
4242
`Delete ${keyList.length} object(s) from '${bucket}'?`
4343
);

src/lib/rm.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ let _jsonMode = false;
1515

1616
export default async function rm(options: Record<string, unknown>) {
1717
const pathString = getOption<string>(options, ['path']);
18-
const force = getOption<boolean>(options, ['force', 'f', 'F']);
18+
const force = getOption<boolean>(options, ['force', 'f', 'F', 'yes', 'y']);
1919
const recursive = !!getOption<boolean>(options, ['recursive', 'r']);
2020
const jsonFlag = getOption<boolean>(options, ['json']);
2121
const format = jsonFlag
@@ -46,7 +46,7 @@ export default async function rm(options: Record<string, unknown>) {
4646
const rawEndsWithSlash = pathString.endsWith('/');
4747
if (!path && !rawEndsWithSlash) {
4848
if (!force) {
49-
requireInteractive('Use --force to skip confirmation');
49+
requireInteractive('Use --yes to skip confirmation');
5050
const confirmed = await confirm(
5151
`Are you sure you want to delete bucket '${bucket}'?`
5252
);
@@ -153,7 +153,7 @@ export default async function rm(options: Record<string, unknown>) {
153153
}
154154

155155
if (!force) {
156-
requireInteractive('Use --force to skip confirmation');
156+
requireInteractive('Use --yes to skip confirmation');
157157
const confirmed = await confirm(
158158
`Are you sure you want to delete ${totalItems} object(s)?`
159159
);
@@ -209,7 +209,7 @@ export default async function rm(options: Record<string, unknown>) {
209209
} else {
210210
// Remove single object
211211
if (!force) {
212-
requireInteractive('Use --force to skip confirmation');
212+
requireInteractive('Use --yes to skip confirmation');
213213
const confirmed = await confirm(
214214
`Are you sure you want to delete 't3://${bucket}/${path}'?`
215215
);

test/cli.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -246,16 +246,16 @@ describe('Destructive commands require --force in non-TTY', () => {
246246
// when stdin is not a TTY (piped/scripted mode). Since runCli uses
247247
// stdio: ['ignore', ...], stdin is not a TTY.
248248

249-
it('objects delete should require --force', () => {
249+
it('objects delete should require confirmation in non-TTY', () => {
250250
const result = runCli('objects delete fake-bucket fake-key');
251251
expect(result.exitCode).toBe(1);
252-
expect(result.stderr).toContain('--force');
252+
expect(result.stderr).toContain('Use --yes to skip confirmation');
253253
});
254254

255-
it('buckets delete should require --force', () => {
255+
it('buckets delete should require confirmation in non-TTY', () => {
256256
const result = runCli('buckets delete fake-bucket');
257257
expect(result.exitCode).toBe(1);
258-
expect(result.stderr).toContain('--force');
258+
expect(result.stderr).toContain('Use --yes to skip confirmation');
259259
});
260260
});
261261

@@ -1196,7 +1196,7 @@ describe.skipIf(skipTests)('CLI Integration Tests', () => {
11961196
runCli(`mk ${name}`);
11971197
const result = runCli(`buckets delete ${name}`);
11981198
expect(result.exitCode).toBe(1);
1199-
expect(result.stderr).toContain('--force');
1199+
expect(result.stderr).toContain('--yes');
12001200
// Cleanup
12011201
runCli(`buckets delete ${name} --force`);
12021202
});
@@ -1660,7 +1660,7 @@ describe.skipIf(skipTests)('CLI Integration Tests', () => {
16601660
`objects delete ${testBucket} objdel-noforce.txt`
16611661
);
16621662
expect(result.exitCode).toBe(1);
1663-
expect(result.stderr).toContain('--force');
1663+
expect(result.stderr).toContain('--yes');
16641664
// Cleanup
16651665
runCli(`objects delete ${testBucket} objdel-noforce.txt --force`);
16661666
});

0 commit comments

Comments
 (0)