diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 9a7dffc0..41f12926 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -482,21 +482,6 @@ capy org [options] JSON support: no -### `capy org projects` - -List projects in the active organization; --deleted also lists deleted ones (owners only) - -``` -capy org projects [options] -``` - -| Option | Description | Default | -|---|---|---| -| `--deleted` | also list deleted projects, marked as deleted, with the date | | -| `--json` | emit machine-readable JSON instead of the human UI | | - -JSON support: yes (`--json`) - ## `capy project` Create, delete or restore a project in the active organization @@ -617,6 +602,7 @@ capy projects [options] | Option | Description | Default | |---|---|---| +| `--deleted` | also list deleted projects, marked as deleted, with the date (owners only) | | | `--json` | emit machine-readable JSON instead of the human UI | | JSON support: yes (`--json`) diff --git a/src/index-dev.ts b/src/index-dev.ts index d3d405e8..31e333cd 100644 --- a/src/index-dev.ts +++ b/src/index-dev.ts @@ -787,18 +787,6 @@ projectCmd await restoreProjectCommand(ref, { yes, nonTty, json, dryRun, apiUrl: process.env.CAPY_API_URL, devMode: true }); }); -orgCmd - .command('projects') - .description('List projects in the active organization; --deleted also lists deleted ones (owners only)') // COPY-FLAG - .option('--deleted', 'also list deleted projects, marked as deleted, with the date') // COPY-FLAG - .option('--json', 'emit machine-readable JSON instead of the human UI') - .action(async (_options: any, command: any) => { - const { ProjectsCommand } = await import('./commands/projectsCommand'); - const cmd = new ProjectsCommand(process.env.CAPY_API_URL, true); - const merged = command.optsWithGlobals(); - await cmd.execute({ json: merged.json, deleted: merged.deleted === true }); - }); - program .command('info') .description('Show current session info') @@ -832,11 +820,12 @@ program program .command('projects') .description('List projects in the active organization and their branches') + .option('--deleted', 'also list deleted projects, marked as deleted, with the date (owners only)') // COPY-FLAG .option('--json', 'emit machine-readable JSON instead of the human UI') .action(async (options) => { const { ProjectsCommand } = await import('./commands/projectsCommand'); const cmd = new ProjectsCommand(process.env.CAPY_API_URL, true); - await cmd.execute({ json: options.json }); + await cmd.execute({ json: options.json, deleted: options.deleted === true }); }); const secretsCmd = program diff --git a/src/index.ts b/src/index.ts index 00e6154e..08d25184 100644 --- a/src/index.ts +++ b/src/index.ts @@ -826,19 +826,6 @@ projectCmd await restoreProjectCommand(ref, { yes, nonTty, json, dryRun }); }); -orgCmd - .command('projects') - .description('List projects in the active organization; --deleted also lists deleted ones (owners only)') // COPY-FLAG - .option('--deleted', 'also list deleted projects, marked as deleted, with the date') // COPY-FLAG - .option('--json', 'emit machine-readable JSON instead of the human UI') - .action(async (_options: any, command: any) => { - assertNotLocalOnly('org projects'); - const { ProjectsCommand } = await import('./commands/projectsCommand'); - const cmd = new ProjectsCommand(); - const merged = command.optsWithGlobals(); - await cmd.execute({ json: merged.json, deleted: merged.deleted === true }); - }); - program .command('info') .description('Show current session info') @@ -875,12 +862,13 @@ program program .command('projects') .description('List projects in the active organization and their branches') + .option('--deleted', 'also list deleted projects, marked as deleted, with the date (owners only)') // COPY-FLAG .option('--json', 'emit machine-readable JSON instead of the human UI') .action(async (options) => { assertNotLocalOnly('projects'); const { ProjectsCommand } = await import('./commands/projectsCommand'); const cmd = new ProjectsCommand(); - await cmd.execute({ json: options.json }); + await cmd.execute({ json: options.json, deleted: options.deleted === true }); }); const secretsCmd = program diff --git a/tests/commands/projectDeletedCli.test.ts b/tests/commands/projectDeletedCli.test.ts index cbe17b5c..a0e7260d 100644 --- a/tests/commands/projectDeletedCli.test.ts +++ b/tests/commands/projectDeletedCli.test.ts @@ -28,7 +28,7 @@ async function deletedFolder(h: Harness): Promise { h.markProjectDeleted(); } -describe('project delete / project restore / org projects: flags the program also defines', () => { +describe('project delete / project restore / projects: flags the program also defines', () => { test('--force arrives: the DELETE body is {"force":true}; without it there is no body', async () => { await withHarness(async (h) => { const forced = await h.run(['project', 'delete', PROJECT_ID, '--force', '--yes', '--json']); @@ -67,14 +67,24 @@ describe('project delete / project restore / org projects: flags the program als }); }); - test('org projects --deleted asks the service for the deleted ones too', async () => { + test('projects --deleted asks the service for the deleted ones too', async () => { await withHarness(async (h) => { h.setBranches(PROJECT_ID, [{ id: 'br_1', name: 'production', is_protected: false }]); - const out = await h.run(['org', 'projects', '--deleted', '--json']); + const out = await h.run(['projects', '--deleted', '--json']); expect(out.code).toBe(0); expect(h.requests().some((r) => r.method === 'GET' && r.path === '/projects?include_deleted=1')).toBe(true); }); }); + + test('projects without --deleted sends the plain listing request', async () => { + await withHarness(async (h) => { + h.setBranches(PROJECT_ID, [{ id: 'br_1', name: 'production', is_protected: false }]); + const out = await h.run(['projects', '--json']); + expect(out.code).toBe(0); + const lists = h.requests().filter((r) => r.method === 'GET' && (r.path === '/projects' || r.path.startsWith('/projects?'))); + expect(lists.map((r) => r.path)).toEqual(['/projects']); + }); + }); }); describe('lifecycleOptsFrom: --non-tty and --force, wherever the outer command took them', () => { diff --git a/tests/commands/projectsDeleted.test.ts b/tests/commands/projectsDeleted.test.ts index bb825bc1..6832beb3 100644 --- a/tests/commands/projectsDeleted.test.ts +++ b/tests/commands/projectsDeleted.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect, spyOn, mock, afterAll, beforeEach } from 'bun:test'; /** - * `capy org projects --deleted` (CAP-729): the listing includes deleted + * `capy projects --deleted`: the listing includes deleted * projects, each marked deleted with its date; a plain listing is unchanged. * * Org resolution and the spinner are replaced; `projectsCommand` and the