Skip to content

Commit

Permalink
Adds a flag 'track' to allow users to configure analytics with flags (#…
Browse files Browse the repository at this point in the history
…1450)

* Adds a flag 'no-track' to allow users to configure analytics with flags

* Rework so that no-track bypasses settings.json

* Linting

* Move to --track, fix an issue with --track=true, doc changes

* Update boolean type

* Update version
  • Loading branch information
GJMcGowan authored and Ekrekr committed Oct 27, 2023
1 parent 6e4ce5d commit 4ea2693
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 24 deletions.
52 changes: 39 additions & 13 deletions cli/analytics.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,46 @@
import yargs from "yargs";

import Analytics from "analytics-node";
import { getConfigSettings, getConfigSettingsPath, upsertConfigSettings } from "df/cli/config";
import { ynQuestion } from "df/cli/console";
import { v4 as uuidv4 } from "uuid";
import {getConfigSettings, getConfigSettingsPath, upsertConfigSettings} from "df/cli/config";
import {ynQuestion} from "df/cli/console";
import {INamedOption} from "df/cli/yargswrapper";
import {v4 as uuidv4} from "uuid";

export const trackOption: INamedOption<yargs.Options> = {
name: "track",
option: {
describe: `Sets analytics tracking without asking the user. Overrides settings.json`,
type: "boolean"
}
};

const analytics = new Analytics("eR24ln3MniE3TKZXkvAkOGkiSN02xXqw");

let currentCommand: string;
let allowAnonymousAnalytics: boolean;
let anonymousUserId: string;

