Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds a flag 'track' to allow users to configure analytics with flags #1450

Merged
merged 7 commits into from
Feb 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
GJMcGowan marked this conversation as resolved.
Show resolved Hide resolved
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;
}
GJMcGowan marked this conversation as resolved.
Show resolved Hide resolved
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"