Skip to content

Commit

Permalink
Merge pull request NomicFoundation#4709 from NomicFoundation/analytic…
Browse files Browse the repository at this point in the history
…s-track-telemetry-response

 Report telemetry consent response to Google Analytics
  • Loading branch information
fvictorio authored Dec 26, 2023
2 parents 3f4680f + 308c12b commit 39d9e34
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 24 deletions.
5 changes: 5 additions & 0 deletions .changeset/silly-flowers-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"hardhat": patch
---

Report telemetry consent response to Google Analytics
88 changes: 82 additions & 6 deletions packages/hardhat-core/src/internal/cli/analytics.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { request as RequestT } from "undici";

import debug from "debug";
import os from "os";
import os from "node:os";
import { join } from "node:path";
import { spawn } from "node:child_process";

import { isLocalDev } from "../core/execution-mode";
import { isRunningOnCiServer } from "../util/ci-detection";
Expand All @@ -10,15 +12,28 @@ import {
readFirstLegacyAnalyticsId,
readSecondLegacyAnalyticsId,
writeAnalyticsId,
writeTelemetryConsent,
} from "../util/global-dir";
import { getPackageJson } from "../util/packageInfo";
import { confirmTelemetryConsent } from "./prompt";

const log = debug("hardhat:core:analytics");

/* eslint-disable @typescript-eslint/naming-convention */
interface AnalyticsPayload {
client_id: string;
user_id: string;
user_properties: {};
events: Array<{
name: string;
params: {
engagement_time_msec?: string;
session_id?: string;
};
}>;
}

interface TaskHitPayload extends AnalyticsPayload {
user_properties: {
projectId: {
value?: string;
Expand All @@ -37,14 +52,26 @@ interface AnalyticsPayload {
};
};
events: Array<{
name: string;
name: "task";
params: {
engagement_time_msec?: string;
session_id?: string;
scope?: string;
task?: string;
};
}>;
}

interface TelemetryConsentHitPayload extends AnalyticsPayload {
events: Array<{
name: "TelemetryConsentResponse";
params: {
engagement_time_msec: string;
session_id: string;
engagement_time_msec?: string;
session_id?: string;
userConsent: "yes" | "no";
};
}>;
}
/* eslint-enable @typescript-eslint/naming-convention */

type AbortAnalytics = () => void;

Expand Down Expand Up @@ -109,12 +136,31 @@ export class Analytics {
return this._sendHit(await this._buildTaskHitPayload(eventParams));
}

public async sendTelemetryConsentHit(
userConsent: "yes" | "no"
): Promise<[AbortAnalytics, Promise<void>]> {
const telemetryConsentHitPayload: TelemetryConsentHitPayload = {
client_id: "hardhat_telemetry_consent",
user_id: "hardhat_telemetry_consent",
user_properties: {},
events: [
{
name: "TelemetryConsentResponse",
params: {
userConsent,
},
},
],
};
return this._sendHit(telemetryConsentHitPayload);
}

private async _buildTaskHitPayload(
eventParams: {
scope?: string;
task?: string;
} = {}
): Promise<AnalyticsPayload> {
): Promise<TaskHitPayload> {
return {
client_id: this._clientId,
user_id: this._clientId,
Expand Down Expand Up @@ -207,3 +253,33 @@ async function getHardhatVersion(): Promise<string> {

return `Hardhat ${version}`;
}

export async function requestTelemetryConsent() {
const telemetryConsent = await confirmTelemetryConsent();

if (telemetryConsent === undefined) {
return;
}

writeTelemetryConsent(telemetryConsent);

const reportTelemetryConsentPath = join(
__dirname,
"..",
"util",
"report-telemetry-consent.js"
);

const subprocess = spawn(
process.execPath,
[reportTelemetryConsentPath, telemetryConsent ? "yes" : "no"],
{
detached: true,
stdio: "ignore",
}
);

subprocess.unref();

return telemetryConsent;
}
11 changes: 3 additions & 8 deletions packages/hardhat-core/src/internal/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,15 @@ import {
hasConsentedTelemetry,
hasPromptedForHHVSCode,
writePromptedForHHVSCode,
writeTelemetryConsent,
} from "../util/global-dir";
import { getPackageJson } from "../util/packageInfo";

import { saveFlamegraph } from "../core/flamegraph";
import { Analytics } from "./analytics";
import { Analytics, requestTelemetryConsent } from "./analytics";
import { ArgumentsParser } from "./ArgumentsParser";
import { enableEmoji } from "./emoji";
import { createProject, showSoliditySurveyMessage } from "./project-creation";
import { confirmHHVSCodeInstallation, confirmTelemetryConsent } from "./prompt";
import { confirmHHVSCodeInstallation } from "./prompt";
import {
InstallationState,
installHardhatVSCode,
Expand Down Expand Up @@ -247,11 +246,7 @@ async function main() {
process.stdout.isTTY === true &&
process.env.HARDHAT_DISABLE_TELEMETRY_PROMPT !== "true"
) {
telemetryConsent = await confirmTelemetryConsent();

if (telemetryConsent !== undefined) {
writeTelemetryConsent(telemetryConsent);
}
telemetryConsent = await requestTelemetryConsent();
}

const analytics = await Analytics.getInstance(telemetryConsent);
Expand Down
15 changes: 5 additions & 10 deletions packages/hardhat-core/src/internal/cli/project-creation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,22 @@ import { assertHardhatInvariant, HardhatError } from "../core/errors";
import { ERRORS } from "../core/errors-list";
import { getRecommendedGitIgnore } from "../core/project-structure";
import { getAllFilesMatching } from "../util/fs-utils";
import {
hasConsentedTelemetry,
writeTelemetryConsent,
} from "../util/global-dir";
import { hasConsentedTelemetry } from "../util/global-dir";
import { fromEntries } from "../util/lang";
import {
getPackageJson,
getPackageRoot,
PackageJson,
} from "../util/packageInfo";
import { pluralize } from "../util/strings";
import { isRunningOnCiServer } from "../util/ci-detection";
import {
confirmRecommendedDepsInstallation,
confirmTelemetryConsent,
confirmProjectCreation,
} from "./prompt";
import { emoji } from "./emoji";
import { Dependencies, PackageManager } from "./types";
import { requestTelemetryConsent } from "./analytics";

enum Action {
CREATE_JAVASCRIPT_PROJECT_ACTION = "Create a JavaScript project",
Expand Down Expand Up @@ -463,13 +461,10 @@ export async function createProject() {

if (
process.env.HARDHAT_DISABLE_TELEMETRY_PROMPT !== "true" &&
!isRunningOnCiServer() &&
hasConsentedTelemetry() === undefined
) {
const telemetryConsent = await confirmTelemetryConsent();

if (telemetryConsent !== undefined) {
writeTelemetryConsent(telemetryConsent);
}
await requestTelemetryConsent();
}

await copySampleProject(projectRoot, action, isEsm);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Analytics } from "../cli/analytics";

async function main() {
const [telemetryConsent] = process.argv.slice(2);

// we pass undefined as the telemetryConsent value because
// this hit is done before the consent is saved
const analytics = await Analytics.getInstance(undefined);

const [_, consentHitPromise] = await analytics.sendTelemetryConsentHit(
telemetryConsent as "yes" | "no"
);
await consentHitPromise;
}

main().catch(() => {});

0 comments on commit 39d9e34

Please sign in to comment.