bazel: improve ESLint rule and disable ESLint outside of Bazel (#52667)

- Custom ESLint Bazel rule now relies on `sh_test`. The build part of
the rule produces the output file with ESLint errors, and the `sh_test`
target verifies that it's empty. If it's not empty, the ESLint test
fails, and the report content is printed to stdout.
- Added additional ESLint targets to `*.js` files in the root of each
client package.
- Added additional ESLint targets for `*.story.tsx` files for client
packages with stories. It's temporary until we start building Storybook
story modules with `ts_project`.
- Disabled ESLint outside of Bazel: **10-12m job is gone!** 🎉

## Test plan

bazel test `bazel query 'attr("name", ".*_eslint$", //client/...)'`
This commit is contained in:
Valery Bugakov 2023-06-02 01:37:40 -07:00 committed by GitHub
parent 4794d2ff16
commit ff3ce9fe93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 373 additions and 149 deletions

11
BUILD.bazel generated
View File

@ -9,6 +9,7 @@ load("@io_bazel_rules_go//proto/wkt:well_known_types.bzl", "WELL_KNOWN_TYPES_API
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev/linters/staticcheck:analyzers.bzl", "STATIC_CHECK_ANALYZERS")
load("@npm//:eslint/package_json.bzl", eslint_bin = "bin")
load("//dev:eslint.bzl", "eslint_test_with_types")
# Gazelle config
#
@ -243,6 +244,7 @@ js_library(
],
data = [
".eslintignore",
"package.json",
":eslint-relative-formatter",
],
deps = [
@ -270,6 +272,15 @@ js_library(
],
)
eslint_test_with_types(
name = "eslint_test",
srcs = glob(["*.js"]),
config = ":eslint_config",
deps = [
":node_modules/@types/node",
],
)
# Go
# nogo config

View File

@ -1,11 +1,11 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -1,7 +1,7 @@
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "jest_test", "npm_package", "sass", "ts_project")
load("//client/shared/dev:tools.bzl", "module_style_typings")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root", "eslint_test_with_types")
# TODO(bazel): storybook build
# gazelle:exclude **/*.story.{ts,tsx}
@ -12,7 +12,22 @@ load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
# Temporary ESLint target to lint stories. This will be removed once we have a
# custom gazelle targets. E.g., `gazelle:custom_js_files stories src/**/*.story.tsx`
eslint_test_with_types(
name = "stories_eslint",
srcs = glob([
"src/**/*.story.tsx",
"src/**/*.fixtures.ts",
]),
config = ":eslint_config",
deps = [
"//:jest_config", # required for import/extensions rule not to fail on the `jest.config.base` import.
"//:node_modules/@types/node",
],
)
ts_config(
name = "tsconfig",

View File

@ -7,7 +7,7 @@ load("//client/shared/dev:generate_graphql_operations.bzl", "generate_graphql_op
load("//client/shared/dev:build_code_intel_extensions.bzl", "build_code_intel_extensions")
load("//client/shared/dev:tools.bzl", "module_style_typings")
load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root", "eslint_test_with_types")
# TODO(bazel): storybook build
# gazelle:exclude **/*.story.{ts,tsx}
@ -22,12 +22,28 @@ load("//dev:eslint.bzl", "eslint_config")
npm_link_all_packages(name = "node_modules")
eslint_config(
deps = [
eslint_config_and_lint_root(
config_deps = [
"//client/browser/src/end-to-end:tsconfig",
],
)
# Temporary ESLint target to lint stories. This will be removed once we have a
# custom gazelle targets. E.g., `gazelle:custom_js_files stories src/**/*.story.tsx`
eslint_test_with_types(
name = "stories_eslint",
srcs = glob([
"src/**/*.story.tsx",
"src/**/*.fixtures.ts",
]),
config = ":eslint_config",
deps = [
":node_modules/@sourcegraph/shared", # required for import/extensions rule not to fail.
"//:jest_config", # required for import/extensions rule not to fail on the `jest.config.base` import.
"//:node_modules/@types/node",
],
)
ts_config(
name = "tsconfig",
src = "tsconfig.json",

View File

@ -1,14 +1,14 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "npm_package", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
# TODO(bazel): currently handled with #keep
# gazelle:js_resolve **/esbuild/* //client/build-config/src/esbuild
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -7,5 +7,5 @@
"outDir": "./out",
"baseUrl": "./src",
},
"include": ["./src/**/*", "./*.ts"],
"include": ["src", "*.js"],
}

View File

@ -1,11 +1,11 @@
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "npm_package", "ts_project")
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -22,5 +22,5 @@
"path": "../template-parser",
},
],
"include": ["./src/**/*", "./*.ts"],
"include": ["src", "*.js"],
}

View File

