single and dry run

This commit is contained in:
cupcakearmy 2021-03-26 17:20:34 +01:00
parent f92e983fe5
commit a2ebb6f839
No known key found for this signature in database
GPG Key ID: 81C683415BBD86B0
2 changed files with 42 additions and 10 deletions

View File

@ -10,11 +10,12 @@ program.version(spec.version).name(spec.name)
program
.command('migrate')
.description('run migrations')
// .option('--dry-run', 'run simulation without committing changes')
.option('--dry-run', 'run simulation without committing changes')
.option('-m, --migrations <glob>', 'migration files', './migrations/*.js')
.option('--force', 'ignore remote state and rerun migrations')
.option('--only <version...>', 'only run specific migration')
.option('-f, --force', 'ignore remote state and rerun migrations')
.action(async (args) => {
await migrate({ directory: args.migrations, ignoreRemote: args.force })
await migrate({ directory: args.migrations, ignoreRemote: args.force, single: args.only, dryRun: args.dryRun })
})
program.parse(process.argv)

View File

@ -32,16 +32,23 @@ export type Options = {
directory: string
delimiter: string
ignoreRemote: boolean
single?: string[]
dryRun: boolean
}
const defaults: Options = {
directory: './migrations',
delimiter: '__',
ignoreRemote: false,
dryRun: false,
}
const extension = /\..*$/
function sortMigrationFiles(arr: MigrationFile[]): MigrationFile[] {
return arr.sort((a, b) => (semver.gt(a.version, b.version) ? 1 : -1))
}
async function gather(options: Options): Promise<MigrationFile[]> {
const files = glob
.sync(path.join(options.directory, '*.js'))
@ -68,11 +75,11 @@ async function gather(options: Options): Promise<MigrationFile[]> {
})
)
const sorted = contents.sort((a, b) => (semver.gt(a.version, b.version) ? 1 : -1))
return sorted.map(({ version, ...rest }) => ({
const asMigrationFile = contents.map(({ version, ...rest }) => ({
...rest,
version: version.version,
}))
return sortMigrationFiles(asMigrationFile)
}
function getIdFromMigration(migration: MigrationFile): string {
@ -93,6 +100,11 @@ async function runMigrations(migrations: MigrationFile[], options: Options) {
continue
}
if (options.dryRun) {
printMigration(migration, 'Skip due to dry-run.')
return
}
const start = process.hrtime.bigint()
let error = false
try {
@ -115,15 +127,34 @@ async function runMigrations(migrations: MigrationFile[], options: Options) {
await remoteDoc.ref.set(result)
if (error) {
console.log('⚠️ Skipping next migrations')
break
throw new Error('⚠️ Skipping next migrations')
}
}
}
}
export async function migrate(options?: Partial<Options>) {
const merged: Options = Object.assign(defaults, options)
const migrations = await gather(merged)
await runMigrations(migrations, merged)
try {
const merged: Options = Object.assign(defaults, options)
let migrations = await gather(merged)
console.log(`Found ${chalk.bold(migrations.length)} migrations.`)
if (options?.single) {
const singleVersions = options.single.map((v) => {
const parsed = semver.coerce(v)
if (!parsed) throw new Error(`Invalid version specified: "${v}". Could not parse.`)
return parsed.version
})
const filtered = singleVersions.map((v) => {
const selected = migrations.find((m) => m.version === v)
if (!selected) throw new Error(`Version "${v}" specified in --only does not exist in as migration.`)
return selected
})
migrations = sortMigrationFiles(filtered)
console.log(`Only running specified versions: ${singleVersions.join(', ')}`)
}
await runMigrations(migrations, merged)
} catch (e) {
console.error(chalk.red(e.message))
process.exit(1)
}
}