From 53e52fefc309991f5a04dce61c22fdb1b458ce1b Mon Sep 17 00:00:00 2001 From: Keen Yee Liau Date: Mon, 6 Dec 2021 18:41:31 -0800 Subject: [PATCH] telemetry: collect feature usage for linting during build (#32022) Currently, we have telemetry to measure how ESLint is invoked, but we do not have telemetry that tells us how many users have disabled ESLint during build. This commit adds a new feature, `build lint` to track this metric. ## Bug - [ ] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `yarn lint` --- packages/next/build/index.ts | 11 ++++- packages/next/telemetry/events/build.ts | 1 + test/integration/telemetry/test/index.test.js | 42 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index 777bb5de0ae23db..25b97a50fb80d84 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -243,7 +243,8 @@ export default async function build( const ignoreESLint = Boolean(config.eslint.ignoreDuringBuilds) const eslintCacheDir = path.join(cacheDir, 'eslint/') - if (!ignoreESLint && runLint) { + const shouldLint = !ignoreESLint && runLint + if (shouldLint) { await nextBuildSpan .traceChild('verify-and-lint') .traceAsyncFn(async () => { @@ -257,6 +258,14 @@ export default async function build( ) }) } + const buildLintEvent: EventBuildFeatureUsage = { + featureName: 'build-lint', + invocationCount: shouldLint ? 1 : 0, + } + telemetry.record({ + eventName: EVENT_BUILD_FEATURE_USAGE, + payload: buildLintEvent, + }) const buildSpinner = createSpinner({ prefixText: `${Log.prefixes.info} Creating an optimized production build`, diff --git a/packages/next/telemetry/events/build.ts b/packages/next/telemetry/events/build.ts index 1eb5e90f1ca80d6..0be4c5d4e79a930 100644 --- a/packages/next/telemetry/events/build.ts +++ b/packages/next/telemetry/events/build.ts @@ -134,6 +134,7 @@ export type EventBuildFeatureUsage = { | 'optimizeFonts' | 'swcLoader' | 'swcMinify' + | 'build-lint' invocationCount: number } export function eventBuildFeatureUsage( diff --git a/test/integration/telemetry/test/index.test.js b/test/integration/telemetry/test/index.test.js index 2f939c76caaec1f..add5b0d9665bc10 100644 --- a/test/integration/telemetry/test/index.test.js +++ b/test/integration/telemetry/test/index.test.js @@ -541,6 +541,46 @@ describe('Telemetry CLI', () => { expect(event1).toMatch(/"nextEslintPluginVersion": ".*?\..*?\..*?"/) expect(event1).toMatch(/"nextEslintPluginErrorsCount": \d{1,}/) expect(event1).toMatch(/"nextEslintPluginWarningsCount": \d{1,}/) + + const event2 = /NEXT_BUILD_FEATURE_USAGE[\s\S]+?{([\s\S]+?)}/ + .exec(stderr) + .pop() + expect(event2).toContain(`"featureName": "build-lint"`) + expect(event2).toContain(`"invocationCount": 1`) + }) + + it(`emits telemetry for lint during build when '--no-lint' is specified`, async () => { + const { stderr } = await nextBuild(appDir, ['--no-lint'], { + stderr: true, + env: { NEXT_TELEMETRY_DEBUG: 1 }, + }) + + const event1 = /NEXT_BUILD_FEATURE_USAGE[\s\S]+?{([\s\S]+?)}/ + .exec(stderr) + .pop() + + expect(event1).toContain(`"featureName": "build-lint"`) + expect(event1).toContain(`"invocationCount": 0`) + }) + + it(`emits telemetry for lint during build when 'ignoreDuringBuilds' is specified`, async () => { + const nextConfig = path.join(appDir, 'next.config.js') + await fs.writeFile( + nextConfig, + `module.exports = { eslint: { ignoreDuringBuilds: true } }` + ) + const { stderr } = await nextBuild(appDir, [], { + stderr: true, + env: { NEXT_TELEMETRY_DEBUG: 1 }, + }) + await fs.remove(nextConfig) + + const event1 = /NEXT_BUILD_FEATURE_USAGE[\s\S]+?{([\s\S]+?)}/ + .exec(stderr) + .pop() + + expect(event1).toContain(`"featureName": "build-lint"`) + expect(event1).toContain(`"invocationCount": 0`) }) it('emits telemetry for `next lint`', async () => { @@ -575,6 +615,7 @@ describe('Telemetry CLI', () => { }) const regex = /NEXT_BUILD_FEATURE_USAGE[\s\S]+?{([\s\S]+?)}/g regex.exec(stderr).pop() // optimizeCss + regex.exec(stderr).pop() // build-lint const optimizeFonts = regex.exec(stderr).pop() expect(optimizeFonts).toContain(`"featureName": "optimizeFonts"`) expect(optimizeFonts).toContain(`"invocationCount": 1`) @@ -612,6 +653,7 @@ describe('Telemetry CLI', () => { ) const regex = /NEXT_BUILD_FEATURE_USAGE[\s\S]+?{([\s\S]+?)}/g + regex.exec(stderr).pop() // build-lint const optimizeCss = regex.exec(stderr).pop() expect(optimizeCss).toContain(`"featureName": "experimental/optimizeCss"`) expect(optimizeCss).toContain(`"invocationCount": 1`)