Skip to content

Commit

Permalink
feat: improve CLI usage tracking (#723)
Browse files Browse the repository at this point in the history
  • Loading branch information
adrians5j authored Feb 18, 2020
1 parent fc2bff2 commit 1bbf80a
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 59 deletions.
22 changes: 8 additions & 14 deletions packages/cli/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,26 +133,20 @@ yargs.command(
);

yargs.command(
"disable-tracking",
"Disable tracking of Webiny stats.",
"enable-tracking",
"Enable tracking of Webiny stats.",
() => {},
() => {
const { setTracking } = require("./config");
setTracking(false);
console.log("INFO: tracking of Webiny stats is now DISABLED!");
async () => {
await require("./sls/enableTracking")();
}
);

yargs.command(
"enable-tracking",
"Enable tracking of Webiny stats.",
"disable-tracking",
"Disable tracking of Webiny stats.",
() => {},
() => {
const { setTracking } = require("./config");
setTracking(true);
console.log(
"INFO: tracking of Webiny stats is now ENABLED! Thank you for helping us with anonymous data 🎉"
);
async () => {
await require("./sls/disableTracking")();
}
);

Expand Down
9 changes: 7 additions & 2 deletions packages/cli/create/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ const uuid = require("uuid/v4");
const loadJsonFile = require("load-json-file");
const ora = require("ora");
const writeJsonFile = require("write-json-file");
const { trackProject } = require("@webiny/tracking");
const { trackActivity } = require("@webiny/tracking");
const { version } = require(require.resolve("@webiny/cli/package.json"));
const { getSuccessBanner } = require("./messages");
const { getPackageVersion } = require("./utils");
const uniqueId = require('uniqid');

const globFiles = util.promisify(glob);

Expand All @@ -33,6 +34,10 @@ module.exports = async ({ name, tag }) => {
}

console.log(`📦 Creating a new Webiny project in ${green(root)}...`);

const activityId = uniqueId();
await trackActivity({ activityId, type: "create_project_start", cliVersion: version });

fs.ensureDirSync(root);
process.chdir(root);

Expand Down Expand Up @@ -126,7 +131,7 @@ module.exports = async ({ name, tag }) => {
await execa("yarn", [], { cwd: root });
spinner.succeed(`All dependencies installed successfully!`);

await trackProject({ cliVersion: version });
await trackActivity({ activityId, type: "create_project_end", cliVersion: version });

console.log(await getSuccessBanner());
};
Expand Down
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"semver": "^7.1.2",
"traverse": "^0.6.6",
"update-notifier": "^3.0.1",
"uniqid": "^5.0.3",
"uuid": "^3.3.3",
"write-json-file": "^4.2.0",
"yargs": "^14.0.0"
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/sls/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ module.exports = async inputs => {
webinyJs
)}, skipping processing of hooks.`
);

console.log(`\n🎉 Done! Deploy finished in ${green(duration + "s")}.`);

return;
}

Expand All @@ -119,6 +121,7 @@ module.exports = async inputs => {
}

console.log(`\n🎉 Done! Deploy finished in ${green(duration + "s")}.`);

notify({ message: `API deploy completed in ${duration}s.` });

if (output.cdn) {
Expand Down
10 changes: 10 additions & 0 deletions packages/cli/sls/disableTracking.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const { setTracking } = require("./../config");
const { version } = require(require.resolve("@webiny/cli/package.json"));
const { trackActivity } = require("@webiny/tracking");
const uniqueId = require('uniqid');

module.exports = async () => {
await trackActivity({ type: 'tracking-disabled', cliVersion: version, activityId: uniqueId() });
setTracking(false);
console.log("INFO: tracking of Webiny stats is now DISABLED!");
};
8 changes: 8 additions & 0 deletions packages/cli/sls/enableTracking.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const { setTracking } = require("./../config");

module.exports = async () => {
setTracking(true);
console.log(
"INFO: tracking of Webiny stats is now ENABLED! Thank you for helping us with anonymous data 🎉"
);
};
2 changes: 1 addition & 1 deletion packages/cli/sls/execute.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ module.exports = async (inputs, method = "default") => {
const component = new Template(`Webiny.${env}`, context);
await component.init();

const output = await component[method]({ env, debug, alias });
const output = await component[method]({ env, debug, alias, what });
if (debug) {
// Add an empty line after debug output for nicer output
console.log();
Expand Down
71 changes: 52 additions & 19 deletions packages/cli/sls/template/serverless.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ const fs = require("fs");
const path = require("path");
const { Component } = require("@serverless/core");
const { loadEnv } = require("../utils");
const uniqueId = require("uniqid");
const { trackActivity, trackError } = require("@webiny/tracking");
const { version } = require(require.resolve("@webiny/cli/package.json"));

const {
getTemplate,
Expand Down Expand Up @@ -52,37 +55,67 @@ class Template extends Component {
}

async deploy(inputs = {}) {
this.context.status("Deploying");
const activityId = uniqueId();
const { what } = inputs;

await trackActivity({
activityId,
type: `${what}_deploy_start`,
cliVersion: version,
context: this.context
});

const template = await getTemplate(inputs);
try {
this.context.status("Deploying");

const resolvedTemplate = resolveTemplate(inputs, template);
const template = await getTemplate(inputs);

this.context.debug("Collecting components from the template.");
const resolvedTemplate = resolveTemplate(inputs, template);

const allComponents = getAllComponents(resolvedTemplate);
this.context.debug("Collecting components from the template.");

const allComponentsWithDependencies = setDependencies(allComponents);
const allComponents = getAllComponents(resolvedTemplate);

const graph = createGraph(allComponentsWithDependencies);
const allComponentsWithDependencies = setDependencies(allComponents);

await syncState(allComponentsWithDependencies, this);
const graph = createGraph(allComponentsWithDependencies);

this.context.debug(`Executing the template's components graph.`);
await syncState(allComponentsWithDependencies, this);

const allComponentsWithOutputs = await executeGraph(
allComponentsWithDependencies,
graph,
this,
inputs
);
this.context.debug(`Executing the template's components graph.`);

const outputs = getOutputs(allComponentsWithOutputs);
const allComponentsWithOutputs = await executeGraph(
allComponentsWithDependencies,
graph,
this,
inputs
);

this.state.outputs = outputs;
await this.save();
const outputs = getOutputs(allComponentsWithOutputs);

return outputs;
this.state.outputs = outputs;
await this.save();

await trackActivity({
activityId,
type: `${what}_deploy_end`,
cliVersion: version,
context: this.context
});

return outputs;
} catch (e) {
await trackError({
context: this.context,
activityId,
type: `${what}_deploy`,
cliVersion: version,
errorMessage: e.message,
errorStack: e.stack
});

throw e;
}
}

