-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1479 from argos-ci/knex-scripts
chore: move knex-scripts to a local package
- Loading branch information
Showing
16 changed files
with
697 additions
and
884 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"$schema": "https://json.schemastore.org/swcrc", | ||
"jsc": { | ||
"parser": { | ||
"syntax": "typescript" | ||
}, | ||
"target": "es2022" | ||
}, | ||
"module": { | ||
"type": "es6", | ||
"resolveFully": true | ||
}, | ||
"sourceMaps": false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/usr/bin/env node | ||
|
||
import "../dist/cli.js"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{ | ||
"name": "@argos/knex-scripts", | ||
"version": "2.0.0", | ||
"private": true, | ||
"bin": { | ||
"knex-scripts": "./bin/knex-scripts.js" | ||
}, | ||
"type": "module", | ||
"exports": { | ||
"./package.json": "./package.json" | ||
}, | ||
"scripts": { | ||
"build": "rm -rf dist && swc src -d dist --strip-leading-paths", | ||
"watch-build": "pnpm run build -- --watch --quiet", | ||
"check-types": "tsc --noEmit", | ||
"check-format": "prettier --check --cache --ignore-path=../../.gitignore --ignore-path=../../.prettierignore .", | ||
"lint": "eslint ." | ||
}, | ||
"sideEffects": false, | ||
"dependencies": { | ||
"commander": "^12.1.0", | ||
"fast-glob": "^3.3.2", | ||
"ora": "^8.1.1" | ||
}, | ||
"peerDependencies": { | ||
"knex": "^3.0.0" | ||
}, | ||
"devDependencies": { | ||
"@argos/tsconfig": "workspace:*" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { readFile } from "node:fs/promises"; | ||
import { Command } from "commander"; | ||
import { oraPromise } from "ora"; | ||
|
||
import { getConfig } from "./config.js"; | ||
import { getInsertsFromMigrations } from "./utils.js"; | ||
|
||
/** | ||
* Get inserts from the structure file. | ||
*/ | ||
async function getInsertsFromStructure(input: { | ||
structurePath: string; | ||
}): Promise<string[]> { | ||
const structure = await readFile(input.structurePath, "utf-8"); | ||
const regex = | ||
/INSERT INTO public\.knex_migrations\(name, batch, migration_time\) VALUES \('.*', 1, NOW\(\)\);/g; | ||
const inserts = []; | ||
|
||
let match: RegExpExecArray | null; | ||
while ((match = regex.exec(structure))) { | ||
inserts.push(match[0]); | ||
} | ||
|
||
return inserts; | ||
} | ||
|
||
/** | ||
* Check if the structure is up to date. | ||
*/ | ||
async function checkIsStructureUpToDate() { | ||
const config = await getConfig(); | ||
const [migrationsInFolder, migrationsInStructure] = await Promise.all([ | ||
getInsertsFromMigrations(config), | ||
getInsertsFromStructure(config), | ||
]); | ||
|
||
if (migrationsInFolder.length !== migrationsInStructure.length) { | ||
return false; | ||
} | ||
|
||
return migrationsInFolder.every( | ||
(insert, index) => migrationsInStructure[index] === insert, | ||
); | ||
} | ||
|
||
export function addCheckStructureCommand(program: Command) { | ||
program | ||
.command("check-structure") | ||
.description( | ||
"Compare the dumped structure with the structure in the database.", | ||
) | ||
.action(async () => { | ||
await oraPromise( | ||
(async () => { | ||
const isUpToDate = await checkIsStructureUpToDate(); | ||
if (!isUpToDate) { | ||
throw new Error("Structure is outdated."); | ||
} | ||
})(), | ||
"Checking structure...", | ||
); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { readFile } from "node:fs/promises"; | ||
import { resolve } from "node:path"; | ||
import { fileURLToPath, URL } from "node:url"; | ||
import { program } from "commander"; | ||
|
||
import { addCheckStructureCommand } from "./check-structure.js"; | ||
import { addCreateCommand } from "./create.js"; | ||
import { addDropCommand } from "./drop.js"; | ||
import { addDumpCommand } from "./dump.js"; | ||
import { addLoadCommand } from "./load.js"; | ||
import { addTruncateCommand } from "./truncate.js"; | ||
|
||
const __dirname = fileURLToPath(new URL(".", import.meta.url)); | ||
|
||
const rawPkg = await readFile(resolve(__dirname, "..", "package.json"), "utf8"); | ||
const pkg = JSON.parse(rawPkg); | ||
|
||
program | ||
.name(pkg.name) | ||
.version(pkg.version) | ||
.description("CLI tool to manage PostgresSQL database over Knex.js."); | ||
|
||
addCheckStructureCommand(program); | ||
addCreateCommand(program); | ||
addDropCommand(program); | ||
addDumpCommand(program); | ||
addLoadCommand(program); | ||
addTruncateCommand(program); | ||
|
||
if (!process.argv.slice(2).length) { | ||
program.outputHelp(); | ||
} else { | ||
program.parse(process.argv); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { join } from "node:path"; | ||
import type { Knex } from "knex"; | ||
|
||
type Config = { | ||
knexConfig: Knex.Config; | ||
structurePath: string; | ||
migrationsPath: string; | ||
}; | ||
|
||
async function readKnexConfig(): Promise<Knex.Config> { | ||
const knexFile = join(process.cwd(), "knexfile.js"); | ||
try { | ||
const config: unknown = await import(knexFile); | ||
if ( | ||
!config || | ||
typeof config !== "object" || | ||
!("default" in config) || | ||
!config.default | ||
) { | ||
throw new Error(`Invalid knexfile.js`); | ||
} | ||
return config.default; | ||
} catch { | ||
throw new Error(`Could not find ${knexFile}`); | ||
} | ||
} | ||
|
||
export async function getConfig(): Promise<Config> { | ||
const knexConfig = await readKnexConfig(); | ||
return { | ||
knexConfig, | ||
structurePath: join(process.cwd(), "db/structure.sql"), | ||
migrationsPath: join(process.cwd(), "db/migrations"), | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Command } from "commander"; | ||
import { oraPromise } from "ora"; | ||
|
||
import { getConfig } from "./config.js"; | ||
import { | ||
getCommandEnv, | ||
getPostgresCommand, | ||
preventRunningInProduction, | ||
runCommand, | ||
} from "./utils.js"; | ||
|
||
/** | ||
* Create the database based on the configuration in the knexfile. | ||
*/ | ||
async function createDatabase() { | ||
preventRunningInProduction(); | ||
|
||
const config = await getConfig(); | ||
const env = getCommandEnv(config); | ||
const { command, args } = getPostgresCommand(config, "createdb"); | ||
await runCommand({ command, args, env }); | ||
} | ||
|
||
/** | ||
* Add the "create" command to the program. | ||
*/ | ||
export function addCreateCommand(program: Command) { | ||
program | ||
.command("create") | ||
.description( | ||
"Create the database based on the configuration in the knexfile.", | ||
) | ||
.action(async () => { | ||
await oraPromise(createDatabase(), "Creating database..."); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { Command } from "commander"; | ||
import { oraPromise } from "ora"; | ||
|
||
import { getConfig } from "./config.js"; | ||
import { | ||
getCommandEnv, | ||
getPostgresCommand, | ||
preventRunningInProduction, | ||
runCommand, | ||
} from "./utils.js"; | ||
|
||
/** | ||
* Drop the database based on the configuration in the knexfile. | ||
*/ | ||
async function dropDatabase() { | ||
preventRunningInProduction(); | ||
|
||
const config = await getConfig(); | ||
const env = getCommandEnv(config); | ||
const { command, args } = getPostgresCommand(config, "dropdb", [ | ||
"--if-exists", | ||
]); | ||
await runCommand({ command, args, env }); | ||
} | ||
|
||
/** | ||
* Add the "drop" command to the program. | ||
*/ | ||
export function addDropCommand(program: Command) { | ||
program | ||
.command("drop") | ||
.description( | ||
"Drop the database based on the configuration in the knexfile.", | ||
) | ||
.action(async () => { | ||
await oraPromise(dropDatabase(), "Dropping database..."); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { appendFile, mkdir } from "fs/promises"; | ||
import { dirname } from "path"; | ||
import { Command } from "commander"; | ||
import { oraPromise } from "ora"; | ||
|
||
import { getConfig } from "./config.js"; | ||
import { | ||
getCommandEnv, | ||
getInsertsFromMigrations, | ||
getPostgresCommand, | ||
requireEnv, | ||
runCommand, | ||
} from "./utils.js"; | ||
|
||
/** | ||
* Dump the database schema to a file. | ||
*/ | ||
async function dumpDatabaseSchema() { | ||
const config = await getConfig(); | ||
requireEnv("development"); | ||
|
||
await mkdir(dirname(config.structurePath), { recursive: true }); | ||
|
||
const env = getCommandEnv(config); | ||
const { command, args } = getPostgresCommand(config, "pg_dump", [ | ||
"--schema-only", | ||
"-f", | ||
config.structurePath, | ||
]); | ||
|
||
await runCommand({ command, args, env }); | ||
|
||
const migrationInserts = await getInsertsFromMigrations(config); | ||
await appendFile( | ||
config.structurePath, | ||
`-- Knex migrations\n\n${migrationInserts.join("\n")}`, | ||
); | ||
} | ||
|
||
/** | ||
* Add the "dump" command to the program. | ||
*/ | ||
export function addDumpCommand(program: Command) { | ||
program | ||
.command("dump") | ||
.description("Dump the database schema to a file.") | ||
.action(async () => { | ||
await oraPromise(dumpDatabaseSchema(), "Dumping database schema..."); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { Command } from "commander"; | ||
import { oraPromise } from "ora"; | ||
|
||
import { getConfig } from "./config.js"; | ||
import { | ||
getCommandEnv, | ||
getPostgresCommand, | ||
preventRunningInProduction, | ||
runCommand, | ||
} from "./utils.js"; | ||
|
||
/** | ||
* Load database schema from file. | ||
*/ | ||
async function loadDatabaseSchema() { | ||
preventRunningInProduction(); | ||
|
||
const config = await getConfig(); | ||
|
||
const env = getCommandEnv(config); | ||
|
||
const { command, args } = getPostgresCommand(config, "psql", [ | ||
"-v", | ||
"ON_ERROR_STOP=1", | ||
"-f", | ||
config.structurePath, | ||
]); | ||
|
||
await runCommand({ command, args, env }); | ||
} | ||
|
||
/** | ||
* Add the "load" command to the program. | ||
*/ | ||
export function addLoadCommand(program: Command) { | ||
program | ||
.command("load") | ||
.description("Load the database schema from a file.") | ||
.action(async () => { | ||
await oraPromise(loadDatabaseSchema(), "Loading database schema..."); | ||
}); | ||
} |
Oops, something went wrong.