Skip to content

Commit c7008eb

Browse files
authored
Merge pull request #14 from supabase-community/feat/reset
feat: support resetting branch to a specific migration version
2 parents d4c17aa + 6c46af7 commit c7008eb

File tree

3 files changed

+106
-4
lines changed

3 files changed

+106
-4
lines changed

packages/mcp-server-supabase/src/server.test.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,91 @@ describe('tools', () => {
825825
);
826826
});
827827

828+
test('revert migrations', async () => {
829+
const { callTool } = await setup();
830+
const project = mockProjects.values().next().value!;
831+
832+
await callTool({
833+
name: 'enable_branching',
834+
arguments: {
835+
project_id: project.id,
836+
},
837+
});
838+
839+
const branch = await callTool({
840+
name: 'create_branch',
841+
arguments: {
842+
project_id: project.id,
843+
name: 'test-branch',
844+
},
845+
});
846+
847+
const migrationName = 'sample_migration';
848+
const migrationQuery =
849+
'create table sample (id integer generated always as identity primary key)';
850+
await callTool({
851+
name: 'apply_migration',
852+
arguments: {
853+
project_id: branch.project_ref,
854+
name: migrationName,
855+
query: migrationQuery,
856+
},
857+
});
858+
859+
// Check that migration has been applied to the branch
860+
const firstListResult = await callTool({
861+
name: 'list_migrations',
862+
arguments: {
863+
project_id: branch.project_ref,
864+
},
865+
});
866+
867+
expect(firstListResult).toContainEqual({
868+
name: migrationName,
869+
version: expect.stringMatching(/^\d{14}$/),
870+
});
871+
872+
const firstTablesResult = await callTool({
873+
name: 'list_tables',
874+
arguments: {
875+
project_id: branch.project_ref,
876+
},
877+
});
878+
879+
expect(firstTablesResult).toContainEqual(
880+
expect.objectContaining({ name: 'sample' })
881+
);
882+
883+
await callTool({
884+
name: 'reset_branch',
885+
arguments: {
886+
branch_id: branch.id,
887+
migration_version: '0',
888+
},
889+
});
890+
891+
// Check that all migrations have been reverted
892+
const secondListResult = await callTool({
893+
name: 'list_migrations',
894+
arguments: {
895+
project_id: branch.project_ref,
896+
},
897+
});
898+
899+
expect(secondListResult).toStrictEqual([]);
900+
901+
const secondTablesResult = await callTool({
902+
name: 'list_tables',
903+
arguments: {
904+
project_id: branch.project_ref,
905+
},
906+
});
907+
908+
expect(secondTablesResult).not.toContainEqual(
909+
expect.objectContaining({ name: 'sample' })
910+
);
911+
});
912+
828913
test('rebase branch', async () => {
829914
const { callTool } = await setup();
830915
const project = mockProjects.values().next().value!;

packages/mcp-server-supabase/src/server.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -592,8 +592,14 @@ export function createSupabaseMcpServer(options: SupabaseMcpServerOptions) {
592592
'Resets migrations of a development branch. Any untracked data or schema changes will be lost.',
593593
parameters: z.object({
594594
branch_id: z.string(),
595+
migration_version: z
596+
.string()
597+
.optional()
598+
.describe(
599+
'Reset your development branch to a specific migration version.'
600+
),
595601
}),
596-
execute: async ({ branch_id }) => {
602+
execute: async ({ branch_id, migration_version }) => {
597603
const response = await managementApiClient.POST(
598604
'/v1/branches/{branch_id}/reset',
599605
{
@@ -602,7 +608,9 @@ export function createSupabaseMcpServer(options: SupabaseMcpServerOptions) {
602608
branch_id,
603609
},
604610
},
605-
body: {},
611+
body: {
612+
migration_version,
613+
},
606614
}
607615
);
608616

packages/mcp-server-supabase/test/mocks.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,9 +436,9 @@ export const mockManagementApi = [
436436
/**
437437
* Resets a branch and re-runs migrations
438438
*/
439-
http.post<{ branchId: string }>(
439+
http.post<{ branchId: string }, { migration_version?: string }>(
440440
`${API_URL}/v1/branches/:branchId/reset`,
441-
async ({ params }) => {
441+
async ({ params, request }) => {
442442
const branch = mockBranches.get(params.branchId);
443443
if (!branch) {
444444
return HttpResponse.json(
@@ -455,6 +455,15 @@ export const mockManagementApi = [
455455
);
456456
}
457457

458+
// Clear migrations below the specified version
459+
const body = await request.json();
460+
if (body.migration_version) {
461+
const target = body.migration_version;
462+
project.migrations = project.migrations.filter(
463+
(m) => m.version <= target
464+
);
465+
}
466+
458467
// Reset the DB a re-run migrations
459468
await project.resetDb();
460469
try {

0 commit comments

Comments
 (0)