Skip to content
Permalink
Browse files

Fix: Refactor telemetry events logic

Fix #2962
Close #2993
  • Loading branch information...
molant committed Sep 18, 2019
1 parent ed79303 commit 9f8af134727a795379e004c163598315a2537f64
@@ -12,33 +12,22 @@
* ------------------------------------------------------------------------------
*/

const tracking = (/--tracking[=\s]+([^\s]*)/i).exec(process.argv.join(' '));
const telemetry = (/--tracking[=\s]+([^\s]*)/i).exec(process.argv.join(' '));

import { configStore, appInsights } from '@hint/utils';
import { appInsights } from '@hint/utils';

const trackingEnv = process.env.HINT_TRACKING;
let enableTracking;
const telemetryEnv = process.env.HINT_TRACKING;
let enableTelemetry;

if (tracking) {
enableTracking = tracking[1] === 'on';
} else if (trackingEnv) {
enableTracking = trackingEnv === 'on';
if (telemetry) {
enableTelemetry = telemetry[1] === 'on';
} else if (telemetryEnv) {
enableTelemetry = telemetryEnv === 'on';
}

if (typeof enableTracking !== 'undefined') {
if (enableTracking) {
const alreadyRun: boolean = configStore.get('run');
const configured = appInsights.isConfigured();

if (typeof enableTelemetry !== 'undefined') {
if (enableTelemetry) {
appInsights.enable();

if (!configured) {
if (!alreadyRun) {
appInsights.trackEvent('FirstRun');
} else {
appInsights.trackEvent('SecondRun');
}
}
} else {
appInsights.disable();
}
@@ -27,7 +27,7 @@ const { askQuestion, mergeEnvWithOptions } = misc;
const { installPackages } = npm;
const { cwd } = fs;
const debug: debug.IDebugger = d(__filename);
const configStoreKey: string = 'run';
const alreadyRunKey: string = 'run';
const spinner = ora({ spinner: 'line' });

/*
@@ -104,46 +104,57 @@ const pruneUserConfig = (userConfig: UserConfig) => {
};
};

/** Ask user if he wants to activate the telemetry or not. */
const askForTelemetryConfirmation = async (userConfig: UserConfig) => {
if (appInsights.isConfigured()) {
return;
}

if (isCI) {
if (!appInsights.isConfigured()) {
showCITelemetryMessage();
}
const askForTelemetryConfirmation = async () => {
showTelemetryMessage();

return;
}
const message = `Do you want to opt-in?`;

const alreadyRun: boolean = configStore.get(configStoreKey);
debug(`Prompting telemetry permission.`);

if (!alreadyRun) { /* This is the first time, don't ask anything. */
configStore.set(configStoreKey, true);
const telemetryEnabled = await askQuestion(message);

return;
if (telemetryEnabled) {
appInsights.enable();
} else {
appInsights.disable();
}

showTelemetryMessage();

const message: string = `Do you want to opt-in?`;
return telemetryEnabled;
};

debug(`Prompting telemetry permission.`);
/** Ask user if he wants to activate the telemetry or not. */
const sendTelemetryIfEnabled = async (userConfig: UserConfig) => {
const telemetryConfigured = appInsights.isConfigured();
let telemetryEnabled = appInsights.isEnabled();
const alreadyRun: boolean = configStore.get(alreadyRunKey);

const confirm: boolean = await askQuestion(message);
if (!alreadyRun) {
configStore.set(alreadyRunKey, true);
}

if (confirm) {
appInsights.enable();
if (!telemetryConfigured) {
if (isCI) {
showCITelemetryMessage();
telemetryEnabled = false;
} else if (alreadyRun) {
/* Only prompt the user about opt-intelemetry if they have run webhint before. */
telemetryEnabled = await askForTelemetryConfirmation();

appInsights.trackEvent('SecondRun');
appInsights.trackEvent('analyze', pruneUserConfig(userConfig));
if (telemetryEnabled) {
appInsights.trackEvent('cli-telemetry');
}
}
}

if (!telemetryEnabled) {
return;
}

appInsights.disable();
appInsights.trackEvent('cli-analyze', {
ci: isCI,
previouslyRun: alreadyRun,
...pruneUserConfig(userConfig)
});
};

/**
@@ -269,11 +280,11 @@ const loadUserConfig = async (actions: CLIOptions, targets: URL[]): Promise<User

const askToInstallPackages = async (resources: HintResources): Promise<boolean> => {
if (resources.missing.length > 0) {
appInsights.trackEvent('missing', resources.missing);
appInsights.trackEvent('cli-missing', resources.missing);
}

if (resources.incompatible.length > 0) {
appInsights.trackEvent('incompatible', resources.incompatible);
appInsights.trackEvent('cli-incompatible', resources.incompatible);
}

const missingPackages = resources.missing.map((name) => {
@@ -384,8 +395,6 @@ export default async (actions: CLIOptions): Promise<boolean> => {
return false;
}

appInsights.trackEvent('analyze', pruneUserConfig(userConfig));

const start = Date.now();
let exitCode = 0;

@@ -453,7 +462,7 @@ export default async (actions: CLIOptions): Promise<boolean> => {
try {
await webhint.analyze(targets, getAnalyzeOptions());

await askForTelemetryConfirmation(userConfig!);
await sendTelemetryIfEnabled(userConfig!);
} catch (e) {
exitCode = 1;
endSpinner('fail');
@@ -464,9 +464,9 @@ test('If there is missing or incompatible packages, they should be tracked', asy
}

t.true(appInsightTrackEventSpy.calledTwice);
t.is(appInsightTrackEventSpy.args[0][0], 'missing');
t.is(appInsightTrackEventSpy.args[0][0], 'cli-missing');
t.deepEqual(appInsightTrackEventSpy.args[0][1], ['hint1']);
t.is(appInsightTrackEventSpy.args[1][0], 'incompatible');
t.is(appInsightTrackEventSpy.args[1][0], 'cli-incompatible');
t.deepEqual(appInsightTrackEventSpy.args[1][1], ['hint2']);
});

@@ -477,7 +477,7 @@ test('If no sites are defined, it should return false', async (t) => {
t.false(result);
});

test('If there is no errors analyzing the url, and it is the second time running a scan, and the user confirm telemetry, telemetry should be enabled', async (t) => {
test('If there is no errors analyzing the url, webhint was previously run, and the user confirm telemetry, the payload should indicate it', async (t) => {
const sandbox = t.context.sandbox;
const fakeAnalyzer = new FakeAnalyzer();

@@ -499,16 +499,21 @@ test('If there is no errors analyzing the url, and it is the second time running
const args = appInsightTrackEventSpy.args;

t.true(appInsightEnableSpy.calledOnce);
t.true(appInsightTrackEventSpy.calledThrice);
t.is(args[1][0], 'SecondRun');
t.is(args[2][0], 'analyze');
t.true(appInsightTrackEventSpy.calledTwice);
t.is(args[0][0], 'cli-telemetry');
t.is(args[1][0], 'cli-analyze');
t.true(args[1][1].previouslyRun);
});

test('Telemetry should trim options from a connector', async (t) => {
const sandbox = t.context.sandbox;
const fakeAnalyzer = new FakeAnalyzer();

sandbox.stub(t.context.analyzer.Analyzer as any, 'create').returns(fakeAnalyzer);
sandbox.stub(t.context.appInsight, 'isConfigured').returns(true);
sandbox.stub(t.context.appInsight, 'isEnabled').returns(true);
sandbox.stub(t.context.configStore, 'get').returns(true);

sandbox.stub(fakeAnalyzer, 'analyze').resolves();

sandbox.stub(t.context.analyzer.Analyzer as any, 'getUserConfig').returns({
@@ -530,10 +535,11 @@ test('Telemetry should trim options from a connector', async (t) => {

await analyze(actions);

t.true(appInsightTrackEventSpy.calledOnce);
t.falsy(appInsightTrackEventSpy.args[0][1].connector.options);
});

test('Telemetry should remove properties from rules', async (t) => {
test('Telemetry should remove properties from rules and send the "cli-telemetry" when opting-in', async (t) => {
const sandbox = t.context.sandbox;
const fakeAnalyzer = new FakeAnalyzer();

@@ -562,8 +568,10 @@ test('Telemetry should remove properties from rules', async (t) => {

await analyze(actions);

const hints = appInsightTrackEventSpy.args[0][1].hints;

const hints = appInsightTrackEventSpy.args[1][1].hints;

t.is(appInsightTrackEventSpy.args[0][0], 'cli-telemetry');
t.is(hints.hint1, 'error');
t.is(hints.hint2, 'warning');
});
@@ -10,7 +10,7 @@ interface IFlushOptions {
const debug: debug.IDebugger = d(__filename);
const configStoreKey: string = 'insight';

let insightsEnabled = configStore.get(configStoreKey);
let insightsEnabled: boolean | undefined = configStore.get(configStoreKey);

let appInsightsClient: appInsights.TelemetryClient = {
flush(options: IFlushOptions) {

0 comments on commit 9f8af13

Please sign in to comment.
You can’t perform that action at this time.