From 7ae0d551fe85dec6af7a1ba98d7c0b333ddf5520 Mon Sep 17 00:00:00 2001 From: Tom Ratcliffe Date: Fri, 15 Nov 2024 14:01:39 +0000 Subject: [PATCH] Chore: Move betterer eslint rules to separate file and allow opting in (#96240) * Move betterer eslint rules to separate file and allow opt-in for local dev * Add betterer eslint to codeowners --- .betterer.eslint.config.js | 45 +++++++++++++++++++++++++++++++ .betterer.ts | 54 +++----------------------------------- .github/CODEOWNERS | 1 + conf/defaults.ini | 3 +++ eslint.config.js | 8 ++++++ 5 files changed, 60 insertions(+), 51 deletions(-) create mode 100644 .betterer.eslint.config.js diff --git a/.betterer.eslint.config.js b/.betterer.eslint.config.js new file mode 100644 index 00000000000..ee4f3825179 --- /dev/null +++ b/.betterer.eslint.config.js @@ -0,0 +1,45 @@ +// @ts-check +/** + * @type {Array} + */ +module.exports = [ + { + files: ['**/*.{js,jsx,ts,tsx}'], + rules: { + '@typescript-eslint/no-explicit-any': 'error', + '@grafana/no-aria-label-selectors': 'error', + 'no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: ['@grafana/ui*', '*/Layout/*'], + importNames: ['Layout', 'HorizontalGroup', 'VerticalGroup'], + message: 'Use Stack component instead.', + }, + ], + }, + ], + }, + }, + { + files: ['**/*.{ts,tsx}'], + ignores: ['**/*.{test,spec}.{ts,tsx}', '**/__mocks__/**', '**/public/test/**'], + rules: { + '@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'never' }], + }, + }, + { + files: ['public/app/**/*.{ts,tsx}'], + rules: { + 'no-barrel-files/no-barrel-files': 'error', + }, + }, + { + files: ['public/**/*.tsx', 'packages/grafana-ui/**/*.tsx'], + ignores: ['public/app/plugins/**', '**/*.story.tsx', '**/*.{test,spec}.{ts,tsx}', '**/__mocks__/', 'public/test'], + rules: { + '@grafana/no-untranslated-strings': 'error', + }, + }, +]; diff --git a/.betterer.ts b/.betterer.ts index f123e391548..2ebb3f89390 100644 --- a/.betterer.ts +++ b/.betterer.ts @@ -1,7 +1,9 @@ import { BettererFileTest } from '@betterer/betterer'; -import { ESLint, Linter } from 'eslint'; +import { ESLint } from 'eslint'; import { promises as fs } from 'fs'; +import config from './.betterer.eslint.config'; + // Why are we ignoring these? // They're all deprecated/being removed so doesn't make sense to fix types const eslintPathsToIgnore = [ @@ -81,56 +83,6 @@ function countEslintErrors() { const { baseDirectory } = resolver; - const baseRules: Partial = { - '@typescript-eslint/no-explicit-any': 'error', - '@grafana/no-aria-label-selectors': 'error', - 'no-restricted-imports': [ - 'error', - { - patterns: [ - { - group: ['@grafana/ui*', '*/Layout/*'], - importNames: ['Layout', 'HorizontalGroup', 'VerticalGroup'], - message: 'Use Stack component instead.', - }, - ], - }, - ], - }; - - const config: Linter.Config[] = [ - { - files: ['**/*.{js,jsx,ts,tsx}'], - rules: baseRules, - }, - { - files: ['**/*.{ts,tsx}'], - ignores: ['**/*.{test,spec}.{ts,tsx}', '**/__mocks__/**', '**/public/test/**'], - rules: { - '@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'never' }], - }, - }, - { - files: ['public/app/**/*.{ts,tsx}'], - rules: { - 'no-barrel-files/no-barrel-files': 'error', - }, - }, - { - files: ['public/**/*.tsx', 'packages/grafana-ui/**/*.tsx'], - ignores: [ - 'public/app/plugins/**', - '**/*.story.tsx', - '**/*.{test,spec}.{ts,tsx}', - '**/__mocks__/', - 'public/test', - ], - rules: { - '@grafana/no-untranslated-strings': 'error', - }, - }, - ]; - const runner = new ESLint({ overrideConfig: config, cwd: baseDirectory, diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ea7b14b71ff..d0207f4c4d3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -385,6 +385,7 @@ /tsconfig.json @grafana/frontend-ops /.editorconfig @grafana/frontend-ops /eslint.config.js @grafana/frontend-ops +/.betterer.eslint.config.js @grafana/frontend-ops /.gitattributes @grafana/frontend-ops /.gitignore @grafana/frontend-ops /.nvmrc @grafana/frontend-ops diff --git a/conf/defaults.ini b/conf/defaults.ini index 4ee34159a96..4f247e5121d 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -2034,3 +2034,6 @@ fail_tests_on_console = true # Whether or not to enable the MSW mock API, which intercepts requests and returns mock data # Should only be used for local development or demo purposes mock_api = false +# Whether to enable betterer eslint rules for local development +# Useful if you want to always see betterer rules that we're trying to fix so they're more prevalent +betterer_eslint_rules = false diff --git a/eslint.config.js b/eslint.config.js index 29df2b02563..450fba7f66d 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -14,6 +14,12 @@ const unicornPlugin = require('eslint-plugin-unicorn'); const grafanaConfig = require('@grafana/eslint-config/flat'); const grafanaPlugin = require('@grafana/eslint-plugin'); +const bettererConfig = require('./.betterer.eslint.config'); +const getEnvConfig = require('./scripts/webpack/env-util'); + +const envConfig = getEnvConfig(); +const enableBettererRules = envConfig.frontend_dev_betterer_eslint_rules; + /** * @type {Array} */ @@ -43,6 +49,8 @@ module.exports = [ 'scripts/grafana-server/tmp', ], }, + // Conditionally run the betterer rules if enabled in dev's config + ...(enableBettererRules ? bettererConfig : []), grafanaConfig, { name: 'react/jsx-runtime',