Skip to content

Commit a1487b3

Browse files
clydinmgechev
authored andcommitted
feat(@angular/cli): check/prompt for workspace level analytics configuration (#14264)
1 parent 676b329 commit a1487b3

File tree

2 files changed

+82
-4
lines changed

2 files changed

+82
-4
lines changed

packages/angular/cli/models/analytics.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,67 @@ export async function getGlobalAnalytics(): Promise<UniversalAnalytics | undefin
565565
}
566566
}
567567

568+
export async function hasWorkspaceAnalyticsConfiguration(): Promise<boolean> {
569+
try {
570+
const globalWorkspace = await getWorkspace('local');
571+
const analyticsConfig: string | undefined | null | { uid?: string } = globalWorkspace
572+
&& globalWorkspace.getCli()
573+
&& globalWorkspace.getCli()['analytics'];
574+
575+
if (analyticsConfig !== undefined) {
576+
return true;
577+
}
578+
} catch {}
579+
580+
return false;
581+
}
582+
583+
/**
584+
* Get the workspace analytics object for the user. This returns an instance of UniversalAnalytics,
585+
* or undefined if analytics are disabled.
586+
*
587+
* If any problem happens, it is considered the user has been opting out of analytics.
588+
*/
589+
export async function getWorkspaceAnalytics(): Promise<UniversalAnalytics | undefined> {
590+
analyticsDebug('getWorkspaceAnalytics');
591+
try {
592+
const globalWorkspace = await getWorkspace('local');
593+
const analyticsConfig: string | undefined | null | { uid?: string } = globalWorkspace
594+
&& globalWorkspace.getCli()
595+
&& globalWorkspace.getCli()['analytics'];
596+
analyticsDebug('Workspace Analytics config found: %j', analyticsConfig);
597+
598+
if (analyticsConfig === false) {
599+
analyticsDebug('Analytics disabled. Ignoring all analytics.');
600+
601+
return undefined;
602+
} else if (analyticsConfig === undefined || analyticsConfig === null) {
603+
analyticsDebug('Analytics settings not found. Ignoring all analytics.');
604+
605+
return undefined;
606+
} else {
607+
let uid: string | undefined = undefined;
608+
if (typeof analyticsConfig == 'string') {
609+
uid = analyticsConfig;
610+
} else if (typeof analyticsConfig == 'object' && typeof analyticsConfig['uid'] == 'string') {
611+
uid = analyticsConfig['uid'];
612+
}
613+
614+
analyticsDebug('client id: %j', uid);
615+
if (uid == undefined) {
616+
return undefined;
617+
}
618+
619+
return new UniversalAnalytics(AnalyticsProperties.AngularCliDefault, uid);
620+
}
621+
} catch (err) {
622+
analyticsDebug('Error happened during reading of analytics config: %s', err.message);
623+
624+
return undefined;
625+
}
626+
627+
}
628+
568629
/**
569630
* Return the usage analytics sharing setting, which is either a property string (GA-XXXXXXX-XX),
570631
* or undefined if no sharing.

packages/angular/cli/models/command-runner.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ import * as debug from 'debug';
1919
import { readFileSync } from 'fs';
2020
import { join, resolve } from 'path';
2121
import { parseJsonSchemaToCommandDescription } from '../utilities/json-schema';
22-
import { UniversalAnalytics, getGlobalAnalytics, getSharedAnalytics } from './analytics';
22+
import {
23+
getGlobalAnalytics,
24+
getSharedAnalytics,
25+
getWorkspaceAnalytics,
26+
hasWorkspaceAnalyticsConfiguration,
27+
promptProjectAnalytics,
28+
} from './analytics';
2329
import { Command } from './command';
2430
import { CommandDescription, CommandWorkspace } from './interface';
2531
import * as parser from './parser';
@@ -58,8 +64,19 @@ export interface CommandMapOptions {
5864
* Create the analytics instance.
5965
* @private
6066
*/
61-
async function _createAnalytics(): Promise<analytics.Analytics> {
62-
const config = await getGlobalAnalytics();
67+
async function _createAnalytics(workspace: boolean): Promise<analytics.Analytics> {
68+
let config = await getGlobalAnalytics();
69+
// If in workspace and global analytics is enabled, defer to workspace level
70+
if (workspace && config) {
71+
// TODO: This should honor the `no-interactive` option.
72+
// It is currently not an `ng` option but rather only an option for specific commands.
73+
// The concept of `ng`-wide options are needed to cleanly handle this.
74+
if (!(await hasWorkspaceAnalyticsConfiguration())) {
75+
await promptProjectAnalytics();
76+
}
77+
config = await getWorkspaceAnalytics();
78+
}
79+
6380
const maybeSharedAnalytics = await getSharedAnalytics();
6481

6582
if (config && maybeSharedAnalytics) {
@@ -214,7 +231,7 @@ export async function runCommand(
214231
return map;
215232
});
216233

217-
const analytics = options.analytics || await _createAnalytics();
234+
const analytics = options.analytics || await _createAnalytics(!!workspace.configFile);
218235
const context = { workspace, analytics };
219236
const command = new description.impl(context, description, logger);
220237

0 commit comments

Comments
 (0)