From fd71a2185d7bb15dd24c40324234bceb450841d3 Mon Sep 17 00:00:00 2001 From: Max Korp Date: Tue, 4 Jan 2022 18:06:17 -0700 Subject: [PATCH 01/16] feat: add --forceActions option to watch --- src/commands/watch.ts | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/commands/watch.ts b/src/commands/watch.ts index ba526424..b28a5abe 100644 --- a/src/commands/watch.ts +++ b/src/commands/watch.ts @@ -19,12 +19,14 @@ import { CommonArgv, getSettings } from "./_common"; interface WatchArgv extends CommonArgv { once: boolean; shadow: boolean; + forceActions: boolean; } export function _makeCurrentMigrationRunner( parsedSettings: ParsedSettings, _once = false, shadow = false, + forceActions = false, ): () => Promise { async function run(): Promise { const currentLocation = await getCurrentMigrationLocation(parsedSettings); @@ -85,7 +87,7 @@ export function _makeCurrentMigrationRunner( currentBodyMinified === previousBodyMinified; // 4: if different - if (!migrationsAreEquivalent) { + if (forceActions || !migrationsAreEquivalent) { await executeActions( parsedSettings, shadow, @@ -173,6 +175,7 @@ export async function _watch( parsedSettings: ParsedSettings, once = false, shadow = false, + forceActions = false, ): Promise { await _migrate(parsedSettings, shadow); @@ -185,7 +188,12 @@ export async function _watch( ); } - const run = _makeCurrentMigrationRunner(parsedSettings, once, shadow); + const run = _makeCurrentMigrationRunner( + parsedSettings, + once, + shadow, + forceActions, + ); if (once) { return run(); } else { @@ -249,9 +257,10 @@ export async function watch( settings: Settings, once = false, shadow = false, + forceActions = false, ): Promise { const parsedSettings = await parseSettings(settings, shadow); - return _watch(parsedSettings, once, shadow); + return _watch(parsedSettings, once, shadow, forceActions); } export const watchCommand: CommandModule = { @@ -270,6 +279,12 @@ export const watchCommand: CommandModule = { default: false, description: "Applies changes to shadow DB.", }, + forceActions: { + type: "boolean", + default: false, + description: + "Run beforeAllMigrations and afterAllMigrations actions even if no migration was necessary.", + }, }, handler: async argv => { await watch( From 3c048844124ce27309a90294376e8790d7ba13af Mon Sep 17 00:00:00 2001 From: Max Korp Date: Tue, 4 Jan 2022 18:06:17 -0700 Subject: [PATCH 02/16] Revert "feat: add --forceActions option to watch" This reverts commit fd71a2185d7bb15dd24c40324234bceb450841d3. --- src/commands/watch.ts | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/commands/watch.ts b/src/commands/watch.ts index b28a5abe..ba526424 100644 --- a/src/commands/watch.ts +++ b/src/commands/watch.ts @@ -19,14 +19,12 @@ import { CommonArgv, getSettings } from "./_common"; interface WatchArgv extends CommonArgv { once: boolean; shadow: boolean; - forceActions: boolean; } export function _makeCurrentMigrationRunner( parsedSettings: ParsedSettings, _once = false, shadow = false, - forceActions = false, ): () => Promise { async function run(): Promise { const currentLocation = await getCurrentMigrationLocation(parsedSettings); @@ -87,7 +85,7 @@ export function _makeCurrentMigrationRunner( currentBodyMinified === previousBodyMinified; // 4: if different - if (forceActions || !migrationsAreEquivalent) { + if (!migrationsAreEquivalent) { await executeActions( parsedSettings, shadow, @@ -175,7 +173,6 @@ export async function _watch( parsedSettings: ParsedSettings, once = false, shadow = false, - forceActions = false, ): Promise { await _migrate(parsedSettings, shadow); @@ -188,12 +185,7 @@ export async function _watch( ); } - const run = _makeCurrentMigrationRunner( - parsedSettings, - once, - shadow, - forceActions, - ); + const run = _makeCurrentMigrationRunner(parsedSettings, once, shadow); if (once) { return run(); } else { @@ -257,10 +249,9 @@ export async function watch( settings: Settings, once = false, shadow = false, - forceActions = false, ): Promise { const parsedSettings = await parseSettings(settings, shadow); - return _watch(parsedSettings, once, shadow, forceActions); + return _watch(parsedSettings, once, shadow); } export const watchCommand: CommandModule = { @@ -279,12 +270,6 @@ export const watchCommand: CommandModule = { default: false, description: "Applies changes to shadow DB.", }, - forceActions: { - type: "boolean", - default: false, - description: - "Run beforeAllMigrations and afterAllMigrations actions even if no migration was necessary.", - }, }, handler: async argv => { await watch( From b683b82a1f41f32ed0ec55fd4d1321c6d0bc4016 Mon Sep 17 00:00:00 2001 From: Max Korp Date: Mon, 7 Feb 2022 11:44:48 -0700 Subject: [PATCH 03/16] feat: add forceActions back to underlying watch function for use externally --- __tests__/watch.test.ts | 2 ++ src/commands/watch.ts | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/__tests__/watch.test.ts b/__tests__/watch.test.ts index df5f0852..17973e19 100644 --- a/__tests__/watch.test.ts +++ b/__tests__/watch.test.ts @@ -30,6 +30,7 @@ it("doesn't run current.sql if it's already up to date", async () => { parsedSettings, false, false, + false, ); expect(getActionCalls()).toEqual([]); @@ -81,6 +82,7 @@ it("watches symlinked files", async () => { parsedSettings, false, false, + false, ); expect(getActionCalls()).toEqual([]); diff --git a/src/commands/watch.ts b/src/commands/watch.ts index ba526424..1e2ca369 100644 --- a/src/commands/watch.ts +++ b/src/commands/watch.ts @@ -25,6 +25,7 @@ export function _makeCurrentMigrationRunner( parsedSettings: ParsedSettings, _once = false, shadow = false, + forceActions = false, ): () => Promise { async function run(): Promise { const currentLocation = await getCurrentMigrationLocation(parsedSettings); @@ -85,7 +86,7 @@ export function _makeCurrentMigrationRunner( currentBodyMinified === previousBodyMinified; // 4: if different - if (!migrationsAreEquivalent) { + if (forceActions || !migrationsAreEquivalent) { await executeActions( parsedSettings, shadow, @@ -185,7 +186,7 @@ export async function _watch( ); } - const run = _makeCurrentMigrationRunner(parsedSettings, once, shadow); + const run = _makeCurrentMigrationRunner(parsedSettings, once, shadow, false); if (once) { return run(); } else { From e297767f4a23133b7ae1892817a5b7adfbb309ca Mon Sep 17 00:00:00 2001 From: Max Korp Date: Mon, 7 Feb 2022 11:44:55 -0700 Subject: [PATCH 04/16] feat: add new `current` command --- src/cli.ts | 2 + src/commands/current.ts | 86 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 src/commands/current.ts diff --git a/src/cli.ts b/src/cli.ts index 6d8f9754..98c50cd5 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -6,6 +6,7 @@ import * as yargs from "yargs"; import { version } from "../package.json"; import { commitCommand } from "./commands/commit"; import { compileCommand } from "./commands/compile"; +import { currentCommand } from "./commands/current"; import { initCommand } from "./commands/init"; import { migrateCommand } from "./commands/migrate"; import { resetCommand } from "./commands/reset"; @@ -76,6 +77,7 @@ yargs .command(wrapHandler(statusCommand)) .command(wrapHandler(resetCommand)) .command(wrapHandler(compileCommand)) + .command(wrapHandler(currentCommand)) .command(wrapHandler(runCommand)) // Make sure options added here are represented in CommonArgv diff --git a/src/commands/current.ts b/src/commands/current.ts new file mode 100644 index 00000000..5a8cec1a --- /dev/null +++ b/src/commands/current.ts @@ -0,0 +1,86 @@ +import { CommandModule } from "yargs"; + +import { executeActions } from "../actions"; +import { + getLastMigration, + getMigrationsAfter, + runCommittedMigration, +} from "../migration"; +import { _migrate } from "./migrate"; +import { _makeCurrentMigrationRunner } from "./watch"; +import { + getCurrentMigrationLocation, + readCurrentMigration, + writeCurrentMigration, +} from "../current"; + +import { withClient } from "../pg"; +import { withAdvisoryLock } from "../pgReal"; +import { ParsedSettings, parseSettings, Settings } from "../settings"; +import { CommonArgv, getSettings } from "./_common"; + +interface CurrentArgv extends CommonArgv { + shadow: boolean; + forceActions: boolean; +} + +export async function _current( + parsedSettings: ParsedSettings, + shadow = false, + forceActions = false, +): Promise { + await _migrate(parsedSettings, shadow); + + const currentLocation = await getCurrentMigrationLocation(parsedSettings); + if (!currentLocation.exists) { + await writeCurrentMigration( + parsedSettings, + currentLocation, + parsedSettings.blankMigrationContent.trim() + "\n", + ); + } + + const run = _makeCurrentMigrationRunner( + parsedSettings, + false, + shadow, + forceActions, + ); + return run(); +} + +export async function current( + settings: Settings, + shadow = false, + forceActions = false, +): Promise { + const parsedSettings = await parseSettings(settings, shadow); + return _current(parsedSettings, shadow, forceActions); +} + +export const currentCommand: CommandModule = { + command: "current", + aliases: [], + describe: + "Runs any un-executed committed migrations, as well as the current migration. For development.", + builder: { + shadow: { + type: "boolean", + default: false, + description: "Apply migrations to the shadow DB (for development).", + }, + forceActions: { + type: "boolean", + default: false, + description: + "Run beforeAllMigrations and afterAllMigrations actions even if no migration was necessary.", + }, + }, + handler: async argv => { + await current( + await getSettings({ configFile: argv.config }), + argv.shadow, + argv.forceActions, + ); + }, +}; From 179357f2dc2c48790f112650ed205c1e68b83aaa Mon Sep 17 00:00:00 2001 From: Max Korp Date: Mon, 7 Feb 2022 11:54:19 -0700 Subject: [PATCH 05/16] feat: add test to new current command --- __tests__/current.test.ts | 145 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 __tests__/current.test.ts diff --git a/__tests__/current.test.ts b/__tests__/current.test.ts new file mode 100644 index 00000000..aeed182d --- /dev/null +++ b/__tests__/current.test.ts @@ -0,0 +1,145 @@ +import "./helpers"; // Has side-effects; must come first + +import * as mockFs from "mock-fs"; + +import { migrate } from "../src"; +import { withClient } from "../src/pg"; +import { ParsedSettings, parseSettings } from "../src/settings"; +import { makeMigrations, resetDb, settings } from "./helpers"; + +beforeEach(resetDb); +beforeEach(async () => { + mockFs({ migrations: mockFs.directory() }); +}); +afterEach(() => { + mockFs.restore(); +}); +const { + MIGRATION_1_COMMITTED, + MIGRATION_2_TEXT, + MIGRATION_ENUM_COMMITTED, + MIGRATION_NOTRX_TEXT, + MIGRATION_NOTRX_COMMITTED, +} = makeMigrations(); + +function getStuff(parsedSettings: ParsedSettings) { + return withClient( + parsedSettings.connectionString, + parsedSettings, + async (pgClient, _context) => { + const { rows: migrations } = await pgClient.query( + "select * from graphile_migrate.migrations", + ); + const { rows: tables } = await pgClient.query( + "select * from pg_class where relnamespace = 'public'::regnamespace and relkind = 'r'", + ); + const { rows: enums } = await pgClient.query( + "select typname, (select count(*) from pg_enum where enumtypid = pg_type.oid) as value_count from pg_type where typnamespace = 'public'::regnamespace and typtype = 'e'", + ); + return { migrations, tables, enums }; + }, + ); +} + +it("runs migrations", async () => { + const parsedSettings = await parseSettings(settings); + + { + const { migrations, tables, enums } = await getStuff(parsedSettings); + expect(migrations).toHaveLength(0); + expect(tables).toHaveLength(0); + expect(enums).toHaveLength(0); + } + + mockFs({ + [`migrations/committed/000001.sql`]: MIGRATION_1_COMMITTED, + [`migrations/committed/000002.sql`]: MIGRATION_ENUM_COMMITTED, + "migrations/current.sql": MIGRATION_NOTRX_TEXT, + }); + + await migrate(settings); + + { + const { migrations, tables, enums } = await getStuff(parsedSettings); + + expect(migrations).toHaveLength(3); + expect(migrations.map(({ date, ...rest }) => rest)).toMatchInlineSnapshot(` + Array [ + Object { + "filename": "000001.sql", + "hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", + "previous_hash": null, + }, + Object { + "filename": "000002.sql", + "hash": "sha1:bddc1ead3310dc1c42cdc7f63537ebdff2e9fd7b", + "previous_hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", + }, + ] + `); + expect(tables).toHaveLength(1); + expect(tables.map(t => t.relname)).toMatchInlineSnapshot(` + Array [ + "foo", + ] + `); + expect(enums).toHaveLength(1); + expect(enums).toMatchInlineSnapshot(` +Array [ + Object { + "typname": "user_role", + "value_count": "2", + }, +] +`); + } + + mockFs({ + [`migrations/committed/000001.sql`]: MIGRATION_1_COMMITTED, + [`migrations/committed/000002.sql`]: MIGRATION_ENUM_COMMITTED, + [`migrations/committed/000003.sql`]: MIGRATION_NOTRX_COMMITTED, + "migrations/current.sql": "", + }); + + await migrate(settings); + + { + const { migrations, tables, enums } = await getStuff(parsedSettings); + + expect(migrations).toHaveLength(3); + expect(migrations.map(({ date, ...rest }) => rest)).toMatchInlineSnapshot(` + Array [ + Object { + "filename": "000001.sql", + "hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", + "previous_hash": null, + }, + Object { + "filename": "000002.sql", + "hash": "sha1:bddc1ead3310dc1c42cdc7f63537ebdff2e9fd7b", + "previous_hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", + }, + Object { + "filename": "000003.sql", + "hash": "sha1:2d248344ac299ebbad2aeba5bfec2ae3c3cb0a4f", + "previous_hash": "sha1:bddc1ead3310dc1c42cdc7f63537ebdff2e9fd7b", + }, + ] + `); + expect(tables).toHaveLength(1); + expect(tables.map(t => t.relname)).toMatchInlineSnapshot(` + Array [ + "foo", + ] + `); + expect(enums).toHaveLength(1); + expect(enums).toMatchInlineSnapshot(` +Array [ + Object { + "typname": "user_role", + "value_count": "2", + }, +] +`); + } +}); From 370ae01d6cad8bdf1f0ace7528b0386114968800 Mon Sep 17 00:00:00 2001 From: Max Korp Date: Mon, 7 Feb 2022 12:01:06 -0700 Subject: [PATCH 06/16] chore: fix lint --- __tests__/current.test.ts | 1 - src/commands/current.ts | 19 +++---------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/__tests__/current.test.ts b/__tests__/current.test.ts index aeed182d..5baa6444 100644 --- a/__tests__/current.test.ts +++ b/__tests__/current.test.ts @@ -16,7 +16,6 @@ afterEach(() => { }); const { MIGRATION_1_COMMITTED, - MIGRATION_2_TEXT, MIGRATION_ENUM_COMMITTED, MIGRATION_NOTRX_TEXT, MIGRATION_NOTRX_COMMITTED, diff --git a/src/commands/current.ts b/src/commands/current.ts index 5a8cec1a..01978421 100644 --- a/src/commands/current.ts +++ b/src/commands/current.ts @@ -1,23 +1,10 @@ import { CommandModule } from "yargs"; -import { executeActions } from "../actions"; -import { - getLastMigration, - getMigrationsAfter, - runCommittedMigration, -} from "../migration"; -import { _migrate } from "./migrate"; -import { _makeCurrentMigrationRunner } from "./watch"; -import { - getCurrentMigrationLocation, - readCurrentMigration, - writeCurrentMigration, -} from "../current"; - -import { withClient } from "../pg"; -import { withAdvisoryLock } from "../pgReal"; +import { getCurrentMigrationLocation, writeCurrentMigration } from "../current"; import { ParsedSettings, parseSettings, Settings } from "../settings"; import { CommonArgv, getSettings } from "./_common"; +import { _migrate } from "./migrate"; +import { _makeCurrentMigrationRunner } from "./watch"; interface CurrentArgv extends CommonArgv { shadow: boolean; From ea397598660a0579fe6aa52318b4308b1790300b Mon Sep 17 00:00:00 2001 From: Max Korp Date: Mon, 7 Feb 2022 12:27:04 -0700 Subject: [PATCH 07/16] fix test --- __tests__/current.test.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/__tests__/current.test.ts b/__tests__/current.test.ts index 5baa6444..7b5cd7f8 100644 --- a/__tests__/current.test.ts +++ b/__tests__/current.test.ts @@ -2,7 +2,7 @@ import "./helpers"; // Has side-effects; must come first import * as mockFs from "mock-fs"; -import { migrate } from "../src"; +import { current } from "../src"; import { withClient } from "../src/pg"; import { ParsedSettings, parseSettings } from "../src/settings"; import { makeMigrations, resetDb, settings } from "./helpers"; @@ -41,6 +41,11 @@ function getStuff(parsedSettings: ParsedSettings) { } it("runs migrations", async () => { + mockFs({ + "migrations/current.sql": "", + }); + + await current(settings); const parsedSettings = await parseSettings(settings); { @@ -56,12 +61,12 @@ it("runs migrations", async () => { "migrations/current.sql": MIGRATION_NOTRX_TEXT, }); - await migrate(settings); + await current(settings); { const { migrations, tables, enums } = await getStuff(parsedSettings); - expect(migrations).toHaveLength(3); + expect(migrations).toHaveLength(2); expect(migrations.map(({ date, ...rest }) => rest)).toMatchInlineSnapshot(` Array [ Object { @@ -100,7 +105,7 @@ Array [ "migrations/current.sql": "", }); - await migrate(settings); + await current(settings); { const { migrations, tables, enums } = await getStuff(parsedSettings); From b31e83dc13dc681f26815992b149ddb523fcf22a Mon Sep 17 00:00:00 2001 From: Max Korp Date: Mon, 7 Feb 2022 12:27:22 -0700 Subject: [PATCH 08/16] fix missing import/export --- src/commands/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/index.ts b/src/commands/index.ts index 725c5cd3..8821ec66 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -7,3 +7,4 @@ export { status } from "./status"; export { reset } from "./reset"; export { compile } from "./compile"; export { run } from "./run"; +export { current } from "./current"; From 32943842ab0b5c79736f87ff07fcc762bc4b3821 Mon Sep 17 00:00:00 2001 From: Max Korp Date: Wed, 9 Feb 2022 14:17:30 -0700 Subject: [PATCH 09/16] feat: add `current` documentation to README --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index 7223a54c..89046738 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,9 @@ Commands: graphile-migrate watch Runs any un-executed committed migrations and then runs and watches the current migration, re-running it on any change. For development. + graphile-migrate current Runs any un-executed committed migrations and + then runs the current migration. For + development. graphile-migrate commit Commits the current migration into the `committed/` folder, resetting the current migration. Resets the shadow database. @@ -287,6 +290,24 @@ Options: ``` +## graphile-migrate current + +``` +graphile-migrate current + +Runs any un-executed committed migrations and then runs the current migration. +For development. + +Options: + --help Show help [boolean] + --config, -c Optional path to gmrc file string] [default: .gmrc[.js]] + --shadow Applies changes to shadow DB. [boolean] [default: false] + --forceActions Run beforeAllMigrations, afterAllMigrations, beforeCurrent, + and afterCurrent actions even if no migration was necessary. + [boolean] [default: false] +``` + + ## graphile-migrate commit ``` From fdd73fb714a1aa9ca504b7ca0c3e2dd6ad503bf4 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 22 Apr 2026 13:18:02 +0100 Subject: [PATCH 10/16] Refactor/fix --- __tests__/current.test.ts | 6 +++--- src/commands/current.ts | 33 +++++++++++++++------------------ 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/__tests__/current.test.ts b/__tests__/current.test.ts index 7b5cd7f8..3eb9f089 100644 --- a/__tests__/current.test.ts +++ b/__tests__/current.test.ts @@ -1,6 +1,6 @@ import "./helpers"; // Has side-effects; must come first -import * as mockFs from "mock-fs"; +import mockFs from "mock-fs"; import { current } from "../src"; import { withClient } from "../src/pg"; @@ -82,7 +82,7 @@ it("runs migrations", async () => { ] `); expect(tables).toHaveLength(1); - expect(tables.map(t => t.relname)).toMatchInlineSnapshot(` + expect(tables.map((t) => t.relname)).toMatchInlineSnapshot(` Array [ "foo", ] @@ -131,7 +131,7 @@ Array [ ] `); expect(tables).toHaveLength(1); - expect(tables.map(t => t.relname)).toMatchInlineSnapshot(` + expect(tables.map((t) => t.relname)).toMatchInlineSnapshot(` Array [ "foo", ] diff --git a/src/commands/current.ts b/src/commands/current.ts index 01978421..0be4a214 100644 --- a/src/commands/current.ts +++ b/src/commands/current.ts @@ -1,10 +1,10 @@ import { CommandModule } from "yargs"; import { getCurrentMigrationLocation, writeCurrentMigration } from "../current"; +import { makeCurrentMigrationRunner } from "../currentRunner"; import { ParsedSettings, parseSettings, Settings } from "../settings"; import { CommonArgv, getSettings } from "./_common"; import { _migrate } from "./migrate"; -import { _makeCurrentMigrationRunner } from "./watch"; interface CurrentArgv extends CommonArgv { shadow: boolean; @@ -13,9 +13,9 @@ interface CurrentArgv extends CommonArgv { export async function _current( parsedSettings: ParsedSettings, - shadow = false, - forceActions = false, + options: Partial, ): Promise { + const { shadow = false, forceActions = false } = options; await _migrate(parsedSettings, shadow); const currentLocation = await getCurrentMigrationLocation(parsedSettings); @@ -27,25 +27,26 @@ export async function _current( ); } - const run = _makeCurrentMigrationRunner( - parsedSettings, - false, + const run = makeCurrentMigrationRunner(parsedSettings, { + once: true, shadow, forceActions, - ); + }); return run(); } export async function current( settings: Settings, - shadow = false, - forceActions = false, + options: Partial = {}, ): Promise { - const parsedSettings = await parseSettings(settings, shadow); - return _current(parsedSettings, shadow, forceActions); + const parsedSettings = await parseSettings(settings, options.shadow); + return _current(parsedSettings, options); } -export const currentCommand: CommandModule = { +export const currentCommand: CommandModule< + Record, + CurrentArgv +> = { command: "current", aliases: [], describe: @@ -63,11 +64,7 @@ export const currentCommand: CommandModule = { "Run beforeAllMigrations and afterAllMigrations actions even if no migration was necessary.", }, }, - handler: async argv => { - await current( - await getSettings({ configFile: argv.config }), - argv.shadow, - argv.forceActions, - ); + handler: async (argv) => { + await current(await getSettings({ configFile: argv.config }), argv); }, }; From 3d449ee95a890ec701980c8d8516283790e7b152 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 22 Apr 2026 13:20:23 +0100 Subject: [PATCH 11/16] Update snapshot shapes --- __tests__/current.test.ts | 46 +++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/__tests__/current.test.ts b/__tests__/current.test.ts index 3eb9f089..8b8752eb 100644 --- a/__tests__/current.test.ts +++ b/__tests__/current.test.ts @@ -68,13 +68,13 @@ it("runs migrations", async () => { expect(migrations).toHaveLength(2); expect(migrations.map(({ date, ...rest }) => rest)).toMatchInlineSnapshot(` - Array [ - Object { + [ + { "filename": "000001.sql", "hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", "previous_hash": null, }, - Object { + { "filename": "000002.sql", "hash": "sha1:bddc1ead3310dc1c42cdc7f63537ebdff2e9fd7b", "previous_hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", @@ -83,19 +83,19 @@ it("runs migrations", async () => { `); expect(tables).toHaveLength(1); expect(tables.map((t) => t.relname)).toMatchInlineSnapshot(` - Array [ + [ "foo", ] `); expect(enums).toHaveLength(1); expect(enums).toMatchInlineSnapshot(` -Array [ - Object { - "typname": "user_role", - "value_count": "2", - }, -] -`); + [ + { + "typname": "user_role", + "value_count": "2", + }, + ] + `); } mockFs({ @@ -112,18 +112,18 @@ Array [ expect(migrations).toHaveLength(3); expect(migrations.map(({ date, ...rest }) => rest)).toMatchInlineSnapshot(` - Array [ - Object { + [ + { "filename": "000001.sql", "hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", "previous_hash": null, }, - Object { + { "filename": "000002.sql", "hash": "sha1:bddc1ead3310dc1c42cdc7f63537ebdff2e9fd7b", "previous_hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", }, - Object { + { "filename": "000003.sql", "hash": "sha1:2d248344ac299ebbad2aeba5bfec2ae3c3cb0a4f", "previous_hash": "sha1:bddc1ead3310dc1c42cdc7f63537ebdff2e9fd7b", @@ -132,18 +132,18 @@ Array [ `); expect(tables).toHaveLength(1); expect(tables.map((t) => t.relname)).toMatchInlineSnapshot(` - Array [ + [ "foo", ] `); expect(enums).toHaveLength(1); expect(enums).toMatchInlineSnapshot(` -Array [ - Object { - "typname": "user_role", - "value_count": "2", - }, -] -`); + [ + { + "typname": "user_role", + "value_count": "2", + }, + ] + `); } }); From 6fd41e159e29823960832246c71646cb5bb9b3aa Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 22 Apr 2026 13:25:05 +0100 Subject: [PATCH 12/16] More refactoring --- src/commands/current.ts | 27 +++++++++++---------------- src/commands/run.ts | 10 +--------- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/src/commands/current.ts b/src/commands/current.ts index 0be4a214..949b2c23 100644 --- a/src/commands/current.ts +++ b/src/commands/current.ts @@ -2,20 +2,22 @@ import { CommandModule } from "yargs"; import { getCurrentMigrationLocation, writeCurrentMigration } from "../current"; import { makeCurrentMigrationRunner } from "../currentRunner"; -import { ParsedSettings, parseSettings, Settings } from "../settings"; -import { CommonArgv, getSettings } from "./_common"; +import { parseSettings, Settings } from "../settings"; +import type { CommonArgv } from "./_common"; +import { getSettings } from "./_common"; import { _migrate } from "./migrate"; interface CurrentArgv extends CommonArgv { - shadow: boolean; - forceActions: boolean; + shadow?: boolean; + forceActions?: boolean; } -export async function _current( - parsedSettings: ParsedSettings, - options: Partial, +export async function current( + settings: Settings, + options: Partial = {}, ): Promise { const { shadow = false, forceActions = false } = options; + const parsedSettings = await parseSettings(settings, shadow); await _migrate(parsedSettings, shadow); const currentLocation = await getCurrentMigrationLocation(parsedSettings); @@ -35,14 +37,6 @@ export async function _current( return run(); } -export async function current( - settings: Settings, - options: Partial = {}, -): Promise { - const parsedSettings = await parseSettings(settings, options.shadow); - return _current(parsedSettings, options); -} - export const currentCommand: CommandModule< Record, CurrentArgv @@ -65,6 +59,7 @@ export const currentCommand: CommandModule< }, }, handler: async (argv) => { - await current(await getSettings({ configFile: argv.config }), argv); + const settings = await getSettings({ configFile: argv.config }); + await current(settings, argv); }, }; diff --git a/src/commands/run.ts b/src/commands/run.ts index 486b207b..1dd8b276 100644 --- a/src/commands/run.ts +++ b/src/commands/run.ts @@ -24,15 +24,7 @@ export async function run( settings: Settings, rawContent: string, filename: string, - { - shadow = false, - root = false, - rootDatabase = false, - }: { - shadow?: boolean; - root?: boolean; - rootDatabase?: boolean; - } = {}, + { shadow = false, root = false, rootDatabase = false }: RunArgv = {}, ): Promise { const parsedSettings = await parseSettings(settings, shadow); const content = await compileIncludes( From 360599a7dba3ed751a8c370105da9144d6f23b4e Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 22 Apr 2026 13:36:17 +0100 Subject: [PATCH 13/16] Remove forceActions flag --- src/commands/current.ts | 10 +--------- src/currentRunner.ts | 5 ++--- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/commands/current.ts b/src/commands/current.ts index 949b2c23..29e42412 100644 --- a/src/commands/current.ts +++ b/src/commands/current.ts @@ -9,14 +9,13 @@ import { _migrate } from "./migrate"; interface CurrentArgv extends CommonArgv { shadow?: boolean; - forceActions?: boolean; } export async function current( settings: Settings, options: Partial = {}, ): Promise { - const { shadow = false, forceActions = false } = options; + const { shadow = false } = options; const parsedSettings = await parseSettings(settings, shadow); await _migrate(parsedSettings, shadow); @@ -32,7 +31,6 @@ export async function current( const run = makeCurrentMigrationRunner(parsedSettings, { once: true, shadow, - forceActions, }); return run(); } @@ -51,12 +49,6 @@ export const currentCommand: CommandModule< default: false, description: "Apply migrations to the shadow DB (for development).", }, - forceActions: { - type: "boolean", - default: false, - description: - "Run beforeAllMigrations and afterAllMigrations actions even if no migration was necessary.", - }, }, handler: async (argv) => { const settings = await getSettings({ configFile: argv.config }); diff --git a/src/currentRunner.ts b/src/currentRunner.ts index 61e92ba4..35758c14 100644 --- a/src/currentRunner.ts +++ b/src/currentRunner.ts @@ -13,10 +13,9 @@ export function makeCurrentMigrationRunner( options: { once?: boolean; shadow?: boolean; - forceActions?: boolean; } = {}, ): () => Promise { - const { shadow = false, forceActions = false } = options; + const { shadow = false } = options; async function run(): Promise { const currentLocation = await getCurrentMigrationLocation(parsedSettings); const body = await readCurrentMigration(parsedSettings, currentLocation); @@ -76,7 +75,7 @@ export function makeCurrentMigrationRunner( currentBodyMinified === previousBodyMinified; // 4: if different - if (forceActions || !migrationsAreEquivalent) { + if (!migrationsAreEquivalent) { await executeActions( parsedSettings, shadow, From 914068d7504fd26f6cc60a8924d10a2e2ab6dc65 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 22 Apr 2026 13:39:39 +0100 Subject: [PATCH 14/16] Integrate into README update --- README.md | 16 +++++++--------- scripts/usage | 4 ++++ src/cli.ts | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 88d03c6c..d06e2ad9 100644 --- a/README.md +++ b/README.md @@ -180,8 +180,8 @@ Commands: graphile-migrate watch Runs any un-executed committed migrations and then runs and watches the current migration, re-running it on any change. For development. - graphile-migrate current Runs any un-executed committed migrations and - then runs the current migration. For + graphile-migrate current Runs any un-executed committed migrations, as + well as the current migration. For development. graphile-migrate commit Commits the current migration into the `committed/` folder, resetting the current @@ -298,15 +298,13 @@ Options: ``` graphile-migrate current -Runs any un-executed committed migrations and then runs the current migration. -For development. +Runs any un-executed committed migrations, as well as the current migration. For +development. Options: - --help Show help [boolean] - --config, -c Optional path to gmrc file string] [default: .gmrc[.js]] - --shadow Applies changes to shadow DB. [boolean] [default: false] - --forceActions Run beforeAllMigrations, afterAllMigrations, beforeCurrent, - and afterCurrent actions even if no migration was necessary. + --help Show help [boolean] + -c, --config Optional path to gmrc file [string] [default: .gmrc[.js|.cjs]] + --shadow Apply migrations to the shadow DB (for development). [boolean] [default: false] ``` diff --git a/scripts/usage b/scripts/usage index 7b2addcc..6cb6fe04 100755 --- a/scripts/usage +++ b/scripts/usage @@ -21,6 +21,10 @@ echo -e '## graphile-migrate watch\n\n```' $GRAPHILE_MIGRATE watch --help echo -e '```\n\n' +echo -e '## graphile-migrate current\n\n```' +$GRAPHILE_MIGRATE current --help +echo -e '```\n\n' + echo -e '## graphile-migrate commit\n\n```' $GRAPHILE_MIGRATE commit --help echo -e '```\n\n' diff --git a/src/cli.ts b/src/cli.ts index 13e0dff0..cb48bc46 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -68,12 +68,12 @@ const f = yargs .command(wrapHandler(initCommand)) .command(wrapHandler(migrateCommand)) .command(wrapHandler(watchCommand)) + .command(wrapHandler(currentCommand)) .command(wrapHandler(commitCommand)) .command(wrapHandler(uncommitCommand)) .command(wrapHandler(statusCommand)) .command(wrapHandler(resetCommand)) .command(wrapHandler(compileCommand)) - .command(wrapHandler(currentCommand)) .command(wrapHandler(runCommand)) // Make sure options added here are represented in CommonArgv From e31c8b7e37c2acef7daad96622d9d35880a95541 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 22 Apr 2026 13:46:54 +0100 Subject: [PATCH 15/16] Clarify tests --- __tests__/current.test.ts | 133 +++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 73 deletions(-) diff --git a/__tests__/current.test.ts b/__tests__/current.test.ts index 8b8752eb..aa98590f 100644 --- a/__tests__/current.test.ts +++ b/__tests__/current.test.ts @@ -57,46 +57,44 @@ it("runs migrations", async () => { mockFs({ [`migrations/committed/000001.sql`]: MIGRATION_1_COMMITTED, - [`migrations/committed/000002.sql`]: MIGRATION_ENUM_COMMITTED, - "migrations/current.sql": MIGRATION_NOTRX_TEXT, + [`migrations/committed/000002.sql`]: MIGRATION_ENUM_COMMITTED, // Creates enum with 1 value + "migrations/current.sql": MIGRATION_NOTRX_TEXT, // Adds a value to the enum - total = 2 }); await current(settings); - { - const { migrations, tables, enums } = await getStuff(parsedSettings); + const { migrations, tables, enums } = await getStuff(parsedSettings); - expect(migrations).toHaveLength(2); - expect(migrations.map(({ date, ...rest }) => rest)).toMatchInlineSnapshot(` - [ - { - "filename": "000001.sql", - "hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", - "previous_hash": null, - }, - { - "filename": "000002.sql", - "hash": "sha1:bddc1ead3310dc1c42cdc7f63537ebdff2e9fd7b", - "previous_hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", - }, - ] - `); - expect(tables).toHaveLength(1); - expect(tables.map((t) => t.relname)).toMatchInlineSnapshot(` - [ - "foo", - ] - `); - expect(enums).toHaveLength(1); - expect(enums).toMatchInlineSnapshot(` - [ - { - "typname": "user_role", - "value_count": "2", - }, - ] - `); - } + expect(migrations).toHaveLength(2); + expect(migrations.map(({ date, ...rest }) => rest)).toMatchInlineSnapshot(` + [ + { + "filename": "000001.sql", + "hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", + "previous_hash": null, + }, + { + "filename": "000002.sql", + "hash": "sha1:bddc1ead3310dc1c42cdc7f63537ebdff2e9fd7b", + "previous_hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", + }, + ] + `); + expect(tables).toHaveLength(1); + expect(tables.map((t) => t.relname)).toMatchInlineSnapshot(` + [ + "foo", + ] + `); + expect(enums).toHaveLength(1); + expect(enums).toMatchInlineSnapshot(` + [ + { + "typname": "user_role", + "value_count": "2", + }, + ] + `); mockFs({ [`migrations/committed/000001.sql`]: MIGRATION_1_COMMITTED, @@ -107,43 +105,32 @@ it("runs migrations", async () => { await current(settings); - { - const { migrations, tables, enums } = await getStuff(parsedSettings); + const { + migrations: newMigrations, + tables: newTables, + enums: newEnums, + } = await getStuff(parsedSettings); - expect(migrations).toHaveLength(3); - expect(migrations.map(({ date, ...rest }) => rest)).toMatchInlineSnapshot(` - [ - { - "filename": "000001.sql", - "hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", - "previous_hash": null, - }, - { - "filename": "000002.sql", - "hash": "sha1:bddc1ead3310dc1c42cdc7f63537ebdff2e9fd7b", - "previous_hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", - }, - { - "filename": "000003.sql", - "hash": "sha1:2d248344ac299ebbad2aeba5bfec2ae3c3cb0a4f", - "previous_hash": "sha1:bddc1ead3310dc1c42cdc7f63537ebdff2e9fd7b", - }, - ] - `); - expect(tables).toHaveLength(1); - expect(tables.map((t) => t.relname)).toMatchInlineSnapshot(` - [ - "foo", - ] - `); - expect(enums).toHaveLength(1); - expect(enums).toMatchInlineSnapshot(` - [ - { - "typname": "user_role", - "value_count": "2", - }, - ] - `); - } + expect(newMigrations).toHaveLength(3); + expect(newMigrations.map(({ date, ...rest }) => rest)).toMatchInlineSnapshot(` + [ + { + "filename": "000001.sql", + "hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", + "previous_hash": null, + }, + { + "filename": "000002.sql", + "hash": "sha1:bddc1ead3310dc1c42cdc7f63537ebdff2e9fd7b", + "previous_hash": "sha1:e00ec93314a423ee5cc68d1182ad52f16442d7df", + }, + { + "filename": "000003.sql", + "hash": "sha1:2d248344ac299ebbad2aeba5bfec2ae3c3cb0a4f", + "previous_hash": "sha1:bddc1ead3310dc1c42cdc7f63537ebdff2e9fd7b", + }, + ] + `); + expect(newTables).toEqual(tables); + expect(newEnums).toEqual(enums); }); From d0c6e3d9f11bd5cec843e4b59c1d3f96f528f820 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 22 Apr 2026 13:49:26 +0100 Subject: [PATCH 16/16] Note equivalence --- README.md | 4 ++-- src/commands/watch.ts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d06e2ad9..9cb31221 100644 --- a/README.md +++ b/README.md @@ -287,8 +287,8 @@ migration, re-running it on any change. For development. Options: --help Show help [boolean] -c, --config Optional path to gmrc file [string] [default: .gmrc[.js|.cjs]] - --once Runs the current migration and then exits. - [boolean] [default: false] + --once Runs the current migration and then exits (equivalent to + `graphile-migrate current`). [boolean] [default: false] --shadow Applies changes to shadow DB. [boolean] [default: false] ``` diff --git a/src/commands/watch.ts b/src/commands/watch.ts index b178b44c..70348604 100644 --- a/src/commands/watch.ts +++ b/src/commands/watch.ts @@ -110,7 +110,8 @@ export const watchCommand: CommandModule, WatchArgv> = { once: { type: "boolean", default: false, - description: "Runs the current migration and then exits.", + description: + "Runs the current migration and then exits (equivalent to `graphile-migrate current`).", }, shadow: { type: "boolean",