async deployAlias(alias, inputs) {
Expand Down
5 changes: 1 addition & 4 deletions packages/cli/sls/template/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,7 @@ const executeGraph = async (allComponents, graph, instance, inputs) => {
await trackComponent({ context: instance.context, component: componentData.path });
} catch (err) {
instance.context.log(`An error occurred during deployment of ${red(alias)}`);
console.log();
console.log(err);
console.log();
process.exit(1);
throw err;
}

graph.removeNode(alias);
Expand Down
28 changes: 22 additions & 6 deletions packages/http-handler-ssr/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,34 @@ import ssrServe from "./ssrServe";
import models from "./models";
import { withFields, boolean, number, string, fields } from "@webiny/commodo/fields";

const OptionsModel = withFields({
ssrFunction: string({ value: process.env.SSR_FUNCTION }),
cache: fields({
const Animal = withFields({
name: string({
validate: value => {
if (!value) {
throw Error("A pet must have a name!");
}
}
}),
age: number(),
isAwesome: boolean(),
about: fields({
value: {},
instanceOf: withFields({
enabled: boolean({ value: false }),
ttl: number({ value: 80 }),
staleTtl: number({ value: 20 })
type: string({ value: "cat" }),
dangerous: boolean({ value: true })
})()
})
})();

const animal = new Animal();
animal.populate({ age: "7" }); // Throws data type error, cannot populate a string with number.

animal.populate({ age: 7 });
await animal.validate(); // Throws a validation error - name must be defined.

animal.name = "Garfield";
await animal.validate(); // All good.

export default rawOptions => {
const options = new OptionsModel().populate(rawOptions);
const plugins = [models(options), ssrServe(options)];
Expand Down
76 changes: 63 additions & 13 deletions packages/tracking/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,24 @@ const os = require("os");
const path = require("path");
const readJson = require("load-json-file");
const request = require("request");
const get = require("lodash.get");

let config;
const defaultLogger = () => {};

const sendStats = data => {
const sendStats = (action, data) => {
return new Promise(resolve => {
request.post(
{
url: "https://stats.webiny.com/track",
json: data
json: { action, data }
},
resolve
);
});
};

const loadConfig = async ({ logger = defaultLogger }) => {
const loadConfig = async ({ logger = defaultLogger } = {}) => {
if (!config) {
const dataPath = path.join(os.homedir(), ".webiny", "config");
try {
Expand All @@ -45,10 +46,10 @@ const trackComponent = async ({ context, component, method = "deploy" }) => {

const { name, version } = readJson.sync(path.join(path.dirname(component), "package.json"));
context.debug(`Tracking component: ${name} (${method})`);
await sendStats({
await sendStats("telemetry", {
type: "component",
user: config.id,
instance: context.instance.id,
instance: get(context, "instance.id") || "",
component: name,
version,
method
Expand All @@ -58,25 +59,74 @@ const trackComponent = async ({ context, component, method = "deploy" }) => {
}
};

const trackProject = async ({ cliVersion }) => {
const trackActivity = async ({ cliVersion, type, activityId, context = {} }) => {
if (!cliVersion) {
throw new Error(`Cannot track activity - "cliVersion" not specified.`);
}

if (!type) {
throw new Error(`Cannot track activity - "type" not specified.`);
}

if (!activityId) {
throw new Error(`Cannot track activity - "activityId" not specified.`);
}

try {
await loadConfig();
await loadConfig({ logger: context.debug });

if (config.tracking !== true) {
return;
}

await sendStats({
type: "project",
user: config.id,
version: cliVersion
await sendStats("activities", {
version: cliVersion,
type,
activityId,
instance: get(context, "instance.id") || "",
user: config.id
});
} catch (e) {
// Ignore errors
}
};

const trackError = async ({ cliVersion, type, errorMessage, errorStack, activityId, context = {} }) => {
if (!cliVersion) {
throw new Error("Cannot track activity - CLI version not specified.");
}

if (!type) {
throw new Error("Cannot track activity - type not specified.");
}

if (!errorMessage) {
throw new Error("Cannot track activity - CLI version not specified.");
}

try {
await loadConfig({ logger: context.debug });

if (config.tracking !== true) {
return;
}

await sendStats("errors", {
version: cliVersion,
type,
errorMessage,
errorStack,
activityId,
instance: get(context, "instance.id") || "",
user: config.id
});
} catch (e) {
// Ignore errors
}
};

module.exports = {
trackProject,
trackComponent
trackComponent,
trackActivity,
trackError
};
Loading

0 comments on commit 1bbf80a

Please sign in to comment.