Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support kinetic #90

Open
wants to merge 4 commits into
base: trunk
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mystore/*
myadmin/*
myshop/*
mykinetic/*
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
.env
.vscode
node_modules
mydir
myadmin
mystore
mykinetic
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ reaction develop

### Congratulations!! You're ready to start developing with Open Commerce

## Add the Admin/Storefront
## Add the Admin/Kinetic/Storefront
---
Open Commerce includes an Admin panel for managing your system plus an example storefront implementation so you can see how you would go about building your own.

Expand All @@ -145,6 +145,33 @@ reaction develop
```
For more information about developing the admin you can go to [Mailchimp Open Commerce Documentation](https://mailchimp.com/developer/open-commerce/)

## Adding the Kinetic
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably drop the "the" here. It's just Kinetic

The Kinetic project uses pnpm as package manager so ensure you have this installed in your local development.

Using npm to install:
```
npm install -g pnpm
```
To add the kinetic project you can run:
```
reaction create-project kinetic <your-kinetic-name>
```
and a `your-kinetic-name` directory will be created in the new directory.

Change to that directory by running:
```
cd <your-kinetic-name>
```
Then run:
```
pnpm install
```
and you can start the kinetic project by running:
```
reaction develop
```
The kinetic will be available on port https//localhost:3001

## Adding a Storefront
To add the example storefront project so you can browse your installation just run:
```
Expand Down
58 changes: 58 additions & 0 deletions commands/create-project-kinetic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { writeFile, readFile } from "fs/promises";
import simpleGit from "simple-git";
import { copy } from "fs-extra";
import Logger from "../utils/logger.js";

/**
* @summary modify package.json for use as a thin development project
* @param {String} packageJson - The contents of package.json
* @param {String} projectName - The name of the project
* @returns {String} The modified contents
*/
function updatePackageJson(packageJson, projectName) {
const packageData = JSON.parse(packageJson);
packageData.name = projectName;
packageData.version = "1.0.0";
packageData.projectType = "kinetic";
return JSON.stringify(packageData, null, 2);
}

/**
* @summary Update the core file for this project
* @param {String} projectName - The name of the project we are creating
* @returns {Promise<Boolean>} True if success
*/
async function updateCoreFile(projectName) {
const packageJsonPath = `${projectName}/package.json`;
const packageJson = await readFile(packageJsonPath, { encoding: "utf8", flag: "r" });
const updatedPackageJson = updatePackageJson(packageJson, projectName);
await writeFile(packageJsonPath, updatedPackageJson);
return true;
}

/**
* @summary clones projects locally from repo
* @param {String} projectName name of the project to create
* @returns {Boolean} true for success
*/
export default async function createProjectKinetic(projectName) {
Logger.info("Creating kinetic", { projectName });
const gitOptions = {
baseDir: `${process.cwd()}`,
binary: "git",
maxConcurrentProcesses: 6
};
const git = simpleGit(gitOptions);
Logger.info("Cloning project");
try {
await git.clone("[email protected]:reactioncommerce/kinetic.git", projectName);
} catch (error) {
Logger.error(error);
return false;
}
await updateCoreFile(projectName);
await copy(`${projectName}/.env.example`, `${projectName}/.env`);
Logger.success("Kinetic project created. You can change to this directory and run `pnpm install`");
return true;
}

5 changes: 4 additions & 1 deletion commands/create-project.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ import Logger from "../utils/logger.js";
import checkDependencies from "../utils/checkDependencies.js";
import createProjectApi from "./create-project-api.js";
import createProjectAdmin from "./create-project-admin.js";
import createProjectKinetic from "./create-project-kinetic.js";
import createProjectStorefront from "./create-project-storefront.js";
import createProjectDemo from "./create-project-demo.js";

const methodMap = {
api: createProjectApi,
admin: createProjectAdmin,
storefront: createProjectStorefront,
kinetic: createProjectKinetic,
demo: createProjectDemo
};

const extraDependencyMap = {
storefront: ["yarn"]
storefront: ["yarn"],
kinetic: ["pnpm"]
};

