pgpm 3.1.1 → 3.2.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 +3 -1
- package/commands/init/index.js +128 -36
- package/commands/init/workspace.js +4 -3
- package/esm/commands/init/index.js +128 -36
- package/esm/commands/init/workspace.js +4 -3
- package/esm/index.js +6 -1
- package/index.js +6 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -70,6 +70,8 @@ Here are some useful commands for reference:
|
|
|
70
70
|
|
|
71
71
|
- `pgpm init` - Initialize a new module
|
|
72
72
|
- `pgpm init workspace` - Initialize a new workspace
|
|
73
|
+
- `pgpm init --template <path>` - Initialize using a full template path (e.g., `pnpm/module`)
|
|
74
|
+
- `pgpm init -w` - Create a workspace first, then create the module inside it
|
|
73
75
|
|
|
74
76
|
### Development Setup
|
|
75
77
|
|
|
@@ -142,7 +144,7 @@ pgpm deploy --createdb
|
|
|
142
144
|
|
|
143
145
|
## 🧰 Templates, Caching, and Updates
|
|
144
146
|
|
|
145
|
-
- `pgpm init` now scaffolds workspaces/modules from `https://github.com/constructive-io/pgpm-boilerplates.git` using `create-gen-app` with a one-week cache (stored under `~/.pgpm/cache/repos`). Override with `--repo`, `--from-branch`, and `--template
|
|
147
|
+
- `pgpm init` now scaffolds workspaces/modules from `https://github.com/constructive-io/pgpm-boilerplates.git` using `create-gen-app` with a one-week cache (stored under `~/.pgpm/cache/repos`). Override with `--repo`, `--from-branch`, and `--template`, or use a local template path.
|
|
146
148
|
- Run `pgpm cache clean` to wipe the cached boilerplates if you need a fresh pull.
|
|
147
149
|
- The CLI performs a lightweight npm version check at most once per week (skipped in CI or when `PGPM_SKIP_UPDATE_CHECK` is set). Use `pgpm update` to upgrade to the latest release.
|
|
148
150
|
|
package/commands/init/index.js
CHANGED
|
@@ -32,16 +32,20 @@ Options:
|
|
|
32
32
|
--repo <repo> Template repo (default: https://github.com/constructive-io/pgpm-boilerplates.git)
|
|
33
33
|
--from-branch <branch> Branch/tag to use when cloning repo
|
|
34
34
|
--dir <variant> Template variant directory (e.g., supabase, drizzle)
|
|
35
|
+
--template, -t <path> Full template path (e.g., pnpm/module) - combines dir and fromPath
|
|
35
36
|
--boilerplate Prompt to select from available boilerplates
|
|
37
|
+
--create-workspace, -w Create a workspace first, then create the module inside it
|
|
36
38
|
|
|
37
39
|
Examples:
|
|
38
40
|
${binaryName} init Initialize new module (default)
|
|
39
41
|
${binaryName} init workspace Initialize new workspace
|
|
40
42
|
${binaryName} init module Initialize new module explicitly
|
|
41
43
|
${binaryName} init workspace --dir <variant> Use variant templates
|
|
44
|
+
${binaryName} init --template pnpm/module Use full template path (dir + type)
|
|
42
45
|
${binaryName} init --boilerplate Select from available boilerplates
|
|
43
46
|
${binaryName} init --repo owner/repo Use templates from GitHub repository
|
|
44
47
|
${binaryName} init --repo owner/repo --from-branch develop Use specific branch
|
|
48
|
+
${binaryName} init --dir pnpm -w Create pnpm workspace + module in one command
|
|
45
49
|
`;
|
|
46
50
|
};
|
|
47
51
|
exports.createInitUsageText = createInitUsageText;
|
|
@@ -57,11 +61,28 @@ async function handleInit(argv, prompter) {
|
|
|
57
61
|
const { cwd = process.cwd() } = argv;
|
|
58
62
|
const templateRepo = argv.repo ?? core_1.DEFAULT_TEMPLATE_REPO;
|
|
59
63
|
const branch = argv.fromBranch;
|
|
60
|
-
const dir = argv.dir;
|
|
61
64
|
const noTty = Boolean(argv.noTty || argv['no-tty'] || process.env.CI === 'true');
|
|
62
65
|
const useBoilerplatePrompt = Boolean(argv.boilerplate);
|
|
66
|
+
const createWorkspace = Boolean(argv.createWorkspace || argv['create-workspace'] || argv.w);
|
|
63
67
|
// Get fromPath from first positional arg
|
|
64
68
|
const positionalFromPath = argv._?.[0];
|
|
69
|
+
// Handle --template flag: parses "dir/fromPath" format and extracts both components
|
|
70
|
+
// When --template is provided, it takes precedence over --dir and positional fromPath
|
|
71
|
+
const templateArg = argv.template;
|
|
72
|
+
let dir = argv.dir;
|
|
73
|
+
let templateFromPath;
|
|
74
|
+
if (templateArg) {
|
|
75
|
+
// Parse template path like "pnpm/module" into dir="pnpm" and fromPath="module"
|
|
76
|
+
const slashIndex = templateArg.indexOf('/');
|
|
77
|
+
if (slashIndex > 0) {
|
|
78
|
+
dir = templateArg.substring(0, slashIndex);
|
|
79
|
+
templateFromPath = templateArg.substring(slashIndex + 1);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// No slash - treat the whole thing as fromPath (e.g., --template workspace)
|
|
83
|
+
templateFromPath = templateArg;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
65
86
|
// Handle --boilerplate flag: separate path from regular init
|
|
66
87
|
if (useBoilerplatePrompt) {
|
|
67
88
|
return handleBoilerplateInit(argv, prompter, {
|
|
@@ -73,10 +94,10 @@ async function handleInit(argv, prompter) {
|
|
|
73
94
|
cwd,
|
|
74
95
|
});
|
|
75
96
|
}
|
|
76
|
-
// Regular init path: default to 'module'
|
|
77
|
-
const fromPath = positionalFromPath || 'module';
|
|
78
|
-
// Track if user explicitly requested module (e.g., `pgpm init module`)
|
|
79
|
-
const wasExplicitModuleRequest = positionalFromPath === 'module';
|
|
97
|
+
// Regular init path: --template takes precedence, then positional arg, then default to 'module'
|
|
98
|
+
const fromPath = templateFromPath || positionalFromPath || 'module';
|
|
99
|
+
// Track if user explicitly requested module (e.g., `pgpm init module` or `--template pnpm/module`)
|
|
100
|
+
const wasExplicitModuleRequest = positionalFromPath === 'module' || templateFromPath === 'module';
|
|
80
101
|
// Inspect the template to get its type
|
|
81
102
|
const inspection = (0, core_1.inspectTemplate)({
|
|
82
103
|
fromPath,
|
|
@@ -107,6 +128,7 @@ async function handleInit(argv, prompter) {
|
|
|
107
128
|
noTty,
|
|
108
129
|
cwd,
|
|
109
130
|
requiresWorkspace: inspection.config?.requiresWorkspace,
|
|
131
|
+
createWorkspace,
|
|
110
132
|
}, wasExplicitModuleRequest);
|
|
111
133
|
}
|
|
112
134
|
async function handleBoilerplateInit(argv, prompter, ctx) {
|
|
@@ -235,12 +257,47 @@ async function handleWorkspaceInit(argv, prompter, ctx) {
|
|
|
235
257
|
process.stdout.write(`\n✨ Enjoy!\n\ncd ./${dirName}\n`);
|
|
236
258
|
return { ...argv, ...answers, cwd: targetPath };
|
|
237
259
|
}
|
|
260
|
+
function resolveWorkspaceTemplateRepo(options) {
|
|
261
|
+
const { templateRepo, branch, dir, workspaceType, cwd } = options;
|
|
262
|
+
// Determine the dir to use for workspace template
|
|
263
|
+
// If dir is specified, use it; otherwise use the workspaceType as the dir variant
|
|
264
|
+
const workspaceDir = dir || workspaceType;
|
|
265
|
+
// Try to find workspace template in the specified repo
|
|
266
|
+
try {
|
|
267
|
+
const inspection = (0, core_1.inspectTemplate)({
|
|
268
|
+
fromPath: 'workspace',
|
|
269
|
+
templateRepo,
|
|
270
|
+
branch,
|
|
271
|
+
dir: workspaceDir,
|
|
272
|
+
toolName: core_1.DEFAULT_TEMPLATE_TOOL_NAME,
|
|
273
|
+
cwd,
|
|
274
|
+
});
|
|
275
|
+
// If we found a valid workspace template, use the specified repo
|
|
276
|
+
if (inspection.config?.type === 'workspace') {
|
|
277
|
+
return {
|
|
278
|
+
repo: templateRepo,
|
|
279
|
+
branch,
|
|
280
|
+
dir: workspaceDir,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
// Template not found in specified repo, fall through to default
|
|
286
|
+
}
|
|
287
|
+
// Fall back to default template repo
|
|
288
|
+
// Use the workspaceType as the dir variant (pgpm or pnpm)
|
|
289
|
+
return {
|
|
290
|
+
repo: core_1.DEFAULT_TEMPLATE_REPO,
|
|
291
|
+
branch: undefined, // Use default branch for default repo
|
|
292
|
+
dir: workspaceType,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
238
295
|
async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest = false) {
|
|
239
296
|
// Determine workspace requirement (defaults to 'pgpm' for backward compatibility)
|
|
240
297
|
const workspaceType = ctx.requiresWorkspace ?? 'pgpm';
|
|
241
298
|
// Whether this is a pgpm-managed template (creates pgpm.plan, .control files)
|
|
242
299
|
const isPgpmTemplate = workspaceType === 'pgpm';
|
|
243
|
-
|
|
300
|
+
let project = new core_1.PgpmPackage(ctx.cwd);
|
|
244
301
|
// Track resolved workspace path for both pgpm and non-pgpm workspace types
|
|
245
302
|
let resolvedWorkspacePath;
|
|
246
303
|
let workspaceTypeName = '';
|
|
@@ -256,39 +313,74 @@ async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest =
|
|
|
256
313
|
}
|
|
257
314
|
if (!resolvedWorkspacePath) {
|
|
258
315
|
const noTty = Boolean(argv.noTty || argv['no-tty'] || process.env.CI === 'true');
|
|
259
|
-
//
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
316
|
+
// Handle --create-workspace flag: create workspace first, then module
|
|
317
|
+
if (ctx.createWorkspace && (workspaceType === 'pgpm' || workspaceType === 'pnpm')) {
|
|
318
|
+
// Resolve workspace template repo with fallback to default
|
|
319
|
+
const workspaceTemplateConfig = resolveWorkspaceTemplateRepo({
|
|
320
|
+
templateRepo: ctx.templateRepo,
|
|
321
|
+
branch: ctx.branch,
|
|
322
|
+
dir: ctx.dir,
|
|
323
|
+
workspaceType,
|
|
324
|
+
cwd: ctx.cwd,
|
|
325
|
+
});
|
|
326
|
+
// Create workspace first
|
|
327
|
+
const workspaceResult = await handleWorkspaceInit(argv, prompter, {
|
|
328
|
+
fromPath: 'workspace',
|
|
329
|
+
templateRepo: workspaceTemplateConfig.repo,
|
|
330
|
+
branch: workspaceTemplateConfig.branch,
|
|
331
|
+
dir: workspaceTemplateConfig.dir,
|
|
332
|
+
noTty: ctx.noTty,
|
|
333
|
+
cwd: ctx.cwd,
|
|
334
|
+
});
|
|
335
|
+
// Update context to point to new workspace and continue with module creation
|
|
336
|
+
const newCwd = workspaceResult.cwd;
|
|
337
|
+
project = new core_1.PgpmPackage(newCwd);
|
|
338
|
+
// Re-resolve workspace path with new cwd
|
|
339
|
+
if (workspaceType === 'pgpm') {
|
|
340
|
+
resolvedWorkspacePath = project.workspacePath;
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
resolvedWorkspacePath = (0, env_1.resolveWorkspaceByType)(newCwd, workspaceType);
|
|
344
|
+
}
|
|
345
|
+
// Update ctx for module creation
|
|
346
|
+
ctx.cwd = newCwd;
|
|
347
|
+
// Continue to module creation below (don't return here)
|
|
264
348
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
{
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
349
|
+
else {
|
|
350
|
+
// If user explicitly requested module init or we're in non-interactive mode,
|
|
351
|
+
// just show the error with helpful guidance
|
|
352
|
+
if (wasExplicitModuleRequest || noTty) {
|
|
353
|
+
process.stderr.write(`Not inside a ${workspaceTypeName} workspace.\n`);
|
|
354
|
+
throw types_1.errors.NOT_IN_WORKSPACE({});
|
|
355
|
+
}
|
|
356
|
+
// Offer to create a workspace for pgpm templates or when --dir is specified
|
|
357
|
+
// (when --dir is specified, we know which workspace variant to use)
|
|
358
|
+
if (workspaceType === 'pgpm' || ctx.dir) {
|
|
359
|
+
const recoveryQuestion = [
|
|
360
|
+
{
|
|
361
|
+
name: 'workspace',
|
|
362
|
+
alias: 'W',
|
|
363
|
+
message: `You are not inside a ${workspaceTypeName} workspace. Would you like to create a new workspace instead?`,
|
|
364
|
+
type: 'confirm',
|
|
365
|
+
required: true,
|
|
366
|
+
},
|
|
367
|
+
];
|
|
368
|
+
const { workspace } = await prompter.prompt(argv, recoveryQuestion);
|
|
369
|
+
if (workspace) {
|
|
370
|
+
return handleWorkspaceInit(argv, prompter, {
|
|
371
|
+
fromPath: 'workspace',
|
|
372
|
+
templateRepo: ctx.templateRepo,
|
|
373
|
+
branch: ctx.branch,
|
|
374
|
+
dir: ctx.dir,
|
|
375
|
+
noTty: ctx.noTty,
|
|
376
|
+
cwd: ctx.cwd,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
287
379
|
}
|
|
380
|
+
// User declined or non-pgpm workspace type without --dir, show the error
|
|
381
|
+
process.stderr.write(`Not inside a ${workspaceTypeName} workspace.\n`);
|
|
382
|
+
throw types_1.errors.NOT_IN_WORKSPACE({});
|
|
288
383
|
}
|
|
289
|
-
// User declined or non-pgpm workspace type without --dir, show the error
|
|
290
|
-
process.stderr.write(`Not inside a ${workspaceTypeName} workspace.\n`);
|
|
291
|
-
throw types_1.errors.NOT_IN_WORKSPACE({});
|
|
292
384
|
}
|
|
293
385
|
}
|
|
294
386
|
// Only check workspace directory constraints if we're in a workspace
|
|
@@ -29,15 +29,16 @@ async function runWorkspaceSetup(argv, prompter) {
|
|
|
29
29
|
// Prevent double-echoed keystrokes by closing our prompter before template prompts.
|
|
30
30
|
prompter.close();
|
|
31
31
|
const templateRepo = argv.repo ?? core_1.DEFAULT_TEMPLATE_REPO;
|
|
32
|
-
// Don't set default
|
|
33
|
-
|
|
32
|
+
// Don't set default template - let scaffoldTemplate use metadata-driven resolution
|
|
33
|
+
// Support both --template (new) and --template-path (deprecated) for backward compatibility
|
|
34
|
+
const template = (argv.template || argv.templatePath);
|
|
34
35
|
// Register workspace.dirname resolver so boilerplate templates can use it via defaultFrom/setFrom
|
|
35
36
|
// This provides the intended workspace directory name before the folder is created
|
|
36
37
|
const dirName = path_1.default.basename(targetPath);
|
|
37
38
|
(0, inquirerer_1.registerDefaultResolver)('workspace.dirname', () => dirName);
|
|
38
39
|
const dir = argv.dir;
|
|
39
40
|
await (0, core_1.scaffoldTemplate)({
|
|
40
|
-
fromPath:
|
|
41
|
+
fromPath: template ?? 'workspace',
|
|
41
42
|
outputDir: targetPath,
|
|
42
43
|
templateRepo,
|
|
43
44
|
branch: argv.fromBranch,
|
|
@@ -26,16 +26,20 @@ Options:
|
|
|
26
26
|
--repo <repo> Template repo (default: https://github.com/constructive-io/pgpm-boilerplates.git)
|
|
27
27
|
--from-branch <branch> Branch/tag to use when cloning repo
|
|
28
28
|
--dir <variant> Template variant directory (e.g., supabase, drizzle)
|
|
29
|
+
--template, -t <path> Full template path (e.g., pnpm/module) - combines dir and fromPath
|
|
29
30
|
--boilerplate Prompt to select from available boilerplates
|
|
31
|
+
--create-workspace, -w Create a workspace first, then create the module inside it
|
|
30
32
|
|
|
31
33
|
Examples:
|
|
32
34
|
${binaryName} init Initialize new module (default)
|
|
33
35
|
${binaryName} init workspace Initialize new workspace
|
|
34
36
|
${binaryName} init module Initialize new module explicitly
|
|
35
37
|
${binaryName} init workspace --dir <variant> Use variant templates
|
|
38
|
+
${binaryName} init --template pnpm/module Use full template path (dir + type)
|
|
36
39
|
${binaryName} init --boilerplate Select from available boilerplates
|
|
37
40
|
${binaryName} init --repo owner/repo Use templates from GitHub repository
|
|
38
41
|
${binaryName} init --repo owner/repo --from-branch develop Use specific branch
|
|
42
|
+
${binaryName} init --dir pnpm -w Create pnpm workspace + module in one command
|
|
39
43
|
`;
|
|
40
44
|
};
|
|
41
45
|
export default async (argv, prompter, _options) => {
|
|
@@ -50,11 +54,28 @@ async function handleInit(argv, prompter) {
|
|
|
50
54
|
const { cwd = process.cwd() } = argv;
|
|
51
55
|
const templateRepo = argv.repo ?? DEFAULT_TEMPLATE_REPO;
|
|
52
56
|
const branch = argv.fromBranch;
|
|
53
|
-
const dir = argv.dir;
|
|
54
57
|
const noTty = Boolean(argv.noTty || argv['no-tty'] || process.env.CI === 'true');
|
|
55
58
|
const useBoilerplatePrompt = Boolean(argv.boilerplate);
|
|
59
|
+
const createWorkspace = Boolean(argv.createWorkspace || argv['create-workspace'] || argv.w);
|
|
56
60
|
// Get fromPath from first positional arg
|
|
57
61
|
const positionalFromPath = argv._?.[0];
|
|
62
|
+
// Handle --template flag: parses "dir/fromPath" format and extracts both components
|
|
63
|
+
// When --template is provided, it takes precedence over --dir and positional fromPath
|
|
64
|
+
const templateArg = argv.template;
|
|
65
|
+
let dir = argv.dir;
|
|
66
|
+
let templateFromPath;
|
|
67
|
+
if (templateArg) {
|
|
68
|
+
// Parse template path like "pnpm/module" into dir="pnpm" and fromPath="module"
|
|
69
|
+
const slashIndex = templateArg.indexOf('/');
|
|
70
|
+
if (slashIndex > 0) {
|
|
71
|
+
dir = templateArg.substring(0, slashIndex);
|
|
72
|
+
templateFromPath = templateArg.substring(slashIndex + 1);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// No slash - treat the whole thing as fromPath (e.g., --template workspace)
|
|
76
|
+
templateFromPath = templateArg;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
58
79
|
// Handle --boilerplate flag: separate path from regular init
|
|
59
80
|
if (useBoilerplatePrompt) {
|
|
60
81
|
return handleBoilerplateInit(argv, prompter, {
|
|
@@ -66,10 +87,10 @@ async function handleInit(argv, prompter) {
|
|
|
66
87
|
cwd,
|
|
67
88
|
});
|
|
68
89
|
}
|
|
69
|
-
// Regular init path: default to 'module'
|
|
70
|
-
const fromPath = positionalFromPath || 'module';
|
|
71
|
-
// Track if user explicitly requested module (e.g., `pgpm init module`)
|
|
72
|
-
const wasExplicitModuleRequest = positionalFromPath === 'module';
|
|
90
|
+
// Regular init path: --template takes precedence, then positional arg, then default to 'module'
|
|
91
|
+
const fromPath = templateFromPath || positionalFromPath || 'module';
|
|
92
|
+
// Track if user explicitly requested module (e.g., `pgpm init module` or `--template pnpm/module`)
|
|
93
|
+
const wasExplicitModuleRequest = positionalFromPath === 'module' || templateFromPath === 'module';
|
|
73
94
|
// Inspect the template to get its type
|
|
74
95
|
const inspection = inspectTemplate({
|
|
75
96
|
fromPath,
|
|
@@ -100,6 +121,7 @@ async function handleInit(argv, prompter) {
|
|
|
100
121
|
noTty,
|
|
101
122
|
cwd,
|
|
102
123
|
requiresWorkspace: inspection.config?.requiresWorkspace,
|
|
124
|
+
createWorkspace,
|
|
103
125
|
}, wasExplicitModuleRequest);
|
|
104
126
|
}
|
|
105
127
|
async function handleBoilerplateInit(argv, prompter, ctx) {
|
|
@@ -228,12 +250,47 @@ async function handleWorkspaceInit(argv, prompter, ctx) {
|
|
|
228
250
|
process.stdout.write(`\n✨ Enjoy!\n\ncd ./${dirName}\n`);
|
|
229
251
|
return { ...argv, ...answers, cwd: targetPath };
|
|
230
252
|
}
|
|
253
|
+
function resolveWorkspaceTemplateRepo(options) {
|
|
254
|
+
const { templateRepo, branch, dir, workspaceType, cwd } = options;
|
|
255
|
+
// Determine the dir to use for workspace template
|
|
256
|
+
// If dir is specified, use it; otherwise use the workspaceType as the dir variant
|
|
257
|
+
const workspaceDir = dir || workspaceType;
|
|
258
|
+
// Try to find workspace template in the specified repo
|
|
259
|
+
try {
|
|
260
|
+
const inspection = inspectTemplate({
|
|
261
|
+
fromPath: 'workspace',
|
|
262
|
+
templateRepo,
|
|
263
|
+
branch,
|
|
264
|
+
dir: workspaceDir,
|
|
265
|
+
toolName: DEFAULT_TEMPLATE_TOOL_NAME,
|
|
266
|
+
cwd,
|
|
267
|
+
});
|
|
268
|
+
// If we found a valid workspace template, use the specified repo
|
|
269
|
+
if (inspection.config?.type === 'workspace') {
|
|
270
|
+
return {
|
|
271
|
+
repo: templateRepo,
|
|
272
|
+
branch,
|
|
273
|
+
dir: workspaceDir,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
// Template not found in specified repo, fall through to default
|
|
279
|
+
}
|
|
280
|
+
// Fall back to default template repo
|
|
281
|
+
// Use the workspaceType as the dir variant (pgpm or pnpm)
|
|
282
|
+
return {
|
|
283
|
+
repo: DEFAULT_TEMPLATE_REPO,
|
|
284
|
+
branch: undefined, // Use default branch for default repo
|
|
285
|
+
dir: workspaceType,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
231
288
|
async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest = false) {
|
|
232
289
|
// Determine workspace requirement (defaults to 'pgpm' for backward compatibility)
|
|
233
290
|
const workspaceType = ctx.requiresWorkspace ?? 'pgpm';
|
|
234
291
|
// Whether this is a pgpm-managed template (creates pgpm.plan, .control files)
|
|
235
292
|
const isPgpmTemplate = workspaceType === 'pgpm';
|
|
236
|
-
|
|
293
|
+
let project = new PgpmPackage(ctx.cwd);
|
|
237
294
|
// Track resolved workspace path for both pgpm and non-pgpm workspace types
|
|
238
295
|
let resolvedWorkspacePath;
|
|
239
296
|
let workspaceTypeName = '';
|
|
@@ -249,39 +306,74 @@ async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest =
|
|
|
249
306
|
}
|
|
250
307
|
if (!resolvedWorkspacePath) {
|
|
251
308
|
const noTty = Boolean(argv.noTty || argv['no-tty'] || process.env.CI === 'true');
|
|
252
|
-
//
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
309
|
+
// Handle --create-workspace flag: create workspace first, then module
|
|
310
|
+
if (ctx.createWorkspace && (workspaceType === 'pgpm' || workspaceType === 'pnpm')) {
|
|
311
|
+
// Resolve workspace template repo with fallback to default
|
|
312
|
+
const workspaceTemplateConfig = resolveWorkspaceTemplateRepo({
|
|
313
|
+
templateRepo: ctx.templateRepo,
|
|
314
|
+
branch: ctx.branch,
|
|
315
|
+
dir: ctx.dir,
|
|
316
|
+
workspaceType,
|
|
317
|
+
cwd: ctx.cwd,
|
|
318
|
+
});
|
|
319
|
+
// Create workspace first
|
|
320
|
+
const workspaceResult = await handleWorkspaceInit(argv, prompter, {
|
|
321
|
+
fromPath: 'workspace',
|
|
322
|
+
templateRepo: workspaceTemplateConfig.repo,
|
|
323
|
+
branch: workspaceTemplateConfig.branch,
|
|
324
|
+
dir: workspaceTemplateConfig.dir,
|
|
325
|
+
noTty: ctx.noTty,
|
|
326
|
+
cwd: ctx.cwd,
|
|
327
|
+
});
|
|
328
|
+
// Update context to point to new workspace and continue with module creation
|
|
329
|
+
const newCwd = workspaceResult.cwd;
|
|
330
|
+
project = new PgpmPackage(newCwd);
|
|
331
|
+
// Re-resolve workspace path with new cwd
|
|
332
|
+
if (workspaceType === 'pgpm') {
|
|
333
|
+
resolvedWorkspacePath = project.workspacePath;
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
resolvedWorkspacePath = resolveWorkspaceByType(newCwd, workspaceType);
|
|
337
|
+
}
|
|
338
|
+
// Update ctx for module creation
|
|
339
|
+
ctx.cwd = newCwd;
|
|
340
|
+
// Continue to module creation below (don't return here)
|
|
257
341
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
{
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
342
|
+
else {
|
|
343
|
+
// If user explicitly requested module init or we're in non-interactive mode,
|
|
344
|
+
// just show the error with helpful guidance
|
|
345
|
+
if (wasExplicitModuleRequest || noTty) {
|
|
346
|
+
process.stderr.write(`Not inside a ${workspaceTypeName} workspace.\n`);
|
|
347
|
+
throw errors.NOT_IN_WORKSPACE({});
|
|
348
|
+
}
|
|
349
|
+
// Offer to create a workspace for pgpm templates or when --dir is specified
|
|
350
|
+
// (when --dir is specified, we know which workspace variant to use)
|
|
351
|
+
if (workspaceType === 'pgpm' || ctx.dir) {
|
|
352
|
+
const recoveryQuestion = [
|
|
353
|
+
{
|
|
354
|
+
name: 'workspace',
|
|
355
|
+
alias: 'W',
|
|
356
|
+
message: `You are not inside a ${workspaceTypeName} workspace. Would you like to create a new workspace instead?`,
|
|
357
|
+
type: 'confirm',
|
|
358
|
+
required: true,
|
|
359
|
+
},
|
|
360
|
+
];
|
|
361
|
+
const { workspace } = await prompter.prompt(argv, recoveryQuestion);
|
|
362
|
+
if (workspace) {
|
|
363
|
+
return handleWorkspaceInit(argv, prompter, {
|
|
364
|
+
fromPath: 'workspace',
|
|
365
|
+
templateRepo: ctx.templateRepo,
|
|
366
|
+
branch: ctx.branch,
|
|
367
|
+
dir: ctx.dir,
|
|
368
|
+
noTty: ctx.noTty,
|
|
369
|
+
cwd: ctx.cwd,
|
|
370
|
+
});
|
|
371
|
+
}
|
|
280
372
|
}
|
|
373
|
+
// User declined or non-pgpm workspace type without --dir, show the error
|
|
374
|
+
process.stderr.write(`Not inside a ${workspaceTypeName} workspace.\n`);
|
|
375
|
+
throw errors.NOT_IN_WORKSPACE({});
|
|
281
376
|
}
|
|
282
|
-
// User declined or non-pgpm workspace type without --dir, show the error
|
|
283
|
-
process.stderr.write(`Not inside a ${workspaceTypeName} workspace.\n`);
|
|
284
|
-
throw errors.NOT_IN_WORKSPACE({});
|
|
285
377
|
}
|
|
286
378
|
}
|
|
287
379
|
// Only check workspace directory constraints if we're in a workspace
|
|
@@ -23,15 +23,16 @@ export default async function runWorkspaceSetup(argv, prompter) {
|
|
|
23
23
|
// Prevent double-echoed keystrokes by closing our prompter before template prompts.
|
|
24
24
|
prompter.close();
|
|
25
25
|
const templateRepo = argv.repo ?? DEFAULT_TEMPLATE_REPO;
|
|
26
|
-
// Don't set default
|
|
27
|
-
|
|
26
|
+
// Don't set default template - let scaffoldTemplate use metadata-driven resolution
|
|
27
|
+
// Support both --template (new) and --template-path (deprecated) for backward compatibility
|
|
28
|
+
const template = (argv.template || argv.templatePath);
|
|
28
29
|
// Register workspace.dirname resolver so boilerplate templates can use it via defaultFrom/setFrom
|
|
29
30
|
// This provides the intended workspace directory name before the folder is created
|
|
30
31
|
const dirName = path.basename(targetPath);
|
|
31
32
|
registerDefaultResolver('workspace.dirname', () => dirName);
|
|
32
33
|
const dir = argv.dir;
|
|
33
34
|
await scaffoldTemplate({
|
|
34
|
-
fromPath:
|
|
35
|
+
fromPath: template ?? 'workspace',
|
|
35
36
|
outputDir: targetPath,
|
|
36
37
|
templateRepo,
|
|
37
38
|
branch: argv.fromBranch,
|
package/esm/index.js
CHANGED
|
@@ -32,7 +32,12 @@ export const options = {
|
|
|
32
32
|
v: 'version',
|
|
33
33
|
h: 'help',
|
|
34
34
|
'from-branch': 'fromBranch',
|
|
35
|
-
|
|
35
|
+
// Support both --template and --template-path (deprecated) for backward compatibility
|
|
36
|
+
'template-path': 'template',
|
|
37
|
+
t: 'template',
|
|
38
|
+
// -w for --create-workspace flag
|
|
39
|
+
w: 'createWorkspace',
|
|
40
|
+
'create-workspace': 'createWorkspace'
|
|
36
41
|
}
|
|
37
42
|
}
|
|
38
43
|
};
|
package/index.js
CHANGED
|
@@ -75,7 +75,12 @@ exports.options = {
|
|
|
75
75
|
v: 'version',
|
|
76
76
|
h: 'help',
|
|
77
77
|
'from-branch': 'fromBranch',
|
|
78
|
-
|
|
78
|
+
// Support both --template and --template-path (deprecated) for backward compatibility
|
|
79
|
+
'template-path': 'template',
|
|
80
|
+
t: 'template',
|
|
81
|
+
// -w for --create-workspace flag
|
|
82
|
+
w: 'createWorkspace',
|
|
83
|
+
'create-workspace': 'createWorkspace'
|
|
79
84
|
}
|
|
80
85
|
}
|
|
81
86
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pgpm",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "PostgreSQL Package Manager - Database migration and package management CLI",
|
|
6
6
|
"main": "index.js",
|
|
@@ -74,5 +74,5 @@
|
|
|
74
74
|
"pg",
|
|
75
75
|
"pgsql"
|
|
76
76
|
],
|
|
77
|
-
"gitHead": "
|
|
77
|
+
"gitHead": "10d6dc9d8f3846c7347272874537702949422a64"
|
|
78
78
|
}
|