spring-boot-cli
Version:
CLI for Spring Boot
185 lines (184 loc) • 9.08 kB
JavaScript
import { Command } from "commander";
import inquirer from "inquirer";
import { isValidMavenArtifactId, isValidMavenGroupId, isValidProjectName } from "../utils/validator.utils.mjs";
import chalk from "chalk";
import path from "node:path";
import crypto from "crypto";
import { copyFiles, createFolder, deleteFolder, getJavaFiles, readFile, renameFile, writeFile } from "../utils/file-manager.utils.mjs";
import { cloneStarterPack, commitInitialProject } from "../utils/git.utils.mjs";
import ora from "ora";
import { parseObjectToXmlString, parseStringToXml } from "../utils/xml.utils.mjs";
import { parseObjectToYamlString, parseStringToYaml } from "../utils/yaml.utils.mjs";
const createCommand = new Command("create")
.command("create")
.alias("c")
.description("Create a new spring boot project with starter pack")
.argument("<name>", "Name of the project")
.action(async (name) => {
// =========================================
// Validate parameters
// =========================================
if (!validateName(name)) {
console.error(chalk.red("Please enter a valid project name"));
process.exit(1);
}
const groupId = await getGroupId();
const artifactId = await getArtifactId();
// =========================================
// Loading spinner
// =========================================
const spinner = ora(`Creating project folder...\n`).start(); // Start the spinner
// =========================================
// Create project folder
// =========================================
spinner.start(`Creating project folder...`);
const projectPath = path.join(process.cwd(), name);
createFolder(projectPath);
spinner.info(`Project folder created at ${projectPath}`);
// =========================================
// Clone starter pack from git
// =========================================
spinner.start(`Cloning starter pack...`);
await cloneStarterPack(projectPath);
deleteFolder(path.join(projectPath, ".git"));
spinner.info(`Starter pack cloned at ${projectPath}`);
// =========================================
// Edit pom.xml
// =========================================
spinner.start(`Generating project...`);
const pomPath = path.join(projectPath, "pom.xml");
const pom = readFile(pomPath);
let pomXml = await parseStringToXml(pom);
pomXml = editPom(pomXml, groupId, artifactId, name);
const pomString = await parseObjectToXmlString(pomXml);
writeFile(pomPath, pomString);
// =========================================
// Replace imports in java files with groupId
// =========================================
const javaFilePattern = path.posix.join(projectPath, "src", "main", "java", "**", "*.java");
const javaTestFilePattern = path.posix.join(projectPath, "src", "test", "java", "**", "*.java");
let javaFiles = getJavaFiles(javaFilePattern);
let javaTestFiles = getJavaFiles(javaTestFilePattern);
javaFiles.push(...javaTestFiles);
javaFiles.forEach((file) => {
let fileContent = readFile(file);
fileContent = fileContent.replaceAll("it.theapplegeek.spring_starter_pack", `${groupId.replaceAll("-", "_")}.${artifactId.replaceAll("-", "_")}`);
writeFile(file, fileContent);
});
// =========================================
// Rename main application class
// =========================================
const mainApplicationPath = path.join(projectPath, "src", "main", "java", "it", "theapplegeek", "spring_starter_pack", "Application.java");
let mainApplicationContent = readFile(mainApplicationPath);
const artifactIdCamelCase = artifactId.split(/[.-]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
mainApplicationContent = mainApplicationContent.replaceAll("class Application", `class ${artifactIdCamelCase}Application`);
mainApplicationContent = mainApplicationContent.replaceAll("Application.class", `${artifactIdCamelCase}Application.class`);
writeFile(mainApplicationPath, mainApplicationContent);
const mainApplicationNewPath = path.join(projectPath, "src", "main", "java", "it", "theapplegeek", "spring_starter_pack", `${artifactIdCamelCase}Application.java`);
renameFile(mainApplicationPath, mainApplicationNewPath);
// =========================================
// Edit application.yml
// =========================================
const applicationYmlPath = path.join(projectPath, "src", "main", "resources", "application.yml");
const applicationYmlFile = readFile(applicationYmlPath);
let applicationYmlContent = parseStringToYaml(applicationYmlFile);
applicationYmlContent.spring.application.name = artifactId.split(/[.-]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
const secretKeyHex = crypto.randomBytes(32).toString('hex');
applicationYmlContent.application.security.jwt['secret-key'] = Buffer.from(secretKeyHex).toString('base64');
applicationYmlContent = parseObjectToYamlString(applicationYmlContent);
writeFile(applicationYmlPath, applicationYmlContent);
// =========================================
// Replace package path with groupId and artifactId
// =========================================
const groupIdSplit = groupId.replaceAll("-", "_").split(".");
const artifactIdSplit = artifactId.replaceAll("-", "_").split(".");
const defaultFolderPath = path.join(projectPath, "src", "main", "java", "it", "theapplegeek", "spring_starter_pack");
const newFolderPath = path.join(projectPath, "src", "main", "java", ...groupIdSplit, ...artifactIdSplit);
createFolder(newFolderPath, false);
copyFiles(defaultFolderPath, newFolderPath);
const defaultTestFolderPath = path.join(projectPath, "src", "test", "java", "it", "theapplegeek", "spring_starter_pack");
const newTestFolderPath = path.join(projectPath, "src", "test", "java", ...groupIdSplit, ...artifactIdSplit);
createFolder(newTestFolderPath, false);
copyFiles(defaultTestFolderPath, newTestFolderPath);
deleteDefaultFolder(groupId, artifactId, projectPath);
spinner.info(`Project created at ${projectPath}`);
// =========================================
// Commit initial project
// =========================================
spinner.start(`Initializing git...`);
await commitInitialProject(projectPath);
spinner.info(`Git initialized`);
spinner.succeed(chalk.green(`Project created successfully!`));
console.log(`\nNext steps:`);
console.log(`1. cd ${name}`);
console.log(`2. open the project in your favorite IDE`);
});
const validateName = (input) => {
if (input === "")
return false;
else if (!isValidProjectName(input))
return false;
return true;
};
const getGroupId = async () => {
return inquirer.prompt({
type: "input",
name: "groupId",
message: "Enter the group ID: ",
validate: (input) => {
if (input === "") {
return "Please enter a group ID";
}
else if (!isValidMavenGroupId(input)) {
return "Please enter a valid group ID";
}
return true;
}
}).then((answers) => {
return answers.groupId;
});
};
const getArtifactId = async () => {
return inquirer.prompt({
type: "input",
name: "artifactId",
message: "Enter the artifact ID: ",
validate: (input) => {
if (input === "") {
return "Please enter an artifact ID";
}
else if (!isValidMavenArtifactId(input)) {
return "Please enter a valid artifact ID";
}
return true;
}
}).then((answers) => {
return answers.artifactId;
});
};
const editPom = (pom, groupId, artifactId, name) => {
pom.project.groupId[0] = groupId;
pom.project.artifactId[0] = artifactId;
pom.project.name[0] = name;
pom.project.description[0] = 'Insert project description here';
delete pom.project.licenses[0];
delete pom.project.developers[0];
return pom;
};
const deleteDefaultFolder = (groupId, artifactId, projectPath) => {
if (groupId === "it.theapplegeek" && artifactId === "spring-starter-pack")
return;
if (groupId === "it.theapplegeek") {
deleteFolder(path.join(projectPath, "src", "main", "java", "it", "theapplegeek", "spring_starter_pack"));
deleteFolder(path.join(projectPath, "src", "test", "java", "it", "theapplegeek", "spring_starter_pack"));
}
else if (groupId.startsWith("it.")) {
deleteFolder(path.join(projectPath, "src", "main", "java", "it", "theapplegeek"));
deleteFolder(path.join(projectPath, "src", "test", "java", "it", "theapplegeek"));
}
else {
deleteFolder(path.join(projectPath, "src", "main", "java", "it"));
deleteFolder(path.join(projectPath, "src", "test", "java", "it"));
}
};
export { createCommand };