From 85d9099fd933db5f1a7fbe6dcc98b9fe54247c01 Mon Sep 17 00:00:00 2001 From: samir Date: Fri, 26 Mar 2021 14:18:57 +0545 Subject: [PATCH 1/5] Add --config(-c) flag to each command in sync-db to provide a entrypoint for custom configuration. --- src/commands/make-publish.ts | 13 +++- src/commands/make.ts | 7 ++- src/commands/migrate-latest.ts | 7 ++- src/commands/migrate-list.ts | 7 ++- src/commands/migrate-rollback.ts | 7 ++- src/commands/prune.ts | 7 ++- src/commands/synchronize.ts | 7 ++- src/config.ts | 4 +- test/cli/commands/make-publish.test.ts | 59 ++++++++++++++++++ test/cli/commands/make.test.ts | 84 ++++++++++++++++---------- 10 files changed, 158 insertions(+), 44 deletions(-) diff --git a/src/commands/make-publish.ts b/src/commands/make-publish.ts index 707a3e12..50230c8e 100644 --- a/src/commands/make-publish.ts +++ b/src/commands/make-publish.ts @@ -1,5 +1,5 @@ import { grey, cyan } from 'chalk'; -import { Command } from '@oclif/command'; +import { Command, flags } from '@oclif/command'; import { loadConfig } from '../config'; import { printInfo, printLine } from '../util/io'; @@ -7,14 +7,21 @@ import * as fileMakerService from '../service/fileMaker'; class MakePublish extends Command { static description = 'Publish migration templates files.'; - + static flags = { + config: flags.string({ + char: 'c', + default: 'sync-db.yml', + description: 'Custom configuration file.' + }) + }; /** * CLI command execution handler. * * @returns {Promise} */ async run(): Promise { - const config = await loadConfig(); + const { flags: parsedFlags } = this.parse(MakePublish); + const config = await loadConfig(parsedFlags.config); await printLine(); diff --git a/src/commands/make.ts b/src/commands/make.ts index c7034bc6..6126f261 100644 --- a/src/commands/make.ts +++ b/src/commands/make.ts @@ -17,6 +17,11 @@ class Make extends Command { default: false, description: 'Generate create table stub.' }), + config: flags.string({ + char: 'c', + default: 'sync-db.yml', + description: 'Custom configuration file.' + }), type: flags.string({ char: 't', helpValue: 'TYPE', @@ -33,7 +38,7 @@ class Make extends Command { */ async run(): Promise { const { args, flags: parsedFlags } = this.parse(Make); - const config = await loadConfig(); + const config = await loadConfig(parsedFlags.config); const list = await this.makeFiles(config, args.name, parsedFlags.type, { create: parsedFlags.create, objectName: parsedFlags['object-name'] diff --git a/src/commands/migrate-latest.ts b/src/commands/migrate-latest.ts index 128c5746..7282f847 100644 --- a/src/commands/migrate-latest.ts +++ b/src/commands/migrate-latest.ts @@ -19,6 +19,11 @@ class MigrateLatest extends Command { 'connection-resolver': flags.string({ helpValue: 'PATH', description: 'Path to the connection resolver.' + }), + config: flags.string({ + char: 'c', + default: 'sync-db.yml', + description: 'Custom configuration file.' }) }; @@ -72,7 +77,7 @@ class MigrateLatest extends Command { async run(): Promise { const { flags: parsedFlags } = this.parse(MigrateLatest); const isDryRun = parsedFlags['dry-run']; - const config = await loadConfig(); + const config = await loadConfig(parsedFlags.config); const connections = await resolveConnections(config, parsedFlags['connection-resolver']); if (isDryRun) await printLine(magenta('\n• DRY RUN STARTED\n')); diff --git a/src/commands/migrate-list.ts b/src/commands/migrate-list.ts index c067b0e2..4326be50 100644 --- a/src/commands/migrate-list.ts +++ b/src/commands/migrate-list.ts @@ -17,6 +17,11 @@ class MigrateList extends Command { 'connection-resolver': flags.string({ helpValue: 'PATH', description: 'Path to the connection resolver.' + }), + config: flags.string({ + char: 'c', + default: 'sync-db.yml', + description: 'Custom configuration file.' }) }; @@ -67,7 +72,7 @@ class MigrateList extends Command { */ async run(): Promise { const { flags: parsedFlags } = this.parse(MigrateList); - const config = await loadConfig(); + const config = await loadConfig(parsedFlags.config); const connections = await resolveConnections(config, parsedFlags['connection-resolver']); const results = await migrateList(config, connections, { diff --git a/src/commands/migrate-rollback.ts b/src/commands/migrate-rollback.ts index 91569c78..c6f7d635 100644 --- a/src/commands/migrate-rollback.ts +++ b/src/commands/migrate-rollback.ts @@ -19,6 +19,11 @@ class MigrateRollback extends Command { 'connection-resolver': flags.string({ helpValue: 'PATH', description: 'Path to the connection resolver.' + }), + config: flags.string({ + char: 'c', + default: 'sync-db.yml', + description: 'Custom configuration file.' }) }; @@ -71,7 +76,7 @@ class MigrateRollback extends Command { async run(): Promise { const { flags: parsedFlags } = this.parse(MigrateRollback); const isDryRun = parsedFlags['dry-run']; - const config = await loadConfig(); + const config = await loadConfig(parsedFlags.config); const connections = await resolveConnections(config, parsedFlags['connection-resolver']); if (isDryRun) await printLine(magenta('\n• DRY RUN STARTED\n')); diff --git a/src/commands/prune.ts b/src/commands/prune.ts index 97d96b54..ce281320 100644 --- a/src/commands/prune.ts +++ b/src/commands/prune.ts @@ -18,6 +18,11 @@ class Prune extends Command { 'connection-resolver': flags.string({ helpValue: 'PATH', description: 'Path to the connection resolver.' + }), + config: flags.string({ + char: 'c', + default: 'sync-db.yml', + description: 'Custom configuration file.' }) }; @@ -51,7 +56,7 @@ class Prune extends Command { async run(): Promise { const { flags: parsedFlags } = this.parse(Prune); const isDryRun = parsedFlags['dry-run']; - const config = await loadConfig(); + const config = await loadConfig(parsedFlags.config); const connections = await resolveConnections(config, parsedFlags['connection-resolver']); if (isDryRun) await printLine(magenta('\n• DRY RUN STARTED\n')); diff --git a/src/commands/synchronize.ts b/src/commands/synchronize.ts index 78f92075..89c549b3 100644 --- a/src/commands/synchronize.ts +++ b/src/commands/synchronize.ts @@ -25,6 +25,11 @@ class Synchronize extends Command { 'connection-resolver': flags.string({ helpValue: 'PATH', description: 'Path to the connection resolver.' + }), + config: flags.string({ + char: 'c', + default: 'sync-db.yml', + description: 'Custom configuration file.' }) }; @@ -131,7 +136,7 @@ class Synchronize extends Command { const isDryRun = parsedFlags['dry-run']; try { - const config = await loadConfig(); + const config = await loadConfig(parsedFlags.config); const connections = await resolveConnections(config, parsedFlags['connection-resolver']); const timeStart = process.hrtime(); diff --git a/src/config.ts b/src/config.ts index 423c5c0b..e08e383e 100644 --- a/src/config.ts +++ b/src/config.ts @@ -41,10 +41,10 @@ export function getSqlBasePath(config: Configuration): string { * * @returns {Promise} */ -export async function loadConfig(): Promise { +export async function loadConfig(configFileName: string = CONFIG_FILENAME): Promise { log('Resolving config file.'); - const filename = path.resolve(process.cwd(), CONFIG_FILENAME); + const filename = path.resolve(process.cwd(), configFileName); const loadedConfig = (await yaml.load(filename)) as Configuration; log('Resolved config file.'); diff --git a/test/cli/commands/make-publish.test.ts b/test/cli/commands/make-publish.test.ts index 03e7047b..e46cd265 100644 --- a/test/cli/commands/make-publish.test.ts +++ b/test/cli/commands/make-publish.test.ts @@ -143,4 +143,63 @@ describe('CLI: make-publish', () => { expect(createUp).to.equal('CREATE TABLE {{table}} (id INT PRIMARY KEY)'); expect(createDown).to.equal('DROP TABLE {{table}}'); }); + + it('should create respective stub files based on configuration from --config flag.', async () => { + // Write sync-db.yml file. + const cwd = await mkdtemp(); + const stubPath = path.join(cwd, 'src/stub'); + await mkdir(stubPath, { recursive: true }); + + const migrationPath1 = path.join(cwd, 'src/migration1'); + await mkdir(migrationPath1, { recursive: true }); + + await write( + path.join(cwd, 'sync-db.yml'), + yaml.stringify({ + migration: { + directory: 'migration', + sourceType: 'typescript' + } + } as Configuration) + ); + + await write( + path.join(cwd, 'sync-db-test.yml'), + yaml.stringify({ + migration: { + directory: 'migration1', + sourceType: 'javascript' + } + } as Configuration) + ); + + const { stdout } = await runCli(['make-publish'], { cwd }); + + // Check the output. + expect(stdout).to.match(/src\/stub\/create_ts\.stub/); + expect(stdout).to.match(/src\/stub\/update_ts\.stub/); + + // Check files are created. + const files = await glob(stubPath); + const createFileExists = await exists(path.join(stubPath, queryByPattern(files, /create_ts\.stub/))); + const updateFileExists = await exists(path.join(stubPath, queryByPattern(files, /update_ts\.stub/))); + + expect(files.length).to.equal(2); + expect(createFileExists).to.equal(true); + expect(updateFileExists).to.equal(true); + + const { stdout: stdout1 } = await runCli(['make-publish', '--config=sync-db-test.yml'], { cwd }); + + // Check the output. + expect(stdout1).to.match(/src\/stub\/create_js\.stub/); + expect(stdout1).to.match(/src\/stub\/update_js\.stub/); + + // Check files are created. + const files1 = await glob(stubPath); + const createFileExists1 = await exists(path.join(stubPath, queryByPattern(files1, /create_ts\.stub/))); + const updateFileExists1 = await exists(path.join(stubPath, queryByPattern(files1, /update_ts\.stub/))); + + expect(createFileExists1).to.equal(true); + expect(updateFileExists1).to.equal(true); + }); }); diff --git a/test/cli/commands/make.test.ts b/test/cli/commands/make.test.ts index 4808460c..41fd0863 100644 --- a/test/cli/commands/make.test.ts +++ b/test/cli/commands/make.test.ts @@ -198,39 +198,6 @@ describe('CLI: make', () => { expect(migrationFile).to.equal(interpolate(fileOutput, { table: 'demo_users' })); }); - it('should create a migration file with template when name matches filename convention for typescript.', async () => { - // Write sync-db.yml file. - const cwd = await mkdtemp(); - const migrationPath = path.join(cwd, 'src/migration'); - await mkdir(migrationPath, { recursive: true }); - await write( - path.join(cwd, 'sync-db.yml'), - yaml.stringify({ - migration: { - directory: 'migration', - sourceType: 'typescript' - } - } as Configuration) - ); - - const { stdout } = await runCli(['make', 'create_demo_users_table'], { cwd }); - - // Check the output. - expect(stdout).to.match(/Created.+\d{13}_create_demo_users_table\.ts/); - - // Check files are created. - const files = await glob(migrationPath); - - expect(files.length).to.equal(1); - - const migrationFile = await read( - path.join(migrationPath, queryByPattern(files, /\d{13}_create_demo_users_table\.ts/)) - ); - const fileOutput = await read(path.join(MIGRATION_TEMPLATE_PATH, 'create_ts.stub')); - - expect(migrationFile).to.equal(interpolate(fileOutput, { table: 'demo_users' })); - }); - it('should create a migration file with custom template for typescript.', async () => { // Write sync-db.yml file. const cwd = await mkdtemp(); @@ -334,4 +301,55 @@ describe('CLI: make', () => { expect(upFile).to.equal(interpolate(upSQL, { table: 'settings' })); expect(downFile).to.equal(interpolate(downSQL, { table: 'settings' })); }); + + it('should make migration based on custom configurations with --config flag.', async () => { + // Write sync-db.yml file. + const cwd = await mkdtemp(); + + const migrationPath = path.join(cwd, 'src/migration'); + await mkdir(migrationPath, { recursive: true }); + + const migrationPath1 = path.join(cwd, 'src/migration1'); + await mkdir(migrationPath1, { recursive: true }); + + await write( + path.join(cwd, 'sync-db.yml'), + yaml.stringify({ + migration: { + directory: 'migration' + } + } as Configuration) + ); + + await write( + path.join(cwd, 'sync-db-test.yml'), + yaml.stringify({ + migration: { + directory: 'migration1', + sourceType: 'typescript' + } + } as Configuration) + ); + + const { stdout } = await runCli(['make', 'settings'], { cwd }); + + // Check the output. + expect(stdout).to.match(/Created.+\d{13}_settings\.up\.sql/); + expect(stdout).to.match(/Created.+\d{13}_settings\.down\.sql/); + + // Check files are created. + const files = await glob(migrationPath); + + expect(files.length).to.equal(2); + + const { stdout: stdout1 } = await runCli(['make', 'settings', '--config=sync-db-test.yml'], { cwd }); + + // Check the output. + expect(stdout1).to.match(/Created.+\d{13}_settings\.ts/); + + // Check files are created. + const files1 = await glob(migrationPath1); + + expect(files1.length).to.equal(1); + }); }); From 3f411b4b0abc25664ecaf0b339434db0a331e6f7 Mon Sep 17 00:00:00 2001 From: samir Date: Fri, 26 Mar 2021 15:53:59 +0545 Subject: [PATCH 2/5] Use constant for default config and updaate package veersion. --- package.json | 2 +- src/commands/make-publish.ts | 3 ++- src/commands/make.ts | 3 ++- src/commands/migrate-latest.ts | 3 ++- src/commands/migrate-list.ts | 3 ++- src/commands/migrate-rollback.ts | 3 ++- src/commands/prune.ts | 3 ++- src/commands/synchronize.ts | 3 ++- src/config.ts | 4 ++-- 9 files changed, 17 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 88e79356..7d1b3a30 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@leapfrogtechnology/sync-db", "description": "Command line utility to synchronize and version control relational database objects across databases", - "version": "1.0.0-beta.11", + "version": "1.0.0-beta.12", "license": "MIT", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/src/commands/make-publish.ts b/src/commands/make-publish.ts index 50230c8e..e1055888 100644 --- a/src/commands/make-publish.ts +++ b/src/commands/make-publish.ts @@ -2,6 +2,7 @@ import { grey, cyan } from 'chalk'; import { Command, flags } from '@oclif/command'; import { loadConfig } from '../config'; +import { CONFIG_FILENAME } from '../constants'; import { printInfo, printLine } from '../util/io'; import * as fileMakerService from '../service/fileMaker'; @@ -10,7 +11,7 @@ class MakePublish extends Command { static flags = { config: flags.string({ char: 'c', - default: 'sync-db.yml', + default: CONFIG_FILENAME, description: 'Custom configuration file.' }) }; diff --git a/src/commands/make.ts b/src/commands/make.ts index 6126f261..63b1bd8d 100644 --- a/src/commands/make.ts +++ b/src/commands/make.ts @@ -1,5 +1,6 @@ import { loadConfig } from '../config'; import { printLine } from '../util/io'; +import { CONFIG_FILENAME } from '../constants'; import { Command, flags } from '@oclif/command'; import MakeOptions from '../domain/MakeOptions'; import Configuration from '../domain/Configuration'; @@ -19,7 +20,7 @@ class Make extends Command { }), config: flags.string({ char: 'c', - default: 'sync-db.yml', + default: CONFIG_FILENAME, description: 'Custom configuration file.' }), type: flags.string({ diff --git a/src/commands/migrate-latest.ts b/src/commands/migrate-latest.ts index 7282f847..ed60bf9b 100644 --- a/src/commands/migrate-latest.ts +++ b/src/commands/migrate-latest.ts @@ -3,6 +3,7 @@ import { bold, red, cyan, magenta } from 'chalk'; import { migrateLatest } from '../api'; import { dbLogger } from '../util/logger'; +import { CONFIG_FILENAME } from '../constants'; import { loadConfig, resolveConnections } from '..'; import { printLine, printError, printInfo } from '../util/io'; import OperationResult from '../domain/operation/OperationResult'; @@ -22,7 +23,7 @@ class MigrateLatest extends Command { }), config: flags.string({ char: 'c', - default: 'sync-db.yml', + default: CONFIG_FILENAME, description: 'Custom configuration file.' }) }; diff --git a/src/commands/migrate-list.ts b/src/commands/migrate-list.ts index 4326be50..ed8c1b53 100644 --- a/src/commands/migrate-list.ts +++ b/src/commands/migrate-list.ts @@ -2,6 +2,7 @@ import { Command, flags } from '@oclif/command'; import { bold, grey, red, cyan, yellow } from 'chalk'; import { migrateList } from '../api'; +import { CONFIG_FILENAME } from '../constants'; import { printLine, printError } from '../util/io'; import { loadConfig, resolveConnections } from '..'; import OperationResult from '../domain/operation/OperationResult'; @@ -20,7 +21,7 @@ class MigrateList extends Command { }), config: flags.string({ char: 'c', - default: 'sync-db.yml', + default: CONFIG_FILENAME, description: 'Custom configuration file.' }) }; diff --git a/src/commands/migrate-rollback.ts b/src/commands/migrate-rollback.ts index c6f7d635..27046642 100644 --- a/src/commands/migrate-rollback.ts +++ b/src/commands/migrate-rollback.ts @@ -3,6 +3,7 @@ import { bold, red, cyan, magenta } from 'chalk'; import { migrateRollback } from '../api'; import { dbLogger } from '../util/logger'; +import { CONFIG_FILENAME } from '../constants'; import { loadConfig, resolveConnections } from '..'; import { printLine, printError, printInfo } from '../util/io'; import OperationResult from '../domain/operation/OperationResult'; @@ -22,7 +23,7 @@ class MigrateRollback extends Command { }), config: flags.string({ char: 'c', - default: 'sync-db.yml', + default: CONFIG_FILENAME, description: 'Custom configuration file.' }) }; diff --git a/src/commands/prune.ts b/src/commands/prune.ts index ce281320..584cbcca 100644 --- a/src/commands/prune.ts +++ b/src/commands/prune.ts @@ -2,6 +2,7 @@ import { bold, magenta, red } from 'chalk'; import { Command, flags } from '@oclif/command'; import { prune } from '../api'; +import { CONFIG_FILENAME } from '../constants'; import { loadConfig, resolveConnections } from '..'; import { printLine, printError, printInfo } from '../util/io'; import OperationResult from '../domain/operation/OperationResult'; @@ -21,7 +22,7 @@ class Prune extends Command { }), config: flags.string({ char: 'c', - default: 'sync-db.yml', + default: CONFIG_FILENAME, description: 'Custom configuration file.' }) }; diff --git a/src/commands/synchronize.ts b/src/commands/synchronize.ts index 89c549b3..a6359cc2 100644 --- a/src/commands/synchronize.ts +++ b/src/commands/synchronize.ts @@ -3,6 +3,7 @@ import { bold, cyan, red, green, magenta } from 'chalk'; import { synchronize } from '../api'; import { getElapsedTime } from '../util/ts'; +import { CONFIG_FILENAME } from '../constants'; import { log, dbLogger } from '../util/logger'; import { loadConfig, resolveConnections } from '../config'; import { printError, printLine, printInfo } from '../util/io'; @@ -28,7 +29,7 @@ class Synchronize extends Command { }), config: flags.string({ char: 'c', - default: 'sync-db.yml', + default: CONFIG_FILENAME, description: 'Custom configuration file.' }) }; diff --git a/src/config.ts b/src/config.ts index e08e383e..521e4889 100644 --- a/src/config.ts +++ b/src/config.ts @@ -41,10 +41,10 @@ export function getSqlBasePath(config: Configuration): string { * * @returns {Promise} */ -export async function loadConfig(configFileName: string = CONFIG_FILENAME): Promise { +export async function loadConfig(configFilename: string = CONFIG_FILENAME): Promise { log('Resolving config file.'); - const filename = path.resolve(process.cwd(), configFileName); + const filename = path.resolve(process.cwd(), configFilename); const loadedConfig = (await yaml.load(filename)) as Configuration; log('Resolved config file.'); From 38528953ed79a5e54fe108f945e920611f6edafc Mon Sep 17 00:00:00 2001 From: samir Date: Fri, 26 Mar 2021 19:01:04 +0545 Subject: [PATCH 3/5] Add more test for loadConfig function, revert change in version from package json --- package.json | 2 +- src/commands/make-publish.ts | 3 +- src/commands/make.ts | 2 - src/commands/migrate-latest.ts | 2 - src/commands/migrate-list.ts | 2 - src/commands/migrate-rollback.ts | 2 - src/commands/prune.ts | 2 - src/commands/synchronize.ts | 2 - src/config.ts | 12 +++- test/unit/util/config.test.ts | 116 ++++++++++++++++++++++++++++++- 10 files changed, 128 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 7d1b3a30..88e79356 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@leapfrogtechnology/sync-db", "description": "Command line utility to synchronize and version control relational database objects across databases", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.11", "license": "MIT", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/src/commands/make-publish.ts b/src/commands/make-publish.ts index e1055888..604c3ef2 100644 --- a/src/commands/make-publish.ts +++ b/src/commands/make-publish.ts @@ -2,7 +2,6 @@ import { grey, cyan } from 'chalk'; import { Command, flags } from '@oclif/command'; import { loadConfig } from '../config'; -import { CONFIG_FILENAME } from '../constants'; import { printInfo, printLine } from '../util/io'; import * as fileMakerService from '../service/fileMaker'; @@ -11,10 +10,10 @@ class MakePublish extends Command { static flags = { config: flags.string({ char: 'c', - default: CONFIG_FILENAME, description: 'Custom configuration file.' }) }; + /** * CLI command execution handler. * diff --git a/src/commands/make.ts b/src/commands/make.ts index 63b1bd8d..ad33d45a 100644 --- a/src/commands/make.ts +++ b/src/commands/make.ts @@ -1,6 +1,5 @@ import { loadConfig } from '../config'; import { printLine } from '../util/io'; -import { CONFIG_FILENAME } from '../constants'; import { Command, flags } from '@oclif/command'; import MakeOptions from '../domain/MakeOptions'; import Configuration from '../domain/Configuration'; @@ -20,7 +19,6 @@ class Make extends Command { }), config: flags.string({ char: 'c', - default: CONFIG_FILENAME, description: 'Custom configuration file.' }), type: flags.string({ diff --git a/src/commands/migrate-latest.ts b/src/commands/migrate-latest.ts index ed60bf9b..1bf63452 100644 --- a/src/commands/migrate-latest.ts +++ b/src/commands/migrate-latest.ts @@ -3,7 +3,6 @@ import { bold, red, cyan, magenta } from 'chalk'; import { migrateLatest } from '../api'; import { dbLogger } from '../util/logger'; -import { CONFIG_FILENAME } from '../constants'; import { loadConfig, resolveConnections } from '..'; import { printLine, printError, printInfo } from '../util/io'; import OperationResult from '../domain/operation/OperationResult'; @@ -23,7 +22,6 @@ class MigrateLatest extends Command { }), config: flags.string({ char: 'c', - default: CONFIG_FILENAME, description: 'Custom configuration file.' }) }; diff --git a/src/commands/migrate-list.ts b/src/commands/migrate-list.ts index ed8c1b53..79cf4ead 100644 --- a/src/commands/migrate-list.ts +++ b/src/commands/migrate-list.ts @@ -2,7 +2,6 @@ import { Command, flags } from '@oclif/command'; import { bold, grey, red, cyan, yellow } from 'chalk'; import { migrateList } from '../api'; -import { CONFIG_FILENAME } from '../constants'; import { printLine, printError } from '../util/io'; import { loadConfig, resolveConnections } from '..'; import OperationResult from '../domain/operation/OperationResult'; @@ -21,7 +20,6 @@ class MigrateList extends Command { }), config: flags.string({ char: 'c', - default: CONFIG_FILENAME, description: 'Custom configuration file.' }) }; diff --git a/src/commands/migrate-rollback.ts b/src/commands/migrate-rollback.ts index 27046642..19a015ed 100644 --- a/src/commands/migrate-rollback.ts +++ b/src/commands/migrate-rollback.ts @@ -3,7 +3,6 @@ import { bold, red, cyan, magenta } from 'chalk'; import { migrateRollback } from '../api'; import { dbLogger } from '../util/logger'; -import { CONFIG_FILENAME } from '../constants'; import { loadConfig, resolveConnections } from '..'; import { printLine, printError, printInfo } from '../util/io'; import OperationResult from '../domain/operation/OperationResult'; @@ -23,7 +22,6 @@ class MigrateRollback extends Command { }), config: flags.string({ char: 'c', - default: CONFIG_FILENAME, description: 'Custom configuration file.' }) }; diff --git a/src/commands/prune.ts b/src/commands/prune.ts index 584cbcca..5de2caf2 100644 --- a/src/commands/prune.ts +++ b/src/commands/prune.ts @@ -2,7 +2,6 @@ import { bold, magenta, red } from 'chalk'; import { Command, flags } from '@oclif/command'; import { prune } from '../api'; -import { CONFIG_FILENAME } from '../constants'; import { loadConfig, resolveConnections } from '..'; import { printLine, printError, printInfo } from '../util/io'; import OperationResult from '../domain/operation/OperationResult'; @@ -22,7 +21,6 @@ class Prune extends Command { }), config: flags.string({ char: 'c', - default: CONFIG_FILENAME, description: 'Custom configuration file.' }) }; diff --git a/src/commands/synchronize.ts b/src/commands/synchronize.ts index a6359cc2..eb527e14 100644 --- a/src/commands/synchronize.ts +++ b/src/commands/synchronize.ts @@ -3,7 +3,6 @@ import { bold, cyan, red, green, magenta } from 'chalk'; import { synchronize } from '../api'; import { getElapsedTime } from '../util/ts'; -import { CONFIG_FILENAME } from '../constants'; import { log, dbLogger } from '../util/logger'; import { loadConfig, resolveConnections } from '../config'; import { printError, printLine, printInfo } from '../util/io'; @@ -29,7 +28,6 @@ class Synchronize extends Command { }), config: flags.string({ char: 'c', - default: CONFIG_FILENAME, description: 'Custom configuration file.' }) }; diff --git a/src/config.ts b/src/config.ts index 521e4889..9bb4a9ab 100644 --- a/src/config.ts +++ b/src/config.ts @@ -11,6 +11,8 @@ import ConnectionsFileSchema from './domain/ConnectionsFileSchema'; import { prepareInjectionConfigVars } from './service/configInjection'; import { DEFAULT_CONFIG, CONFIG_FILENAME, CONNECTIONS_FILENAME, REQUIRED_ENV_KEYS } from './constants'; +const CONFIG_FILE_CONVENTION = /^sync-db(-?)[\w]*\.yml$/; + interface ConnectionResolver { resolve: (config: Configuration) => Promise; } @@ -43,8 +45,16 @@ export function getSqlBasePath(config: Configuration): string { */ export async function loadConfig(configFilename: string = CONFIG_FILENAME): Promise { log('Resolving config file.'); + const isConfigFilePathAbsolute = path.isAbsolute(configFilename); + const filenameMatched = isConfigFilePathAbsolute + ? path.parse(configFilename).base.match(CONFIG_FILE_CONVENTION) + : configFilename.match(CONFIG_FILE_CONVENTION); + + if (!filenameMatched) { + throw new Error(`The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)`); + } - const filename = path.resolve(process.cwd(), configFilename); + const filename = isConfigFilePathAbsolute ? configFilename : path.join(process.cwd(), configFilename); const loadedConfig = (await yaml.load(filename)) as Configuration; log('Resolved config file.'); diff --git a/test/unit/util/config.test.ts b/test/unit/util/config.test.ts index ae23462c..0d6cd3c5 100644 --- a/test/unit/util/config.test.ts +++ b/test/unit/util/config.test.ts @@ -1,8 +1,12 @@ +import * as path from 'path'; import { expect } from 'chai'; +import * as yaml from 'yamljs'; import { it, describe } from 'mocha'; +import { mkdtemp, write } from '../../../src/util/fs'; +import Configuration from '../../../src/domain/Configuration'; import ConnectionConfig from '../../../src/domain/ConnectionConfig'; -import { validate, getConnectionId, resolveConnectionsFromEnv, isCLI } from '../../../src/config'; +import { validate, getConnectionId, resolveConnectionsFromEnv, isCLI, loadConfig } from '../../../src/config'; describe('CONFIG:', () => { describe('isCLI', () => { @@ -109,4 +113,114 @@ describe('CONFIG:', () => { expect(getConnectionId({ connection: 'someconnectionstring' } as ConnectionConfig)).to.equal(''); }); }); + + describe('loadConfig', () => { + it('should load the config file that is provided.', async () => { + const cwd = await mkdtemp(); + await write( + path.join(cwd, 'sync-db.yml'), + yaml.stringify({ + migration: { + directory: 'migration', + sourceType: 'javascript' + } + } as Configuration) + ); + + await write( + path.join(cwd, 'sync-db-test.yml'), + yaml.stringify({ + migration: { + directory: 'migration', + sourceType: 'typescript' + } + } as Configuration) + ); + process.chdir(cwd); + const config = await loadConfig(); + expect(config.migration.sourceType).to.equal('javascript'); + + process.chdir(cwd); + const config1 = await loadConfig('sync-db-test.yml'); + expect(config1.migration.sourceType).to.equal('typescript'); + }); + + it('should load the config file only if it matches the naming convention.', async () => { + const cwd = await mkdtemp(); + + await write( + path.join(cwd, 'sync-db-test.yml'), + yaml.stringify({ + migration: { + directory: 'migration', + sourceType: 'typescript' + } + } as Configuration) + ); + + await write( + path.join(cwd, 'sync-db.yml'), + yaml.stringify({ + migration: { + directory: 'migration', + sourceType: 'javascript' + } + } as Configuration) + ); + + process.chdir(cwd); + + await expect(loadConfig('sync-db.yml')).not.to.be.rejectedWith( + Error, + `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + ); + await expect(loadConfig('sync-db-test.yml')).not.to.be.rejectedWith( + Error, + `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + ); + + const config = await loadConfig(); + expect(config).to.have.property('migration'); + + const config1 = await loadConfig('sync-db-test.yml'); + expect(config1).to.have.property('migration'); + }); + + it(`should throw an error if the config file doesn't match the naming convention.`, async () => { + await expect(loadConfig('sync-db.txt')).to.be.rejectedWith( + Error, + `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + ); + await expect(loadConfig('sync-db-test.js')).to.be.rejectedWith( + Error, + `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + ); + await expect(loadConfig('sync.yml')).to.be.rejectedWith( + Error, + `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + ); + await expect(loadConfig('sync-db.yml.txt')).to.be.rejectedWith( + Error, + `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + ); + }); + + it(`should load config file with given absolute path.`, async () => { + const cwd = await mkdtemp(); + + await write( + path.join(cwd, 'sync-db-test.yml'), + yaml.stringify({ + migration: { + directory: 'migration', + sourceType: 'typescript' + } + } as Configuration) + ); + + process.chdir(cwd); + const config = await loadConfig(path.join(cwd, 'sync-db-test.yml')); + expect(config).to.have.property('migration'); + }); + }); }); From 18106ccba946c06b95c1f240cc0c00847347d9ae Mon Sep 17 00:00:00 2001 From: samir Date: Sat, 27 Mar 2021 21:16:27 +0545 Subject: [PATCH 4/5] Fix the pattern match for filename & add test. --- src/config.ts | 11 +++++------ test/unit/util/config.test.ts | 27 +++++++++------------------ 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/config.ts b/src/config.ts index 9bb4a9ab..96eebcdc 100644 --- a/src/config.ts +++ b/src/config.ts @@ -11,7 +11,7 @@ import ConnectionsFileSchema from './domain/ConnectionsFileSchema'; import { prepareInjectionConfigVars } from './service/configInjection'; import { DEFAULT_CONFIG, CONFIG_FILENAME, CONNECTIONS_FILENAME, REQUIRED_ENV_KEYS } from './constants'; -const CONFIG_FILE_CONVENTION = /^sync-db(-?)[\w]*\.yml$/; +const CONFIG_FILE_CONVENTION = /^sync-db-[\w]+\.yml$/; interface ConnectionResolver { resolve: (config: Configuration) => Promise; @@ -46,16 +46,15 @@ export function getSqlBasePath(config: Configuration): string { export async function loadConfig(configFilename: string = CONFIG_FILENAME): Promise { log('Resolving config file.'); const isConfigFilePathAbsolute = path.isAbsolute(configFilename); - const filenameMatched = isConfigFilePathAbsolute - ? path.parse(configFilename).base.match(CONFIG_FILE_CONVENTION) - : configFilename.match(CONFIG_FILE_CONVENTION); + const filename = isConfigFilePathAbsolute ? path.parse(configFilename).base : configFilename; + const filenameMatched = filename.match(CONFIG_FILE_CONVENTION) || filename === CONFIG_FILENAME; if (!filenameMatched) { throw new Error(`The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)`); } - const filename = isConfigFilePathAbsolute ? configFilename : path.join(process.cwd(), configFilename); - const loadedConfig = (await yaml.load(filename)) as Configuration; + const filepath = isConfigFilePathAbsolute ? configFilename : path.join(process.cwd(), configFilename); + const loadedConfig = (await yaml.load(filepath)) as Configuration; log('Resolved config file.'); diff --git a/test/unit/util/config.test.ts b/test/unit/util/config.test.ts index 0d6cd3c5..45b765a5 100644 --- a/test/unit/util/config.test.ts +++ b/test/unit/util/config.test.ts @@ -158,32 +158,15 @@ describe('CONFIG:', () => { } as Configuration) ); - await write( - path.join(cwd, 'sync-db.yml'), - yaml.stringify({ - migration: { - directory: 'migration', - sourceType: 'javascript' - } - } as Configuration) - ); - process.chdir(cwd); - await expect(loadConfig('sync-db.yml')).not.to.be.rejectedWith( - Error, - `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` - ); await expect(loadConfig('sync-db-test.yml')).not.to.be.rejectedWith( Error, `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` ); - const config = await loadConfig(); + const config = await loadConfig('sync-db-test.yml'); expect(config).to.have.property('migration'); - - const config1 = await loadConfig('sync-db-test.yml'); - expect(config1).to.have.property('migration'); }); it(`should throw an error if the config file doesn't match the naming convention.`, async () => { @@ -203,6 +186,14 @@ describe('CONFIG:', () => { Error, `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` ); + await expect(loadConfig('sync-db-.yml')).to.be.rejectedWith( + Error, + `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + ); + await expect(loadConfig('sync-dbasdfghjkl.yml')).to.be.rejectedWith( + Error, + `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + ); }); it(`should load config file with given absolute path.`, async () => { From 14a3044eb3bb868dd18f3b198b664e779bdeaaa9 Mon Sep 17 00:00:00 2001 From: Saugat Acharya Date: Sat, 27 Mar 2021 23:53:54 +0545 Subject: [PATCH 5/5] Fix error text grammar --- src/config.ts | 14 +++++++------- test/unit/util/config.test.ts | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/config.ts b/src/config.ts index 96eebcdc..e1e670e1 100644 --- a/src/config.ts +++ b/src/config.ts @@ -11,7 +11,7 @@ import ConnectionsFileSchema from './domain/ConnectionsFileSchema'; import { prepareInjectionConfigVars } from './service/configInjection'; import { DEFAULT_CONFIG, CONFIG_FILENAME, CONNECTIONS_FILENAME, REQUIRED_ENV_KEYS } from './constants'; -const CONFIG_FILE_CONVENTION = /^sync-db-[\w]+\.yml$/; +const CONFIG_FILE_CONVENTION = /^sync-db-\w+\.yml$/; interface ConnectionResolver { resolve: (config: Configuration) => Promise; @@ -45,15 +45,15 @@ export function getSqlBasePath(config: Configuration): string { */ export async function loadConfig(configFilename: string = CONFIG_FILENAME): Promise { log('Resolving config file.'); - const isConfigFilePathAbsolute = path.isAbsolute(configFilename); - const filename = isConfigFilePathAbsolute ? path.parse(configFilename).base : configFilename; - const filenameMatched = filename.match(CONFIG_FILE_CONVENTION) || filename === CONFIG_FILENAME; + const isAbsolutePath = path.isAbsolute(configFilename); + const filename = isAbsolutePath ? path.parse(configFilename).base : configFilename; + const match = filename.match(CONFIG_FILE_CONVENTION) || filename === CONFIG_FILENAME; - if (!filenameMatched) { - throw new Error(`The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)`); + if (!match) { + throw new Error(`The config filename doesn't match the pattern sync-db.yml or sync-db-*.yml`); } - const filepath = isConfigFilePathAbsolute ? configFilename : path.join(process.cwd(), configFilename); + const filepath = isAbsolutePath ? configFilename : path.join(process.cwd(), configFilename); const loadedConfig = (await yaml.load(filepath)) as Configuration; log('Resolved config file.'); diff --git a/test/unit/util/config.test.ts b/test/unit/util/config.test.ts index 45b765a5..13fb9025 100644 --- a/test/unit/util/config.test.ts +++ b/test/unit/util/config.test.ts @@ -162,7 +162,7 @@ describe('CONFIG:', () => { await expect(loadConfig('sync-db-test.yml')).not.to.be.rejectedWith( Error, - `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + `The config filename doesn't match the pattern sync-db.yml or sync-db-*.yml` ); const config = await loadConfig('sync-db-test.yml'); @@ -172,27 +172,27 @@ describe('CONFIG:', () => { it(`should throw an error if the config file doesn't match the naming convention.`, async () => { await expect(loadConfig('sync-db.txt')).to.be.rejectedWith( Error, - `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + `The config filename doesn't match the pattern sync-db.yml or sync-db-*.yml` ); await expect(loadConfig('sync-db-test.js')).to.be.rejectedWith( Error, - `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + `The config filename doesn't match the pattern sync-db.yml or sync-db-*.yml` ); await expect(loadConfig('sync.yml')).to.be.rejectedWith( Error, - `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + `The config filename doesn't match the pattern sync-db.yml or sync-db-*.yml` ); await expect(loadConfig('sync-db.yml.txt')).to.be.rejectedWith( Error, - `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + `The config filename doesn't match the pattern sync-db.yml or sync-db-*.yml` ); await expect(loadConfig('sync-db-.yml')).to.be.rejectedWith( Error, - `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + `The config filename doesn't match the pattern sync-db.yml or sync-db-*.yml` ); await expect(loadConfig('sync-dbasdfghjkl.yml')).to.be.rejectedWith( Error, - `The config filename doesn't meet the pattern (sync-db.yml or sync-db-*.yml)` + `The config filename doesn't match the pattern sync-db.yml or sync-db-*.yml` ); });