export async function maybeConfigureAnalytics() {
export async function maybeConfigureAnalytics(track?: boolean) {
const settings = await getConfigSettings();
if (track !== undefined) {
allowAnonymousAnalytics = track;
if (track) {
// in the case where the user *wants* tracking and has no settings.json
// assign them a temporary tracking id
anonymousUserId = settings.anonymousUserId || uuidv4();
}
return;
}
// We should only ask if users want to track analytics if they are in an interactive terminal;
if (!process.stdout.isTTY) {
return;
}
if (settings.allowAnonymousAnalytics !== undefined) {
allowAnonymousAnalytics = settings.allowAnonymousAnalytics;
anonymousUserId = settings.anonymousUserId;
return;
}

const optInResponse = ynQuestion(
`
To help improve the quality of our products, we collect anonymized usage data and anonymized stacktraces when crashes are encountered.
Expand All @@ -24,22 +49,24 @@ This can be changed at any point by modifying your settings file: ${getConfigSet
Would you like to opt-in to anonymous usage and error tracking?`,
false
);
allowAnonymousAnalytics = optInResponse;
anonymousUserId = uuidv4();

await upsertConfigSettings({
allowAnonymousAnalytics: optInResponse,
anonymousUserId: uuidv4()
allowAnonymousAnalytics,
anonymousUserId
});
}

export async function trackCommand(command: string) {
currentCommand = command;
const config = await getConfigSettings();
if (!config.allowAnonymousAnalytics) {
if (!allowAnonymousAnalytics) {
return;
}
currentCommand = command;
await new Promise(resolve => {
analytics.track(
{
userId: config.anonymousUserId,
userId: anonymousUserId,
event: "event_dataform_cli_command",
properties: {
command
Expand All @@ -54,14 +81,13 @@ export async function trackCommand(command: string) {
}

export async function trackError() {
const config = await getConfigSettings();
if (!config.allowAnonymousAnalytics) {
if (!allowAnonymousAnalytics) {
return;
}
await new Promise(resolve => {
analytics.track(
{
userId: config.anonymousUserId,
userId: anonymousUserId,
event: "event_dataform_cli_error",
properties: {
currentCommand
Expand Down
20 changes: 12 additions & 8 deletions cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { build, compile, credentials, init, install, run, table, test } from "df
import { CREDENTIALS_FILENAME } from "df/api/commands/credentials";
import * as dbadapters from "df/api/dbadapters";
import { prettyJsonStringify } from "df/api/utils";
import { trackError } from "df/cli/analytics";
import {trackError, trackOption} from "df/cli/analytics";
import {
print,
printCompiledGraph,
Expand Down Expand Up @@ -242,6 +242,7 @@ export function runCli() {
description: "Create a new dataform project.",
positionalOptions: [warehouseOption, projectDirOption],
options: [
trackOption,
{
name: defaultDatabaseOptionName,
option: {
Expand Down Expand Up @@ -316,7 +317,7 @@ export function runCli() {
format: `install [${projectDirMustExistOption.name}]`,
description: "Install a project's NPM dependencies.",
positionalOptions: [projectDirMustExistOption],
options: [],
options: [trackOption],
processFn: async argv => {
print("Installing NPM dependencies...\n");
await install(argv[projectDirMustExistOption.name]);
Expand All @@ -329,6 +330,7 @@ export function runCli() {
description: `Create a ${credentials.CREDENTIALS_FILENAME} file for Dataform to use when accessing your warehouse.`,
positionalOptions: [warehouseOption, projectDirMustExistOption],
options: [
trackOption,
{
name: testConnectionOptionName,
option: {
Expand Down Expand Up @@ -414,7 +416,8 @@ export function runCli() {
schemaSuffixOverrideOption,
jsonOutputOption,
varsOption,
timeoutOption
timeoutOption,
trackOption
],
processFn: async argv => {
const projectDir = argv[projectDirMustExistOption.name];
Expand Down Expand Up @@ -503,7 +506,7 @@ export function runCli() {
format: `test [${projectDirMustExistOption.name}]`,
description: "Run the dataform project's unit tests on the configured data warehouse.",
positionalOptions: [projectDirMustExistOption],
options: [credentialsOption, varsOption, timeoutOption],
options: [credentialsOption, varsOption, timeoutOption, trackOption],
processFn: async argv => {
print("Compiling...\n");
const compiledGraph = await compile({
Expand Down Expand Up @@ -574,7 +577,8 @@ export function runCli() {
credentialsOption,
jsonOutputOption,
varsOption,
timeoutOption
timeoutOption,
trackOption
],
processFn: async argv => {
if (!argv[jsonOutputOption.name]) {
Expand Down Expand Up @@ -692,7 +696,7 @@ export function runCli() {
format: `format [${projectDirMustExistOption.name}]`,
description: "Format the dataform project's files.",
positionalOptions: [projectDirMustExistOption],
options: [],
options: [trackOption],
processFn: async argv => {
const filenames = glob.sync("{definitions,includes}/**/*.{js,sqlx}", {
cwd: argv[projectDirMustExistOption.name]
Expand Down Expand Up @@ -722,7 +726,7 @@ export function runCli() {
format: `listtables <${warehouseOption.name}>`,
description: "List tables on the configured data warehouse.",
positionalOptions: [warehouseOption],
options: [credentialsOption],
options: [credentialsOption, trackOption],
processFn: async argv => {
const readCredentials = credentials.read(
argv[warehouseOption.name],
Expand Down Expand Up @@ -757,7 +761,7 @@ export function runCli() {
}
}
],
options: [credentialsOption],
options: [credentialsOption, trackOption],
processFn: async argv => {
const readCredentials = credentials.read(
argv[warehouseOption.name],
Expand Down
4 changes: 2 additions & 2 deletions cli/yargswrapper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import yargs from "yargs";

import { maybeConfigureAnalytics, trackCommand } from "df/cli/analytics";
import {maybeConfigureAnalytics, trackCommand, trackOption} from "df/cli/analytics";

export interface ICli {
commands: ICommand[];
Expand Down Expand Up @@ -28,7 +28,7 @@ export function createYargsCli(cli: ICli) {
command.description,
(yargsChainer: yargs.Argv) => createOptionsChain(yargsChainer, command),
async (argv: { [argumentName: string]: any }) => {
await maybeConfigureAnalytics();
await maybeConfigureAnalytics(argv[trackOption.name]);
const analyticsTrack = trackCommand(command.format.split(" ")[0]);
const exitCode = await command.processFn(argv);
let timer: NodeJS.Timer;
Expand Down
2 changes: 1 addition & 1 deletion version.bzl
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# NOTE: If you change the format of this line, you must change the bash command
# in /scripts/publish to extract the version string correctly.
DF_VERSION = "2.4.0"
DF_VERSION = "2.4.1"

0 comments on commit 4ea2693

Please sign in to comment.