Skip to content
This repository was archived by the owner on Oct 10, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5fd41a3
ASBLY-29 changed initial opt in and state of having set initial opt i…
robester0403 Apr 29, 2024
434d77d
ASBLY-29 added required login to use commands, if not logged in login…
robester0403 Apr 30, 2024
5899686
Merge pull request #92 from crowdbotics/main
taylor-cb Apr 30, 2024
e42c393
checking, printing and comparing local and registry version of crowdb…
shahraizali Apr 30, 2024
6e7002b
ASBLY-29 added a message about analytics data
robester0403 May 1, 2024
45ebd0c
ASBLY-29 removed message about analytics
robester0403 May 1, 2024
c9ee552
ASBLY-29 replaced list with constant
robester0403 May 1, 2024
4ef800f
PLAT-13615: Remove cookiecutter from demo command (#85)
alaisgomes May 1, 2024
86e5edc
ASBLY-29 changed to section
robester0403 May 1, 2024
af1dd0c
ASBLY-29 Added bug for saving opt in
robester0403 May 2, 2024
58397aa
PLAT-14510 cli verbose mode (#94)
taylor-cb May 2, 2024
ecdb7ec
flatten the checks and added semver for version comparison
shahraizali May 3, 2024
01bf626
Merge branch 'develop' into ASBLY-26
shahraizali May 3, 2024
1592be7
updated yarn lock file
shahraizali May 3, 2024
eb7a7ae
PLAT-14510: Adding verbose to more commands (#95)
taylor-cb May 3, 2024
b9f4c7b
updated docs link
shahraizali May 6, 2024
a1f0e4d
Merge pull request #93 from crowdbotics/ASBLY-26
shahraiz-cb May 6, 2024
0ddc7fe
Merge branch 'develop' into ASBLY-29
robester0403 May 7, 2024
fc88283
Merge pull request #91 from crowdbotics/ASBLY-29
robester0403 May 7, 2024
fbac8ff
fix: replace unzip library (#102)
alaisgomes May 7, 2024
d224830
added check for not installed local CLI
shahraizali May 7, 2024
b1197b9
Merge pull request #104 from crowdbotics/ASBLY-26
shahraiz-cb May 8, 2024
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
3 changes: 2 additions & 1 deletion config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export default {
CROWDBOTICS_FILE: ".crowdbotics.json",
COOKIECUTTER_PACKAGE: "cookiecutter==1.7.3",
REACT_NATIVE_SCAFFOLD_REPO_ORIGIN:
"https://github.com/crowdbotics/react-native-scaffold"
"https://github.com/crowdbotics/react-native-scaffold",
DJANGO_SCAFFOLD_REPO_ORIGIN: "https://github.com/crowdbotics/django-scaffold"
},
scaffold: {
directory: SCAFFOLD_DIRECTORY
Expand Down
115 changes: 91 additions & 24 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { info } from "./scripts/info.js";
import { removeModules } from "./scripts/remove.js";
import { commitModules } from "./scripts/commit-module.js";
import { upgradeScaffold } from "./scripts/upgrade.js";
import { valid, invalid, section, isUserEnvironment } from "./utils.js";
import { valid, invalid, section, isUserEnvironment, isLoginNotReqCommand } from "./utils.js";
import { createModule } from "./scripts/create.js";
import { login } from "./scripts/login.js";
import { configFile } from "./scripts/utils/configFile.js";
Expand All @@ -41,11 +41,20 @@ import {
EnvironmentDependency
} from "./scripts/utils/environment.js";
import { analytics } from "./scripts/analytics/wrapper.js";
import { HAS_ASKED_OPT_IN_NAME } from "./scripts/analytics/config.js";
import {
HAS_ASKED_OPT_IN_NAME,
OPT_IN_NAME
} from "./scripts/analytics/config.js";
import { EVENT } from "./scripts/analytics/constants.js";
import { askOptIn } from "./scripts/analytics/scripts.js";
import { configureInitialLogin } from "./scripts/analytics/scripts.js";
import { sentryMonitoring } from "./scripts/utils/sentry.js";
import { setModuleDetails } from "./scripts/setModuleDetails.js";
import { isUserLoggedIn } from "./scripts/utils/auth.js";
import { logger, prettyPrintShellOutput } from "./scripts/utils/logger.js";

const GLOBAL_ARGS = {
"--verbose": Boolean
};

const gitRoot = () => {
try {
Expand All @@ -61,12 +70,19 @@ Visit our official documentation for more information and try again: https://doc
async function dispatcher() {
const useDefaults = process.env.npm_config_yes;

// check config if they have been asked opted in or out of amplitude
const hasAskedOptIn = configFile.get(HAS_ASKED_OPT_IN_NAME) || false;
if (!hasAskedOptIn && isUserEnvironment && !useDefaults) {
await askOptIn();
// check config if the inital login has been done
const isInitialLogin = configFile.get(HAS_ASKED_OPT_IN_NAME) || false;
if (!isInitialLogin && isUserEnvironment && !useDefaults) {
await configureInitialLogin();
}

// Compulsory dependencies check on each command
// Note: This is a forced check, so no cache is used
// consider performance implications when adding new dependencies
validateEnvironmentDependencies([
EnvironmentDependency.CLI
], true, false);

const command = process.argv[2];

if (!command) {
Expand All @@ -79,6 +95,13 @@ async function dispatcher() {

sentryMonitoring.registerCommandName(command);

const isLoggedIn = isUserLoggedIn();

if (!isLoggedIn && !isLoginNotReqCommand(command)) {
section("We see you are not logged in. Please log in to run Crowdbotics commands");
await login();
}

await commands[command]();

if (!analytics.event.name && !useDefaults) {
Expand All @@ -93,16 +116,20 @@ async function dispatcher() {
}

const commands = {
demo: () => {
validateEnvironmentDependencies([
EnvironmentDependency.Python,
EnvironmentDependency.PipEnv
]);
createDemo(path.join(gitRoot(), "demo"));
demo: async () => {
const args = arg({
...GLOBAL_ARGS,
"--source": String
});

const { "--source": source = "master" } = args;

await createDemo(path.join(gitRoot(), "demo"), source);
valid("demo app successfully generated");
},
parse: () => {
const args = arg({
...GLOBAL_ARGS,
"--source": String,
"--write": String
});
Expand Down Expand Up @@ -130,6 +157,7 @@ const commands = {
]);

const args = arg({
...GLOBAL_ARGS,
"--source": String,
"--project": String
});
Expand All @@ -143,6 +171,7 @@ const commands = {
validateEnvironmentDependencies([EnvironmentDependency.Yarn]);

const args = arg({
...GLOBAL_ARGS,
"--source": String,
"--project": String
});
Expand All @@ -153,12 +182,10 @@ const commands = {
removeModules(modules, args["--source"], args["--project"], gitRoot());
},
create: () => {
validateEnvironmentDependencies([
EnvironmentDependency.Python,
EnvironmentDependency.CookieCutter
]);
validateEnvironmentDependencies([EnvironmentDependency.Python]);

const args = arg({
...GLOBAL_ARGS,
"--name": String,
"--type": String,
"--target": String,
Expand All @@ -182,6 +209,7 @@ const commands = {
},
commit: () => {
const args = arg({
...GLOBAL_ARGS,
"--source": String
});
const modules = args._.slice(1);
Expand All @@ -194,12 +222,16 @@ const commands = {
validateEnvironmentDependencies([EnvironmentDependency.Git]);

const args = arg({
...GLOBAL_ARGS,
"--name": String
});
if (!args["--name"]) {
invalid("missing required argument: --name");
}
const baseDir = path.join(process.cwd(), args["--name"]);

logger.verbose("init base dir", baseDir);

const git = spawnSync("git init", [args["--name"]], {
cwd: process.cwd(),
shell: true
Expand All @@ -220,17 +252,23 @@ demo`;
fs.mkdirSync(path.join(baseDir, "modules"));
fs.writeFileSync(path.join(baseDir, ".gitignore"), gitignore, "utf8");
fs.writeFileSync(path.join(baseDir, "modules", ".keep"), "", "utf8");
spawnSync("git add .gitignore modules", [], {
const gitAddResult = spawnSync("git add .gitignore modules", [], {
cwd: baseDir,
shell: true
});
spawnSync("git commit -m 'Initial commit'", [], {

logger.verbose("init git add", prettyPrintShellOutput(gitAddResult));

const gitCommitResult = spawnSync("git commit -m 'Initial commit'", [], {
cwd: baseDir,
shell: true
});

logger.verbose("init git commit", prettyPrintShellOutput(gitCommitResult));
},
upgrade: () => {
const args = arg({
...GLOBAL_ARGS,
"--version": String
});
analytics.sendEvent({ name: EVENT.UPGRADE });
Expand All @@ -246,7 +284,9 @@ demo`;
info();
},
config: () => {
const args = arg({});
const args = arg({
...GLOBAL_ARGS
});

const action = args._[1];
const key = args._[2];
Expand Down Expand Up @@ -284,6 +324,7 @@ demo`;

modules: async () => {
const args = arg({
...GLOBAL_ARGS,
"--search": String,
"--visibility": String,
"--status": String,
Expand Down Expand Up @@ -336,7 +377,8 @@ demo`;
);
}

await setModuleDetails(id,
await setModuleDetails(
id,
args["--name"],
args["--description"],
args["--acceptance-criteria"],
Expand Down Expand Up @@ -382,7 +424,9 @@ demo`;
},

feedback: () => {
const args = arg({});
const args = arg({
...GLOBAL_ARGS
});
const action = args._[1];

if (!action) {
Expand All @@ -407,7 +451,24 @@ demo`;
sendFeedback(action);
}
},

optout: () => {
if (!configFile.get(OPT_IN_NAME)) {
console.log("You are already opted out for analytics");
return;
}
configFile.set(OPT_IN_NAME, false);
configFile.save();
valid("Successfully opted out of analytics");
},
optin: () => {
if (configFile.get(OPT_IN_NAME)) {
console.log("You are already opted in for analytics");
return;
}
configFile.set(OPT_IN_NAME, true);
configFile.save();
valid("Successfully opted in of analytics");
},
help: () => {
console.log(`usage: cb <command>

Expand All @@ -429,6 +490,8 @@ Commands available:
logout Logout of your Crowdbotics account
publish Publish your modules to your organization's private catalog
modules Manage modules for your organization
optin Opt in for Crowdbotics analytics
optout Opt out for Crowdbotics analytics

Parse and validate your modules:
cb parse --source <path>
Expand Down Expand Up @@ -486,7 +549,11 @@ Glossary:
};

try {
dispatcher();
dispatcher().catch((error) => {
sentryMonitoring.captureException(error);
invalid(error);
});
} catch (err) {
sentryMonitoring.captureException(err);
invalid(err);
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@
"js-yaml": "^4.1.0",
"node-fetch": "^3.3.2",
"ora": "^7.0.1",
"prettier": "^2.6.2"
"prettier": "^2.6.2",
"semver": "^7.6.0",
"unzip-stream": "^0.3.4"
},
"resolutions": {
"shell-quote": "1.7.3"
Expand Down
17 changes: 17 additions & 0 deletions scripts/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import fse from "fs-extra";
import path from "path";
import find from "find";
import { execSync } from "child_process";
import { logger } from "./utils/logger.js";

const IGNORED_ENTRIES = ["meta.json", "node_modules"];

Expand All @@ -25,12 +26,15 @@ const getPkgJsonDeps = (pkgJson) => {
};

function installPipPackage(file, moduleDir, appDir, metaRoot) {
logger.verbose("installing pip package", file, moduleDir);

const packagePath = path
.join(metaRoot, path.dirname(file).replace(moduleDir, ""))
.replace(/^\/backend/, "");

process.chdir(path.join(appDir, "backend"));
const command = `pipenv install -e ./${packagePath}`;

try {
execSync(command);
} catch (err) {
Expand All @@ -39,6 +43,8 @@ function installPipPackage(file, moduleDir, appDir, metaRoot) {
}

function installNpmPackage(file, moduleDir, appDir, metaRoot) {
logger.verbose("installing npm package", file, moduleDir);

const pkgJson = JSON.parse(fs.readFileSync(file, "utf8"));
const yarnPath = path.join(
"file:.",
Expand All @@ -47,8 +53,11 @@ function installNpmPackage(file, moduleDir, appDir, metaRoot) {
);
const packages = [yarnPath, ...getPkgJsonDeps(pkgJson)].join(" ");

logger.verbose("installing npm packages", packages, yarnPath);

process.chdir(appDir);
const command = `yarn add ${packages}`;

try {
execSync(command);
} catch (err) {
Expand All @@ -71,12 +80,20 @@ export function addModules(modules, source, dir, gitRoot) {
dir = path.join(gitRoot, "demo");
}

logger.verbose("add source", source, "dir", dir);

modules.forEach((module) => {
process.chdir(gitRoot);
const originModuleDir = path.join(source, module);

logger.verbose("add module", module, originModuleDir);

const meta = JSON.parse(
fs.readFileSync(path.join(originModuleDir, "meta.json"), "utf8")
);

logger.verbose("add module meta", meta);

const targetModuleDir = path.join(dir, meta.root);

// cleanup node_modules
Expand Down
4 changes: 2 additions & 2 deletions scripts/analytics/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
PRODUCTION_SEGMENT_KEY
} from "./constants.js";

export const HAS_ASKED_OPT_IN_NAME = "has-asked-opt-in";
export const OPT_IN_NAME = "opt-in";
export const HAS_ASKED_OPT_IN_NAME = "has-asked-opt-in-default";
export const OPT_IN_NAME = "opted-in-default";

export const SEGMENT_API_KEY =
configFile.get(HOST_CONFIG_NAME) === DEFAULT_HOST
Expand Down
21 changes: 2 additions & 19 deletions scripts/analytics/scripts.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,8 @@
import inquirer from "inquirer";
import { section } from "../../utils.js";
import { configFile } from "../utils/configFile.js";
import { HAS_ASKED_OPT_IN_NAME, OPT_IN_NAME } from "./config.js";

export const askOptIn = async () => {
const { optInStatus } = await inquirer.prompt({
message: "Send diagnostics & usage to Crowdbotics (y/n):",
name: "optInStatus",
type: "input"
});

const optedIn = optInStatus.trim().toLowerCase() === "y";

if (!optedIn) {
section("Thanks for your response. We will not send diagnostics & usage.");
configFile.set(OPT_IN_NAME, false);
} else {
section("Thanks for your response. We will send diagnostics & usage.");
configFile.set(OPT_IN_NAME, true);
}
export const configureInitialLogin = async () => {
configFile.set(OPT_IN_NAME, true);
configFile.set(HAS_ASKED_OPT_IN_NAME, true);
configFile.save();
return optedIn;
};
Loading