/**
Expand Down
33 changes: 33 additions & 0 deletions commands/develop-kinetic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { spawn } from "child_process";
import diehard from "diehard";
import Logger from "../utils/logger.js";
import checkBeforeDevelop from "../utils/checkBeforeDevelop.js";

/**
* @summary start develop mode for kinetic
* @param {Object} options - Any options for project creation
* @returns {Boolean} true for success
*/
export default async function developKinetic(options) {
if (!await checkBeforeDevelop("kinetic")) return;
Logger.info("Starting Open Commerce Kinetic Application Server in dev mode", { options });
const api = spawn("pnpm", ["run", "dev"]);
api.stdout.on("data", (data) => {
// eslint-disable-next-line no-console
console.log(data.toString().trim()); // Echo output of command to console
});

api.stderr.on("data", (data) => {
// eslint-disable-next-line no-console
console.log(data.toString().trim()); // Echo error output
});

diehard.register(async (signal, uncaughtErr, done) => {
if (signal === "SIGINT") {
Logger.warn("Shutting down from Ctrl-C");
}
done();
});

diehard.listen();
}
10 changes: 8 additions & 2 deletions commands/develop.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@ import Logger from "../utils/logger.js";
import checkDependencies from "../utils/checkDependencies.js";
import developStorefront from "./develop-storefront.js";
import developAdmin from "./develop-admin.js";
import developKinetic from "./develop-kinetic.js";
import developApi from "./develop-api.js";

const functionMap = {
api: developApi,
admin: developAdmin,
kinetic: developKinetic,
storefront: developStorefront
};

const extraDependencyMap = {
storefront: ["yarn"]
storefront: ["yarn"],
kinetic: ["pnpm"]
};

const validProjectTypes = ["api", "admin-meteor", "storefront-example"];
const validProjectTypes = ["api", "admin-meteor", "storefront-example", "kinetic"];

/**
* @summary check if projectType exists, if not return empty string
Expand Down Expand Up @@ -44,6 +47,9 @@ async function getProjectType() {
case "admin-meteor":
Logger.info("Found project type: admin-meteor");
return "admin";
case "kinetic":
Logger.info("Found project type: kinetic");
return "kinetic";
case "storefront-example":
Logger.info("Found project type: storefront-example");
return "storefront";
Expand Down
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ program.version(pkg.version);
program
.command("create-project")
.description("Create a new Open Commerce project of one of several types")
.addArgument(new commander.Argument("<type>", "which project type to create").choices(["api", "storefront", "admin", "demo"]))
.addArgument(new commander.Argument("<type>", "which project type to create").choices(["api", "storefront", "admin", "kinetic", "demo"]))
.argument("<name>", "what to name the project")
// .option("--populate")
.option("--skip-meteor-install", "Skip Meteor install when creating admin project")
Expand All @@ -37,7 +37,7 @@ program
.command("develop")
.description("Run a project locally in development mode")
.addArgument(new commander.Argument("[type]", "which project type to develop on")
.choices(["api", "storefront", "admin"]))
.choices(["api", "storefront", "admin", "kinetic"]))
.option("--no-debug")
.option("--no-mongo-shutdown", "don't shut down mongo on abort")
.action((type, options) => {
Expand Down
32 changes: 32 additions & 0 deletions tests/create-kinetic-project.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-disable jest/valid-expect */
import { EOL } from "os";
import { spawn } from "child_process";
import rimraf from "rimraf";
import { expect } from "chai";
import { sync as cmdExists } from "command-exists";
import getConfig from "../utils/getConfig.js";
import execute from "./utils/execute.js";

const config = getConfig();

beforeEach(async () => {
await rimraf.sync("./mykinetic");
// Mock that we have alredy used the command to bypass telemetry logs
config.set("runOnce", true);
if (!cmdExists("pnpm")) {
spawn("npm", ["install", "pnpm", "-g"]);
}
});

describe("The create-project-kinetic command", () => {
it("should print the correct output", async () => {
const response = await execute("./index.js", ["create-project", "kinetic", "mykinetic"]);
const responseLines = response.trim().split(EOL);
// eslint-disable-next-line jest/valid-expect
expect(responseLines[0]).to.equal('reaction-cli: Creating kinetic: {"projectName":"mykinetic"}');
}).timeout(350000); // cloning the admin takes a long time
});

afterEach(async () => {
config.set("runOnce", false);
});
18 changes: 12 additions & 6 deletions utils/checkBeforeDevelop.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,18 @@ async function checkForApi() {
*/
export default async function checkBeforeDevelop(type = "api") {
if (!await pathExists("node_modules")) {
if (type === "storefront") {
Logger.error("It looks like you have not run `yarn install` in this directory");
Logger.error("Please run `yarn install` and try again");
} else {
Logger.error("It looks like you have not run `npm install` in this directory");
Logger.error("Please run `npm install` and try again");
switch (type) {
case "storefront":
Logger.error("It looks like you have not run `yarn install` in this directory");
Logger.error("Please run `yarn install` and try again");
break;
case "kinetic":
Logger.error("It looks like you have not run `pnpm install` in this directory");
Logger.error("Please run `pnpm install` and try again");
break;
default:
Logger.error("It looks like you have not run `npm install` in this directory");
Logger.error("Please run `npm install` and try again");
}
return false;
}
Expand Down