summaryrefslogtreecommitdiff
path: root/packages/telemetry
diff options
context:
space:
mode:
Diffstat (limited to 'packages/telemetry')
-rw-r--r--packages/telemetry/src/index.ts35
-rw-r--r--packages/telemetry/test/index.test.js78
2 files changed, 101 insertions, 12 deletions
diff --git a/packages/telemetry/src/index.ts b/packages/telemetry/src/index.ts
index 3d08cd529..b63ff9c23 100644
--- a/packages/telemetry/src/index.ts
+++ b/packages/telemetry/src/index.ts
@@ -10,6 +10,9 @@ import { getSystemInfo, type SystemInfo } from './system-info.js';
export type AstroTelemetryOptions = { astroVersion: string; viteVersion: string };
export type TelemetryEvent = { eventName: string; payload: Record<string, any> };
+// In the event of significant policy changes, update this!
+const VALID_TELEMETRY_NOTICE_DATE = '2023-08-25';
+
type EventMeta = SystemInfo;
interface EventContext extends ProjectInfo {
anonymousId: string;
@@ -20,6 +23,8 @@ export class AstroTelemetry {
private _anonymousProjectInfo: ProjectInfo | undefined;
private config = new GlobalConfig({ name: 'astro' });
private debug = debug('astro:telemetry');
+ private isCI = isCI;
+ private env = process.env;
private get astroVersion() {
return this.opts.astroVersion;
@@ -28,10 +33,10 @@ export class AstroTelemetry {
return this.opts.viteVersion;
}
private get ASTRO_TELEMETRY_DISABLED() {
- return process.env.ASTRO_TELEMETRY_DISABLED;
+ return this.env.ASTRO_TELEMETRY_DISABLED;
}
private get TELEMETRY_DISABLED() {
- return process.env.TELEMETRY_DISABLED;
+ return this.env.TELEMETRY_DISABLED;
}
constructor(private opts: AstroTelemetryOptions) {
@@ -47,7 +52,7 @@ export class AstroTelemetry {
*/
private getConfigWithFallback<T>(key: string, getValue: () => T): T {
const currentValue = this.config.get(key);
- if (currentValue) {
+ if (currentValue !== undefined) {
return currentValue;
}
const newValue = getValue();
@@ -75,7 +80,7 @@ export class AstroTelemetry {
private get anonymousProjectInfo(): ProjectInfo {
// NOTE(fks): this value isn't global, so it can't use getConfigWithFallback().
- this._anonymousProjectInfo = this._anonymousProjectInfo || getProjectInfo(isCI);
+ this._anonymousProjectInfo = this._anonymousProjectInfo || getProjectInfo(this.isCI);
return this._anonymousProjectInfo;
}
@@ -94,19 +99,29 @@ export class AstroTelemetry {
return this.config.clear();
}
- async notify(callback: () => Promise<boolean>) {
- if (this.isDisabled || isCI) {
+ isValidNotice() {
+ if (!this.notifyDate) return false;
+ const current = Number(this.notifyDate);
+ const valid = new Date(VALID_TELEMETRY_NOTICE_DATE).valueOf();
+
+ return current > valid;
+ }
+
+ async notify(callback: () => boolean | Promise<boolean>) {
+ if (this.isDisabled || this.isCI) {
+ this.debug(`[notify] telemetry has been disabled`);
return;
}
// The end-user has already been notified about our telemetry integration!
// Don't bother them about it again.
- // In the event of significant changes, we should invalidate old dates.
- if (this.notifyDate) {
+ if (this.isValidNotice()) {
+ this.debug(`[notify] last notified on ${this.notifyDate}`)
return;
}
const enabled = await callback();
- this.config.set(KEY.TELEMETRY_NOTIFY_DATE, Date.now().toString());
+ this.config.set(KEY.TELEMETRY_NOTIFY_DATE, new Date().valueOf().toString());
this.config.set(KEY.TELEMETRY_ENABLED, enabled);
+ this.debug(`[notify] telemetry has been ${enabled ? 'enabled' : 'disabled'}`)
}
async record(event: TelemetryEvent | TelemetryEvent[] = []) {
@@ -117,7 +132,7 @@ export class AstroTelemetry {
// Skip recording telemetry if the feature is disabled
if (this.isDisabled) {
- this.debug('telemetry disabled');
+ this.debug('[record] telemetry has been disabled');
return Promise.resolve();
}
diff --git a/packages/telemetry/test/index.test.js b/packages/telemetry/test/index.test.js
index 29ade53f9..a8929329e 100644
--- a/packages/telemetry/test/index.test.js
+++ b/packages/telemetry/test/index.test.js
@@ -1,9 +1,83 @@
import { expect } from 'chai';
import { AstroTelemetry } from '../dist/index.js';
-describe('AstroTelemetry', () => {
+function setup() {
+ const config = new Map();
+ const telemetry = new AstroTelemetry({ version: '0.0.0-test.1' });
+ const logs = [];
+ // Stub isCI to false so we can test user-facing behavior
+ telemetry.isCI = false;
+ // Stub process.env to properly test in Astro's own CI
+ telemetry.env = {};
+ // Override config so we can inspect it
+ telemetry.config = config;
+ // Override debug so we can inspect it
+ telemetry.debug.enabled = true;
+ telemetry.debug.log = (...args) => logs.push(args);
+
+ return { telemetry, config, logs }
+}
+describe('AstroTelemetry', () => {
+ let oldCI;
+ before(() => {
+ oldCI = process.env.CI;
+ // Stub process.env.CI to `false`
+ process.env.CI = 'false';
+ })
+ after(() => {
+ process.env.CI = oldCI;
+ })
it('initializes when expected arguments are given', () => {
- const telemetry = new AstroTelemetry({ version: '0.0.0-test.1' });
+ const { telemetry } = setup();
expect(telemetry).to.be.instanceOf(AstroTelemetry);
});
+ it('does not record event if disabled', async () => {
+ const { telemetry, config, logs } = setup();
+ telemetry.setEnabled(false);
+ const [key] = Array.from(config.keys());
+ expect(key).not.to.be.undefined;
+ expect(config.get(key)).to.be.false;
+ expect(telemetry.enabled).to.be.false;
+ expect(telemetry.isDisabled).to.be.true;
+ const result = await telemetry.record(['TEST']);
+ expect(result).to.be.undefined;
+ const [log] = logs;
+ expect(log).not.to.be.undefined;
+ expect(logs.join('')).to.match(/disabled/);
+ });
+ it('records event if enabled', async () => {
+ const { telemetry, config, logs } = setup();
+ telemetry.setEnabled(true);
+ const [key] = Array.from(config.keys());
+ expect(key).not.to.be.undefined;
+ expect(config.get(key)).to.be.true;
+ expect(telemetry.enabled).to.be.true;
+ expect(telemetry.isDisabled).to.be.false;
+ await telemetry.record(['TEST']);
+ expect(logs.length).to.equal(2);
+ });
+ it('respects disable from notify', async () => {
+ const { telemetry, config, logs } = setup();
+ await telemetry.notify(() => false);
+ const [key] = Array.from(config.keys());
+ expect(key).not.to.be.undefined;
+ expect(config.get(key)).to.be.false;
+ expect(telemetry.enabled).to.be.false;
+ expect(telemetry.isDisabled).to.be.true;
+ const [log] = logs;
+ expect(log).not.to.be.undefined;
+ expect(logs.join('')).to.match(/disabled/);
+ });
+ it('respects enable from notify', async () => {
+ const { telemetry, config, logs } = setup();
+ await telemetry.notify(() => true);
+ const [key] = Array.from(config.keys());
+ expect(key).not.to.be.undefined;
+ expect(config.get(key)).to.be.true;
+ expect(telemetry.enabled).to.be.true;
+ expect(telemetry.isDisabled).to.be.false;
+ const [log] = logs;
+ expect(log).not.to.be.undefined;
+ expect(logs.join('')).to.match(/enabled/);
+ });
});