Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@insforge/cli",
"version": "0.1.68",
"version": "0.1.69",
"description": "InsForge CLI - Command line tool for InsForge platform",
"type": "module",
"bin": {
Expand Down
7 changes: 3 additions & 4 deletions src/commands/branch/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ export function registerBranchDeleteCommand(branch: Command): void {
branch
.command('delete <name>')
.description('Delete a branch')
.option('-y, --yes', 'Skip confirmation')
.action(async (name: string, opts: { yes?: boolean }, cmd) => {
const { json, apiUrl } = getRootOpts(cmd);
.action(async (name: string, _opts: Record<string, never>, cmd) => {
const { json, apiUrl, yes } = getRootOpts(cmd);
try {
await requireAuth(apiUrl);
const project = getProjectConfig();
Expand All @@ -25,7 +24,7 @@ export function registerBranchDeleteCommand(branch: Command): void {
const target = branches.find(b => b.name === name);
if (!target) throw new CLIError(`Branch '${name}' not found.`);

if (!opts.yes && !json) {
if (!yes && !json) {
const confirmed = await clack.confirm({
message: `Delete branch '${name}'? This terminates its EC2 instance.`,
});
Expand Down
29 changes: 29 additions & 0 deletions src/commands/branch/merge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,18 @@ vi.mock('../../lib/analytics.js', () => ({
shutdownAnalytics: vi.fn(async () => {}),
}));

const clackConfirmMock = vi.hoisted(() => vi.fn(async () => true));
vi.mock('@clack/prompts', () => ({
confirm: clackConfirmMock,
isCancel: () => false,
}));

describe('branch merge', () => {
beforeEach(() => {
vi.clearAllMocks();
fsMock.writeFileSync.mockReset();
clackConfirmMock.mockClear();
clackConfirmMock.mockResolvedValue(true);
});

it('--dry-run prints rendered_sql + summary, does not call execute', async () => {
Expand Down Expand Up @@ -112,6 +120,27 @@ describe('branch merge', () => {
expect(mergeBranchExecuteApi).toHaveBeenCalledWith('b1', undefined);
});

// Regression: -y on the merge subcommand previously got shadowed by the
// same-named global option, so the prompt fired even when the user passed -y.
// Test nests under a `branch` parent to mirror the real CLI wiring, since
// the shadowing only manifested through that registration path.
it('-y after positional skips confirmation prompt (no --json)', async () => {
const program = new Command().exitOverride();
program.option('--json').option('--api-url <url>').option('-y, --yes');
const branch = program.command('branch');
registerBranchMergeCommand(branch);
const origLog = console.log;
console.log = () => {};
try {
await program.parseAsync(['branch', 'merge', 'feat-x', '-y'], { from: 'user' });
} finally {
console.log = origLog;
}
expect(clackConfirmMock).not.toHaveBeenCalled();
const { mergeBranchExecuteApi } = await import('../../lib/api/platform.js');
expect(mergeBranchExecuteApi).toHaveBeenCalledWith('b1', undefined);
});

it('conflict path exits with code 2 and prints per-conflict summary', async () => {
const { mergeBranchDryRunApi } = await import('../../lib/api/platform.js');
(mergeBranchDryRunApi as any).mockResolvedValueOnce({
Expand Down
6 changes: 2 additions & 4 deletions src/commands/branch/merge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { captureEvent, shutdownAnalytics } from '../../lib/analytics.js';

interface MergeOptions {
dryRun?: boolean;
yes?: boolean;
saveSql?: string;
}

Expand All @@ -23,10 +22,9 @@ export function registerBranchMergeCommand(branch: Command): void {
.command('merge <name>')
.description('Merge a branch back to its parent project')
.option('--dry-run', 'Compute the diff and print rendered SQL; do not apply')
.option('-y, --yes', 'Skip confirmation prompt')
.option('--save-sql <path>', 'Write rendered SQL preview to a file')
.action(async (name: string, opts: MergeOptions, cmd) => {
const { json, apiUrl } = getRootOpts(cmd);
const { json, apiUrl, yes } = getRootOpts(cmd);
try {
await requireAuth(apiUrl);
const project = getProjectConfig();
Expand Down Expand Up @@ -89,7 +87,7 @@ export function registerBranchMergeCommand(branch: Command): void {
}

// Confirm before executing (unless --yes or --json).
if (!opts.yes && !json) {
if (!yes && !json) {
const parentLabel = project.branched_from?.project_name ?? project.project_name;
const confirmed = await clack.confirm({
message: `Apply this merge to parent project '${parentLabel}'?`,
Expand Down
7 changes: 3 additions & 4 deletions src/commands/branch/reset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ export function registerBranchResetCommand(branch: Command): void {
branch
.command('reset <name>')
.description("Reset a branch's database back to T0 (the parent snapshot at branch creation)")
.option('-y, --yes', 'Skip confirmation')
.action(async (name: string, opts: { yes?: boolean }, cmd) => {
const { json, apiUrl } = getRootOpts(cmd);
.action(async (name: string, _opts: Record<string, never>, cmd) => {
const { json, apiUrl, yes } = getRootOpts(cmd);
try {
await requireAuth(apiUrl);
const project = getProjectConfig();
Expand All @@ -40,7 +39,7 @@ export function registerBranchResetCommand(branch: Command): void {
}
const entryState = target.branch_state;

if (!opts.yes && !json) {
if (!yes && !json) {
const confirmed = await clack.confirm({
message:
`Reset branch '${name}' back to T0? This wipes all schema/data/policy/function/migration changes made on the branch since creation.` +
Expand Down
Loading