@constructive-io/cli 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +412 -0
- package/commands/add.d.ts +7 -0
- package/commands/add.js +86 -0
- package/commands/admin-users/add.d.ts +4 -0
- package/commands/admin-users/add.js +89 -0
- package/commands/admin-users/bootstrap.d.ts +4 -0
- package/commands/admin-users/bootstrap.js +50 -0
- package/commands/admin-users/remove.d.ts +4 -0
- package/commands/admin-users/remove.js +82 -0
- package/commands/admin-users.d.ts +4 -0
- package/commands/admin-users.js +68 -0
- package/commands/analyze.d.ts +4 -0
- package/commands/analyze.js +21 -0
- package/commands/clear.d.ts +3 -0
- package/commands/clear.js +59 -0
- package/commands/deploy.d.ts +4 -0
- package/commands/deploy.js +146 -0
- package/commands/docker.d.ts +3 -0
- package/commands/docker.js +194 -0
- package/commands/env.d.ts +4 -0
- package/commands/env.js +124 -0
- package/commands/export.d.ts +3 -0
- package/commands/export.js +129 -0
- package/commands/extension.d.ts +4 -0
- package/commands/extension.js +48 -0
- package/commands/init/index.d.ts +7 -0
- package/commands/init/index.js +47 -0
- package/commands/init/module.d.ts +4 -0
- package/commands/init/module.js +71 -0
- package/commands/init/workspace.d.ts +4 -0
- package/commands/init/workspace.js +52 -0
- package/commands/install.d.ts +4 -0
- package/commands/install.js +37 -0
- package/commands/kill.d.ts +3 -0
- package/commands/kill.js +107 -0
- package/commands/migrate/deps.d.ts +4 -0
- package/commands/migrate/deps.js +186 -0
- package/commands/migrate/init.d.ts +4 -0
- package/commands/migrate/init.js +65 -0
- package/commands/migrate/list.d.ts +4 -0
- package/commands/migrate/list.js +85 -0
- package/commands/migrate/status.d.ts +4 -0
- package/commands/migrate/status.js +94 -0
- package/commands/migrate.d.ts +4 -0
- package/commands/migrate.js +69 -0
- package/commands/package.d.ts +3 -0
- package/commands/package.js +65 -0
- package/commands/plan.d.ts +3 -0
- package/commands/plan.js +62 -0
- package/commands/remove.d.ts +3 -0
- package/commands/remove.js +42 -0
- package/commands/rename.d.ts +4 -0
- package/commands/rename.js +35 -0
- package/commands/revert.d.ts +3 -0
- package/commands/revert.js +107 -0
- package/commands/tag.d.ts +6 -0
- package/commands/tag.js +168 -0
- package/commands/verify.d.ts +3 -0
- package/commands/verify.js +85 -0
- package/commands.d.ts +6 -0
- package/commands.js +113 -0
- package/dist/README.md +412 -0
- package/dist/package.json +64 -0
- package/esm/commands/add.js +51 -0
- package/esm/commands/admin-users/add.js +87 -0
- package/esm/commands/admin-users/bootstrap.js +48 -0
- package/esm/commands/admin-users/remove.js +80 -0
- package/esm/commands/admin-users.js +63 -0
- package/esm/commands/analyze.js +16 -0
- package/esm/commands/clear.js +54 -0
- package/esm/commands/deploy.js +144 -0
- package/esm/commands/docker.js +192 -0
- package/esm/commands/env.js +122 -0
- package/esm/commands/export.js +127 -0
- package/esm/commands/extension.js +46 -0
- package/esm/commands/init/index.js +42 -0
- package/esm/commands/init/module.js +68 -0
- package/esm/commands/init/workspace.js +46 -0
- package/esm/commands/install.js +35 -0
- package/esm/commands/kill.js +105 -0
- package/esm/commands/migrate/deps.js +184 -0
- package/esm/commands/migrate/init.js +63 -0
- package/esm/commands/migrate/list.js +83 -0
- package/esm/commands/migrate/status.js +92 -0
- package/esm/commands/migrate.js +64 -0
- package/esm/commands/package.js +63 -0
- package/esm/commands/plan.js +60 -0
- package/esm/commands/remove.js +40 -0
- package/esm/commands/rename.js +30 -0
- package/esm/commands/revert.js +105 -0
- package/esm/commands/tag.js +133 -0
- package/esm/commands/verify.js +83 -0
- package/esm/commands.js +105 -0
- package/esm/index.js +48 -0
- package/esm/package.js +26 -0
- package/esm/utils/argv.js +92 -0
- package/esm/utils/cli-error.js +48 -0
- package/esm/utils/database.js +78 -0
- package/esm/utils/deployed-changes.js +68 -0
- package/esm/utils/display.js +58 -0
- package/esm/utils/index.js +6 -0
- package/esm/utils/module-utils.js +51 -0
- package/index.d.ts +25 -0
- package/index.js +87 -0
- package/package.d.ts +1 -0
- package/package.js +29 -0
- package/package.json +64 -0
- package/utils/argv.d.ts +46 -0
- package/utils/argv.js +100 -0
- package/utils/cli-error.d.ts +8 -0
- package/utils/cli-error.js +52 -0
- package/utils/database.d.ts +21 -0
- package/utils/database.js +83 -0
- package/utils/deployed-changes.d.ts +4 -0
- package/utils/deployed-changes.js +72 -0
- package/utils/display.d.ts +3 -0
- package/utils/display.js +66 -0
- package/utils/index.d.ts +6 -0
- package/utils/index.js +22 -0
- package/utils/module-utils.d.ts +8 -0
- package/utils/module-utils.js +54 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { readAndParsePackageJson } from '../package';
|
|
3
|
+
// Function to display the version information
|
|
4
|
+
export function displayVersion() {
|
|
5
|
+
const pkg = readAndParsePackageJson();
|
|
6
|
+
console.log(chalk.green(`Name: ${pkg.name}`));
|
|
7
|
+
console.log(chalk.blue(`Version: ${pkg.version}`));
|
|
8
|
+
}
|
|
9
|
+
export const usageText = `
|
|
10
|
+
Usage: constructive <command> [options]
|
|
11
|
+
|
|
12
|
+
Core Database Operations:
|
|
13
|
+
add Add database changes to plans and create SQL files
|
|
14
|
+
deploy Deploy database changes and migrations
|
|
15
|
+
verify Verify database state and migrations
|
|
16
|
+
revert Revert database changes and migrations
|
|
17
|
+
|
|
18
|
+
Project Management:
|
|
19
|
+
init Initialize workspace or module
|
|
20
|
+
extension Manage module dependencies
|
|
21
|
+
plan Generate module deployment plans
|
|
22
|
+
package Package module for distribution
|
|
23
|
+
export Export database migrations from existing databases
|
|
24
|
+
|
|
25
|
+
Database Administration:
|
|
26
|
+
kill Terminate database connections and optionally drop databases
|
|
27
|
+
install Install database modules
|
|
28
|
+
tag Add tags to changes for versioning
|
|
29
|
+
clear Clear database state
|
|
30
|
+
remove Remove database changes
|
|
31
|
+
analyze Analyze database structure
|
|
32
|
+
rename Rename database changes
|
|
33
|
+
admin-users Manage admin users
|
|
34
|
+
|
|
35
|
+
Migration Tools:
|
|
36
|
+
migrate Migration management subcommands
|
|
37
|
+
init Initialize migration tracking
|
|
38
|
+
status Show migration status
|
|
39
|
+
list List all changes
|
|
40
|
+
deps Show change dependencies
|
|
41
|
+
|
|
42
|
+
Global Options:
|
|
43
|
+
-h, --help Display this help information
|
|
44
|
+
-v, --version Display version information
|
|
45
|
+
--cwd <directory> Working directory (default: current directory)
|
|
46
|
+
|
|
47
|
+
Individual Command Help:
|
|
48
|
+
constructive <command> --help Display detailed help for specific command
|
|
49
|
+
constructive <command> -h Display detailed help for specific command
|
|
50
|
+
|
|
51
|
+
Examples:
|
|
52
|
+
constructive deploy --help Show deploy command options
|
|
53
|
+
constructive init --workspace Initialize new workspace
|
|
54
|
+
constructive install @pgpm/base32 Install a database module
|
|
55
|
+
`;
|
|
56
|
+
export function displayUsage() {
|
|
57
|
+
console.log(usageText);
|
|
58
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { LaunchQLPackage } from '@launchql/core';
|
|
2
|
+
import { errors } from '@launchql/types';
|
|
3
|
+
/**
|
|
4
|
+
* Handle package selection for operations that need a specific package
|
|
5
|
+
* Returns the selected package name, or undefined if validation fails or no packages exist
|
|
6
|
+
*/
|
|
7
|
+
export async function selectPackage(argv, prompter, cwd, operationName, log) {
|
|
8
|
+
const pkg = new LaunchQLPackage(cwd);
|
|
9
|
+
const modules = await pkg.getModules();
|
|
10
|
+
const moduleNames = modules.map(mod => mod.getModuleName());
|
|
11
|
+
// Check if any modules exist
|
|
12
|
+
if (!moduleNames.length) {
|
|
13
|
+
const errorMsg = 'No modules found in the specified directory.';
|
|
14
|
+
if (log) {
|
|
15
|
+
log.error(errorMsg);
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
prompter.close();
|
|
20
|
+
throw errors.NOT_FOUND({}, errorMsg);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// If a specific package was provided, validate it
|
|
24
|
+
if (argv.package) {
|
|
25
|
+
const packageName = argv.package;
|
|
26
|
+
if (log)
|
|
27
|
+
log.info(`Using specified package: ${packageName}`);
|
|
28
|
+
if (!moduleNames.includes(packageName)) {
|
|
29
|
+
const errorMsg = `Package '${packageName}' not found. Available packages: ${moduleNames.join(', ')}`;
|
|
30
|
+
if (log) {
|
|
31
|
+
log.error(errorMsg);
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
throw errors.NOT_FOUND({}, errorMsg);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return packageName;
|
|
39
|
+
}
|
|
40
|
+
// Interactive selection
|
|
41
|
+
const { package: selectedPackage } = await prompter.prompt(argv, [{
|
|
42
|
+
type: 'autocomplete',
|
|
43
|
+
name: 'package',
|
|
44
|
+
message: `Choose a package to ${operationName}`,
|
|
45
|
+
options: moduleNames,
|
|
46
|
+
required: true
|
|
47
|
+
}]);
|
|
48
|
+
if (log)
|
|
49
|
+
log.info(`Selected package: ${selectedPackage}`);
|
|
50
|
+
return selectedPackage;
|
|
51
|
+
}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { CLIOptions } from 'inquirerer';
|
|
3
|
+
import { createConstructiveCommandMap } from './commands';
|
|
4
|
+
export { createConstructiveCommandMap };
|
|
5
|
+
export { default as add } from './commands/add';
|
|
6
|
+
export { default as adminUsers } from './commands/admin-users';
|
|
7
|
+
export { default as analyze } from './commands/analyze';
|
|
8
|
+
export { default as clear } from './commands/clear';
|
|
9
|
+
export { default as deploy } from './commands/deploy';
|
|
10
|
+
export { default as docker } from './commands/docker';
|
|
11
|
+
export { default as env } from './commands/env';
|
|
12
|
+
export { default as _export } from './commands/export';
|
|
13
|
+
export { default as extension } from './commands/extension';
|
|
14
|
+
export { default as install } from './commands/install';
|
|
15
|
+
export { default as kill } from './commands/kill';
|
|
16
|
+
export { default as migrate } from './commands/migrate';
|
|
17
|
+
export { default as _package } from './commands/package';
|
|
18
|
+
export { default as plan } from './commands/plan';
|
|
19
|
+
export { default as remove } from './commands/remove';
|
|
20
|
+
export { default as renameCmd } from './commands/rename';
|
|
21
|
+
export { default as revert } from './commands/revert';
|
|
22
|
+
export { default as tag } from './commands/tag';
|
|
23
|
+
export { default as verify } from './commands/verify';
|
|
24
|
+
export * from './utils';
|
|
25
|
+
export declare const options: Partial<CLIOptions>;
|
package/index.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
15
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
16
|
+
};
|
|
17
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.options = exports.verify = exports.tag = exports.revert = exports.renameCmd = exports.remove = exports.plan = exports._package = exports.migrate = exports.kill = exports.install = exports.extension = exports._export = exports.env = exports.docker = exports.deploy = exports.clear = exports.analyze = exports.adminUsers = exports.add = exports.createConstructiveCommandMap = void 0;
|
|
22
|
+
const fs_1 = require("fs");
|
|
23
|
+
const inquirerer_1 = require("inquirerer");
|
|
24
|
+
const path_1 = require("path");
|
|
25
|
+
const commands_1 = require("./commands");
|
|
26
|
+
Object.defineProperty(exports, "createConstructiveCommandMap", { enumerable: true, get: function () { return commands_1.createConstructiveCommandMap; } });
|
|
27
|
+
var add_1 = require("./commands/add");
|
|
28
|
+
Object.defineProperty(exports, "add", { enumerable: true, get: function () { return __importDefault(add_1).default; } });
|
|
29
|
+
var admin_users_1 = require("./commands/admin-users");
|
|
30
|
+
Object.defineProperty(exports, "adminUsers", { enumerable: true, get: function () { return __importDefault(admin_users_1).default; } });
|
|
31
|
+
var analyze_1 = require("./commands/analyze");
|
|
32
|
+
Object.defineProperty(exports, "analyze", { enumerable: true, get: function () { return __importDefault(analyze_1).default; } });
|
|
33
|
+
var clear_1 = require("./commands/clear");
|
|
34
|
+
Object.defineProperty(exports, "clear", { enumerable: true, get: function () { return __importDefault(clear_1).default; } });
|
|
35
|
+
var deploy_1 = require("./commands/deploy");
|
|
36
|
+
Object.defineProperty(exports, "deploy", { enumerable: true, get: function () { return __importDefault(deploy_1).default; } });
|
|
37
|
+
var docker_1 = require("./commands/docker");
|
|
38
|
+
Object.defineProperty(exports, "docker", { enumerable: true, get: function () { return __importDefault(docker_1).default; } });
|
|
39
|
+
var env_1 = require("./commands/env");
|
|
40
|
+
Object.defineProperty(exports, "env", { enumerable: true, get: function () { return __importDefault(env_1).default; } });
|
|
41
|
+
var export_1 = require("./commands/export");
|
|
42
|
+
Object.defineProperty(exports, "_export", { enumerable: true, get: function () { return __importDefault(export_1).default; } });
|
|
43
|
+
var extension_1 = require("./commands/extension");
|
|
44
|
+
Object.defineProperty(exports, "extension", { enumerable: true, get: function () { return __importDefault(extension_1).default; } });
|
|
45
|
+
var install_1 = require("./commands/install");
|
|
46
|
+
Object.defineProperty(exports, "install", { enumerable: true, get: function () { return __importDefault(install_1).default; } });
|
|
47
|
+
var kill_1 = require("./commands/kill");
|
|
48
|
+
Object.defineProperty(exports, "kill", { enumerable: true, get: function () { return __importDefault(kill_1).default; } });
|
|
49
|
+
var migrate_1 = require("./commands/migrate");
|
|
50
|
+
Object.defineProperty(exports, "migrate", { enumerable: true, get: function () { return __importDefault(migrate_1).default; } });
|
|
51
|
+
var package_1 = require("./commands/package");
|
|
52
|
+
Object.defineProperty(exports, "_package", { enumerable: true, get: function () { return __importDefault(package_1).default; } });
|
|
53
|
+
var plan_1 = require("./commands/plan");
|
|
54
|
+
Object.defineProperty(exports, "plan", { enumerable: true, get: function () { return __importDefault(plan_1).default; } });
|
|
55
|
+
var remove_1 = require("./commands/remove");
|
|
56
|
+
Object.defineProperty(exports, "remove", { enumerable: true, get: function () { return __importDefault(remove_1).default; } });
|
|
57
|
+
var rename_1 = require("./commands/rename");
|
|
58
|
+
Object.defineProperty(exports, "renameCmd", { enumerable: true, get: function () { return __importDefault(rename_1).default; } });
|
|
59
|
+
var revert_1 = require("./commands/revert");
|
|
60
|
+
Object.defineProperty(exports, "revert", { enumerable: true, get: function () { return __importDefault(revert_1).default; } });
|
|
61
|
+
var tag_1 = require("./commands/tag");
|
|
62
|
+
Object.defineProperty(exports, "tag", { enumerable: true, get: function () { return __importDefault(tag_1).default; } });
|
|
63
|
+
var verify_1 = require("./commands/verify");
|
|
64
|
+
Object.defineProperty(exports, "verify", { enumerable: true, get: function () { return __importDefault(verify_1).default; } });
|
|
65
|
+
__exportStar(require("./utils"), exports);
|
|
66
|
+
exports.options = {
|
|
67
|
+
minimistOpts: {
|
|
68
|
+
alias: {
|
|
69
|
+
v: 'version',
|
|
70
|
+
h: 'help'
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
if (require.main === module) {
|
|
75
|
+
if (process.argv.includes('--version') || process.argv.includes('-v')) {
|
|
76
|
+
const pkgPath = (0, path_1.join)(__dirname, 'package.json');
|
|
77
|
+
const pkg = JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf8'));
|
|
78
|
+
console.log(pkg.version);
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
const app = new inquirerer_1.CLI(commands_1.commands, exports.options);
|
|
82
|
+
app.run().then(() => {
|
|
83
|
+
}).catch(error => {
|
|
84
|
+
console.error('Unexpected error:', error);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
});
|
|
87
|
+
}
|
package/package.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function readAndParsePackageJson(): any;
|
package/package.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readAndParsePackageJson = readAndParsePackageJson;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
// need to search due to the dist/ folder and src/, etc.
|
|
7
|
+
function findPackageJson(currentDir) {
|
|
8
|
+
const filePath = (0, path_1.join)(currentDir, 'package.json');
|
|
9
|
+
// Check if package.json exists in the current directory
|
|
10
|
+
if ((0, fs_1.existsSync)(filePath)) {
|
|
11
|
+
return filePath;
|
|
12
|
+
}
|
|
13
|
+
// Get the parent directory
|
|
14
|
+
const parentDir = (0, path_1.dirname)(currentDir);
|
|
15
|
+
// If reached the root directory, package.json is not found
|
|
16
|
+
if (parentDir === currentDir) {
|
|
17
|
+
throw new Error('package.json not found in any parent directory');
|
|
18
|
+
}
|
|
19
|
+
// Recursively look in the parent directory
|
|
20
|
+
return findPackageJson(parentDir);
|
|
21
|
+
}
|
|
22
|
+
function readAndParsePackageJson() {
|
|
23
|
+
// Start searching from the current directory
|
|
24
|
+
const pkgPath = findPackageJson(__dirname);
|
|
25
|
+
// Read and parse the package.json
|
|
26
|
+
const str = (0, fs_1.readFileSync)(pkgPath, 'utf8');
|
|
27
|
+
const pkg = JSON.parse(str);
|
|
28
|
+
return pkg;
|
|
29
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@constructive-io/cli",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Platform for schemas, APIs, and application programming",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"module": "esm/index.js",
|
|
7
|
+
"types": "index.d.ts",
|
|
8
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"access": "public",
|
|
11
|
+
"directory": "dist"
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"constructive": "index.js"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"copy": "copyfiles -f ../../LICENSE README.md package.json dist",
|
|
18
|
+
"clean": "rimraf dist/**",
|
|
19
|
+
"prepack": "npm run build",
|
|
20
|
+
"build": "npm run clean; tsc -p tsconfig.json; tsc -p tsconfig.esm.json; npm run copy",
|
|
21
|
+
"build:dev": "npm run clean; tsc -p tsconfig.json --declarationMap; tsc -p tsconfig.esm.json; npm run copy",
|
|
22
|
+
"dev": "ts-node ./src/index.ts",
|
|
23
|
+
"lint": "eslint . --fix",
|
|
24
|
+
"test": "jest",
|
|
25
|
+
"test:watch": "jest --watch"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/glob": "^8.1.0",
|
|
29
|
+
"@types/js-yaml": "^4.0.9",
|
|
30
|
+
"@types/minimist": "^1.2.5",
|
|
31
|
+
"@types/node": "^20.12.7",
|
|
32
|
+
"@types/pg": "^8.15.2",
|
|
33
|
+
"@types/shelljs": "^0.8.16",
|
|
34
|
+
"glob": "^11.0.2",
|
|
35
|
+
"pg": "^8.16.0",
|
|
36
|
+
"ts-node": "^10.9.2"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@launchql/core": "2.15.4",
|
|
40
|
+
"@launchql/env": "2.5.1",
|
|
41
|
+
"@launchql/logger": "1.1.6",
|
|
42
|
+
"@launchql/templatizer": "2.5.1",
|
|
43
|
+
"@launchql/types": "2.8.1",
|
|
44
|
+
"chalk": "^4.1.0",
|
|
45
|
+
"inquirerer": "^2.0.8",
|
|
46
|
+
"js-yaml": "^4.1.0",
|
|
47
|
+
"minimist": "^1.2.8",
|
|
48
|
+
"pg-cache": "1.4.2",
|
|
49
|
+
"pg-env": "1.1.3",
|
|
50
|
+
"shelljs": "^0.9.2"
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"cli",
|
|
54
|
+
"command-line",
|
|
55
|
+
"tool",
|
|
56
|
+
"postgres",
|
|
57
|
+
"postgresql",
|
|
58
|
+
"migration",
|
|
59
|
+
"package-manager",
|
|
60
|
+
"database",
|
|
61
|
+
"pg",
|
|
62
|
+
"pgsql"
|
|
63
|
+
]
|
|
64
|
+
}
|
package/utils/argv.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ParsedArgs } from 'minimist';
|
|
2
|
+
export declare const extractFirst: (argv: Partial<ParsedArgs>) => {
|
|
3
|
+
first: string;
|
|
4
|
+
newArgv: {
|
|
5
|
+
_: string[];
|
|
6
|
+
"--"?: string[] | undefined;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Common CLI argument validation and processing utilities
|
|
11
|
+
*/
|
|
12
|
+
export interface ValidatedArgv extends ParsedArgs {
|
|
13
|
+
cwd: string;
|
|
14
|
+
database?: string;
|
|
15
|
+
package?: string;
|
|
16
|
+
to?: string;
|
|
17
|
+
recursive?: boolean;
|
|
18
|
+
yes?: boolean;
|
|
19
|
+
tx?: boolean;
|
|
20
|
+
fast?: boolean;
|
|
21
|
+
logOnly?: boolean;
|
|
22
|
+
createdb?: boolean;
|
|
23
|
+
usePlan?: boolean;
|
|
24
|
+
cache?: boolean;
|
|
25
|
+
drop?: boolean;
|
|
26
|
+
all?: boolean;
|
|
27
|
+
summary?: boolean;
|
|
28
|
+
help?: boolean;
|
|
29
|
+
h?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Validates and normalizes common CLI arguments
|
|
33
|
+
*/
|
|
34
|
+
export declare function validateCommonArgs(argv: Partial<ParsedArgs>): ValidatedArgv;
|
|
35
|
+
/**
|
|
36
|
+
* Checks if required flags are provided when certain conditions are met
|
|
37
|
+
*/
|
|
38
|
+
export declare function validateFlagDependencies(argv: ValidatedArgv): void;
|
|
39
|
+
/**
|
|
40
|
+
* Logs the effective CLI arguments for debugging
|
|
41
|
+
*/
|
|
42
|
+
export declare function logEffectiveArgs(argv: ValidatedArgv, commandName: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* Constructs a deployment target string from package and to arguments
|
|
45
|
+
*/
|
|
46
|
+
export declare function constructTarget(argv: ValidatedArgv, packageName?: string): string | undefined;
|
package/utils/argv.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractFirst = void 0;
|
|
4
|
+
exports.validateCommonArgs = validateCommonArgs;
|
|
5
|
+
exports.validateFlagDependencies = validateFlagDependencies;
|
|
6
|
+
exports.logEffectiveArgs = logEffectiveArgs;
|
|
7
|
+
exports.constructTarget = constructTarget;
|
|
8
|
+
const logger_1 = require("@launchql/logger");
|
|
9
|
+
const log = new logger_1.Logger('argv-utils');
|
|
10
|
+
const extractFirst = (argv) => {
|
|
11
|
+
const first = argv._?.[0];
|
|
12
|
+
const newArgv = {
|
|
13
|
+
...argv,
|
|
14
|
+
_: argv._?.slice(1) ?? []
|
|
15
|
+
};
|
|
16
|
+
return { first, newArgv };
|
|
17
|
+
};
|
|
18
|
+
exports.extractFirst = extractFirst;
|
|
19
|
+
/**
|
|
20
|
+
* Validates and normalizes common CLI arguments
|
|
21
|
+
*/
|
|
22
|
+
function validateCommonArgs(argv) {
|
|
23
|
+
const validated = {
|
|
24
|
+
...argv,
|
|
25
|
+
cwd: argv.cwd || process.cwd(),
|
|
26
|
+
_: argv._ || []
|
|
27
|
+
};
|
|
28
|
+
const booleanFlags = ['recursive', 'yes', 'tx', 'fast', 'logOnly', 'createdb', 'usePlan', 'cache', 'drop', 'all', 'summary', 'help', 'h'];
|
|
29
|
+
for (const flag of booleanFlags) {
|
|
30
|
+
if (argv[flag] !== undefined && typeof argv[flag] !== 'boolean') {
|
|
31
|
+
log.warn(`--${flag} flag should be boolean, converting to true`);
|
|
32
|
+
validated[flag] = true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const stringFlags = ['package', 'to', 'database'];
|
|
36
|
+
for (const flag of stringFlags) {
|
|
37
|
+
if (argv[flag] !== undefined && typeof argv[flag] !== 'string') {
|
|
38
|
+
log.warn(`--${flag} should be a string, converting`);
|
|
39
|
+
validated[flag] = String(argv[flag]);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return validated;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Checks if required flags are provided when certain conditions are met
|
|
46
|
+
*/
|
|
47
|
+
function validateFlagDependencies(argv) {
|
|
48
|
+
if (argv.to && !argv.package && !argv.recursive) {
|
|
49
|
+
log.warn('--to flag provided without --package or --recursive. Target may not work as expected.');
|
|
50
|
+
}
|
|
51
|
+
if (argv.package && argv.recursive) {
|
|
52
|
+
if (argv.package.includes(':')) {
|
|
53
|
+
log.warn('--package should not contain ":" when using --recursive. Use --to for target specification.');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Logs the effective CLI arguments for debugging
|
|
59
|
+
*/
|
|
60
|
+
function logEffectiveArgs(argv, commandName) {
|
|
61
|
+
const relevantArgs = {
|
|
62
|
+
cwd: argv.cwd,
|
|
63
|
+
database: argv.database,
|
|
64
|
+
package: argv.package,
|
|
65
|
+
to: argv.to,
|
|
66
|
+
recursive: argv.recursive,
|
|
67
|
+
yes: argv.yes,
|
|
68
|
+
tx: argv.tx,
|
|
69
|
+
fast: argv.fast,
|
|
70
|
+
logOnly: argv.logOnly,
|
|
71
|
+
createdb: argv.createdb,
|
|
72
|
+
usePlan: argv.usePlan,
|
|
73
|
+
cache: argv.cache,
|
|
74
|
+
drop: argv.drop,
|
|
75
|
+
all: argv.all,
|
|
76
|
+
summary: argv.summary
|
|
77
|
+
};
|
|
78
|
+
const definedArgs = Object.fromEntries(Object.entries(relevantArgs).filter(([_, value]) => value !== undefined));
|
|
79
|
+
if (Object.keys(definedArgs).length > 1) { // More than just cwd
|
|
80
|
+
log.debug(`${commandName} effective arguments:`, definedArgs);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Constructs a deployment target string from package and to arguments
|
|
85
|
+
*/
|
|
86
|
+
function constructTarget(argv, packageName) {
|
|
87
|
+
if (packageName && argv.to) {
|
|
88
|
+
return `${packageName}:${argv.to}`;
|
|
89
|
+
}
|
|
90
|
+
else if (packageName) {
|
|
91
|
+
return packageName;
|
|
92
|
+
}
|
|
93
|
+
else if (argv.package && argv.to) {
|
|
94
|
+
return `${argv.package}:${argv.to}`;
|
|
95
|
+
}
|
|
96
|
+
else if (argv.package) {
|
|
97
|
+
return argv.package;
|
|
98
|
+
}
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { LaunchQLError } from '@launchql/types';
|
|
2
|
+
/**
|
|
3
|
+
* CLI error utility that logs error information and exits with code 1.
|
|
4
|
+
* Provides consistent error handling and user experience across all CLI commands.
|
|
5
|
+
*
|
|
6
|
+
* IMPORTANT: This function properly cleans up PostgreSQL connections before exiting.
|
|
7
|
+
*/
|
|
8
|
+
export declare const cliExitWithError: (error: LaunchQLError | Error | string, context?: Record<string, any>) => Promise<never>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cliExitWithError = void 0;
|
|
4
|
+
const logger_1 = require("@launchql/logger");
|
|
5
|
+
const types_1 = require("@launchql/types");
|
|
6
|
+
const pg_cache_1 = require("pg-cache");
|
|
7
|
+
const log = new logger_1.Logger('cli');
|
|
8
|
+
/**
|
|
9
|
+
* CLI error utility that logs error information and exits with code 1.
|
|
10
|
+
* Provides consistent error handling and user experience across all CLI commands.
|
|
11
|
+
*
|
|
12
|
+
* IMPORTANT: This function properly cleans up PostgreSQL connections before exiting.
|
|
13
|
+
*/
|
|
14
|
+
const cliExitWithError = async (error, context) => {
|
|
15
|
+
if (error instanceof types_1.LaunchQLError) {
|
|
16
|
+
// For LaunchQLError instances, use structured logging
|
|
17
|
+
log.error(`Error: ${error.message}`);
|
|
18
|
+
// Log additional context if available
|
|
19
|
+
if (error.context && Object.keys(error.context).length > 0) {
|
|
20
|
+
log.debug('Error context:', error.context);
|
|
21
|
+
}
|
|
22
|
+
// Log any additional context provided
|
|
23
|
+
if (context) {
|
|
24
|
+
log.debug('Additional context:', context);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else if (error instanceof Error) {
|
|
28
|
+
// For generic Error instances
|
|
29
|
+
log.error(`Error: ${error.message}`);
|
|
30
|
+
if (context) {
|
|
31
|
+
log.debug('Context:', context);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else if (typeof error === 'string') {
|
|
35
|
+
// For simple string messages
|
|
36
|
+
log.error(`Error: ${error}`);
|
|
37
|
+
if (context) {
|
|
38
|
+
log.debug('Context:', context);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Perform cleanup before exiting
|
|
42
|
+
try {
|
|
43
|
+
await (0, pg_cache_1.teardownPgPools)();
|
|
44
|
+
log.debug('Database connections cleaned up');
|
|
45
|
+
}
|
|
46
|
+
catch (cleanupError) {
|
|
47
|
+
log.warn('Failed to cleanup database connections:', cleanupError);
|
|
48
|
+
// Don't let cleanup errors prevent the exit
|
|
49
|
+
}
|
|
50
|
+
process.exit(1);
|
|
51
|
+
};
|
|
52
|
+
exports.cliExitWithError = cliExitWithError;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Inquirerer } from 'inquirerer';
|
|
2
|
+
import { ParsedArgs } from 'minimist';
|
|
3
|
+
export interface DatabaseSelectionOptions {
|
|
4
|
+
message?: string;
|
|
5
|
+
excludeTemplates?: boolean;
|
|
6
|
+
excludePostgres?: boolean;
|
|
7
|
+
excludeSystemDbs?: boolean;
|
|
8
|
+
multiple?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get list of available databases from PostgreSQL
|
|
12
|
+
*/
|
|
13
|
+
export declare function getAvailableDatabases(options?: DatabaseSelectionOptions): Promise<string[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Prompt user to select a database
|
|
16
|
+
*/
|
|
17
|
+
export declare function selectDatabase(argv: Partial<ParsedArgs>, prompter: Inquirerer, options?: DatabaseSelectionOptions): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Get target database with fallback to environment
|
|
20
|
+
*/
|
|
21
|
+
export declare function getTargetDatabase(argv: Partial<ParsedArgs>, prompter: Inquirerer, options?: DatabaseSelectionOptions): Promise<string>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAvailableDatabases = getAvailableDatabases;
|
|
4
|
+
exports.selectDatabase = selectDatabase;
|
|
5
|
+
exports.getTargetDatabase = getTargetDatabase;
|
|
6
|
+
const pg_cache_1 = require("pg-cache");
|
|
7
|
+
const pg_env_1 = require("pg-env");
|
|
8
|
+
/**
|
|
9
|
+
* Get list of available databases from PostgreSQL
|
|
10
|
+
*/
|
|
11
|
+
async function getAvailableDatabases(options = {}) {
|
|
12
|
+
const { excludeTemplates = true, excludePostgres = true, excludeSystemDbs = true } = options;
|
|
13
|
+
const db = await (0, pg_cache_1.getPgPool)({
|
|
14
|
+
database: 'postgres'
|
|
15
|
+
});
|
|
16
|
+
let query = `
|
|
17
|
+
SELECT datname FROM pg_catalog.pg_database
|
|
18
|
+
WHERE 1=1
|
|
19
|
+
`;
|
|
20
|
+
if (excludeTemplates) {
|
|
21
|
+
query += ` AND datistemplate = FALSE`;
|
|
22
|
+
}
|
|
23
|
+
if (excludePostgres) {
|
|
24
|
+
query += ` AND datname NOT IN ('postgres')`;
|
|
25
|
+
}
|
|
26
|
+
if (excludeSystemDbs) {
|
|
27
|
+
query += ` AND datname !~ '^pg_'`;
|
|
28
|
+
}
|
|
29
|
+
query += ` ORDER BY datname`;
|
|
30
|
+
const result = await db.query(query);
|
|
31
|
+
return result.rows.map((row) => row.datname);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Prompt user to select a database
|
|
35
|
+
*/
|
|
36
|
+
async function selectDatabase(argv, prompter, options = {}) {
|
|
37
|
+
const { message = 'Select target database', multiple = false } = options;
|
|
38
|
+
// Check if database is already specified
|
|
39
|
+
if (!multiple && (argv.db || argv.database)) {
|
|
40
|
+
return argv.db || argv.database;
|
|
41
|
+
}
|
|
42
|
+
// Get available databases
|
|
43
|
+
const databases = await getAvailableDatabases(options);
|
|
44
|
+
if (databases.length === 0) {
|
|
45
|
+
throw new Error('No databases found');
|
|
46
|
+
}
|
|
47
|
+
// If only one database and not forcing selection, use it
|
|
48
|
+
if (!multiple && databases.length === 1 && !argv.interactive) {
|
|
49
|
+
return databases[0];
|
|
50
|
+
}
|
|
51
|
+
// Prompt for selection
|
|
52
|
+
const answer = await prompter.prompt(argv, [
|
|
53
|
+
{
|
|
54
|
+
type: multiple ? 'checkbox' : 'autocomplete',
|
|
55
|
+
name: 'database',
|
|
56
|
+
message,
|
|
57
|
+
options: databases,
|
|
58
|
+
required: true
|
|
59
|
+
}
|
|
60
|
+
]);
|
|
61
|
+
return answer.database;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get target database with fallback to environment
|
|
65
|
+
*/
|
|
66
|
+
async function getTargetDatabase(argv, prompter, options = {}) {
|
|
67
|
+
// If database is specified in args, use it
|
|
68
|
+
if (argv.db || argv.database) {
|
|
69
|
+
return argv.db || argv.database;
|
|
70
|
+
}
|
|
71
|
+
// Try to select from available databases
|
|
72
|
+
try {
|
|
73
|
+
return await selectDatabase(argv, prompter, options);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
// Fall back to environment database
|
|
77
|
+
const pgEnv = (0, pg_env_1.getPgEnvOptions)();
|
|
78
|
+
if (pgEnv.database) {
|
|
79
|
+
return pgEnv.database;
|
|
80
|
+
}
|
|
81
|
+
throw new Error('No database specified and no default database found');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Logger } from '@launchql/logger';
|
|
2
|
+
import { Inquirerer } from 'inquirerer';
|
|
3
|
+
export declare function selectDeployedChange(database: string, argv: Partial<Record<string, any>>, prompter: Inquirerer, log: Logger, action?: 'revert' | 'verify'): Promise<string | undefined>;
|
|
4
|
+
export declare function selectDeployedPackage(database: string, argv: Partial<Record<string, any>>, prompter: Inquirerer, log: Logger, action?: 'revert' | 'verify'): Promise<string | undefined>;
|