mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-21 22:47:48 +00:00
Merge pull request #1410 from balena-io/oclif-mixpanel
Add missing oclif-based commands to mixpanel tracking
This commit is contained in:
commit
596d1bdc21
@ -4,7 +4,7 @@
|
||||
"target": "es2017",
|
||||
"strict": true,
|
||||
"strictPropertyInitialization": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"preserveConstEnums": true,
|
||||
"removeComments": true,
|
||||
|
@ -154,5 +154,17 @@ exports.run = (argv) ->
|
||||
else
|
||||
capitanoExecuteAsync(cli)
|
||||
|
||||
Promise.all([events.trackCommand(cli), runCommand()])
|
||||
trackCommand = ->
|
||||
getMatchCommandAsync = Promise.promisify(capitano.state.getMatchCommand)
|
||||
getMatchCommandAsync(cli.command)
|
||||
.then (command) ->
|
||||
# cmdSignature is literally a string like, for example:
|
||||
# "push <applicationOrDevice>"
|
||||
# ("applicationOrDevice" is NOT replaced with its actual value)
|
||||
# In case of failures like an inexistent or invalid command,
|
||||
# command.signature.toString() returns '*'
|
||||
cmdSignature = command.signature.toString()
|
||||
events.trackCommand(cmdSignature)
|
||||
|
||||
Promise.all([trackCommand(), runCommand()])
|
||||
.catch(require('./errors').handleError)
|
||||
|
@ -19,7 +19,7 @@ import { Main } from '@oclif/command';
|
||||
import { ExitError } from '@oclif/errors';
|
||||
|
||||
import { AppOptions } from './app';
|
||||
import { handleError } from './errors';
|
||||
import { trackPromise } from './hooks/prerun/track';
|
||||
|
||||
class CustomMain extends Main {
|
||||
protected _helpOverride(): boolean {
|
||||
@ -36,7 +36,7 @@ class CustomMain extends Main {
|
||||
* oclif CLI entrypoint
|
||||
*/
|
||||
export function run(command: string[], options: AppOptions) {
|
||||
return CustomMain.run(command).then(
|
||||
const runPromise = CustomMain.run(command).then(
|
||||
() => {
|
||||
if (!options.noFlush) {
|
||||
return require('@oclif/command/flush');
|
||||
@ -46,8 +46,12 @@ export function run(command: string[], options: AppOptions) {
|
||||
// oclif sometimes exits with ExitError code 0 (not an error)
|
||||
if (error instanceof ExitError && error.oclif.exit === 0) {
|
||||
return;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
handleError(error);
|
||||
},
|
||||
);
|
||||
return Promise.all([trackPromise, runPromise]).catch(
|
||||
require('./errors').handleError,
|
||||
);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import { exitWithExpectedError } from './utils/patterns';
|
||||
|
||||
export interface AppOptions {
|
||||
// Prevent the default behaviour of flushing stdout after running a command
|
||||
noFlush: boolean;
|
||||
noFlush?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,7 +160,7 @@ function isOclifCommand(argvSlice: string[]): [boolean, boolean] {
|
||||
* CLI entrypoint, but see also `bin/balena` and `bin/balena-dev` which
|
||||
* call this function.
|
||||
*/
|
||||
export function run(cliArgs = process.argv, options: AppOptions): void {
|
||||
export function run(cliArgs = process.argv, options: AppOptions = {}): void {
|
||||
// globalInit() must be called very early on (before other imports) because
|
||||
// it sets up Sentry error reporting, global HTTP proxy settings, balena-sdk
|
||||
// shared options, and performs node version requirement checks.
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
import BalenaSdk = require('balena-sdk');
|
||||
import Promise = require('bluebird');
|
||||
import * as Capitano from 'capitano';
|
||||
import _ = require('lodash');
|
||||
import Mixpanel = require('mixpanel');
|
||||
import Raven = require('raven');
|
||||
@ -24,7 +23,6 @@ import Raven = require('raven');
|
||||
import packageJSON = require('../package.json');
|
||||
|
||||
const getBalenaSdk = _.once(() => BalenaSdk.fromSharedOptions());
|
||||
const getMatchCommandAsync = Promise.promisify(Capitano.state.getMatchCommand);
|
||||
const getMixpanel = _.once<any>(() => {
|
||||
const settings = require('balena-settings-client');
|
||||
return Mixpanel.init('00000000000000000000000000000000', {
|
||||
@ -34,7 +32,7 @@ const getMixpanel = _.once<any>(() => {
|
||||
});
|
||||
});
|
||||
|
||||
export function trackCommand(capitanoCli: Capitano.Cli) {
|
||||
export function trackCommand(commandSignature: string) {
|
||||
const balena = getBalenaSdk();
|
||||
return Promise.props({
|
||||
balenaUrl: balena.settings.get('balenaUrl'),
|
||||
@ -42,20 +40,20 @@ export function trackCommand(capitanoCli: Capitano.Cli) {
|
||||
mixpanel: getMixpanel(),
|
||||
})
|
||||
.then(({ username, balenaUrl, mixpanel }) => {
|
||||
return getMatchCommandAsync(capitanoCli.command).then(command => {
|
||||
return Promise.try(() => {
|
||||
Raven.mergeContext({
|
||||
user: {
|
||||
id: username,
|
||||
username,
|
||||
},
|
||||
});
|
||||
// `command.signature.toString()` results in a string like, for example:
|
||||
// commandSignature is a string like, for example:
|
||||
// "push <applicationOrDevice>"
|
||||
// That's literally so: "applicationOrDevice" is NOT replaced with
|
||||
// the actual application ID or device ID. The purpose is find out the
|
||||
// most / least used command verbs, so we can focus our development
|
||||
// effort where it is most beneficial to end users.
|
||||
return mixpanel.track(`[CLI] ${command.signature.toString()}`, {
|
||||
return mixpanel.track(`[CLI] ${commandSignature}`, {
|
||||
distinct_id: username,
|
||||
version: packageJSON.version,
|
||||
node: process.version,
|
||||
|
44
lib/hooks/prerun/track.ts
Normal file
44
lib/hooks/prerun/track.ts
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2019 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Hook } from '@oclif/config';
|
||||
|
||||
// note: trackPromise is subject to a Bluebird.timeout, defined in events.ts
|
||||
export let trackPromise: PromiseLike<void>;
|
||||
|
||||
/**
|
||||
* This is an oclif 'prerun' hook. This hook runs after the command line is
|
||||
* parsed by oclif, but before the command's run() function is called.
|
||||
* See: https://oclif.io/docs/hooks
|
||||
*
|
||||
* This hook is used to track CLI command signatures with mixpanel. This
|
||||
* is the oclif version of what is already done for Capitano commands.
|
||||
*
|
||||
* A command signature is something like "env add NAME [VALUE]". That's
|
||||
* literally so: 'NAME' and 'VALUE' are NOT replaced with actual values.
|
||||
*/
|
||||
const hook: Hook<'prerun'> = async function(options) {
|
||||
const events = await import('../../events');
|
||||
const usage: string | string[] | undefined = options.Command.usage;
|
||||
const cmdSignature =
|
||||
usage == null ? '*' : typeof usage === 'string' ? usage : usage.join(' ');
|
||||
|
||||
// Intentionally do not await for the track promise here, in order to
|
||||
// run the command tracking and the command itself in parallel.
|
||||
trackPromise = events.trackCommand(cmdSignature);
|
||||
};
|
||||
|
||||
export default hook;
|
@ -31,6 +31,7 @@
|
||||
"assets": [
|
||||
"build/actions-oclif",
|
||||
"build/auth/pages/*.ejs",
|
||||
"build/hooks",
|
||||
"node_modules/resin-discoverable-services/services/**/*"
|
||||
]
|
||||
},
|
||||
@ -71,6 +72,9 @@
|
||||
"oclif": {
|
||||
"bin": "balena",
|
||||
"commands": "./build/actions-oclif",
|
||||
"hooks": {
|
||||
"prerun": "./build/hooks/prerun/track"
|
||||
},
|
||||
"macos": {
|
||||
"identifier": "io.balena.cli",
|
||||
"sign": "Developer ID Installer: Rulemotion Ltd (66H43P8FRG)"
|
||||
|
Loading…
Reference in New Issue
Block a user