pgpm 0.2.17 → 0.3.0
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 +1 -1
- package/README.md +44 -36
- package/commands/cache.d.ts +3 -0
- package/commands/cache.js +32 -0
- package/commands/init/index.d.ts +1 -0
- package/commands/init/index.js +25 -20
- package/commands/init/module.js +19 -25
- package/commands/init/workspace.js +25 -29
- package/commands/update.d.ts +3 -0
- package/commands/update.js +69 -0
- package/commands.js +15 -1
- package/esm/commands/cache.js +30 -0
- package/esm/commands/init/index.js +23 -20
- package/esm/commands/init/module.js +21 -27
- package/esm/commands/init/workspace.js +26 -30
- package/esm/commands/update.js +67 -0
- package/esm/commands.js +15 -1
- package/esm/index.js +1 -0
- package/esm/utils/display.js +3 -1
- package/esm/utils/index.js +3 -0
- package/esm/utils/npm-version.js +46 -0
- package/esm/utils/update-check.js +57 -0
- package/esm/utils/update-config.js +50 -0
- package/index.d.ts +1 -0
- package/index.js +3 -1
- package/package.json +15 -12
- package/utils/display.d.ts +1 -1
- package/utils/display.js +3 -1
- package/utils/index.d.ts +3 -0
- package/utils/index.js +3 -0
- package/utils/npm-version.d.ts +2 -0
- package/utils/npm-version.js +54 -0
- package/utils/update-check.d.ts +10 -0
- package/utils/update-check.js +60 -0
- package/utils/update-config.d.ts +10 -0
- package/utils/update-config.js +60 -0
|
@@ -1,42 +1,45 @@
|
|
|
1
1
|
import runModuleSetup from './module';
|
|
2
2
|
import runWorkspaceSetup from './workspace';
|
|
3
|
-
const
|
|
3
|
+
export const createInitUsageText = (binaryName, productLabel) => {
|
|
4
|
+
const displayName = productLabel ?? binaryName;
|
|
5
|
+
return `
|
|
4
6
|
Init Command:
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
${binaryName} init [OPTIONS] [workspace]
|
|
7
9
|
|
|
8
|
-
Initialize
|
|
10
|
+
Initialize ${displayName} workspace or module.
|
|
9
11
|
|
|
10
12
|
Options:
|
|
11
13
|
--help, -h Show this help message
|
|
12
|
-
--workspace Initialize workspace instead of module
|
|
13
14
|
--cwd <directory> Working directory (default: current directory)
|
|
14
|
-
--repo <repo>
|
|
15
|
-
--template-path <path>
|
|
16
|
-
--from-branch <branch>
|
|
15
|
+
--repo <repo> Template repo (default: https://github.com/launchql/pgpm-boilerplates.git)
|
|
16
|
+
--template-path <path> Template sub-path (default: workspace/module) or local path override
|
|
17
|
+
--from-branch <branch> Branch/tag to use when cloning repo
|
|
17
18
|
|
|
18
19
|
Examples:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
${binaryName} init Initialize new module in existing workspace
|
|
21
|
+
${binaryName} init workspace Initialize new workspace
|
|
22
|
+
${binaryName} init --repo owner/repo Use templates from GitHub repository
|
|
23
|
+
${binaryName} init --template-path ./custom-templates Use templates from local path
|
|
24
|
+
${binaryName} init --repo owner/repo --from-branch develop Use specific branch
|
|
24
25
|
`;
|
|
26
|
+
};
|
|
25
27
|
export default async (argv, prompter, _options) => {
|
|
26
28
|
// Show usage if explicitly requested
|
|
27
29
|
if (argv.help || argv.h) {
|
|
28
|
-
console.log(
|
|
30
|
+
console.log(createInitUsageText('pgpm'));
|
|
29
31
|
process.exit(0);
|
|
30
32
|
}
|
|
31
33
|
return handlePromptFlow(argv, prompter);
|
|
32
34
|
};
|
|
33
35
|
async function handlePromptFlow(argv, prompter) {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
const firstArg = argv._?.[0] || undefined;
|
|
37
|
+
if (firstArg === 'workspace') {
|
|
38
|
+
const nextArgv = {
|
|
39
|
+
...argv,
|
|
40
|
+
_: (argv._ ?? []).slice(1)
|
|
41
|
+
};
|
|
42
|
+
return runWorkspaceSetup(nextArgv, prompter);
|
|
41
43
|
}
|
|
44
|
+
return runModuleSetup(argv, prompter);
|
|
42
45
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { LaunchQLPackage, sluggify } from '@launchql/core';
|
|
1
|
+
import { DEFAULT_TEMPLATE_REPO, DEFAULT_TEMPLATE_TOOL_NAME, LaunchQLPackage, sluggify } from '@launchql/core';
|
|
2
2
|
import { Logger } from '@launchql/logger';
|
|
3
|
-
import { errors
|
|
3
|
+
import { errors } from '@launchql/types';
|
|
4
4
|
const log = new Logger('module-init');
|
|
5
5
|
export default async function runModuleSetup(argv, prompter) {
|
|
6
|
-
const { email, username } = getGitConfigInfo();
|
|
7
6
|
const { cwd = process.cwd() } = argv;
|
|
8
7
|
const project = new LaunchQLPackage(cwd);
|
|
9
8
|
if (!project.workspacePath) {
|
|
@@ -17,7 +16,7 @@ export default async function runModuleSetup(argv, prompter) {
|
|
|
17
16
|
const availExtensions = project.getAvailableModules();
|
|
18
17
|
const moduleQuestions = [
|
|
19
18
|
{
|
|
20
|
-
name: '
|
|
19
|
+
name: 'moduleName',
|
|
21
20
|
message: 'Enter the module name',
|
|
22
21
|
required: true,
|
|
23
22
|
type: 'text',
|
|
@@ -32,36 +31,31 @@ export default async function runModuleSetup(argv, prompter) {
|
|
|
32
31
|
},
|
|
33
32
|
];
|
|
34
33
|
const answers = await prompter.prompt(argv, moduleQuestions);
|
|
35
|
-
const modName = sluggify(answers.
|
|
34
|
+
const modName = sluggify(answers.moduleName);
|
|
35
|
+
// Avoid overlapping readline listeners with create-gen-app's prompts.
|
|
36
|
+
prompter.close();
|
|
36
37
|
const extensions = answers.extensions
|
|
37
38
|
.filter((opt) => opt.selected)
|
|
38
39
|
.map((opt) => opt.name);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
templateSource = {
|
|
43
|
-
type: 'github',
|
|
44
|
-
path: argv.repo,
|
|
45
|
-
branch: argv.fromBranch
|
|
46
|
-
};
|
|
47
|
-
log.info(`Loading templates from GitHub repository: ${argv.repo}`);
|
|
48
|
-
}
|
|
49
|
-
else if (argv.templatePath) {
|
|
50
|
-
templateSource = {
|
|
51
|
-
type: 'local',
|
|
52
|
-
path: argv.templatePath
|
|
53
|
-
};
|
|
54
|
-
log.info(`Loading templates from local path: ${argv.templatePath}`);
|
|
55
|
-
}
|
|
56
|
-
project.initModule({
|
|
40
|
+
const templateRepo = argv.repo ?? DEFAULT_TEMPLATE_REPO;
|
|
41
|
+
const templatePath = argv.templatePath;
|
|
42
|
+
const templateAnswers = {
|
|
57
43
|
...argv,
|
|
58
44
|
...answers,
|
|
45
|
+
moduleName: modName,
|
|
46
|
+
packageIdentifier: argv.packageIdentifier || modName
|
|
47
|
+
};
|
|
48
|
+
await project.initModule({
|
|
59
49
|
name: modName,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
USEREMAIL: email,
|
|
50
|
+
description: answers.description || modName,
|
|
51
|
+
author: answers.author || modName,
|
|
63
52
|
extensions,
|
|
64
|
-
|
|
53
|
+
templateRepo,
|
|
54
|
+
templatePath,
|
|
55
|
+
branch: argv.fromBranch,
|
|
56
|
+
toolName: DEFAULT_TEMPLATE_TOOL_NAME,
|
|
57
|
+
answers: templateAnswers,
|
|
58
|
+
noTty: Boolean(argv.noTty || argv['no-tty'] || process.env.CI === 'true')
|
|
65
59
|
});
|
|
66
60
|
log.success(`Initialized module: ${modName}`);
|
|
67
61
|
return { ...argv, ...answers };
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { sluggify } from '@launchql/core';
|
|
1
|
+
import { DEFAULT_TEMPLATE_REPO, DEFAULT_TEMPLATE_TOOL_NAME, scaffoldTemplate, sluggify } from '@launchql/core';
|
|
2
2
|
import { Logger } from '@launchql/logger';
|
|
3
|
-
// @ts-ignore - TypeScript module resolution issue with @launchql/templatizer
|
|
4
|
-
import { loadTemplates, workspaceTemplate, writeRenderedTemplates } from '@launchql/templatizer';
|
|
5
|
-
import { mkdirSync } from 'fs';
|
|
6
3
|
import path from 'path';
|
|
7
4
|
const log = new Logger('workspace-init');
|
|
8
5
|
export default async function runWorkspaceSetup(argv, prompter) {
|
|
@@ -11,36 +8,35 @@ export default async function runWorkspaceSetup(argv, prompter) {
|
|
|
11
8
|
name: 'name',
|
|
12
9
|
message: 'Enter workspace name',
|
|
13
10
|
required: true,
|
|
14
|
-
type: 'text'
|
|
11
|
+
type: 'text'
|
|
15
12
|
}
|
|
16
13
|
];
|
|
17
14
|
const answers = await prompter.prompt(argv, workspaceQuestions);
|
|
18
|
-
const { cwd } = argv;
|
|
15
|
+
const { cwd = process.cwd() } = argv;
|
|
19
16
|
const targetPath = path.join(cwd, sluggify(answers.name));
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
writeRenderedTemplates(templates, targetPath, { ...argv, ...answers });
|
|
17
|
+
// Prevent double-echoed keystrokes by closing our prompter before template prompts.
|
|
18
|
+
prompter.close();
|
|
19
|
+
const templateRepo = argv.repo ?? DEFAULT_TEMPLATE_REPO;
|
|
20
|
+
const templatePath = argv.templatePath ?? 'workspace';
|
|
21
|
+
const scaffoldResult = await scaffoldTemplate({
|
|
22
|
+
type: 'workspace',
|
|
23
|
+
outputDir: targetPath,
|
|
24
|
+
templateRepo,
|
|
25
|
+
branch: argv.fromBranch,
|
|
26
|
+
templatePath,
|
|
27
|
+
answers: {
|
|
28
|
+
...argv,
|
|
29
|
+
...answers,
|
|
30
|
+
workspaceName: answers.name
|
|
31
|
+
},
|
|
32
|
+
toolName: DEFAULT_TEMPLATE_TOOL_NAME,
|
|
33
|
+
noTty: Boolean(argv.noTty || argv['no-tty'] || process.env.CI === 'true'),
|
|
34
|
+
cwd
|
|
35
|
+
});
|
|
36
|
+
const cacheMessage = scaffoldResult.cacheUsed
|
|
37
|
+
? `Using cached templates from ${scaffoldResult.templateDir}`
|
|
38
|
+
: `Fetched templates into ${scaffoldResult.templateDir}`;
|
|
39
|
+
log.success(cacheMessage);
|
|
44
40
|
log.success('Workspace templates rendered.');
|
|
45
41
|
return { ...argv, ...answers, cwd: targetPath };
|
|
46
42
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Logger } from '@launchql/logger';
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import { readAndParsePackageJson } from '../package';
|
|
4
|
+
import { fetchLatestVersion } from '../utils/npm-version';
|
|
5
|
+
import { cliExitWithError } from '../utils/cli-error';
|
|
6
|
+
const log = new Logger('update');
|
|
7
|
+
const updateUsageText = `
|
|
8
|
+
Update Command:
|
|
9
|
+
|
|
10
|
+
pgpm update [OPTIONS]
|
|
11
|
+
|
|
12
|
+
Install the latest version of pgpm from npm.
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
--help, -h Show this help message
|
|
16
|
+
--package <name> Override the package name (default: package.json name)
|
|
17
|
+
--registry <url> Use a custom npm registry
|
|
18
|
+
--dry-run Print the npm command without executing it
|
|
19
|
+
`;
|
|
20
|
+
const runNpmInstall = (pkgName, registry) => {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const args = ['install', '-g', pkgName];
|
|
23
|
+
if (registry) {
|
|
24
|
+
args.push('--registry', registry);
|
|
25
|
+
}
|
|
26
|
+
const child = spawn('npm', args, { stdio: 'inherit' });
|
|
27
|
+
child.on('error', reject);
|
|
28
|
+
child.on('exit', (code) => {
|
|
29
|
+
if (code === 0) {
|
|
30
|
+
resolve();
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
reject(new Error(`npm install exited with code ${code}`));
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
export default async (argv, _prompter, _options) => {
|
|
39
|
+
if (argv.help || argv.h) {
|
|
40
|
+
console.log(updateUsageText);
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
const pkgJson = readAndParsePackageJson();
|
|
44
|
+
const pkgName = argv.package || pkgJson.name || 'pgpm';
|
|
45
|
+
const registry = argv.registry;
|
|
46
|
+
const dryRun = Boolean(argv['dry-run']);
|
|
47
|
+
const npmCommand = `npm install -g ${pkgName}${registry ? ` --registry ${registry}` : ''}`;
|
|
48
|
+
if (dryRun) {
|
|
49
|
+
log.info(`[dry-run] ${npmCommand}`);
|
|
50
|
+
return argv;
|
|
51
|
+
}
|
|
52
|
+
log.info(`Running: ${npmCommand}`);
|
|
53
|
+
try {
|
|
54
|
+
await runNpmInstall(pkgName, registry);
|
|
55
|
+
const latest = await fetchLatestVersion(pkgName);
|
|
56
|
+
if (latest) {
|
|
57
|
+
log.success(`Successfully updated ${pkgName} to version ${latest}.`);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
log.success(`npm install completed for ${pkgName}.`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
await cliExitWithError(error instanceof Error ? error.message : String(error), { package: pkgName, registry });
|
|
65
|
+
}
|
|
66
|
+
return argv;
|
|
67
|
+
};
|
package/esm/commands.js
CHANGED
|
@@ -2,6 +2,7 @@ import { teardownPgPools } from 'pg-cache';
|
|
|
2
2
|
import add from './commands/add';
|
|
3
3
|
import adminUsers from './commands/admin-users';
|
|
4
4
|
import analyze from './commands/analyze';
|
|
5
|
+
import cache from './commands/cache';
|
|
5
6
|
import clear from './commands/clear';
|
|
6
7
|
import deploy from './commands/deploy';
|
|
7
8
|
import docker from './commands/docker';
|
|
@@ -14,6 +15,7 @@ import kill from './commands/kill';
|
|
|
14
15
|
import migrate from './commands/migrate';
|
|
15
16
|
import _package from './commands/package';
|
|
16
17
|
import plan from './commands/plan';
|
|
18
|
+
import updateCmd from './commands/update';
|
|
17
19
|
import remove from './commands/remove';
|
|
18
20
|
import renameCmd from './commands/rename';
|
|
19
21
|
import revert from './commands/revert';
|
|
@@ -22,6 +24,7 @@ import verify from './commands/verify';
|
|
|
22
24
|
import { readAndParsePackageJson } from './package';
|
|
23
25
|
import { extractFirst, usageText } from './utils';
|
|
24
26
|
import { cliExitWithError } from './utils/cli-error';
|
|
27
|
+
import { checkForUpdates } from './utils/update-check';
|
|
25
28
|
const withPgTeardown = (fn, skipTeardown = false) => async (...args) => {
|
|
26
29
|
try {
|
|
27
30
|
await fn(...args);
|
|
@@ -54,7 +57,9 @@ export const createPgpmCommandMap = (skipPgTeardown = false) => {
|
|
|
54
57
|
install: pgt(install),
|
|
55
58
|
migrate: pgt(migrate),
|
|
56
59
|
analyze: pgt(analyze),
|
|
57
|
-
rename: pgt(renameCmd)
|
|
60
|
+
rename: pgt(renameCmd),
|
|
61
|
+
cache,
|
|
62
|
+
update: updateCmd
|
|
58
63
|
};
|
|
59
64
|
};
|
|
60
65
|
export const commands = async (argv, prompter, options) => {
|
|
@@ -84,6 +89,15 @@ export const commands = async (argv, prompter, options) => {
|
|
|
84
89
|
]);
|
|
85
90
|
command = answer.command;
|
|
86
91
|
}
|
|
92
|
+
try {
|
|
93
|
+
await checkForUpdates({
|
|
94
|
+
command,
|
|
95
|
+
pkgVersion: readAndParsePackageJson().version
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// ignore update check failures
|
|
100
|
+
}
|
|
87
101
|
newArgv = await prompter.prompt(newArgv, [
|
|
88
102
|
{
|
|
89
103
|
type: 'text',
|
package/esm/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { readFileSync } from 'fs';
|
|
|
3
3
|
import { CLI } from 'inquirerer';
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
import { commands, createPgpmCommandMap } from './commands';
|
|
6
|
+
export { createInitUsageText } from './commands/init';
|
|
6
7
|
export { createPgpmCommandMap };
|
|
7
8
|
export { default as add } from './commands/add';
|
|
8
9
|
export { default as adminUsers } from './commands/admin-users';
|
package/esm/utils/display.js
CHANGED
|
@@ -21,6 +21,8 @@ export const usageText = `
|
|
|
21
21
|
plan Generate module deployment plans
|
|
22
22
|
package Package module for distribution
|
|
23
23
|
export Export database migrations from existing databases
|
|
24
|
+
update Update pgpm to the latest version
|
|
25
|
+
cache Manage cached templates (clean)
|
|
24
26
|
|
|
25
27
|
Database Administration:
|
|
26
28
|
kill Terminate database connections and optionally drop databases
|
|
@@ -50,7 +52,7 @@ export const usageText = `
|
|
|
50
52
|
|
|
51
53
|
Examples:
|
|
52
54
|
pgpm deploy --help Show deploy command options
|
|
53
|
-
pgpm init
|
|
55
|
+
pgpm init workspace Initialize new workspace
|
|
54
56
|
pgpm install @pgpm/base32 Install a database module
|
|
55
57
|
`;
|
|
56
58
|
export function displayUsage() {
|
package/esm/utils/index.js
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { execFile } from 'child_process';
|
|
2
|
+
import semver from 'semver';
|
|
3
|
+
import { promisify } from 'util';
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
export async function fetchLatestVersion(pkgName, timeoutMs = 5000) {
|
|
6
|
+
try {
|
|
7
|
+
const result = await execFileAsync('npm', ['view', pkgName, 'version', '--json'], {
|
|
8
|
+
timeout: timeoutMs,
|
|
9
|
+
windowsHide: true,
|
|
10
|
+
maxBuffer: 1024 * 1024
|
|
11
|
+
});
|
|
12
|
+
const stdout = typeof result === 'string'
|
|
13
|
+
? result
|
|
14
|
+
: result?.stdout ?? '';
|
|
15
|
+
const parsed = parseVersionOutput(stdout);
|
|
16
|
+
return parsed ?? null;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const parseVersionOutput = (raw) => {
|
|
23
|
+
const trimmed = raw.trim();
|
|
24
|
+
if (!trimmed.length)
|
|
25
|
+
return null;
|
|
26
|
+
try {
|
|
27
|
+
const parsed = JSON.parse(trimmed);
|
|
28
|
+
if (typeof parsed === 'string')
|
|
29
|
+
return parsed;
|
|
30
|
+
if (Array.isArray(parsed) && parsed.length) {
|
|
31
|
+
return String(parsed[parsed.length - 1]);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// fall through to plain string parse
|
|
36
|
+
}
|
|
37
|
+
return trimmed || null;
|
|
38
|
+
};
|
|
39
|
+
export const compareVersions = (current, latest) => {
|
|
40
|
+
const currentSemver = semver.coerce(current);
|
|
41
|
+
const latestSemver = semver.coerce(latest);
|
|
42
|
+
if (currentSemver && latestSemver) {
|
|
43
|
+
return semver.compare(currentSemver, latestSemver);
|
|
44
|
+
}
|
|
45
|
+
return current.localeCompare(latest);
|
|
46
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Logger } from '@launchql/logger';
|
|
2
|
+
import { UPDATE_CHECK_APPSTASH_KEY, UPDATE_CHECK_TTL_MS, UPDATE_PACKAGE_NAME } from '@launchql/types';
|
|
3
|
+
import { readAndParsePackageJson } from '../package';
|
|
4
|
+
import { compareVersions, fetchLatestVersion } from './npm-version';
|
|
5
|
+
import { readUpdateConfig, shouldCheck, writeUpdateConfig } from './update-config';
|
|
6
|
+
const log = new Logger('update-check');
|
|
7
|
+
const shouldSkip = (command) => {
|
|
8
|
+
if (process.env.PGPM_SKIP_UPDATE_CHECK)
|
|
9
|
+
return true;
|
|
10
|
+
if (process.env.CI === 'true')
|
|
11
|
+
return true;
|
|
12
|
+
if (command === 'update')
|
|
13
|
+
return true;
|
|
14
|
+
return false;
|
|
15
|
+
};
|
|
16
|
+
export async function checkForUpdates(options = {}) {
|
|
17
|
+
const { pkgName = UPDATE_PACKAGE_NAME, pkgVersion = readAndParsePackageJson().version, command, now = Date.now(), key = UPDATE_CHECK_APPSTASH_KEY, toolName, baseDir } = options;
|
|
18
|
+
if (shouldSkip(command)) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const existing = await readUpdateConfig({ toolName, baseDir, key });
|
|
23
|
+
let latestKnownVersion = existing?.latestKnownVersion ?? pkgVersion;
|
|
24
|
+
const needsCheck = shouldCheck(now, existing?.lastCheckedAt, UPDATE_CHECK_TTL_MS);
|
|
25
|
+
if (needsCheck) {
|
|
26
|
+
const fetched = await fetchLatestVersion(pkgName);
|
|
27
|
+
if (fetched) {
|
|
28
|
+
latestKnownVersion = fetched;
|
|
29
|
+
}
|
|
30
|
+
await writeUpdateConfig({
|
|
31
|
+
lastCheckedAt: now,
|
|
32
|
+
latestKnownVersion
|
|
33
|
+
}, { toolName, baseDir, key });
|
|
34
|
+
}
|
|
35
|
+
const comparison = compareVersions(pkgVersion, latestKnownVersion);
|
|
36
|
+
const isOutdated = comparison < 0;
|
|
37
|
+
if (isOutdated) {
|
|
38
|
+
const defaultUpdateCommand = pkgName === UPDATE_PACKAGE_NAME
|
|
39
|
+
? 'Run pgpm update to upgrade.'
|
|
40
|
+
: `Run npm i -g ${pkgName}@latest to upgrade.`;
|
|
41
|
+
const updateInstruction = options.updateCommand ?? defaultUpdateCommand;
|
|
42
|
+
log.warn(`A new version of ${pkgName} is available (current ${pkgVersion}, latest ${latestKnownVersion}). ${updateInstruction}`);
|
|
43
|
+
await writeUpdateConfig({
|
|
44
|
+
lastCheckedAt: now,
|
|
45
|
+
latestKnownVersion
|
|
46
|
+
}, { toolName, baseDir, key });
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
lastCheckedAt: now,
|
|
50
|
+
latestKnownVersion
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
log.debug('Update check skipped due to error:', error);
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { appstash, resolve as resolveAppstash } from 'appstash';
|
|
4
|
+
import { UPDATE_CHECK_APPSTASH_KEY } from '@launchql/types';
|
|
5
|
+
const defaultToolName = 'pgpm';
|
|
6
|
+
const getConfigPath = (options = {}) => {
|
|
7
|
+
const toolName = options.toolName ?? defaultToolName;
|
|
8
|
+
const dirs = appstash(toolName, {
|
|
9
|
+
ensure: true,
|
|
10
|
+
baseDir: options.baseDir
|
|
11
|
+
});
|
|
12
|
+
const configDir = resolveAppstash(dirs, 'config');
|
|
13
|
+
if (!fs.existsSync(configDir)) {
|
|
14
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
const fileName = `${(options.key ?? UPDATE_CHECK_APPSTASH_KEY).replace(/[^a-z0-9-_]/gi, '_')}.json`;
|
|
17
|
+
return path.join(configDir, fileName);
|
|
18
|
+
};
|
|
19
|
+
export const shouldCheck = (now, lastCheckedAt, ttlMs) => {
|
|
20
|
+
if (!lastCheckedAt)
|
|
21
|
+
return true;
|
|
22
|
+
return now - lastCheckedAt > ttlMs;
|
|
23
|
+
};
|
|
24
|
+
export async function readUpdateConfig(options = {}) {
|
|
25
|
+
const configPath = getConfigPath(options);
|
|
26
|
+
if (!fs.existsSync(configPath)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const contents = await fs.promises.readFile(configPath, 'utf8');
|
|
31
|
+
const parsed = JSON.parse(contents);
|
|
32
|
+
return parsed;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Corrupted config – clear it
|
|
36
|
+
try {
|
|
37
|
+
await fs.promises.rm(configPath, { force: true });
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// ignore
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export async function writeUpdateConfig(config, options = {}) {
|
|
46
|
+
const configPath = getConfigPath(options);
|
|
47
|
+
await fs.promises.writeFile(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
48
|
+
}
|
|
49
|
+
// Exposed for testing to locate the config path for a given namespace/baseDir
|
|
50
|
+
export const resolveUpdateConfigPath = (options = {}) => getConfigPath(options);
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { CLIOptions } from 'inquirerer';
|
|
3
3
|
import { createPgpmCommandMap } from './commands';
|
|
4
|
+
export { createInitUsageText } from './commands/init';
|
|
4
5
|
export { createPgpmCommandMap };
|
|
5
6
|
export { default as add } from './commands/add';
|
|
6
7
|
export { default as adminUsers } from './commands/admin-users';
|
package/index.js
CHANGED
|
@@ -18,12 +18,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
18
18
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
19
|
};
|
|
20
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.createPgpmCommandMap = void 0;
|
|
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.createPgpmCommandMap = exports.createInitUsageText = void 0;
|
|
22
22
|
const fs_1 = require("fs");
|
|
23
23
|
const inquirerer_1 = require("inquirerer");
|
|
24
24
|
const path_1 = require("path");
|
|
25
25
|
const commands_1 = require("./commands");
|
|
26
26
|
Object.defineProperty(exports, "createPgpmCommandMap", { enumerable: true, get: function () { return commands_1.createPgpmCommandMap; } });
|
|
27
|
+
var init_1 = require("./commands/init");
|
|
28
|
+
Object.defineProperty(exports, "createInitUsageText", { enumerable: true, get: function () { return init_1.createInitUsageText; } });
|
|
27
29
|
var add_1 = require("./commands/add");
|
|
28
30
|
Object.defineProperty(exports, "add", { enumerable: true, get: function () { return __importDefault(add_1).default; } });
|
|
29
31
|
var admin_users_1 = require("./commands/admin-users");
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pgpm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"author": "Dan Lynch <pyramation@gmail.com>",
|
|
5
5
|
"description": "PostgreSQL Package Manager - Database migration and package management CLI",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"module": "esm/index.js",
|
|
8
8
|
"types": "index.d.ts",
|
|
9
|
-
"homepage": "https://github.com/
|
|
9
|
+
"homepage": "https://github.com/constructive-io/constructive",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "public",
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
},
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
20
|
-
"url": "https://github.com/
|
|
20
|
+
"url": "https://github.com/constructive-io/constructive"
|
|
21
21
|
},
|
|
22
22
|
"bugs": {
|
|
23
|
-
"url": "https://github.com/
|
|
23
|
+
"url": "https://github.com/constructive-io/constructive/issues"
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
26
|
"clean": "makage clean",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"@types/minimist": "^1.2.5",
|
|
38
38
|
"@types/node": "^20.12.7",
|
|
39
39
|
"@types/pg": "^8.15.2",
|
|
40
|
+
"@types/semver": "^7.5.8",
|
|
40
41
|
"@types/shelljs": "^0.8.16",
|
|
41
42
|
"glob": "^13.0.0",
|
|
42
43
|
"makage": "^0.1.8",
|
|
@@ -44,16 +45,18 @@
|
|
|
44
45
|
"ts-node": "^10.9.2"
|
|
45
46
|
},
|
|
46
47
|
"dependencies": {
|
|
47
|
-
"@launchql/core": "^2.17.
|
|
48
|
-
"@launchql/env": "^2.5.
|
|
49
|
-
"@launchql/logger": "^1.1.
|
|
50
|
-
"@launchql/
|
|
51
|
-
"
|
|
48
|
+
"@launchql/core": "^2.17.8",
|
|
49
|
+
"@launchql/env": "^2.5.8",
|
|
50
|
+
"@launchql/logger": "^1.1.13",
|
|
51
|
+
"@launchql/types": "^2.9.0",
|
|
52
|
+
"appstash": "^0.2.4",
|
|
53
|
+
"create-gen-app": "^0.3.1",
|
|
52
54
|
"inquirerer": "^2.1.8",
|
|
53
55
|
"js-yaml": "^4.1.0",
|
|
54
56
|
"minimist": "^1.2.8",
|
|
55
|
-
"pg-cache": "^1.4.
|
|
56
|
-
"pg-env": "^1.1.
|
|
57
|
+
"pg-cache": "^1.4.10",
|
|
58
|
+
"pg-env": "^1.1.8",
|
|
59
|
+
"semver": "^7.6.2",
|
|
57
60
|
"shelljs": "^0.10.0",
|
|
58
61
|
"yanse": "^0.1.5"
|
|
59
62
|
},
|
|
@@ -69,5 +72,5 @@
|
|
|
69
72
|
"pg",
|
|
70
73
|
"pgsql"
|
|
71
74
|
],
|
|
72
|
-
"gitHead": "
|
|
75
|
+
"gitHead": "6a35ff5a2c49e0c4cf1ec9abdd81b62c57d621e9"
|
|
73
76
|
}
|
package/utils/display.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare function displayVersion(): void;
|
|
2
|
-
export declare const usageText = "\n Usage: pgpm <command> [options]\n \n Core Database Operations:\n add Add database changes to plans and create SQL files\n deploy Deploy database changes and migrations\n verify Verify database state and migrations\n revert Revert database changes and migrations\n \n Project Management:\n init Initialize workspace or module\n extension Manage module dependencies\n plan Generate module deployment plans\n package Package module for distribution\n export Export database migrations from existing databases\n \n Database Administration:\n kill Terminate database connections and optionally drop databases\n install Install database modules\n tag Add tags to changes for versioning\n clear Clear database state\n remove Remove database changes\n analyze Analyze database structure\n rename Rename database changes\n admin-users Manage admin users\n \n Migration Tools:\n migrate Migration management subcommands\n init Initialize migration tracking\n status Show migration status\n list List all changes\n deps Show change dependencies\n \n Global Options:\n -h, --help Display this help information\n -v, --version Display version information\n --cwd <directory> Working directory (default: current directory)\n \n Individual Command Help:\n pgpm <command> --help Display detailed help for specific command\n pgpm <command> -h Display detailed help for specific command\n \n Examples:\n pgpm deploy --help Show deploy command options\n pgpm init
|
|
2
|
+
export declare const usageText = "\n Usage: pgpm <command> [options]\n \n Core Database Operations:\n add Add database changes to plans and create SQL files\n deploy Deploy database changes and migrations\n verify Verify database state and migrations\n revert Revert database changes and migrations\n \n Project Management:\n init Initialize workspace or module\n extension Manage module dependencies\n plan Generate module deployment plans\n package Package module for distribution\n export Export database migrations from existing databases\n update Update pgpm to the latest version\n cache Manage cached templates (clean)\n \n Database Administration:\n kill Terminate database connections and optionally drop databases\n install Install database modules\n tag Add tags to changes for versioning\n clear Clear database state\n remove Remove database changes\n analyze Analyze database structure\n rename Rename database changes\n admin-users Manage admin users\n \n Migration Tools:\n migrate Migration management subcommands\n init Initialize migration tracking\n status Show migration status\n list List all changes\n deps Show change dependencies\n \n Global Options:\n -h, --help Display this help information\n -v, --version Display version information\n --cwd <directory> Working directory (default: current directory)\n \n Individual Command Help:\n pgpm <command> --help Display detailed help for specific command\n pgpm <command> -h Display detailed help for specific command\n \n Examples:\n pgpm deploy --help Show deploy command options\n pgpm init workspace Initialize new workspace\n pgpm install @pgpm/base32 Install a database module\n ";
|
|
3
3
|
export declare function displayUsage(): void;
|
package/utils/display.js
CHANGED
|
@@ -29,6 +29,8 @@ exports.usageText = `
|
|
|
29
29
|
plan Generate module deployment plans
|
|
30
30
|
package Package module for distribution
|
|
31
31
|
export Export database migrations from existing databases
|
|
32
|
+
update Update pgpm to the latest version
|
|
33
|
+
cache Manage cached templates (clean)
|
|
32
34
|
|
|
33
35
|
Database Administration:
|
|
34
36
|
kill Terminate database connections and optionally drop databases
|
|
@@ -58,7 +60,7 @@ exports.usageText = `
|
|
|
58
60
|
|
|
59
61
|
Examples:
|
|
60
62
|
pgpm deploy --help Show deploy command options
|
|
61
|
-
pgpm init
|
|
63
|
+
pgpm init workspace Initialize new workspace
|
|
62
64
|
pgpm install @pgpm/base32 Install a database module
|
|
63
65
|
`;
|
|
64
66
|
function displayUsage() {
|