Skip to content

Commit a3a8346

Browse files
authored
Merge pull request #120 from leapfrogtechnology/sync-db-custom-config
Ability to provide custom configuration with --config flag
2 parents 090d733 + 14a3044 commit a3a8346

File tree

11 files changed

+267
-45
lines changed

11 files changed

+267
-45
lines changed

src/commands/make-publish.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
11
import { grey, cyan } from 'chalk';
2-
import { Command } from '@oclif/command';
2+
import { Command, flags } from '@oclif/command';
33

44
import { loadConfig } from '../config';
55
import { printInfo, printLine } from '../util/io';
66
import * as fileMakerService from '../service/fileMaker';
77

88
class MakePublish extends Command {
99
static description = 'Publish migration templates files.';
10+
static flags = {
11+
config: flags.string({
12+
char: 'c',
13+
description: 'Custom configuration file.'
14+
})
15+
};
1016

1117
/**
1218
* CLI command execution handler.
1319
*
1420
* @returns {Promise<void>}
1521
*/
1622
async run(): Promise<void> {
17-
const config = await loadConfig();
23+
const { flags: parsedFlags } = this.parse(MakePublish);
24+
const config = await loadConfig(parsedFlags.config);
1825

1926
await printLine();
2027

src/commands/make.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ class Make extends Command {
1717
default: false,
1818
description: 'Generate create table stub.'
1919
}),
20+
config: flags.string({
21+
char: 'c',
22+
description: 'Custom configuration file.'
23+
}),
2024
type: flags.string({
2125
char: 't',
2226
helpValue: 'TYPE',
@@ -33,7 +37,7 @@ class Make extends Command {
3337
*/
3438
async run(): Promise<void> {
3539
const { args, flags: parsedFlags } = this.parse(Make);
36-
const config = await loadConfig();
40+
const config = await loadConfig(parsedFlags.config);
3741
const list = await this.makeFiles(config, args.name, parsedFlags.type, {
3842
create: parsedFlags.create,
3943
objectName: parsedFlags['object-name']

src/commands/migrate-latest.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ class MigrateLatest extends Command {
1919
'connection-resolver': flags.string({
2020
helpValue: 'PATH',
2121
description: 'Path to the connection resolver.'
22+
}),
23+
config: flags.string({
24+
char: 'c',
25+
description: 'Custom configuration file.'
2226
})
2327
};
2428

@@ -72,7 +76,7 @@ class MigrateLatest extends Command {
7276
async run(): Promise<void> {
7377
const { flags: parsedFlags } = this.parse(MigrateLatest);
7478
const isDryRun = parsedFlags['dry-run'];
75-
const config = await loadConfig();
79+
const config = await loadConfig(parsedFlags.config);
7680
const connections = await resolveConnections(config, parsedFlags['connection-resolver']);
7781

7882
if (isDryRun) await printLine(magenta('\n• DRY RUN STARTED\n'));

src/commands/migrate-list.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ class MigrateList extends Command {
1717
'connection-resolver': flags.string({
1818
helpValue: 'PATH',
1919
description: 'Path to the connection resolver.'
20+
}),
21+
config: flags.string({
22+
char: 'c',
23+
description: 'Custom configuration file.'
2024
})
2125
};
2226

@@ -67,7 +71,7 @@ class MigrateList extends Command {
6771
*/
6872
async run(): Promise<void> {
6973
const { flags: parsedFlags } = this.parse(MigrateList);
70-
const config = await loadConfig();
74+
const config = await loadConfig(parsedFlags.config);
7175
const connections = await resolveConnections(config, parsedFlags['connection-resolver']);
7276

7377
const results = await migrateList(config, connections, {

src/commands/migrate-rollback.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ class MigrateRollback extends Command {
1919
'connection-resolver': flags.string({
2020
helpValue: 'PATH',
2121
description: 'Path to the connection resolver.'
22+
}),
23+
config: flags.string({
24+
char: 'c',
25+
description: 'Custom configuration file.'
2226
})
2327
};
2428

@@ -71,7 +75,7 @@ class MigrateRollback extends Command {
7175
async run(): Promise<void> {
7276
const { flags: parsedFlags } = this.parse(MigrateRollback);
7377
const isDryRun = parsedFlags['dry-run'];
74-
const config = await loadConfig();
78+
const config = await loadConfig(parsedFlags.config);
7579
const connections = await resolveConnections(config, parsedFlags['connection-resolver']);
7680

7781
if (isDryRun) await printLine(magenta('\n• DRY RUN STARTED\n'));

src/commands/prune.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ class Prune extends Command {
1818
'connection-resolver': flags.string({
1919
helpValue: 'PATH',
2020
description: 'Path to the connection resolver.'
21+
}),
22+
config: flags.string({
23+
char: 'c',
24+
description: 'Custom configuration file.'
2125
})
2226
};
2327

@@ -51,7 +55,7 @@ class Prune extends Command {
5155
async run(): Promise<void> {
5256
const { flags: parsedFlags } = this.parse(Prune);
5357
const isDryRun = parsedFlags['dry-run'];
54-
const config = await loadConfig();
58+
const config = await loadConfig(parsedFlags.config);
5559
const connections = await resolveConnections(config, parsedFlags['connection-resolver']);
5660

5761
if (isDryRun) await printLine(magenta('\n• DRY RUN STARTED\n'));

src/commands/synchronize.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ class Synchronize extends Command {
2525
'connection-resolver': flags.string({
2626
helpValue: 'PATH',
2727
description: 'Path to the connection resolver.'
28+
}),
29+
config: flags.string({
30+
char: 'c',
31+
description: 'Custom configuration file.'
2832
})
2933
};
3034

@@ -131,7 +135,7 @@ class Synchronize extends Command {
131135
const isDryRun = parsedFlags['dry-run'];
132136

133137
try {
134-
const config = await loadConfig();
138+
const config = await loadConfig(parsedFlags.config);
135139
const connections = await resolveConnections(config, parsedFlags['connection-resolver']);
136140
const timeStart = process.hrtime();
137141

src/config.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import ConnectionsFileSchema from './domain/ConnectionsFileSchema';
1111
import { prepareInjectionConfigVars } from './service/configInjection';
1212
import { DEFAULT_CONFIG, CONFIG_FILENAME, CONNECTIONS_FILENAME, REQUIRED_ENV_KEYS } from './constants';
1313

14+
const CONFIG_FILE_CONVENTION = /^sync-db-\w+\.yml$/;
15+
1416
interface ConnectionResolver {
1517
resolve: (config: Configuration) => Promise<ConnectionConfig[]>;
1618
}
@@ -41,11 +43,18 @@ export function getSqlBasePath(config: Configuration): string {
4143
*
4244
* @returns {Promise<Configuration>}
4345
*/
44-
export async function loadConfig(): Promise<Configuration> {
46+
export async function loadConfig(configFilename: string = CONFIG_FILENAME): Promise<Configuration> {
4547
log('Resolving config file.');
48+
const isAbsolutePath = path.isAbsolute(configFilename);
49+
const filename = isAbsolutePath ? path.parse(configFilename).base : configFilename;
50+
const match = filename.match(CONFIG_FILE_CONVENTION) || filename === CONFIG_FILENAME;
51+
52+
if (!match) {
53+
throw new Error(`The config filename doesn't match the pattern sync-db.yml or sync-db-*.yml`);
54+
}
4655

47-
const filename = path.resolve(process.cwd(), CONFIG_FILENAME);
48-
const loadedConfig = (await yaml.load(filename)) as Configuration;
56+
const filepath = isAbsolutePath ? configFilename : path.join(process.cwd(), configFilename);
57+
const loadedConfig = (await yaml.load(filepath)) as Configuration;
4958

5059
log('Resolved config file.');
5160

test/cli/commands/make-publish.test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,63 @@ describe('CLI: make-publish', () => {
143143
expect(createUp).to.equal('CREATE TABLE {{table}} (id INT PRIMARY KEY)');
144144
expect(createDown).to.equal('DROP TABLE {{table}}');
145145
});
146+
147+
it('should create respective stub files based on configuration from --config flag.', async () => {
148+
// Write sync-db.yml file.
149+
const cwd = await mkdtemp();
150+
const stubPath = path.join(cwd, 'src/stub');
151+
await mkdir(stubPath, { recursive: true });
152+
153+
const migrationPath1 = path.join(cwd, 'src/migration1');
154+
await mkdir(migrationPath1, { recursive: true });
155+
156+
await write(
157+
path.join(cwd, 'sync-db.yml'),
158+
yaml.stringify({
159+
migration: {
160+
directory: 'migration',
161+
sourceType: 'typescript'
162+
}
163+
} as Configuration)
164+
);
165+
166+
await write(
167+
path.join(cwd, 'sync-db-test.yml'),
168+
yaml.stringify({
169+
migration: {
170+
directory: 'migration1',
171+
sourceType: 'javascript'
172+
}
173+
} as Configuration)
174+
);
175+
176+
const { stdout } = await runCli(['make-publish'], { cwd });
177+
178+
// Check the output.
179+
expect(stdout).to.match(/src\/stub\/create_ts\.stub/);
180+
expect(stdout).to.match(/src\/stub\/update_ts\.stub/);
181+
182+
// Check files are created.
183+
const files = await glob(stubPath);
184+
const createFileExists = await exists(path.join(stubPath, queryByPattern(files, /create_ts\.stub/)));
185+
const updateFileExists = await exists(path.join(stubPath, queryByPattern(files, /update_ts\.stub/)));
186+
187+
expect(files.length).to.equal(2);
188+
expect(createFileExists).to.equal(true);
189+
expect(updateFileExists).to.equal(true);
190+
191+
const { stdout: stdout1 } = await runCli(['make-publish', '--config=sync-db-test.yml'], { cwd });
192+
193+
// Check the output.
194+
expect(stdout1).to.match(/src\/stub\/create_js\.stub/);
195+
expect(stdout1).to.match(/src\/stub\/update_js\.stub/);
196+
197+
// Check files are created.
198+
const files1 = await glob(stubPath);
199+
const createFileExists1 = await exists(path.join(stubPath, queryByPattern(files1, /create_ts\.stub/)));
200+
const updateFileExists1 = await exists(path.join(stubPath, queryByPattern(files1, /update_ts\.stub/)));
201+
202+
expect(createFileExists1).to.equal(true);
203+
expect(updateFileExists1).to.equal(true);
204+
});
146205
});

test/cli/commands/make.test.ts

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -198,39 +198,6 @@ describe('CLI: make', () => {
198198
expect(migrationFile).to.equal(interpolate(fileOutput, { table: 'demo_users' }));
199199
});
200200

201-
it('should create a migration file with template when name matches filename convention for typescript.', async () => {
202-
// Write sync-db.yml file.
203-
const cwd = await mkdtemp();
204-
const migrationPath = path.join(cwd, 'src/migration');
205-
await mkdir(migrationPath, { recursive: true });
206-
await write(
207-
path.join(cwd, 'sync-db.yml'),
208-
yaml.stringify({
209-
migration: {
210-
directory: 'migration',
211-
sourceType: 'typescript'
212-
}
213-
} as Configuration)
214-
);
215-
216-
const { stdout } = await runCli(['make', 'create_demo_users_table'], { cwd });
217-
218-
// Check the output.
219-
expect(stdout).to.match(/Created.+\d{13}_create_demo_users_table\.ts/);
220-
221-
// Check files are created.
222-
const files = await glob(migrationPath);
223-
224-
expect(files.length).to.equal(1);
225-
226-
const migrationFile = await read(
227-
path.join(migrationPath, queryByPattern(files, /\d{13}_create_demo_users_table\.ts/))
228-
);
229-
const fileOutput = await read(path.join(MIGRATION_TEMPLATE_PATH, 'create_ts.stub'));
230-
231-
expect(migrationFile).to.equal(interpolate(fileOutput, { table: 'demo_users' }));
232-
});
233-
234201
it('should create a migration file with custom template for typescript.', async () => {
235202
// Write sync-db.yml file.
236203
const cwd = await mkdtemp();
@@ -334,4 +301,55 @@ describe('CLI: make', () => {
334301
expect(upFile).to.equal(interpolate(upSQL, { table: 'settings' }));
335302
expect(downFile).to.equal(interpolate(downSQL, { table: 'settings' }));
336303
});
304+
305+
it('should make migration based on custom configurations with --config flag.', async () => {
306+
// Write sync-db.yml file.
307+
const cwd = await mkdtemp();
308+
309+
const migrationPath = path.join(cwd, 'src/migration');
310+
await mkdir(migrationPath, { recursive: true });
311+
312+
const migrationPath1 = path.join(cwd, 'src/migration1');
313+
await mkdir(migrationPath1, { recursive: true });
314+
315+
await write(
316+
path.join(cwd, 'sync-db.yml'),
317+
yaml.stringify({
318+
migration: {
319+
directory: 'migration'
320+
}
321+
} as Configuration)
322+
);
323+
324+
await write(
325+
path.join(cwd, 'sync-db-test.yml'),
326+
yaml.stringify({
327+
migration: {
328+
directory: 'migration1',
329+
sourceType: 'typescript'
330+
}
331+
} as Configuration)
332+
);
333+
334+
const { stdout } = await runCli(['make', 'settings'], { cwd });
335+
336+
// Check the output.
337+
expect(stdout).to.match(/Created.+\d{13}_settings\.up\.sql/);
338+
expect(stdout).to.match(/Created.+\d{13}_settings\.down\.sql/);
339+
340+
// Check files are created.
341+
const files = await glob(migrationPath);
342+
343+
expect(files.length).to.equal(2);
344+
345+
const { stdout: stdout1 } = await runCli(['make', 'settings', '--config=sync-db-test.yml'], { cwd });
346+
347+
// Check the output.
348+
expect(stdout1).to.match(/Created.+\d{13}_settings\.ts/);
349+
350+
// Check files are created.
351+
const files1 = await glob(migrationPath1);
352+
353+
expect(files1.length).to.equal(1);
354+
});
337355
});

0 commit comments

Comments
 (0)