refactor: consolidate restore under backup command
mcpctl backup restore list/diff/to instead of separate mcpctl restore. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { createBackupCommand, createRestoreCommand } from '../../src/commands/backup.js';
|
||||
import { createBackupCommand } from '../../src/commands/backup.js';
|
||||
|
||||
const mockClient = {
|
||||
get: vi.fn(),
|
||||
@@ -10,14 +10,17 @@ const mockClient = {
|
||||
|
||||
const log = vi.fn();
|
||||
|
||||
function makeCmd() {
|
||||
return createBackupCommand({ client: mockClient as never, log });
|
||||
}
|
||||
|
||||
describe('backup command', () => {
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it('creates backup command', () => {
|
||||
const cmd = createBackupCommand({ client: mockClient as never, log });
|
||||
expect(cmd.name()).toBe('backup');
|
||||
expect(makeCmd().name()).toBe('backup');
|
||||
});
|
||||
|
||||
it('shows status when enabled', async () => {
|
||||
@@ -31,8 +34,7 @@ describe('backup command', () => {
|
||||
pendingCount: 0,
|
||||
});
|
||||
|
||||
const cmd = createBackupCommand({ client: mockClient as never, log });
|
||||
await cmd.parseAsync([], { from: 'user' });
|
||||
await makeCmd().parseAsync([], { from: 'user' });
|
||||
|
||||
expect(mockClient.get).toHaveBeenCalledWith('/api/v1/backup/status');
|
||||
expect(log).toHaveBeenCalledWith(expect.stringContaining('ssh://git@10.0.0.194:2222/michal/mcp-backup.git'));
|
||||
@@ -50,8 +52,7 @@ describe('backup command', () => {
|
||||
pendingCount: 0,
|
||||
});
|
||||
|
||||
const cmd = createBackupCommand({ client: mockClient as never, log });
|
||||
await cmd.parseAsync([], { from: 'user' });
|
||||
await makeCmd().parseAsync([], { from: 'user' });
|
||||
|
||||
expect(log).toHaveBeenCalledWith(expect.stringContaining('disabled'));
|
||||
});
|
||||
@@ -67,8 +68,7 @@ describe('backup command', () => {
|
||||
pendingCount: 5,
|
||||
});
|
||||
|
||||
const cmd = createBackupCommand({ client: mockClient as never, log });
|
||||
await cmd.parseAsync([], { from: 'user' });
|
||||
await makeCmd().parseAsync([], { from: 'user' });
|
||||
|
||||
expect(log).toHaveBeenCalledWith(expect.stringContaining('5 changes pending'));
|
||||
});
|
||||
@@ -76,8 +76,7 @@ describe('backup command', () => {
|
||||
it('shows SSH public key', async () => {
|
||||
mockClient.get.mockResolvedValue({ publicKey: 'ssh-ed25519 AAAA... mcpd@mcpctl.local' });
|
||||
|
||||
const cmd = createBackupCommand({ client: mockClient as never, log });
|
||||
await cmd.parseAsync(['key'], { from: 'user' });
|
||||
await makeCmd().parseAsync(['key'], { from: 'user' });
|
||||
|
||||
expect(mockClient.get).toHaveBeenCalledWith('/api/v1/backup/key');
|
||||
expect(log).toHaveBeenCalledWith('ssh-ed25519 AAAA... mcpd@mcpctl.local');
|
||||
@@ -91,28 +90,20 @@ describe('backup command', () => {
|
||||
],
|
||||
});
|
||||
|
||||
const cmd = createBackupCommand({ client: mockClient as never, log });
|
||||
await cmd.parseAsync(['log'], { from: 'user' });
|
||||
await makeCmd().parseAsync(['log'], { from: 'user' });
|
||||
|
||||
expect(mockClient.get).toHaveBeenCalledWith('/api/v1/backup/log?limit=20');
|
||||
// Header
|
||||
expect(log).toHaveBeenCalledWith(expect.stringContaining('COMMIT'));
|
||||
// Entries
|
||||
expect(log).toHaveBeenCalledWith(expect.stringContaining('abc1234'));
|
||||
expect(log).toHaveBeenCalledWith(expect.stringContaining('[manual]'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('restore command', () => {
|
||||
describe('backup restore subcommands', () => {
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it('creates restore command', () => {
|
||||
const cmd = createRestoreCommand({ client: mockClient as never, log });
|
||||
expect(cmd.name()).toBe('restore');
|
||||
});
|
||||
|
||||
it('lists restore points', async () => {
|
||||
mockClient.get.mockResolvedValue({
|
||||
entries: [
|
||||
@@ -120,8 +111,7 @@ describe('restore command', () => {
|
||||
],
|
||||
});
|
||||
|
||||
const cmd = createRestoreCommand({ client: mockClient as never, log });
|
||||
await cmd.parseAsync(['list'], { from: 'user' });
|
||||
await makeCmd().parseAsync(['restore', 'list'], { from: 'user' });
|
||||
|
||||
expect(mockClient.get).toHaveBeenCalledWith('/api/v1/backup/log?limit=30');
|
||||
expect(log).toHaveBeenCalledWith(expect.stringContaining('abc1234'));
|
||||
@@ -137,8 +127,7 @@ describe('restore command', () => {
|
||||
modified: ['projects/default.yaml'],
|
||||
});
|
||||
|
||||
const cmd = createRestoreCommand({ client: mockClient as never, log });
|
||||
await cmd.parseAsync(['diff', 'abc1234'], { from: 'user' });
|
||||
await makeCmd().parseAsync(['restore', 'diff', 'abc1234'], { from: 'user' });
|
||||
|
||||
expect(mockClient.post).toHaveBeenCalledWith('/api/v1/backup/restore/preview', { commit: 'abc1234' });
|
||||
expect(log).toHaveBeenCalledWith(expect.stringContaining('+ servers/new.yaml'));
|
||||
@@ -156,17 +145,14 @@ describe('restore command', () => {
|
||||
modified: [],
|
||||
});
|
||||
|
||||
const cmd = createRestoreCommand({ client: mockClient as never, log });
|
||||
await cmd.parseAsync(['to', 'abc1234'], { from: 'user' });
|
||||
await makeCmd().parseAsync(['restore', 'to', 'abc1234'], { from: 'user' });
|
||||
|
||||
// Should show preview but NOT call restore endpoint
|
||||
expect(mockClient.post).toHaveBeenCalledWith('/api/v1/backup/restore/preview', { commit: 'abc1234' });
|
||||
expect(mockClient.post).not.toHaveBeenCalledWith('/api/v1/backup/restore', expect.anything());
|
||||
expect(log).toHaveBeenCalledWith(expect.stringContaining('--force'));
|
||||
});
|
||||
|
||||
it('executes restore with --force', async () => {
|
||||
// First call: preview, second call: restore
|
||||
mockClient.post
|
||||
.mockResolvedValueOnce({
|
||||
targetCommit: 'abc1234567890',
|
||||
@@ -183,8 +169,7 @@ describe('restore command', () => {
|
||||
errors: [],
|
||||
});
|
||||
|
||||
const cmd = createRestoreCommand({ client: mockClient as never, log });
|
||||
await cmd.parseAsync(['to', 'abc1234', '--force'], { from: 'user' });
|
||||
await makeCmd().parseAsync(['restore', 'to', 'abc1234', '--force'], { from: 'user' });
|
||||
|
||||
expect(mockClient.post).toHaveBeenCalledWith('/api/v1/backup/restore', { commit: 'abc1234' });
|
||||
expect(log).toHaveBeenCalledWith(expect.stringContaining('1 applied'));
|
||||
@@ -208,8 +193,7 @@ describe('restore command', () => {
|
||||
errors: ['Failed to apply servers/broken.yaml: invalid YAML'],
|
||||
});
|
||||
|
||||
const cmd = createRestoreCommand({ client: mockClient as never, log });
|
||||
await cmd.parseAsync(['to', 'abc1234', '--force'], { from: 'user' });
|
||||
await makeCmd().parseAsync(['restore', 'to', 'abc1234', '--force'], { from: 'user' });
|
||||
|
||||
expect(log).toHaveBeenCalledWith('Errors:');
|
||||
expect(log).toHaveBeenCalledWith(expect.stringContaining('invalid YAML'));
|
||||
|
||||
Reference in New Issue
Block a user