@ -1,11 +1,11 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "jest_test", "npm_package", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -15,5 +15,5 @@
"path": "../extension-api-types",
},
],
"include": ["./src/**/*", "./*.ts"],
"include": ["src", "*.js"],
}

View File

@ -1,11 +1,11 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -1,13 +1,13 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "npm_package", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
# gazelle:js_resolve vscode //:node_modules/@vscode
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -2,12 +2,12 @@ load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
load("@aspect_rules_esbuild//esbuild:defs.bzl", "esbuild")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -1,13 +1,13 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "npm_package", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
# gazelle:js_ignore_imports **/*.css
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -1,13 +1,13 @@
load("//dev:defs.bzl", "ts_project")
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
# gazelle:js_ignore_imports **/*.css
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -1,7 +1,7 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
# gazelle:js_resolve vscode //:node_modules/@vscode
# gazelle:js_files src/**/*.{ts,tsx}
@ -10,8 +10,8 @@ load("//dev:eslint.bzl", "eslint_config")
npm_link_all_packages(name = "node_modules")
eslint_config(
deps = [
eslint_config_and_lint_root(
config_deps = [
"//client/cody/scripts:tsconfig",
"//client/cody/test/integration:tsconfig",
],

View File

@ -1,11 +1,11 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "jest_test", "npm_package", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -7,7 +7,7 @@
"outDir": "./out",
"baseUrl": "./src",
},
"include": ["./src/**/*", "./*.ts"],
"include": ["src", "*.js"],
"references": [
{
"path": "../extension-api-types",

View File

@ -1,7 +1,7 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "npm_package")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
package(default_visibility = ["//visibility:public"])
@ -10,7 +10,7 @@ package(default_visibility = ["//visibility:public"])
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -4,7 +4,7 @@ module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: __dirname + '/tsconfig.json',
project: __dirname + '/tsconfig.eslint.json',
},
overrides: baseConfig.overrides,
}

View File

@ -1,7 +1,7 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "npm_package")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
# Disable gazelle for the js/dts-only package
# gazelle:js disabled
@ -11,7 +11,18 @@ package(default_visibility = ["//visibility:public"])
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root(
config_deps = [":tsconfig-eslint"],
)
ts_config(
name = "tsconfig-eslint",
src = "tsconfig.eslint.json",
visibility = ["//client:__subpackages__"],
deps = [
"//:tsconfig",
],
)
ts_config(
name = "tsconfig",

View File

@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"outDir": "out",
"rootDir": "src",
},
"include": ["src", "*.js"],
}

View File

@ -1,7 +1,7 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "jest_test", "npm_package", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
npm_link_all_packages(name = "node_modules")
@ -81,4 +81,4 @@ jest_test(
],
)
eslint_config()
eslint_config_and_lint_root()

View File

@ -8,7 +8,7 @@
"baseUrl": "./src",
"jsx": "react-jsx",
},
"include": ["./src/**/*", "./*.ts"],
"include": ["src", "*.js"],
"references": [
{
"path": "../common",

View File

@ -1,14 +1,26 @@
load("@aspect_rules_js//js:defs.bzl", "js_library")
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root", "eslint_test_with_types")
# dts-only done manually
# gazelle:js disabled
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
# Temporary ESLint target to lint stories. This will be removed once we have a
# custom gazelle targets. E.g., `gazelle:custom_js_files stories src/**/*.story.tsx`
eslint_test_with_types(
name = "stories_eslint",
srcs = glob(["webview/src/**/*.story.tsx"]),
config = ":eslint_config",
deps = [
"//:jest_config", # required for import/extensions rule not to fail on the `jest.config.base` import.
"//:node_modules/@types/node",
],
)
ts_config(
name = "tsconfig",

View File

@ -1,11 +1,11 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "jest_test", "npm_package", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -1,11 +1,11 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "jest_test", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -7,7 +7,7 @@
"outDir": "./out",
"baseUrl": "./src",
},
"include": ["./src/**/*", "./*.ts"],
"include": ["src", "*.js"],
"references": [
{
"path": "../build-config",

View File

@ -5,7 +5,7 @@ load("//dev:defs.bzl", "jest_test", "npm_package", "sass", "ts_project")
load("//client/shared/dev:generate_schema.bzl", "generate_schema")
load("//client/shared/dev:generate_graphql_operations.bzl", "generate_graphql_operations")
load("//client/shared/dev:tools.bzl", "module_style_typings")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root", "eslint_test_with_types")
# TODO(bazel): storybook build
# gazelle:exclude **/*.story.{ts,tsx}
@ -16,7 +16,22 @@ load("//dev:eslint.bzl", "eslint_config")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
# Temporary ESLint target to lint stories. This will be removed once we have a
# custom gazelle targets. E.g., `gazelle:custom_js_files stories src/**/*.story.tsx`
eslint_test_with_types(
name = "stories_eslint",
srcs = glob([
"src/**/*.story.tsx",
"src/**/*.fixtures.ts",
]),
config = ":eslint_config",
deps = [
"//:jest_config", # required for import/extensions rule not to fail on the `jest.config.base` import.
"//:node_modules/@types/node",
],
)
ts_config(
name = "tsconfig",

View File

@ -1,7 +1,7 @@
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "npm_package", "sass", "ts_project")
load("//client/shared/dev:tools.bzl", "module_style_typings")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
# gazelle:js_resolve **/*.module.scss :module_style_typings
@ -9,7 +9,7 @@ load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -25,5 +25,5 @@
"path": "../wildcard",
},
],
"include": ["./src/**/*", "./*.ts"],
"include": ["src", "*.js"],
}

View File

@ -1,11 +1,11 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "npm_package", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -7,5 +7,5 @@
"outDir": "./out",
"baseUrl": "./src",
},
"include": ["./src/**/*", "./*.ts"],
"include": ["src", "*.js"],
}

