create-cen-app
Version:
create an client-engineering-style app
143 lines (123 loc) • 4.08 kB
text/typescript
import { AvailableFlavours } from "./index.js";
import * as p from "@clack/prompts";
import chalk from "chalk";
import { execa } from "execa";
import fs from "fs-extra";
import path from "path";
import { PKG_ROOT, FULL_STACK_CEN_TEMPLATE_REPO } from "~/consts.js";
import { installDependencies } from "~/helpers/installDependencies.js";
interface FullStackInstallerOptions {
projectName: string;
flavour: AvailableFlavours;
backendDir: string;
frontendDir: string;
projectDir: string;
noInstall?: boolean;
}
export const fullStackInstaller = async ({
projectName,
flavour,
backendDir,
frontendDir,
projectDir,
noInstall,
}: FullStackInstallerOptions) => {
// pull the repo from template repo into project folder
const s = p.spinner();
s.start(`Cloning full-stack-cen-template repository...`);
await execa("git", ["clone", "-b", flavour, FULL_STACK_CEN_TEMPLATE_REPO, projectDir], {
cwd: PKG_ROOT,
stdio: "inherit",
});
// Rename the default branch to main
s.stop();
p.log.success(`Successfully cloned ${chalk.green.bold("full-stack-cen-template")} repository\n`);
p.log.info(`Setting up git...`);
try {
await execa("git", ["branch", "-m", "main"], {
cwd: projectDir,
});
p.log.success(`Successfully renamed branch to ${chalk.green.bold("main")}`);
} catch (error) {
p.log.error(`Failed to rename branch to main: ${error}`);
}
// remove origin
try {
await execa("git", ["remote", "remove", "origin"], {
cwd: projectDir,
});
p.log.success(`Successfully removed git remote ${chalk.green.bold("origin")}`);
} catch (error) {
p.log.error(`Failed to remove git remote origin: ${error}`);
}
// Add the template repo as upstream
try {
await execa("git", ["remote", "add", "upstream", FULL_STACK_CEN_TEMPLATE_REPO], {
cwd: projectDir,
});
p.log.success(`Successfully added ${chalk.green.bold("upstream")} remote`);
} catch (error) {
p.log.error(`Failed to add upstream remote: ${error}`);
}
p.log.success(`Successfully setup git\n`);
// delete .git folder
// p.log.info(`Cleaning up...`);
// fs.removeSync(path.join(projectDir, ".git"));
// p.log.success(`Successfully cleaned up\n`);
// create .env file
const envDest = path.join(projectDir, ".env");
fs.copySync(path.join(projectDir, ".env.example"), envDest);
if (noInstall) {
p.log.info("Skipping dependencies installation");
return;
}
if (
flavour === "backend-only" ||
flavour === "backend-only-no-db" ||
flavour === "main" ||
flavour === "oauth-proxy" ||
flavour === "main-custom-ui" ||
flavour === "oauth-proxy-custom-ui"
) {
p.log.info("Preparing Python environment...");
// Check for available Python versions in descending order
const pythonVersions = ["3.12", "3.11", "3.10"];
let selectedVersion = null;
for (const version of pythonVersions) {
const versionInstalled = await execa(`python${version}`, ["--version"])
.then(() => true)
.catch(() => false);
if (versionInstalled) {
selectedVersion = version;
break;
}
}
if (!selectedVersion) {
p.log.error(
"Python 3.10 or higher is not installed. Please install Python 3.10+ and follow the Backend README.",
);
return;
}
s.start(`Creating virtual environment with Python ${selectedVersion}...`);
try {
await execa("uv", ["venv", "--python", `python${selectedVersion}`], {
cwd: backendDir,
stdio: "inherit",
});
await execa("uv", ["sync"], {
cwd: backendDir,
stdio: "inherit",
});
s.stop();
p.log.success(`Successfully installed ${chalk.green.bold("python")} requirements\n`);
} catch (error) {
s.stop();
p.log.error(
"Failed to setup Python environment. Please check the Backend README for manual setup.",
);
}
}
if (flavour !== "backend-only" && flavour !== "backend-only-no-db") {
await installDependencies({ frontendDir });
}
};