pgpm 0.0.1
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/README.md +416 -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/explorer.d.ts +3 -0
- package/commands/explorer.js +94 -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/server.d.ts +3 -0
- package/commands/server.js +187 -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 +5 -0
- package/commands.js +118 -0
- package/dist/README.md +416 -0
- package/dist/package.json +77 -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/explorer.js +92 -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/server.js +185 -0
- package/esm/commands/tag.js +133 -0
- package/esm/commands/verify.js +83 -0
- package/esm/commands.js +111 -0
- package/esm/index.js +20 -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 +3 -0
- package/esm/utils/module-utils.js +51 -0
- package/index.d.ts +3 -0
- package/index.js +23 -0
- package/package.d.ts +1 -0
- package/package.js +29 -0
- package/package.json +77 -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 +3 -0
- package/utils/index.js +19 -0
- package/utils/module-utils.d.ts +8 -0
- package/utils/module-utils.js +54 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { extractFirst } from '../utils';
|
|
2
|
+
import deps from './migrate/deps';
|
|
3
|
+
// Migrate subcommands
|
|
4
|
+
import init from './migrate/init';
|
|
5
|
+
import list from './migrate/list';
|
|
6
|
+
import status from './migrate/status';
|
|
7
|
+
const subcommandMap = {
|
|
8
|
+
init,
|
|
9
|
+
status,
|
|
10
|
+
list,
|
|
11
|
+
deps
|
|
12
|
+
};
|
|
13
|
+
const migrateUsageText = `
|
|
14
|
+
LaunchQL Migrate Commands:
|
|
15
|
+
|
|
16
|
+
launchql migrate init Initialize migration tracking in database
|
|
17
|
+
launchql migrate status Show current migration status
|
|
18
|
+
launchql migrate list List all changes (deployed and pending)
|
|
19
|
+
launchql migrate deps Show change dependencies
|
|
20
|
+
|
|
21
|
+
Options:
|
|
22
|
+
--help, -h Show this help message
|
|
23
|
+
--cwd Working directory (default: current directory)
|
|
24
|
+
`;
|
|
25
|
+
export default async (argv, prompter, options) => {
|
|
26
|
+
let { first: subcommand, newArgv } = extractFirst(argv);
|
|
27
|
+
// Show usage if explicitly requested
|
|
28
|
+
if (argv.help || argv.h || subcommand === 'help') {
|
|
29
|
+
console.log(migrateUsageText);
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
// Prompt if no subcommand provided
|
|
33
|
+
if (!subcommand) {
|
|
34
|
+
const answer = await prompter.prompt(argv, [
|
|
35
|
+
{
|
|
36
|
+
type: 'autocomplete',
|
|
37
|
+
name: 'subcommand',
|
|
38
|
+
message: 'What migrate operation do you want to perform?',
|
|
39
|
+
options: Object.keys(subcommandMap).map(cmd => ({
|
|
40
|
+
name: cmd,
|
|
41
|
+
value: cmd,
|
|
42
|
+
description: getSubcommandDescription(cmd)
|
|
43
|
+
}))
|
|
44
|
+
}
|
|
45
|
+
]);
|
|
46
|
+
subcommand = answer.subcommand;
|
|
47
|
+
}
|
|
48
|
+
const subcommandFn = subcommandMap[subcommand];
|
|
49
|
+
if (!subcommandFn) {
|
|
50
|
+
console.error(`Unknown migrate subcommand: ${subcommand}`);
|
|
51
|
+
console.log(migrateUsageText);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
await subcommandFn(newArgv, prompter, options);
|
|
55
|
+
};
|
|
56
|
+
function getSubcommandDescription(cmd) {
|
|
57
|
+
const descriptions = {
|
|
58
|
+
init: 'Initialize migration tracking in database',
|
|
59
|
+
status: 'Show current migration status',
|
|
60
|
+
list: 'List all changes (deployed and pending)',
|
|
61
|
+
deps: 'Show change dependencies'
|
|
62
|
+
};
|
|
63
|
+
return descriptions[cmd] || '';
|
|
64
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { LaunchQLPackage, writePackage } from '@launchql/core';
|
|
2
|
+
const packageUsageText = `
|
|
3
|
+
LaunchQL Package Command:
|
|
4
|
+
|
|
5
|
+
lql package [OPTIONS]
|
|
6
|
+
|
|
7
|
+
Package module for distribution.
|
|
8
|
+
|
|
9
|
+
Options:
|
|
10
|
+
--help, -h Show this help message
|
|
11
|
+
--plan Include deployment plan (default: true)
|
|
12
|
+
--pretty Pretty-print output (default: true)
|
|
13
|
+
--functionDelimiter <delimiter> Function delimiter (default: $EOFCODE$)
|
|
14
|
+
--cwd <directory> Working directory (default: current directory)
|
|
15
|
+
|
|
16
|
+
Examples:
|
|
17
|
+
lql package Package with defaults
|
|
18
|
+
lql package --no-plan Package without plan
|
|
19
|
+
`;
|
|
20
|
+
export default async (argv, prompter, _options) => {
|
|
21
|
+
// Show usage if explicitly requested
|
|
22
|
+
if (argv.help || argv.h) {
|
|
23
|
+
console.log(packageUsageText);
|
|
24
|
+
process.exit(0);
|
|
25
|
+
}
|
|
26
|
+
const questions = [
|
|
27
|
+
{
|
|
28
|
+
type: 'confirm',
|
|
29
|
+
name: 'plan',
|
|
30
|
+
default: true,
|
|
31
|
+
useDefault: true,
|
|
32
|
+
required: true
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
type: 'confirm',
|
|
36
|
+
name: 'pretty',
|
|
37
|
+
default: true,
|
|
38
|
+
useDefault: true,
|
|
39
|
+
required: true
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
type: 'text',
|
|
43
|
+
name: 'functionDelimiter',
|
|
44
|
+
default: '$EOFCODE$',
|
|
45
|
+
useDefault: true,
|
|
46
|
+
required: false
|
|
47
|
+
}
|
|
48
|
+
];
|
|
49
|
+
let { cwd, plan, pretty, functionDelimiter } = await prompter.prompt(argv, questions);
|
|
50
|
+
const project = new LaunchQLPackage(cwd);
|
|
51
|
+
project.ensureModule();
|
|
52
|
+
const info = project.getModuleInfo();
|
|
53
|
+
info.version;
|
|
54
|
+
await writePackage({
|
|
55
|
+
version: info.version,
|
|
56
|
+
extension: true,
|
|
57
|
+
usePlan: plan,
|
|
58
|
+
packageDir: project.modulePath,
|
|
59
|
+
pretty,
|
|
60
|
+
functionDelimiter
|
|
61
|
+
});
|
|
62
|
+
return argv;
|
|
63
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { LaunchQLPackage } from '@launchql/core';
|
|
2
|
+
import { Logger } from '@launchql/logger';
|
|
3
|
+
const log = new Logger('plan');
|
|
4
|
+
const planUsageText = `
|
|
5
|
+
LaunchQL Plan Command:
|
|
6
|
+
|
|
7
|
+
lql plan [OPTIONS]
|
|
8
|
+
|
|
9
|
+
Generate module deployment plans.
|
|
10
|
+
|
|
11
|
+
Options:
|
|
12
|
+
--help, -h Show this help message
|
|
13
|
+
--includePackages Include packages in plan (default: true)
|
|
14
|
+
--includeTags Prefer @tag references for external packages when available (default: true)
|
|
15
|
+
--cwd <directory> Working directory (default: current directory)
|
|
16
|
+
|
|
17
|
+
Examples:
|
|
18
|
+
lql plan Generate deployment plan for current module with defaults
|
|
19
|
+
lql plan --includePackages false Disable including external packages
|
|
20
|
+
lql plan --includeTags false Do not prefer tags for external packages
|
|
21
|
+
`;
|
|
22
|
+
export default async (argv, prompter, _options) => {
|
|
23
|
+
// Show usage if explicitly requested
|
|
24
|
+
if (argv.help || argv.h) {
|
|
25
|
+
console.log(planUsageText);
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
const questions = [
|
|
29
|
+
{
|
|
30
|
+
type: 'confirm',
|
|
31
|
+
name: 'includePackages',
|
|
32
|
+
message: 'Include packages in plan?',
|
|
33
|
+
useDefault: true,
|
|
34
|
+
default: true
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
type: 'confirm',
|
|
38
|
+
name: 'includeTags',
|
|
39
|
+
message: 'Prefer @tag references for external packages when available?',
|
|
40
|
+
useDefault: true,
|
|
41
|
+
default: true
|
|
42
|
+
}
|
|
43
|
+
];
|
|
44
|
+
let { cwd, includePackages, includeTags } = await prompter.prompt(argv, questions);
|
|
45
|
+
if (!cwd) {
|
|
46
|
+
cwd = process.cwd();
|
|
47
|
+
log.info(`Using current directory: ${cwd}`);
|
|
48
|
+
}
|
|
49
|
+
const pkg = new LaunchQLPackage(cwd);
|
|
50
|
+
if (!pkg.isInModule()) {
|
|
51
|
+
throw new Error('This command must be run inside a LaunchQL module.');
|
|
52
|
+
}
|
|
53
|
+
const includePackagesFlag = typeof includePackages === 'boolean' ? includePackages : true;
|
|
54
|
+
const includeTagsFlag = typeof includeTags === 'boolean' ? includeTags : true;
|
|
55
|
+
pkg.writeModulePlan({
|
|
56
|
+
includePackages: includePackagesFlag,
|
|
57
|
+
includeTags: includeTagsFlag
|
|
58
|
+
});
|
|
59
|
+
return argv;
|
|
60
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { LaunchQLPackage } from '@launchql/core';
|
|
2
|
+
import { Logger } from '@launchql/logger';
|
|
3
|
+
import { getEnvOptions } from '@launchql/env';
|
|
4
|
+
import { getPgEnvOptions } from 'pg-env';
|
|
5
|
+
import { getTargetDatabase } from '../utils';
|
|
6
|
+
import { cliExitWithError } from '../utils/cli-error';
|
|
7
|
+
const log = new Logger('remove');
|
|
8
|
+
export default async (argv, prompter, _options) => {
|
|
9
|
+
if (!argv.to) {
|
|
10
|
+
await cliExitWithError('No change specified. Usage: lql remove --to <change>');
|
|
11
|
+
}
|
|
12
|
+
const database = await getTargetDatabase(argv, prompter, {
|
|
13
|
+
message: 'Select database'
|
|
14
|
+
});
|
|
15
|
+
const questions = [
|
|
16
|
+
{
|
|
17
|
+
name: 'yes',
|
|
18
|
+
type: 'confirm',
|
|
19
|
+
message: 'Are you sure you want to proceed with removing changes?',
|
|
20
|
+
required: true
|
|
21
|
+
}
|
|
22
|
+
];
|
|
23
|
+
let { yes, cwd } = await prompter.prompt(argv, questions);
|
|
24
|
+
if (!yes) {
|
|
25
|
+
log.info('Operation cancelled.');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
log.debug(`Using current directory: ${cwd}`);
|
|
29
|
+
const pkg = new LaunchQLPackage(cwd);
|
|
30
|
+
if (!pkg.isInModule()) {
|
|
31
|
+
throw new Error('Not in a LaunchQL module directory. Please run this command from within a module.');
|
|
32
|
+
}
|
|
33
|
+
const opts = getEnvOptions({
|
|
34
|
+
pg: getPgEnvOptions({ database })
|
|
35
|
+
});
|
|
36
|
+
const toChange = argv.to;
|
|
37
|
+
await pkg.removeFromPlan(toChange);
|
|
38
|
+
log.success(`✅ Successfully removed changes from '${toChange}' to end of plan.`);
|
|
39
|
+
return argv;
|
|
40
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { LaunchQLPackage } from '@launchql/core';
|
|
3
|
+
import { cliExitWithError } from '../utils/cli-error';
|
|
4
|
+
export default async (argv, _prompter) => {
|
|
5
|
+
const cwd = argv.cwd || process.cwd();
|
|
6
|
+
const to = argv.to || (argv._ && argv._[0]);
|
|
7
|
+
if (!to) {
|
|
8
|
+
await cliExitWithError('Missing new name. Use --to <name> or provide as positional argument.');
|
|
9
|
+
}
|
|
10
|
+
const dryRun = !!argv['dry-run'] || !!argv.dryRun;
|
|
11
|
+
const syncPkg = !!argv['sync-pkg-name'] || !!argv.syncPkgName;
|
|
12
|
+
const proj = new LaunchQLPackage(path.resolve(cwd));
|
|
13
|
+
const res = proj.renameModule(to, { dryRun, syncPackageJsonName: syncPkg });
|
|
14
|
+
if (dryRun) {
|
|
15
|
+
console.log('Dry run');
|
|
16
|
+
}
|
|
17
|
+
if (res.changed.length > 0) {
|
|
18
|
+
console.log('Changed:');
|
|
19
|
+
for (const f of res.changed)
|
|
20
|
+
console.log(`- ${f}`);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
console.log('No changes');
|
|
24
|
+
}
|
|
25
|
+
if (res.warnings.length > 0) {
|
|
26
|
+
console.log('Warnings:');
|
|
27
|
+
for (const w of res.warnings)
|
|
28
|
+
console.log(`- ${w}`);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { LaunchQLPackage } from '@launchql/core';
|
|
2
|
+
import { Logger } from '@launchql/logger';
|
|
3
|
+
import { getEnvOptions } from '@launchql/env';
|
|
4
|
+
import { getPgEnvOptions } from 'pg-env';
|
|
5
|
+
import { getTargetDatabase } from '../utils';
|
|
6
|
+
import { selectDeployedChange, selectDeployedPackage } from '../utils/deployed-changes';
|
|
7
|
+
import { cliExitWithError } from '../utils/cli-error';
|
|
8
|
+
const log = new Logger('revert');
|
|
9
|
+
const revertUsageText = `
|
|
10
|
+
LaunchQL Revert Command:
|
|
11
|
+
|
|
12
|
+
lql revert [OPTIONS]
|
|
13
|
+
|
|
14
|
+
Revert database changes and migrations.
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
--help, -h Show this help message
|
|
18
|
+
--recursive Revert recursively through dependencies
|
|
19
|
+
--package <name> Revert specific package
|
|
20
|
+
--to <target> Revert to specific change or tag
|
|
21
|
+
--to Interactive selection of deployed changes
|
|
22
|
+
--tx Use transactions (default: true)
|
|
23
|
+
--cwd <directory> Working directory (default: current directory)
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
lql revert Revert latest changes
|
|
27
|
+
lql revert --to @v1.0.0 Revert to specific tag
|
|
28
|
+
lql revert --to Interactive selection from deployed changes
|
|
29
|
+
`;
|
|
30
|
+
export default async (argv, prompter, _options) => {
|
|
31
|
+
// Show usage if explicitly requested
|
|
32
|
+
if (argv.help || argv.h) {
|
|
33
|
+
console.log(revertUsageText);
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
const database = await getTargetDatabase(argv, prompter, {
|
|
37
|
+
message: 'Select database'
|
|
38
|
+
});
|
|
39
|
+
const questions = [
|
|
40
|
+
{
|
|
41
|
+
name: 'yes',
|
|
42
|
+
type: 'confirm',
|
|
43
|
+
message: 'Are you sure you want to proceed?',
|
|
44
|
+
required: true
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'recursive',
|
|
48
|
+
type: 'confirm',
|
|
49
|
+
message: 'Deploy recursively through dependencies?',
|
|
50
|
+
useDefault: true,
|
|
51
|
+
default: true,
|
|
52
|
+
required: false
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'tx',
|
|
56
|
+
type: 'confirm',
|
|
57
|
+
message: 'Use Transaction?',
|
|
58
|
+
useDefault: true,
|
|
59
|
+
default: true,
|
|
60
|
+
required: false
|
|
61
|
+
}
|
|
62
|
+
];
|
|
63
|
+
let { yes, recursive, cwd, tx } = await prompter.prompt(argv, questions);
|
|
64
|
+
if (!yes) {
|
|
65
|
+
log.info('Operation cancelled.');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
log.debug(`Using current directory: ${cwd}`);
|
|
69
|
+
let packageName;
|
|
70
|
+
if (recursive && argv.to !== true) {
|
|
71
|
+
packageName = await selectDeployedPackage(database, argv, prompter, log, 'revert');
|
|
72
|
+
if (!packageName) {
|
|
73
|
+
await cliExitWithError('No package found to revert');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const pkg = new LaunchQLPackage(cwd);
|
|
77
|
+
const opts = getEnvOptions({
|
|
78
|
+
pg: getPgEnvOptions({ database }),
|
|
79
|
+
deployment: {
|
|
80
|
+
useTx: tx
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
let target;
|
|
84
|
+
if (argv.to === true) {
|
|
85
|
+
target = await selectDeployedChange(database, argv, prompter, log, 'revert');
|
|
86
|
+
if (!target) {
|
|
87
|
+
await cliExitWithError('No target selected, operation cancelled');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else if (packageName && argv.to) {
|
|
91
|
+
target = `${packageName}:${argv.to}`;
|
|
92
|
+
}
|
|
93
|
+
else if (packageName) {
|
|
94
|
+
target = packageName;
|
|
95
|
+
}
|
|
96
|
+
else if (argv.package && argv.to) {
|
|
97
|
+
target = `${argv.package}:${argv.to}`;
|
|
98
|
+
}
|
|
99
|
+
else if (argv.package) {
|
|
100
|
+
target = argv.package;
|
|
101
|
+
}
|
|
102
|
+
await pkg.revert(opts, target, recursive);
|
|
103
|
+
log.success('Revert complete.');
|
|
104
|
+
return argv;
|
|
105
|
+
};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { Logger } from '@launchql/logger';
|
|
2
|
+
import { LaunchQLServer as server } from '@launchql/server';
|
|
3
|
+
import { getEnvOptions } from '@launchql/env';
|
|
4
|
+
import { getPgPool } from 'pg-cache';
|
|
5
|
+
const log = new Logger('server');
|
|
6
|
+
const serverUsageText = `
|
|
7
|
+
LaunchQL Server Command:
|
|
8
|
+
|
|
9
|
+
lql server [OPTIONS]
|
|
10
|
+
|
|
11
|
+
Start LaunchQL GraphQL development server.
|
|
12
|
+
|
|
13
|
+
Options:
|
|
14
|
+
--help, -h Show this help message
|
|
15
|
+
--port <number> Server port (default: 5555)
|
|
16
|
+
--simpleInflection Use simple inflection (default: true)
|
|
17
|
+
--oppositeBaseNames Use opposite base names (default: false)
|
|
18
|
+
--postgis Enable PostGIS extension (default: true)
|
|
19
|
+
--metaApi Enable Meta API (default: true)
|
|
20
|
+
--cwd <directory> Working directory (default: current directory)
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
lql server Start server with defaults
|
|
24
|
+
lql server --port 8080 Start server on custom port
|
|
25
|
+
lql server --no-postgis Start server without PostGIS
|
|
26
|
+
`;
|
|
27
|
+
const questions = [
|
|
28
|
+
{
|
|
29
|
+
name: 'simpleInflection',
|
|
30
|
+
message: 'Use simple inflection?',
|
|
31
|
+
type: 'confirm',
|
|
32
|
+
required: false,
|
|
33
|
+
default: true,
|
|
34
|
+
useDefault: true
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'oppositeBaseNames',
|
|
38
|
+
message: 'Use opposite base names?',
|
|
39
|
+
type: 'confirm',
|
|
40
|
+
required: false,
|
|
41
|
+
default: false,
|
|
42
|
+
useDefault: true
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'postgis',
|
|
46
|
+
message: 'Enable PostGIS extension?',
|
|
47
|
+
type: 'confirm',
|
|
48
|
+
required: false,
|
|
49
|
+
default: true,
|
|
50
|
+
useDefault: true
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'metaApi',
|
|
54
|
+
message: 'Enable Meta API?',
|
|
55
|
+
type: 'confirm',
|
|
56
|
+
required: false,
|
|
57
|
+
default: true,
|
|
58
|
+
useDefault: true
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'origin',
|
|
62
|
+
message: 'CORS origin (exact URL or *)',
|
|
63
|
+
type: 'text',
|
|
64
|
+
required: false,
|
|
65
|
+
// no default to avoid accidentally opening up CORS; pass explicitly or via env
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'port',
|
|
69
|
+
message: 'Development server port',
|
|
70
|
+
type: 'number',
|
|
71
|
+
required: false,
|
|
72
|
+
default: 5555,
|
|
73
|
+
useDefault: true
|
|
74
|
+
}
|
|
75
|
+
];
|
|
76
|
+
export default async (argv, prompter, _options) => {
|
|
77
|
+
// Show usage if explicitly requested
|
|
78
|
+
if (argv.help || argv.h) {
|
|
79
|
+
console.log(serverUsageText);
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
log.info('🔧 LaunchQL Server Configuration:\n');
|
|
83
|
+
let selectedDb = process.env.PGDATABASE;
|
|
84
|
+
if (!selectedDb) {
|
|
85
|
+
const db = await getPgPool({ database: 'postgres' });
|
|
86
|
+
const result = await db.query(`
|
|
87
|
+
SELECT datname FROM pg_database
|
|
88
|
+
WHERE datistemplate = false AND datname NOT IN ('postgres')
|
|
89
|
+
AND datname !~ '^pg_'
|
|
90
|
+
ORDER BY datname;
|
|
91
|
+
`);
|
|
92
|
+
const dbChoices = result.rows.map(row => row.datname);
|
|
93
|
+
const { database } = await prompter.prompt(argv, [
|
|
94
|
+
{
|
|
95
|
+
type: 'autocomplete',
|
|
96
|
+
name: 'database',
|
|
97
|
+
message: 'Select the database to use',
|
|
98
|
+
options: dbChoices,
|
|
99
|
+
required: true
|
|
100
|
+
}
|
|
101
|
+
]);
|
|
102
|
+
selectedDb = database;
|
|
103
|
+
log.info(`📌 Using database: "${selectedDb}"`);
|
|
104
|
+
}
|
|
105
|
+
const { oppositeBaseNames, port, postgis, simpleInflection, metaApi, origin } = await prompter.prompt(argv, questions);
|
|
106
|
+
// Warn when passing CORS override via CLI, especially in production
|
|
107
|
+
if (origin && origin.trim().length) {
|
|
108
|
+
const env = (process.env.NODE_ENV || 'development').toLowerCase();
|
|
109
|
+
if (env === 'production') {
|
|
110
|
+
if (origin.trim() === '*') {
|
|
111
|
+
log.warn('CORS wildcard ("*") provided via --origin in production: this effectively disables CORS and is not recommended. Prefer per-API CORS via meta schema.');
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
log.warn(`CORS override (origin=${origin.trim()}) provided via --origin in production. Prefer per-API CORS via meta schema.`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
let selectedSchemas = [];
|
|
119
|
+
let authRole;
|
|
120
|
+
let roleName;
|
|
121
|
+
if (!metaApi) {
|
|
122
|
+
const db = await getPgPool({ database: selectedDb });
|
|
123
|
+
const result = await db.query(`
|
|
124
|
+
SELECT nspname
|
|
125
|
+
FROM pg_namespace
|
|
126
|
+
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
|
|
127
|
+
ORDER BY nspname;
|
|
128
|
+
`);
|
|
129
|
+
const schemaChoices = result.rows.map(row => ({
|
|
130
|
+
name: row.nspname,
|
|
131
|
+
value: row.nspname,
|
|
132
|
+
selected: true
|
|
133
|
+
}));
|
|
134
|
+
const { schemas } = await prompter.prompt(argv, [
|
|
135
|
+
{
|
|
136
|
+
type: 'checkbox',
|
|
137
|
+
name: 'schemas',
|
|
138
|
+
message: 'Select schemas to expose',
|
|
139
|
+
options: schemaChoices,
|
|
140
|
+
required: true
|
|
141
|
+
}
|
|
142
|
+
]);
|
|
143
|
+
selectedSchemas = schemas.filter(s => s.selected).map(s => s.value);
|
|
144
|
+
const { authRole: selectedAuthRole, roleName: selectedRoleName } = await prompter.prompt(argv, [
|
|
145
|
+
{
|
|
146
|
+
type: 'autocomplete',
|
|
147
|
+
name: 'authRole',
|
|
148
|
+
message: 'Select the authentication role',
|
|
149
|
+
options: ['postgres', 'authenticated', 'anonymous'],
|
|
150
|
+
required: true
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
type: 'autocomplete',
|
|
154
|
+
name: 'roleName',
|
|
155
|
+
message: 'Enter the default role name:',
|
|
156
|
+
options: ['postgres', 'authenticated', 'anonymous'],
|
|
157
|
+
required: true
|
|
158
|
+
}
|
|
159
|
+
]);
|
|
160
|
+
authRole = selectedAuthRole;
|
|
161
|
+
roleName = selectedRoleName;
|
|
162
|
+
}
|
|
163
|
+
const options = getEnvOptions({
|
|
164
|
+
pg: { database: selectedDb },
|
|
165
|
+
features: {
|
|
166
|
+
oppositeBaseNames,
|
|
167
|
+
simpleInflection,
|
|
168
|
+
postgis
|
|
169
|
+
},
|
|
170
|
+
api: {
|
|
171
|
+
enableMetaApi: metaApi,
|
|
172
|
+
...(metaApi === false && { exposedSchemas: selectedSchemas, authRole, roleName })
|
|
173
|
+
},
|
|
174
|
+
server: {
|
|
175
|
+
port,
|
|
176
|
+
...(origin ? { origin } : {})
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
log.success('✅ Selected Configuration:');
|
|
180
|
+
for (const [key, value] of Object.entries(options)) {
|
|
181
|
+
log.debug(`${key}: ${JSON.stringify(value)}`);
|
|
182
|
+
}
|
|
183
|
+
log.success('🚀 Launching Server...\n');
|
|
184
|
+
server(options);
|
|
185
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { LaunchQLPackage } from '@launchql/core';
|
|
2
|
+
import { Logger } from '@launchql/logger';
|
|
3
|
+
import { errors } from '@launchql/types';
|
|
4
|
+
import { extractFirst } from '../utils/argv';
|
|
5
|
+
import { selectPackage } from '../utils/module-utils';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
const log = new Logger('tag');
|
|
8
|
+
const tagUsageText = `
|
|
9
|
+
LaunchQL Tag Command:
|
|
10
|
+
|
|
11
|
+
lql tag [tag_name] [OPTIONS]
|
|
12
|
+
|
|
13
|
+
Add tags to changes for versioning.
|
|
14
|
+
|
|
15
|
+
Arguments:
|
|
16
|
+
tag_name Name of the tag to create
|
|
17
|
+
|
|
18
|
+
Options:
|
|
19
|
+
--help, -h Show this help message
|
|
20
|
+
--package <name> Target specific package
|
|
21
|
+
--changeName <name> Target specific change (default: latest)
|
|
22
|
+
--comment <text> Optional tag comment
|
|
23
|
+
--cwd <directory> Working directory (default: current directory)
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
lql tag v1.0.0 Add tag to latest change
|
|
27
|
+
lql tag v1.0.0 --comment "Initial release" Add tag with comment
|
|
28
|
+
lql tag v1.1.0 --package mypackage --changeName my-change Tag specific change in package
|
|
29
|
+
`;
|
|
30
|
+
export default async (argv, prompter, _options) => {
|
|
31
|
+
// Show usage if explicitly requested
|
|
32
|
+
if (argv.help || argv.h) {
|
|
33
|
+
console.log(tagUsageText);
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
const { first: tagName, newArgv } = extractFirst(argv);
|
|
37
|
+
const cwdResult = await prompter.prompt(newArgv, [
|
|
38
|
+
{
|
|
39
|
+
type: 'text',
|
|
40
|
+
name: 'cwd',
|
|
41
|
+
message: 'Working directory',
|
|
42
|
+
required: false,
|
|
43
|
+
default: process.cwd(),
|
|
44
|
+
useDefault: true
|
|
45
|
+
}
|
|
46
|
+
]);
|
|
47
|
+
const cwd = cwdResult.cwd || process.cwd();
|
|
48
|
+
const pkg = new LaunchQLPackage(cwd);
|
|
49
|
+
let packageName;
|
|
50
|
+
if (argv.package) {
|
|
51
|
+
packageName = argv.package;
|
|
52
|
+
log.info(`Using specified package: ${packageName}`);
|
|
53
|
+
}
|
|
54
|
+
else if (pkg.isInModule()) {
|
|
55
|
+
packageName = pkg.getModuleName();
|
|
56
|
+
log.info(`Using current module: ${packageName}`);
|
|
57
|
+
}
|
|
58
|
+
else if (pkg.isInWorkspace()) {
|
|
59
|
+
packageName = await selectPackage(newArgv, prompter, cwd, 'add tag to', log);
|
|
60
|
+
if (!packageName) {
|
|
61
|
+
throw new Error('No package selected. Cannot add tag without specifying a target package.');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
throw new Error('This command must be run inside a LaunchQL workspace or module.');
|
|
66
|
+
}
|
|
67
|
+
const questions = [];
|
|
68
|
+
if (!tagName) {
|
|
69
|
+
questions.push({
|
|
70
|
+
type: 'text',
|
|
71
|
+
name: 'tagName',
|
|
72
|
+
message: 'Tag name',
|
|
73
|
+
required: true,
|
|
74
|
+
validate: (value) => {
|
|
75
|
+
if (!value || value.trim().length === 0) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
if (value.includes('/')) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
if (value.includes('@')) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
questions.push({
|
|
89
|
+
type: 'text',
|
|
90
|
+
name: 'changeName',
|
|
91
|
+
message: 'Target change name (leave empty for latest change)',
|
|
92
|
+
required: false
|
|
93
|
+
}, {
|
|
94
|
+
type: 'text',
|
|
95
|
+
name: 'comment',
|
|
96
|
+
message: 'Tag comment (optional)',
|
|
97
|
+
required: false
|
|
98
|
+
});
|
|
99
|
+
const answers = await prompter.prompt(newArgv, questions);
|
|
100
|
+
const finalTagName = tagName || answers.tagName;
|
|
101
|
+
const changeName = answers.changeName;
|
|
102
|
+
const comment = answers.comment;
|
|
103
|
+
try {
|
|
104
|
+
if (argv.package || !pkg.isInModule()) {
|
|
105
|
+
const moduleMap = pkg.getModuleMap();
|
|
106
|
+
const module = moduleMap[packageName];
|
|
107
|
+
if (!module) {
|
|
108
|
+
throw errors.MODULE_NOT_FOUND({ name: packageName });
|
|
109
|
+
}
|
|
110
|
+
const workspacePath = pkg.getWorkspacePath();
|
|
111
|
+
const absoluteModulePath = path.resolve(workspacePath, module.path);
|
|
112
|
+
const originalCwd = process.cwd();
|
|
113
|
+
process.chdir(absoluteModulePath);
|
|
114
|
+
try {
|
|
115
|
+
const modulePkg = new LaunchQLPackage(absoluteModulePath);
|
|
116
|
+
modulePkg.addTag(finalTagName.trim(), changeName?.trim() || undefined, comment?.trim() || undefined);
|
|
117
|
+
log.info(`Successfully added tag '${finalTagName}' to ${changeName || 'latest change'} in package '${packageName}'`);
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
process.chdir(originalCwd);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
pkg.addTag(finalTagName.trim(), changeName?.trim() || undefined, comment?.trim() || undefined);
|
|
125
|
+
log.info(`Successfully added tag '${finalTagName}' to ${changeName || 'latest change'}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
log.error(`Failed to add tag: ${error instanceof Error ? error.message : String(error)}`);
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
return newArgv;
|
|
133
|
+
};
|