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
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ The setup wizard will guide you through project creation and next steps. Make su

During setup, choose a profile:

- **Recommended**: Full app features + Docker deployment assets + CD workflow.
- **Platform-First**: Full app features, no deployment assets.
- **Custom**: Pick app features and deployment options independently.
- **Recommended**: Core app with everything included.
- **Platform-Agnostic**: Core app without dockerfiles.
- **Modular**: Core app with features of your choice.

If you choose **Modular**, the wizard opens feature customization before scaffolding.

**What's running after setup:**

Expand Down
5 changes: 3 additions & 2 deletions apps/api/test/helpers/test-db.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import 'dotenv-flow/config';

import { PrismaPg } from '@prisma/adapter-pg';
import { execSync } from 'child_process';
import dotenvFlow from 'dotenv-flow';
import { Pool } from 'pg';

import { PrismaClient } from '@/generated/client/client.js';

let prisma: PrismaClient | null = null;
let pool: Pool | null = null;

dotenvFlow.config({ silent: true });

/**
* Get test database URL
* Uses DATABASE_URL from env but appends _test suffix to database name
Expand Down
8 changes: 5 additions & 3 deletions create-blitzpack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ pnpm create blitzpack [project-name] [options]

The scaffold wizard supports three profiles:

- **Recommended**: All app features plus Docker deployment assets and CD workflow.
- **Platform-First**: All app features, without deployment assets.
- **Custom**: Pick app features and deployment options independently.
- **Recommended**: Core app with everything included.
- **Platform-Agnostic**: Core app without dockerfiles.
- **Modular**: Core app with features of your choice.

Each profile is a setup path. The **Modular** path opens full feature customization before files are created.

## Requirements

Expand Down
5 changes: 2 additions & 3 deletions create-blitzpack/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-blitzpack",
"version": "0.1.18",
"version": "0.1.20",
"description": "Create a new Blitzpack project - full-stack TypeScript monorepo with Next.js and Fastify",
"type": "module",
"bin": {
Expand All @@ -16,18 +16,17 @@
"clean": "rm -rf dist"
},
"dependencies": {
"@clack/prompts": "^1.0.0",
"chalk": "^5.6.2",
"commander": "^13.1.0",
"fs-extra": "^11.3.3",
"giget": "^2.0.0",
"ora": "^8.2.0",
"prompts": "^2.4.2",
"validate-npm-package-name": "^6.0.2"
},
"devDependencies": {
"@types/fs-extra": "^11.0.4",
"@types/node": "^22.19.3",
"@types/prompts": "^2.4.9",
"@types/validate-npm-package-name": "^4.0.2",
"tsup": "^8.5.1",
"typescript": "^5.9.3"
Expand Down
86 changes: 74 additions & 12 deletions create-blitzpack/src/checks.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import chalk from 'chalk';
import { execSync } from 'child_process';
import ora from 'ora';

import { isDockerInstalled } from './docker.js';
import { isGitInstalled } from './git.js';

interface CheckResult {
passed: boolean;
name: string;
message?: string;
required: boolean;
message: string;
}

function checkNodeVersion(): CheckResult {
Expand All @@ -16,67 +21,124 @@ function checkNodeVersion(): CheckResult {
return {
passed: true,
name: 'Node.js',
required: true,
message: nodeVersion,
};
}

return {
passed: false,
name: 'Node.js',
required: true,
message: `Node.js >= 20.0.0 required (found ${nodeVersion})`,
};
} catch {
return {
passed: false,
name: 'Node.js',
required: true,
message: 'Failed to check Node.js version',
};
}
}

function checkPnpmInstalled(): CheckResult {
try {
execSync('pnpm --version', { stdio: 'ignore' });
const version = execSync('pnpm --version', {
encoding: 'utf-8',
stdio: ['ignore', 'pipe', 'ignore'],
}).trim();
return {
passed: true,
name: 'pnpm',
required: true,
message: `v${version}`,
};
} catch {
return {
passed: false,
name: 'pnpm',
required: true,
message: 'pnpm not found. Install: npm install -g pnpm',
};
}
}

function checkGit(): CheckResult {
const installed = isGitInstalled();
return {
passed: installed,
name: 'git',
required: false,
message: installed
? 'available (repository initialization supported)'
: 'not found (git init step will be skipped)',
};
}

function checkDocker(): CheckResult {
const installed = isDockerInstalled();
return {
passed: installed,
name: 'Docker',
required: false,
message: installed
? 'available (automatic local DB setup supported)'
: 'not found (start PostgreSQL separately)',
};
}

export async function runPreflightChecks(): Promise<boolean> {
console.log();
console.log(chalk.bold(' Checking requirements...'));
console.log(chalk.bold(' System readiness'));
console.log(chalk.dim(' Validating required and optional local tooling...'));
console.log();

const checks: CheckResult[] = [checkNodeVersion(), checkPnpmInstalled()];
const checks: CheckResult[] = [
checkNodeVersion(),
checkPnpmInstalled(),
checkGit(),
checkDocker(),
];

let hasErrors = false;
const requiredFailures: CheckResult[] = [];
const optionalWarnings: CheckResult[] = [];

for (const check of checks) {
const spinner = ora(`Checking ${check.name}...`).start();

if (check.passed) {
console.log(chalk.green(' ✔'), check.name);
spinner.succeed(chalk.bold(check.name));
} else {
hasErrors = true;
console.log(chalk.red(' ✖'), check.name);
if (check.message) {
console.log(chalk.dim(` ${check.message}`));
if (check.required) {
requiredFailures.push(check);
spinner.fail(chalk.bold(check.name));
} else {
optionalWarnings.push(check);
spinner.warn(chalk.bold(check.name));
}
console.log(chalk.dim(` ${check.message}`));
}
}

console.log();

if (hasErrors) {
if (optionalWarnings.length > 0) {
console.log(chalk.yellow(' Optional tools missing:'));
for (const warning of optionalWarnings) {
console.log(chalk.dim(` • ${warning.name}: ${warning.message}`));
}
console.log();
}

if (requiredFailures.length > 0) {
console.log(
chalk.red(' ✖'),
'Requirements not met. Please fix the errors above.'
'Required dependencies are missing. Fix the items below and try again:'
);
for (const failure of requiredFailures) {
console.log(chalk.dim(` • ${failure.name}: ${failure.message}`));
}
console.log();
return false;
}
Expand Down
Loading