diff --git a/packages/core/__tests__/projects/verify-partial.test.ts b/packages/core/__tests__/projects/verify-partial.test.ts new file mode 100644 index 000000000..4a823cc68 --- /dev/null +++ b/packages/core/__tests__/projects/verify-partial.test.ts @@ -0,0 +1,39 @@ +import { TestDatabase } from '../../test-utils'; +import { CoreDeployTestFixture } from '../../test-utils/CoreDeployTestFixture'; + +describe('Partial Verification with toChange parameter', () => { + let fixture: CoreDeployTestFixture; + let db: TestDatabase; + + beforeEach(async () => { + fixture = new CoreDeployTestFixture('sqitch', 'simple-w-tags'); + db = await fixture.setupTestDatabase(); + }); + + afterEach(async () => { + await fixture.cleanup(); + }); + + test('verifies partial deployment with toChange parameter', async () => { + await fixture.deployModule('my-third', db.name, ['sqitch', 'simple-w-tags']); + await fixture.verifyModule('my-third', db.name, ['sqitch', 'simple-w-tags']); + + const verifyScriptPath = fixture.fixturePath('packages', 'my-third', 'verify', 'create_table.sql'); + const fs = require('fs'); + const originalContent = fs.readFileSync(verifyScriptPath, 'utf8'); + + const brokenContent = originalContent.replace( + "table_name = 'customers'", + "table_name = 'nonexistent_table'" + ); + fs.writeFileSync(verifyScriptPath, brokenContent); + + await fixture.verifyModule('my-third', db.name, ['sqitch', 'simple-w-tags'], 'create_schema'); + + await expect( + fixture.verifyModule('my-third', db.name, ['sqitch', 'simple-w-tags']) + ).rejects.toThrow(); + + fs.writeFileSync(verifyScriptPath, originalContent); + }); +}); diff --git a/packages/core/src/core/class/launchql.ts b/packages/core/src/core/class/launchql.ts index b44dd480b..c2e2c0765 100644 --- a/packages/core/src/core/class/launchql.ts +++ b/packages/core/src/core/class/launchql.ts @@ -749,7 +749,7 @@ export class LaunchQLProject { const result = await client.deploy({ modulePath, - toChange, + toChange: extension === name ? toChange : undefined, useTransaction: opts.deployment.useTx, logOnly: opts.deployment.logOnly }); @@ -848,7 +848,7 @@ export class LaunchQLProject { const result = await client.revert({ modulePath, - toChange, + toChange: extension === name ? toChange : undefined, useTransaction: opts.deployment.useTx }); @@ -932,9 +932,10 @@ export class LaunchQLProject { try { const client = new LaunchQLMigrate(opts.pg as PgConfig); + // Only apply toChange to the target module being verified, not its dependencies. const result = await client.verify({ modulePath, - toChange + toChange: extension === name ? toChange : undefined }); if (result.failed.length > 0) { diff --git a/packages/core/src/migrate/client.ts b/packages/core/src/migrate/client.ts index d11c00562..b4be9fffe 100644 --- a/packages/core/src/migrate/client.ts +++ b/packages/core/src/migrate/client.ts @@ -474,10 +474,18 @@ export class LaunchQLMigrate { async verify(options: VerifyOptions): Promise { await this.initialize(); - const { modulePath } = options; + const { modulePath, toChange } = options; const planPath = join(modulePath, 'launchql.plan'); const plan = parsePlanFileSimple(planPath); - const changes = getChangesInOrder(planPath); + let changes = getChangesInOrder(planPath); + + if (toChange) { + const toChangeIndex = changes.findIndex(c => c.name === toChange); + if (toChangeIndex === -1) { + throw new Error(`Change '${toChange}' not found in plan`); + } + changes = changes.slice(0, toChangeIndex + 1); + } const verified: string[] = []; const failed: string[] = [];