View File

@ -1,11 +1,11 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "npm_package", "ts_project")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -9,5 +9,5 @@
"outDir": "./out",
"baseUrl": "./src",
},
"include": ["./src/**/*", "./*.ts"],
"include": ["src", "*.js"],
}

View File

@ -4,7 +4,7 @@ load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "sass", "ts_project")
load("//client/shared/dev:generate_graphql_operations.bzl", "generate_graphql_operations")
load("//client/shared/dev:tools.bzl", "module_style_typings")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root")
# TODO(bazel): webpack workers?
# gazelle:js_ignore_imports **/*.worker.ts
@ -14,7 +14,7 @@ load("//dev:eslint.bzl", "eslint_config")
npm_link_all_packages(name = "node_modules")
eslint_config()
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

25
client/web/BUILD.bazel generated
View File

@ -6,8 +6,8 @@ load("//client/shared/dev:generate_graphql_operations.bzl", "generate_graphql_op
load("//client/shared/dev:tools.bzl", "module_style_typings")
load("//dev:defs.bzl", "jest_test", "npm_package", "sass", "ts_project")
load("//dev:webpack.bzl", "webpack_bundle", "webpack_devserver", "webpack_web_app")
load("//dev:eslint.bzl", "eslint_config")
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root", "eslint_test_with_types")
# TODO(bazel): storybook build
# gazelle:exclude **/*.story.{ts,tsx}
@ -22,12 +22,31 @@ load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
npm_link_all_packages(name = "node_modules")
eslint_config(
deps = [
eslint_config_and_lint_root(
config_deps = [
"//client/web/src/end-to-end:tsconfig",
"//client/web/src/integration:tsconfig",
"//client/web/src/regression:tsconfig",
],
root_js_deps = [
"//client/web/dev:dev",
],
)
# Temporary ESLint target to lint stories. This will be removed once we have a
# custom gazelle targets. E.g., `gazelle:custom_js_files stories src/**/*.story.tsx`
eslint_test_with_types(
name = "stories_eslint",
srcs = glob([
"src/**/*.story.tsx",
"src/**/*.fixtures.ts", # required for import/extensions rule not to fail.
]),
config = ":eslint_config",
deps = [
":web_tests",
"//:jest_config", # required for import/extensions rule not to fail on the `jest.config.base` import.
"//:node_modules/@types/node",
],
)
ts_config(

View File

@ -35,6 +35,7 @@ ts_project(
],
module = "commonjs",
tsconfig = ":tsconfig",
visibility = ["//client/web:__subpackages__"],
deps = [
"//:node_modules/@types/compression",
"//:node_modules/@types/connect-history-api-fallback",

View File

@ -163,7 +163,7 @@ type Report = [Header, Metric, Metric, Metric, Metric, Metric, Metric, Metric, M
function parseReport(commitFile: string, compareFile: string): Report {
const queryFile = path.join(__dirname, 'report-bundle-jora-query')
const rawReport = execSync(`cat "${queryFile}" | ${STATOSCOPE_BIN} query -i "${compareFile}" -i "${commitFile}"`, {
encoding: 'utf-8',
encoding: 'utf8',
})
return JSON.parse(rawReport) as Report

View File

@ -3,7 +3,7 @@ load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//dev:defs.bzl", "jest_test", "npm_package", "sass", "ts_project")
load("//client/shared/dev:tools.bzl", "module_style_typings")
load("//dev:eslint.bzl", "eslint_config")
load("//dev:eslint.bzl", "eslint_config_and_lint_root", "eslint_test_with_types")
# TODO(bazel): storybook build
# gazelle:exclude **/*.story.{ts,tsx}
@ -13,6 +13,23 @@ load("//dev:eslint.bzl", "eslint_config")
npm_link_all_packages(name = "node_modules")
eslint_config_and_lint_root()
# Temporary ESLint target to lint stories. This will be removed once we have a
# custom gazelle targets. E.g., `gazelle:custom_js_files stories src/**/*.story.tsx`
eslint_test_with_types(
name = "stories_eslint",
srcs = glob([
"src/**/*.story.tsx",
"src/**/*.fixtures.ts",
]),
config = ":eslint_config",
deps = [
"//:jest_config", # required for import/extensions rule not to fail on the `jest.config.base` import.
"//:node_modules/@types/node",
],
)
ts_config(
name = "tsconfig",
src = "tsconfig.json",
@ -24,8 +41,6 @@ ts_config(
],
)
eslint_config()
module_style_typings(
name = "module_style_typings",
deps = [

2
dev/BUILD.bazel generated
View File

@ -5,4 +5,4 @@ webpack_binary(
node_modules = "//:node_modules",
)
exports_files(srcs = ["mocha-xvfb.sh"])
exports_files(srcs = ["eslint-report-test.sh"])

View File

@ -32,8 +32,6 @@ def ts_project(name, srcs = [], deps = [], use_preset_env = True, **kwargs):
name = "%s_eslint" % name,
srcs = srcs,
deps = deps,
testonly = True,
binary = "//:eslint",
config = "//{}:eslint_config".format(get_client_package_path()),
)

28
dev/eslint-report-test.sh Executable file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env bash
# The relative path to the eslint report
ESLINT_REPORT="$1"
# Ensure that the eslint report exists
if [ ! -f "$ESLINT_REPORT" ]; then
echo "${ESLINT_REPORT} does not exist."
exit 1
fi
# Check if the eslint report is empty
if [ -s "$ESLINT_REPORT" ]; then
# Get the absolute path to the eslint report.
absolute_report_path="$(realpath "$ESLINT_REPORT")"
# Remove everything before "__main__/" from the absolute path to the report.
workspace_report_path="${absolute_report_path#*__main__/}"
# Print the relative report path.
echo "ESLint report: $workspace_report_path"
cat "$ESLINT_REPORT"
exit 1
else
echo "No ESLint issues found."
exit 0
fi

View File

@ -2,16 +2,33 @@ load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_files_to_bin_actions")
load("//dev:js_lib.bzl", "gather_files_from_js_providers", "gather_runfiles")
load("@aspect_rules_js//js:defs.bzl", "js_library")
load("@aspect_rules_js//js:providers.bzl", "JsInfo")
load("@bazel_skylib//rules:build_test.bzl", "build_test")
def get_client_package_path():
# Used to reference the `eslint_config` target in the client package
# We assume that eslint config files are located at `client/<package>`
return "/".join(native.package_name().split("/")[:2])
def eslint_config_and_lint_root(name = "eslint_config", config_deps = [], root_js_deps = []):
"""
Creates an ESLint configuration target and an ESLint test target for a client package root JS files.
Args:
name: The name of the ESLint configuration target.
config_deps: A list of dependencies for the ESLint config target.
root_js_deps: A list of dependencies for the `root_js_eslint` target.
The macro assumes the presence of specific files (".eslintrc.js", ".eslintignore", "package.json")
and a tsconfig target in the current directory. It adds a reference to a top-level ESLint configuration
as a dependency, and sets the visibility to the current package and its subpackages.
For the 'root_js_eslint' target, it assumes all '.js' files in the current directory as its sources and
additional dependencies provided by 'root_js_deps'. It uses a global ESLint binary and the generated
ESLint configuration as its config.
Example usage:
eslint_config_and_lint_root(
config_deps = ["//my:dependency"],
root_js_deps = ["//other:dependency"],
)
"""
def eslint_config(deps = []):
js_library(
name = "eslint_config",
name = name,
testonly = True,
srcs = [".eslintrc.js"],
data = [
@ -21,15 +38,28 @@ def eslint_config(deps = []):
],
deps = [
"//:eslint_config",
] + deps,
] + config_deps,
visibility = ["//{}:__subpackages__".format(get_client_package_path())],
)
eslint_test_with_types(
name = "root_js_eslint",
srcs = native.glob(["*.js"]),
config = ":eslint_config",
deps = [
"//:jest_config", # required for import/extensions rule not to fail on the `jest.config.base` import.
"//:node_modules/@types/node",
] + root_js_deps,
)
# This private rule implementation wraps the ESLint binary.
# It executes ESLint against the provided source files and
# ensures that depenencies' type are available at lint time.
def _custom_eslint_impl(ctx):
copied_srcs = copy_files_to_bin_actions(ctx, ctx.files.srcs)
inputs_depset = depset(
copied_srcs,
copied_srcs + [ctx.executable.binary],
transitive = [gather_files_from_js_providers(
targets = [ctx.attr.config] + ctx.attr.deps,
include_sources = False,
@ -47,24 +77,17 @@ def _custom_eslint_impl(ctx):
deps = [],
)
args = ctx.actions.args()
# Declare the output file for the ESLint output.
report = ctx.actions.declare_file(ctx.attr.report)
# TODO: add context on why it doesn't work well with `overrides` globs.
# args.add("--no-eslintrc")
# args.add_all(["--config", get_path(ctx.files.config[0])])
args = ctx.actions.args() # Create the argument list for the ESLint command.
args.add("--quiet") # Ignore warnings and fail only on errors.
args.add_all(["--format", "./{}".format(ctx.files.formatter[0].short_path)]) # Use the custom formatter to ouput relative paths.
args.add_all([s.short_path for s in copied_srcs]) # Specify the files to lint.
args.add_all(["--output-file", report.short_path]) # Specify the output file for the ESLint output.
# Ignore warnings and fail only on errors.
args.add("--quiet")
# Use the custom formatter to ouput relative paths.
args.add_all(["--format", "./{}".format(ctx.files.formatter[0].short_path)])
# Specify the files to lint.
args.add_all([s.short_path for s in copied_srcs])
# Declare the output file for the eslint output.
output = ctx.actions.declare_file(ctx.attr.output)
# args.add_all(["--output-file", output.short_path])
# Declare the output file for the exit code output.
exit_code_out = ctx.actions.declare_file("exit_%s" % ctx.attr.report)
env = {
"BAZEL_BINDIR": ctx.bin_dir.path,
@ -72,28 +95,45 @@ def _custom_eslint_impl(ctx):
# "JS_BINARY__LOG_INFO": "1",
# "JS_BINARY__LOG_ERROR": "1",
# "JS_BINARY__SILENT_ON_SUCCESS": "0",
"JS_BINARY__STDOUT_OUTPUT_FILE": output.path,
"JS_BINARY__STDERR_OUTPUT_FILE": output.path,
# "JS_BINARY__EXPECTED_EXIT_CODE": "0",
# "JS_BINARY__EXIT_CODE_OUTPUT_FILE": output.path,
# "JS_BINARY__STDOUT_OUTPUT_FILE": report.path,
# "JS_BINARY__STDERR_OUTPUT_FILE": report.path,
"JS_BINARY__EXIT_CODE_OUTPUT_FILE": exit_code_out.path,
}
ctx.actions.run(
# The script wrapper around the ESLint binary is essential to create an empty 'report'
# file in cases where ESLint finds no errors. Bazel expects all declared outputs of
# ctx.actions.run_shell to be created during its execution. Failure to do so results
# in Bazel errors, hence if ESLint doesn't generate a 'report', we manually create one.
command = """
#!/usr/bin/env bash
set -o pipefail -o errexit -o nounset
# Call the ESLint @aspect_rules_js wrapper.
"{binary}" "$@"
# If the ESLint report is not created, create the empty one.
if [ ! -f "{report}" ]; then
touch "{report}"
fi
""".format(binary = ctx.executable.binary.path, report = report.path)
# Generate and run a bash script to wrap the binary
ctx.actions.run_shell(
env = env,
inputs = inputs_depset,
outputs = [output],
executable = ctx.executable.binary,
outputs = [report, exit_code_out],
command = command,
arguments = [args],
mnemonic = "ESLint",
)
return [
DefaultInfo(
files = depset([output]),
files = depset([report]),
runfiles = runfiles,
),
OutputGroupInfo(
output = depset([output]),
report = depset([report]),
runfiles = runfiles.files,
),
]
@ -106,17 +146,54 @@ _eslint_test_with_types = rule(
"config": attr.label(allow_single_file = True),
"formatter": attr.label(allow_single_file = True, default = Label("//:eslint-relative-formatter")),
"binary": attr.label(executable = True, cfg = "exec", allow_files = True),
"output": attr.string(),
"report": attr.string(),
},
)
def eslint_test_with_types(name, **kwargs):
lint_name = "%s_lint" % name
"""
A higher-level function to perform an ESLint test on TypeScript files with type checking.
build_test(name, targets = [lint_name])
Args:
name: A string representing the name of the test.
**kwargs: Arbitrary keyword arguments for additional customization of the test. This can
include the source files (`srcs`), dependencies (`deps`), ESLint configuration
(`config`), and more.
This macro wraps the `_eslint_test_with_types` rule and subsequently runs a shell test to
verify the output. It generates an output report named '<name>-output.txt' and a linting
target with the name of the original test suffixed with '_lint'.
Example usage:
eslint_test_with_types(
name = "my_test",
srcs = ["my_file.ts"],
deps = [":my_dependency"],
testonly = True,
config = ":my_eslint_config",
)
"""
lint_name = "%s_lint" % name
report = "%s-output.txt" % name
_eslint_test_with_types(
testonly = True,
name = lint_name,
output = "%s-output.txt" % name,
report = report,
binary = "//:eslint",
**kwargs
)
lint_target_name = ":%s" % lint_name
native.sh_test(
name = name,
srcs = ["//dev:eslint-report-test.sh"],
args = ["$(location %s)" % lint_target_name],
data = [lint_target_name],
)
# This function provides the path to the client package, assuming
# that eslint config files are located at `client/<package>`.
def get_client_package_path():
return "/".join(native.package_name().split("/")[:2])

View File

@ -133,3 +133,10 @@ If you want to run tests for a specific package, replace `//...` with the packag
bazel test `bazel query 'attr("name", ".*_typecheck_test", //client/vscode...)'`
```
### How do I run ESLint on a client package?
Similar to the above, we can use bazel query to find all target names ending with `_eslint` and test them:
```sh
bazel test `bazel query 'attr("name", ".*_eslint$", //client/wildcard/...)'`
```

View File

@ -27,7 +27,7 @@ The default run type.
- Tests
- BackCompat Tests
- **Linters and static analysis**: Run sg lint
- **Client checks**: Upload Storybook to Chromatic, Enterprise build, Build (client/jetbrains), Tests for VS Code extension, Unit, integration, and E2E tests for the Cody VS Code extension, ESLint (all), ESLint (web), Stylelint (all)
- **Client checks**: Upload Storybook to Chromatic, Enterprise build, Build (client/jetbrains), Tests for VS Code extension, Unit, integration, and E2E tests for the Cody VS Code extension, Stylelint (all)
- **Pipeline setup**: Trigger async
- Pipeline for `GraphQL` changes:
@ -35,7 +35,7 @@ The default run type.
- Ensure buildfiles are up to date
- Tests
- BackCompat Tests
- **Client checks**: Upload Storybook to Chromatic, Enterprise build, Build (client/jetbrains), Tests for VS Code extension, Unit, integration, and E2E tests for the Cody VS Code extension, ESLint (all), ESLint (web), Stylelint (all)
- **Client checks**: Upload Storybook to Chromatic, Enterprise build, Build (client/jetbrains), Tests for VS Code extension, Unit, integration, and E2E tests for the Cody VS Code extension, Stylelint (all)
- Pipeline for `DatabaseSchema` changes:
- **Metadata**: Pipeline metadata
@ -150,9 +150,9 @@ The run type for environment including `{"BEXT_NIGHTLY":"true"}`.
Base pipeline (more steps might be included based on branch changes):
- Stylelint (all)
- ESLint (all)
- ESLint (web)
- Stylelint (all)
- Test (client/browser)
- Puppeteer tests for chrome extension
- Test (all)
@ -164,9 +164,9 @@ The run type for environment including `{"VSCE_NIGHTLY":"true"}`.
Base pipeline (more steps might be included based on branch changes):
- Stylelint (all)
- ESLint (all)
- ESLint (web)
- Stylelint (all)
- Tests for VS Code extension
### Cody VS Code extension nightly release build
@ -175,9 +175,9 @@ The run type for environment including `{"CODY_NIGHTLY":"true"}`.
Base pipeline (more steps might be included based on branch changes):
- Stylelint (all)
- ESLint (all)
- ESLint (web)
- Stylelint (all)
- Unit, integration, and E2E tests for the Cody VS Code extension
- Cody release
@ -211,7 +211,7 @@ Base pipeline (more steps might be included based on branch changes):
- Tests
- BackCompat Tests
- **Linters and static analysis**: Run sg lint
- **Client checks**: Upload Storybook to Chromatic, Enterprise build, Build (client/jetbrains), Tests for VS Code extension, Unit, integration, and E2E tests for the Cody VS Code extension, ESLint (all), ESLint (web), Stylelint (all)
- **Client checks**: Upload Storybook to Chromatic, Enterprise build, Build (client/jetbrains), Tests for VS Code extension, Unit, integration, and E2E tests for the Cody VS Code extension, Stylelint (all)
- **Integration tests**: Backend integration tests (gRPC), Backend integration tests, Code Intel QA
- **End-to-end tests**: Executors E2E, Sourcegraph E2E, Sourcegraph Upgrade
- **Publish images**: server, executor, alpine-3.14, postgres-12-alpine, blobstore, cadvisor, codeinsights-db, codeintel-db, frontend, github-proxy, gitserver, grafana, indexed-searcher, migrator, node-exporter, opentelemetry-collector, postgres_exporter, precise-code-intel-worker, prometheus, prometheus-gcp, redis-cache, redis-store, redis_exporter, repo-updater, search-indexer, searcher, syntax-highlighter, worker, symbols, batcheshelper, blobstore2, bundled-executor, dind, embeddings, executor-kubernetes, executor-vm, jaeger-agent, jaeger-all-in-one, cody-gateway, sg, cody-slack, Publish executor image, Publish executor binary, Publish docker registry mirror image
@ -230,7 +230,7 @@ Base pipeline (more steps might be included based on branch changes):
- Tests
- BackCompat Tests
- **Linters and static analysis**: Run sg lint
- **Client checks**: Upload Storybook to Chromatic, Enterprise build, Build (client/jetbrains), Tests for VS Code extension, Unit, integration, and E2E tests for the Cody VS Code extension, ESLint (all), ESLint (web), Stylelint (all)
- **Client checks**: Upload Storybook to Chromatic, Enterprise build, Build (client/jetbrains), Tests for VS Code extension, Unit, integration, and E2E tests for the Cody VS Code extension, Stylelint (all)
- **Integration tests**: Backend integration tests (gRPC), Backend integration tests, Code Intel QA
- **End-to-end tests**: Executors E2E, Sourcegraph E2E, Sourcegraph Upgrade
- **Publish images**: server, executor, alpine-3.14, postgres-12-alpine, blobstore, cadvisor, codeinsights-db, codeintel-db, frontend, github-proxy, gitserver, grafana, indexed-searcher, migrator, node-exporter, opentelemetry-collector, postgres_exporter, precise-code-intel-worker, prometheus, prometheus-gcp, redis-cache, redis-store, redis_exporter, repo-updater, search-indexer, searcher, syntax-highlighter, worker, symbols, batcheshelper, blobstore2, bundled-executor, dind, embeddings, executor-kubernetes, executor-vm, jaeger-agent, jaeger-all-in-one, cody-gateway, sg, cody-slack
@ -241,9 +241,9 @@ The run type for branches matching `bext/release` (exact match).
Base pipeline (more steps might be included based on branch changes):
- Stylelint (all)
- ESLint (all)
- ESLint (web)
- Stylelint (all)
- Test (client/browser)
- Puppeteer tests for chrome extension
- Test (all)
@ -258,9 +258,9 @@ The run type for branches matching `vsce/release` (exact match).
Base pipeline (more steps might be included based on branch changes):
- Stylelint (all)
- ESLint (all)
- ESLint (web)
- Stylelint (all)
- Tests for VS Code extension
- Extension release
@ -270,9 +270,9 @@ The run type for branches matching `cody/release` (exact match).
Base pipeline (more steps might be included based on branch changes):
- Stylelint (all)
- ESLint (all)
- ESLint (web)
- Stylelint (all)
- Unit, integration, and E2E tests for the Cody VS Code extension
- Cody release
@ -290,7 +290,7 @@ Base pipeline (more steps might be included based on branch changes):
- Tests
- BackCompat Tests
- **Linters and static analysis**: Run sg lint
- **Client checks**: Upload Storybook to Chromatic, Enterprise build, Build (client/jetbrains), Tests for VS Code extension, Unit, integration, and E2E tests for the Cody VS Code extension, ESLint (all), ESLint (web), Stylelint (all)
- **Client checks**: Upload Storybook to Chromatic, Enterprise build, Build (client/jetbrains), Tests for VS Code extension, Unit, integration, and E2E tests for the Cody VS Code extension, Stylelint (all)
- **Integration tests**: Backend integration tests (gRPC), Backend integration tests, Code Intel QA
- **End-to-end tests**: Executors E2E, Sourcegraph E2E, Sourcegraph Upgrade
- **Publish images**: server, executor, alpine-3.14, postgres-12-alpine, blobstore, cadvisor, codeinsights-db, codeintel-db, frontend, github-proxy, gitserver, grafana, indexed-searcher, migrator, node-exporter, opentelemetry-collector, postgres_exporter, precise-code-intel-worker, prometheus, prometheus-gcp, redis-cache, redis-store, redis_exporter, repo-updater, search-indexer, searcher, syntax-highlighter, worker, symbols, batcheshelper, blobstore2, bundled-executor, dind, embeddings, executor-kubernetes, executor-vm, jaeger-agent, jaeger-all-in-one, cody-gateway, sg, cody-slack, Publish executor image, Publish executor binary
@ -314,7 +314,7 @@ Base pipeline (more steps might be included based on branch changes):
- Tests
- BackCompat Tests
- **Linters and static analysis**: Run sg lint
- **Client checks**: Upload Storybook to Chromatic, Enterprise build, Build (client/jetbrains), Tests for VS Code extension, Unit, integration, and E2E tests for the Cody VS Code extension, ESLint (all), ESLint (web), Stylelint (all)
- **Client checks**: Upload Storybook to Chromatic, Enterprise build, Build (client/jetbrains), Tests for VS Code extension, Unit, integration, and E2E tests for the Cody VS Code extension, Stylelint (all)
- **Integration tests**: Backend integration tests (gRPC), Backend integration tests, Code Intel QA
- **End-to-end tests**: Executors E2E, Sourcegraph E2E, Sourcegraph Upgrade
- **Publish images**: server, executor, alpine-3.14, postgres-12-alpine, blobstore, cadvisor, codeinsights-db, codeintel-db, frontend, github-proxy, gitserver, grafana, indexed-searcher, migrator, node-exporter, opentelemetry-collector, postgres_exporter, precise-code-intel-worker, prometheus, prometheus-gcp, redis-cache, redis-store, redis_exporter, repo-updater, search-indexer, searcher, syntax-highlighter, worker, symbols, batcheshelper, blobstore2, bundled-executor, dind, embeddings, executor-kubernetes, executor-vm, jaeger-agent, jaeger-all-in-one, cody-gateway, sg, cody-slack

View File

@ -22,10 +22,9 @@ import (
// e.g. by adding flags, and not as a condition for adding steps or commands.
type CoreTestOperationsOptions struct {
// for clientChromaticTests
ChromaticShouldAutoAccept bool
MinimumUpgradeableVersion string
ClientLintOnlyChangedFiles bool
ForceReadyForReview bool
ChromaticShouldAutoAccept bool
MinimumUpgradeableVersion string
ForceReadyForReview bool
// for addWebAppOSSBuild
CacheBundleSize bool
CreateBundleSizeDiff bool
@ -80,6 +79,8 @@ func CoreTestOperations(diff changed.Diff, opts CoreTestOperationsOptions) *oper
// addTypescriptCheck is now covered by Bazel
addVsceTests, // ~3.0m
addCodyExtensionTests, // ~2.5m
// addESLint,
addStylelint,
)
} else {
// If there are any Graphql changes, they are impacting the client as well.
@ -94,15 +95,11 @@ func CoreTestOperations(diff changed.Diff, opts CoreTestOperationsOptions) *oper
addTypescriptCheck, // ~4m
addVsceTests, // ~3.0m
addCodyExtensionTests, // ~2.5m
addESLint,
addStylelint,
)
}
if opts.ClientLintOnlyChangedFiles {
clientChecks.Append(addClientLintersForChangedFiles)
} else {
clientChecks.Append(addClientLintersForAllFiles)
}
ops.Merge(clientChecks)
}
@ -169,8 +166,13 @@ func addTypescriptCheck(pipeline *bk.Pipeline) {
bk.Cmd("dev/ci/pnpm-run.sh build-ts"))
}
// Adds client linters to check all files.
func addClientLintersForAllFiles(pipeline *bk.Pipeline) {
func addStylelint(pipeline *bk.Pipeline) {
pipeline.AddStep(":stylelint: Stylelint (all)",
withPnpmCache(),
bk.Cmd("dev/ci/pnpm-run.sh lint:css:all"))
}
func addESLint(pipeline *bk.Pipeline) {
pipeline.AddStep(":eslint: ESLint (all)",
withPnpmCache(),
bk.Cmd("dev/ci/pnpm-run.sh lint:js:all"))
@ -178,21 +180,11 @@ func addClientLintersForAllFiles(pipeline *bk.Pipeline) {
pipeline.AddStep(":eslint: ESLint (web)",
withPnpmCache(),
bk.Cmd("dev/ci/pnpm-run.sh lint:js:web"))
pipeline.AddStep(":stylelint: Stylelint (all)",
withPnpmCache(),
bk.Cmd("dev/ci/pnpm-run.sh lint:css:all"))
}
// Adds client linters to check changed in PR files.
func addClientLintersForChangedFiles(pipeline *bk.Pipeline) {
pipeline.AddStep(":eslint: ESLint (changed)",
withPnpmCache(),
bk.Cmd("dev/ci/pnpm-run.sh lint:js:changed"))
pipeline.AddStep(":stylelint: Stylelint (changed)",
withPnpmCache(),
bk.Cmd("dev/ci/pnpm-run.sh lint:css:changed"))
func addClientLintersForAllFiles(pipeline *bk.Pipeline) {
addStylelint(pipeline)
addESLint(pipeline)
}
// Adds steps for the OSS and Enterprise web app builds. Runs the web app tests.

View File

@ -173,10 +173,8 @@ func GeneratePipeline(c Config) (*bk.Pipeline, error) {
ops.Merge(CoreTestOperations(c.Diff, CoreTestOperationsOptions{
MinimumUpgradeableVersion: minimumUpgradeableVersion,
ForceReadyForReview: c.MessageFlags.ForceReadyForReview,
// TODO: (@umpox, @valerybugakov) Figure out if we can reliably enable this in PRs.
ClientLintOnlyChangedFiles: false,
CreateBundleSizeDiff: true,
ForceBazel: !c.MessageFlags.NoBazel,
CreateBundleSizeDiff: true,
ForceBazel: !c.MessageFlags.NoBazel,
}))
// At this stage, we don't break builds because of a Bazel failure.