From 63afc186eb4dd4ddb6802b805980598a3974cc22 Mon Sep 17 00:00:00 2001 From: Brian Nguyen Date: Thu, 14 Jul 2022 08:41:09 +0700 Subject: [PATCH 1/3] feat: add populate option when create api project Signed-off-by: Brian Nguyen --- .gitignore | 1 + commands/create-project-api.js | 68 ++++++++++++++++++++++++++++------ index.js | 2 +- tests/create-api-project.js | 14 +++++++ 4 files changed, 73 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index e37f118..d1b9d85 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .env +.vscode node_modules mydir myadmin diff --git a/commands/create-project-api.js b/commands/create-project-api.js index f1b6f19..8d4a0b2 100644 --- a/commands/create-project-api.js +++ b/commands/create-project-api.js @@ -1,4 +1,4 @@ -import { mkdir, writeFile } from "fs/promises"; +import { mkdir, writeFile, readFile } from "fs/promises"; import { parse, stringify } from "envfile"; import simpleGit from "simple-git"; import wget from "../utils/wget.js"; @@ -9,6 +9,20 @@ import Logger from "../utils/logger.js"; const reactionRepoRoot = "https://raw.githubusercontent.com/reactioncommerce/reaction/trunk"; +/** + * @summary create the git instance + * @param {String} projectName - The name of the directory to create + * @returns {Object} - the git instance + */ +function getGitInstance(projectName) { + const gitOptions = { + baseDir: `${process.cwd()}/${projectName}`, + binary: "git", + maxConcurrentProcesses: 6 + }; + return simpleGit(gitOptions); +} + /** * @summary create project directory * @param {String} projectName - The name of the directory to create @@ -68,11 +82,17 @@ async function getFileFromCore(fileName) { /** * @summary update dotenv file to point to local mongo * @param {String} envData - file extracted from the reaction repo + * @param {Object} options - Any options for project creation * @returns {String} updated env file */ -function updateEnv(envData) { +function updateEnv(envData, options = {}) { const env = parse(envData); env.MONGO_URL = "mongodb://localhost:27017/reaction"; + + if (options.populate) { + env.LOAD_SAMPLE_DATA = true; + } + const updatedEnv = stringify(env); return updatedEnv; } @@ -80,9 +100,10 @@ function updateEnv(envData) { /** * @summary get files directory from core repo * @param {String} projectName - The name of the project we are creating + * @param {Object} options - Any options for project creation * @returns {Promise} True if success */ -async function getFilesFromCore(projectName) { +async function getFilesFromCore(projectName, options) { // get files directly from repo so it's always up-to-date const packageJson = await getFileFromCore("package.json"); const updatedPackageJson = await updatePackageJson(packageJson, projectName); @@ -104,7 +125,7 @@ async function getFilesFromCore(projectName) { await writeFile(`${projectName}/.nvmrc`, nvmrc); const dotenv = await getFileFromCore(".env.example"); - const updatedDotEnv = updateEnv(dotenv); + const updatedDotEnv = updateEnv(dotenv, options); await writeFile(`${projectName}/.env`, updatedDotEnv); return true; } @@ -116,12 +137,7 @@ async function getFilesFromCore(projectName) { * @returns {Promise} true if success */ async function gitInitDirectory(projectName) { - const gitOptions = { - baseDir: `${process.cwd()}/${projectName}`, - binary: "git", - maxConcurrentProcesses: 6 - }; - const git = simpleGit(gitOptions); + const git = getGitInstance(projectName); try { await git.init(); } catch (error) { @@ -129,6 +145,32 @@ async function gitInitDirectory(projectName) { } } +/** + * @summary add the sample data plugin to project + * @param {String} projectName name of the project to create + * @param {String} pluginName The plugin name + * @returns {Promise} true for success + */ +async function addSampleDataPlugin(projectName) { + const git = getGitInstance(projectName); + try { + await git.clone("git@github.com:reactioncommerce/api-plugin-sample-data.git", "custom-packages/api-plugin-sample-data"); + + const pluginJsonPath = `${projectName}/plugins.json`; + const plugins = JSON.parse(await readFile(pluginJsonPath)); + plugins.sampleData = "./custom-packages/api-plugin-sample-data/index.js"; + + await writeFile(pluginJsonPath, JSON.stringify(plugins, null, "\t")); + + Logger.info("Added the sample data plugin successfully."); + return true; + } catch (error) { + Logger.error(error); + Logger.warn("Can't add the sample data plugin by error. Please add it manual."); + return false; + } +} + /** * @summary clones projects locally from repo @@ -148,10 +190,14 @@ export default async function createProjectApi(projectName, options) { await getFilesFromRepo("/templates/api-project/", projectName); // copy files directly from core that we want to be current - await getFilesFromCore(projectName); + await getFilesFromCore(projectName, options); // git init the new project await gitInitDirectory(projectName); + if (options.populate) { + await addSampleDataPlugin(projectName); + } + Logger.success("Project creation complete. Change to your directory and run `npm install`"); } diff --git a/index.js b/index.js index 1fd78f8..862966b 100755 --- a/index.js +++ b/index.js @@ -17,7 +17,7 @@ program .description("Create a new Open Commerce project of one of several types") .addArgument(new commander.Argument("", "which project type to create").choices(["api", "storefront", "admin", "demo"])) .argument("", "what to name the project") - // .option("--populate") + .option("--populate", "Install the sample data plugin") .option("--skip-meteor-install", "Skip Meteor install when creating admin project") .option("--dont-start-demo", "Don't auto start the demo project after creation") .action((type, name, options) => { diff --git a/tests/create-api-project.js b/tests/create-api-project.js index d63777b..f4cba8f 100644 --- a/tests/create-api-project.js +++ b/tests/create-api-project.js @@ -1,4 +1,5 @@ import { EOL } from "os"; +import fs from "fs/promises"; import { v4 as uuidv4 } from "uuid"; import rimraf from "rimraf"; import { expect } from "chai"; @@ -28,6 +29,19 @@ describe("The create-project-api command", () => { // eslint-disable-next-line jest/valid-expect expect(responseLines[1]).to.equal("reaction-cli: Project creation complete. Change to your directory and run `npm install`"); }).timeout(5000); + + it("should print the correct output when user run with --populate option", async () => { + const response = await execute("./index.js", ["create-project", "api", "myshop", "--populate"]); + const responseLines = response.trim().split(EOL); + expect(responseLines[1]).equal("reaction-cli: Added the sample data plugin successfully."); + expect(responseLines[2]).equal("reaction-cli: Project creation complete. Change to your directory and run `npm install`"); + + const pluginsData = JSON.parse(await fs.readFile("./myshop/plugins.json")); + expect(pluginsData.sampleData).eq("./custom-packages/api-plugin-sample-data/index.js"); + + const envData = await fs.readFile("./myshop/.env", { encoding: "utf-8" }); + expect(envData).contain("LOAD_SAMPLE_DATA=true"); + }).timeout(350000); }); afterEach(async () => { From 37597ae7fa24fa748a647bebb6e5e5d637fb8f0d Mon Sep 17 00:00:00 2001 From: Brian Nguyen Date: Thu, 14 Jul 2022 09:08:20 +0700 Subject: [PATCH 2/3] refactor: better place for getGit Signed-off-by: Brian Nguyen --- commands/create-project-api.js | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/commands/create-project-api.js b/commands/create-project-api.js index 8d4a0b2..a47c8b6 100644 --- a/commands/create-project-api.js +++ b/commands/create-project-api.js @@ -9,20 +9,6 @@ import Logger from "../utils/logger.js"; const reactionRepoRoot = "https://raw.githubusercontent.com/reactioncommerce/reaction/trunk"; -/** - * @summary create the git instance - * @param {String} projectName - The name of the directory to create - * @returns {Object} - the git instance - */ -function getGitInstance(projectName) { - const gitOptions = { - baseDir: `${process.cwd()}/${projectName}`, - binary: "git", - maxConcurrentProcesses: 6 - }; - return simpleGit(gitOptions); -} - /** * @summary create project directory * @param {String} projectName - The name of the directory to create @@ -130,6 +116,19 @@ async function getFilesFromCore(projectName, options) { return true; } +/** + * @summary create the git instance + * @param {String} projectName - The name of the directory to create + * @returns {Object} - the git instance + */ +function getGit(projectName) { + const gitOptions = { + baseDir: `${process.cwd()}/${projectName}`, + binary: "git", + maxConcurrentProcesses: 6 + }; + return simpleGit(gitOptions); +} /** * @summary git init the newly created project @@ -137,9 +136,8 @@ async function getFilesFromCore(projectName, options) { * @returns {Promise} true if success */ async function gitInitDirectory(projectName) { - const git = getGitInstance(projectName); try { - await git.init(); + await getGit(projectName).init(); } catch (error) { Logger.error(error); } @@ -152,9 +150,8 @@ async function gitInitDirectory(projectName) { * @returns {Promise} true for success */ async function addSampleDataPlugin(projectName) { - const git = getGitInstance(projectName); try { - await git.clone("git@github.com:reactioncommerce/api-plugin-sample-data.git", "custom-packages/api-plugin-sample-data"); + await getGit(projectName).clone("git@github.com:reactioncommerce/api-plugin-sample-data.git", "./custom-packages/api-plugin-sample-data"); const pluginJsonPath = `${projectName}/plugins.json`; const plugins = JSON.parse(await readFile(pluginJsonPath)); From bd6490525e1aa906f431ff0336e119aa22497bae Mon Sep 17 00:00:00 2001 From: Brian Nguyen Date: Thu, 14 Jul 2022 09:20:17 +0700 Subject: [PATCH 3/3] tmp: logging Signed-off-by: Brian Nguyen --- tests/create-api-project.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/create-api-project.js b/tests/create-api-project.js index f4cba8f..70291cc 100644 --- a/tests/create-api-project.js +++ b/tests/create-api-project.js @@ -33,6 +33,8 @@ describe("The create-project-api command", () => { it("should print the correct output when user run with --populate option", async () => { const response = await execute("./index.js", ["create-project", "api", "myshop", "--populate"]); const responseLines = response.trim().split(EOL); + // eslint-disable-next-line no-console + console.log(response); expect(responseLines[1]).equal("reaction-cli: Added the sample data plugin successfully."); expect(responseLines[2]).equal("reaction-cli: Project creation complete. Change to your directory and run `npm install`");