Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion pgpm/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ Here are some useful commands for reference:

- `pgpm init` - Initialize a new module
- `pgpm init workspace` - Initialize a new workspace
- `pgpm init --template <path>` - Initialize using a full template path (e.g., `pnpm/module`)
- `pgpm init -w` - Create a workspace first, then create the module inside it

### Development Setup

Expand Down Expand Up @@ -142,7 +144,7 @@ pgpm deploy --createdb

## 🧰 Templates, Caching, and Updates

- `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-path`, or use a local template path.
- `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.
- Run `pgpm cache clean` to wipe the cached boilerplates if you need a fresh pull.
- 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.

Expand Down
8 changes: 4 additions & 4 deletions pgpm/cli/__tests__/init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ describe('cmds:init', () => {
});

describe('with custom templates', () => {
it('initializes workspace with --template-path', async () => {
it('initializes workspace with --template', async () => {
const { mockInput, mockOutput } = environment;
const prompter = new Inquirerer({
input: mockInput,
Expand All @@ -122,7 +122,7 @@ describe('cmds:init', () => {
cwd: fixture.tempDir,
name: 'test-workspace-template',
workspace: true,
templatePath: 'pgpm/workspace'
template: 'pgpm/workspace'
});

await commands(argv, prompter, {
Expand All @@ -139,7 +139,7 @@ describe('cmds:init', () => {
expect(existsSync(path.join(workspaceDir, 'pgpm.json'))).toBe(true);
});

it('initializes module with --template-path', async () => {
it('initializes module with --template', async () => {
// First create a workspace
const workspaceDir = path.join(fixture.tempDir, 'test-workspace-for-module');
const { mockInput, mockOutput } = environment;
Expand Down Expand Up @@ -170,7 +170,7 @@ describe('cmds:init', () => {
name: 'test-module-template',
moduleName: 'test-module-template',
extensions: ['plpgsql'],
templatePath: 'pgpm/module'
template: 'pgpm/module'
}), prompter, {
noTty: true,
input: mockInput,
Expand Down
29 changes: 24 additions & 5 deletions pgpm/cli/src/commands/init/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Options:
--repo <repo> Template repo (default: https://github.com/constructive-io/pgpm-boilerplates.git)
--from-branch <branch> Branch/tag to use when cloning repo
--dir <variant> Template variant directory (e.g., supabase, drizzle)
--template, -t <path> Full template path (e.g., pnpm/module) - combines dir and fromPath
--boilerplate Prompt to select from available boilerplates
--create-workspace, -w Create a workspace first, then create the module inside it

Expand All @@ -47,6 +48,7 @@ Examples:
${binaryName} init workspace Initialize new workspace
${binaryName} init module Initialize new module explicitly
${binaryName} init workspace --dir <variant> Use variant templates
${binaryName} init --template pnpm/module Use full template path (dir + type)
${binaryName} init --boilerplate Select from available boilerplates
${binaryName} init --repo owner/repo Use templates from GitHub repository
${binaryName} init --repo owner/repo --from-branch develop Use specific branch
Expand All @@ -72,14 +74,31 @@ async function handleInit(argv: Partial<Record<string, any>>, prompter: Inquirer
const { cwd = process.cwd() } = argv;
const templateRepo = (argv.repo as string) ?? DEFAULT_TEMPLATE_REPO;
const branch = argv.fromBranch as string | undefined;
const dir = argv.dir as string | undefined;
const noTty = Boolean((argv as any).noTty || argv['no-tty'] || process.env.CI === 'true');
const useBoilerplatePrompt = Boolean(argv.boilerplate);
const createWorkspace = Boolean(argv.createWorkspace || argv['create-workspace'] || argv.w);

// Get fromPath from first positional arg
const positionalFromPath = argv._?.[0] as string | undefined;

// Handle --template flag: parses "dir/fromPath" format and extracts both components
// When --template is provided, it takes precedence over --dir and positional fromPath
const templateArg = argv.template as string | undefined;
let dir = argv.dir as string | undefined;
let templateFromPath: string | undefined;

if (templateArg) {
// Parse template path like "pnpm/module" into dir="pnpm" and fromPath="module"
const slashIndex = templateArg.indexOf('/');
if (slashIndex > 0) {
dir = templateArg.substring(0, slashIndex);
templateFromPath = templateArg.substring(slashIndex + 1);
} else {
// No slash - treat the whole thing as fromPath (e.g., --template workspace)
templateFromPath = templateArg;
}
}

// Handle --boilerplate flag: separate path from regular init
if (useBoilerplatePrompt) {
return handleBoilerplateInit(argv, prompter, {
Expand All @@ -92,10 +111,10 @@ async function handleInit(argv: Partial<Record<string, any>>, prompter: Inquirer
});
}

// Regular init path: default to 'module' if no fromPath provided
const fromPath = positionalFromPath || 'module';
// Track if user explicitly requested module (e.g., `pgpm init module`)
const wasExplicitModuleRequest = positionalFromPath === 'module';
// Regular init path: --template takes precedence, then positional arg, then default to 'module'
const fromPath = templateFromPath || positionalFromPath || 'module';
// Track if user explicitly requested module (e.g., `pgpm init module` or `--template pnpm/module`)
const wasExplicitModuleRequest = positionalFromPath === 'module' || templateFromPath === 'module';

// Inspect the template to get its type
const inspection = inspectTemplate({
Expand Down
7 changes: 4 additions & 3 deletions pgpm/cli/src/commands/init/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ export default async function runWorkspaceSetup(
prompter.close();

const templateRepo = (argv.repo as string) ?? DEFAULT_TEMPLATE_REPO;
// Don't set default templatePath - let scaffoldTemplate use metadata-driven resolution
const templatePath = argv.templatePath as string | undefined;
// Don't set default template - let scaffoldTemplate use metadata-driven resolution
// Support both --template (new) and --template-path (deprecated) for backward compatibility
const template = (argv.template || argv.templatePath) as string | undefined;

// Register workspace.dirname resolver so boilerplate templates can use it via defaultFrom/setFrom
// This provides the intended workspace directory name before the folder is created
Expand All @@ -42,7 +43,7 @@ export default async function runWorkspaceSetup(
const dir = argv.dir as string | undefined;

await scaffoldTemplate({
fromPath: templatePath ?? 'workspace',
fromPath: template ?? 'workspace',
outputDir: targetPath,
templateRepo,
branch: argv.fromBranch as string | undefined,
Expand Down
7 changes: 6 additions & 1 deletion pgpm/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ export const options: Partial<CLIOptions> = {
v: 'version',
h: 'help',
'from-branch': 'fromBranch',
'template-path': 'templatePath'
// Support both --template and --template-path (deprecated) for backward compatibility
'template-path': 'template',
t: 'template',
// -w for --create-workspace flag
w: 'createWorkspace',
'create-workspace': 'createWorkspace'
}
}
};
Expand Down