pgpm 0.2.18 → 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/README.md +12 -4
- 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 +10 -7
- 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,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,6 +1,6 @@
|
|
|
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",
|
|
@@ -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.
|
|
48
|
+
"@launchql/core": "^2.17.8",
|
|
49
|
+
"@launchql/env": "^2.5.8",
|
|
49
50
|
"@launchql/logger": "^1.1.13",
|
|
50
|
-
"@launchql/
|
|
51
|
-
"
|
|
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.
|
|
57
|
+
"pg-cache": "^1.4.10",
|
|
56
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() {
|
package/utils/index.d.ts
CHANGED
package/utils/index.js
CHANGED
|
@@ -20,3 +20,6 @@ __exportStar(require("./display"), exports);
|
|
|
20
20
|
__exportStar(require("./cli-error"), exports);
|
|
21
21
|
__exportStar(require("./deployed-changes"), exports);
|
|
22
22
|
__exportStar(require("./module-utils"), exports);
|
|
23
|
+
__exportStar(require("./npm-version"), exports);
|
|
24
|
+
__exportStar(require("./update-check"), exports);
|
|
25
|
+
__exportStar(require("./update-config"), exports);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.compareVersions = void 0;
|
|
7
|
+
exports.fetchLatestVersion = fetchLatestVersion;
|
|
8
|
+
const child_process_1 = require("child_process");
|
|
9
|
+
const semver_1 = __importDefault(require("semver"));
|
|
10
|
+
const util_1 = require("util");
|
|
11
|
+
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
12
|
+
async function fetchLatestVersion(pkgName, timeoutMs = 5000) {
|
|
13
|
+
try {
|
|
14
|
+
const result = await execFileAsync('npm', ['view', pkgName, 'version', '--json'], {
|
|
15
|
+
timeout: timeoutMs,
|
|
16
|
+
windowsHide: true,
|
|
17
|
+
maxBuffer: 1024 * 1024
|
|
18
|
+
});
|
|
19
|
+
const stdout = typeof result === 'string'
|
|
20
|
+
? result
|
|
21
|
+
: result?.stdout ?? '';
|
|
22
|
+
const parsed = parseVersionOutput(stdout);
|
|
23
|
+
return parsed ?? null;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const parseVersionOutput = (raw) => {
|
|
30
|
+
const trimmed = raw.trim();
|
|
31
|
+
if (!trimmed.length)
|
|
32
|
+
return null;
|
|
33
|
+
try {
|
|
34
|
+
const parsed = JSON.parse(trimmed);
|
|
35
|
+
if (typeof parsed === 'string')
|
|
36
|
+
return parsed;
|
|
37
|
+
if (Array.isArray(parsed) && parsed.length) {
|
|
38
|
+
return String(parsed[parsed.length - 1]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// fall through to plain string parse
|
|
43
|
+
}
|
|
44
|
+
return trimmed || null;
|
|
45
|
+
};
|
|
46
|
+
const compareVersions = (current, latest) => {
|
|
47
|
+
const currentSemver = semver_1.default.coerce(current);
|
|
48
|
+
const latestSemver = semver_1.default.coerce(latest);
|
|
49
|
+
if (currentSemver && latestSemver) {
|
|
50
|
+
return semver_1.default.compare(currentSemver, latestSemver);
|
|
51
|
+
}
|
|
52
|
+
return current.localeCompare(latest);
|
|
53
|
+
};
|
|
54
|
+
exports.compareVersions = compareVersions;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { UpdateCheckConfig } from '@launchql/types';
|
|
2
|
+
import { UpdateConfigOptions } from './update-config';
|
|
3
|
+
export interface CheckForUpdatesOptions extends UpdateConfigOptions {
|
|
4
|
+
pkgName?: string;
|
|
5
|
+
pkgVersion?: string;
|
|
6
|
+
command?: string;
|
|
7
|
+
now?: number;
|
|
8
|
+
updateCommand?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function checkForUpdates(options?: CheckForUpdatesOptions): Promise<UpdateCheckConfig | null>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkForUpdates = checkForUpdates;
|
|
4
|
+
const logger_1 = require("@launchql/logger");
|
|
5
|
+
const types_1 = require("@launchql/types");
|
|
6
|
+
const package_1 = require("../package");
|
|
7
|
+
const npm_version_1 = require("./npm-version");
|
|
8
|
+
const update_config_1 = require("./update-config");
|
|
9
|
+
const log = new logger_1.Logger('update-check');
|
|
10
|
+
const shouldSkip = (command) => {
|
|
11
|
+
if (process.env.PGPM_SKIP_UPDATE_CHECK)
|
|
12
|
+
return true;
|
|
13
|
+
if (process.env.CI === 'true')
|
|
14
|
+
return true;
|
|
15
|
+
if (command === 'update')
|
|
16
|
+
return true;
|
|
17
|
+
return false;
|
|
18
|
+
};
|
|
19
|
+
async function checkForUpdates(options = {}) {
|
|
20
|
+
const { pkgName = types_1.UPDATE_PACKAGE_NAME, pkgVersion = (0, package_1.readAndParsePackageJson)().version, command, now = Date.now(), key = types_1.UPDATE_CHECK_APPSTASH_KEY, toolName, baseDir } = options;
|
|
21
|
+
if (shouldSkip(command)) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const existing = await (0, update_config_1.readUpdateConfig)({ toolName, baseDir, key });
|
|
26
|
+
let latestKnownVersion = existing?.latestKnownVersion ?? pkgVersion;
|
|
27
|
+
const needsCheck = (0, update_config_1.shouldCheck)(now, existing?.lastCheckedAt, types_1.UPDATE_CHECK_TTL_MS);
|
|
28
|
+
if (needsCheck) {
|
|
29
|
+
const fetched = await (0, npm_version_1.fetchLatestVersion)(pkgName);
|
|
30
|
+
if (fetched) {
|
|
31
|
+
latestKnownVersion = fetched;
|
|
32
|
+
}
|
|
33
|
+
await (0, update_config_1.writeUpdateConfig)({
|
|
34
|
+
lastCheckedAt: now,
|
|
35
|
+
latestKnownVersion
|
|
36
|
+
}, { toolName, baseDir, key });
|
|
37
|
+
}
|
|
38
|
+
const comparison = (0, npm_version_1.compareVersions)(pkgVersion, latestKnownVersion);
|
|
39
|
+
const isOutdated = comparison < 0;
|
|
40
|
+
if (isOutdated) {
|
|
41
|
+
const defaultUpdateCommand = pkgName === types_1.UPDATE_PACKAGE_NAME
|
|
42
|
+
? 'Run pgpm update to upgrade.'
|
|
43
|
+
: `Run npm i -g ${pkgName}@latest to upgrade.`;
|
|
44
|
+
const updateInstruction = options.updateCommand ?? defaultUpdateCommand;
|
|
45
|
+
log.warn(`A new version of ${pkgName} is available (current ${pkgVersion}, latest ${latestKnownVersion}). ${updateInstruction}`);
|
|
46
|
+
await (0, update_config_1.writeUpdateConfig)({
|
|
47
|
+
lastCheckedAt: now,
|
|
48
|
+
latestKnownVersion
|
|
49
|
+
}, { toolName, baseDir, key });
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
lastCheckedAt: now,
|
|
53
|
+
latestKnownVersion
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
log.debug('Update check skipped due to error:', error);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { UpdateCheckConfig } from '@launchql/types';
|
|
2
|
+
export interface UpdateConfigOptions {
|
|
3
|
+
toolName?: string;
|
|
4
|
+
baseDir?: string;
|
|
5
|
+
key?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const shouldCheck: (now: number, lastCheckedAt: number | undefined, ttlMs: number) => boolean;
|
|
8
|
+
export declare function readUpdateConfig(options?: UpdateConfigOptions): Promise<UpdateCheckConfig | null>;
|
|
9
|
+
export declare function writeUpdateConfig(config: UpdateCheckConfig, options?: UpdateConfigOptions): Promise<void>;
|
|
10
|
+
export declare const resolveUpdateConfigPath: (options?: UpdateConfigOptions) => string;
|