@samitouri / QOS-React-2 / commits / 60afa3c117

Lint bundles using the bundle config instead of scanning for files (#19025)

* Lint bundles using the bundle config instead of scanning for files This ensures that we look for all the files that we expect to see there. If something doesn't get built we wouldn't detect it. However, this doesn't find files that aren't part of our builds such as indirection files in the root. This will need to change with ESM anyway since indirection files doesn't work. Everything should be built anyway. This ensures that we can use the bundles.js config to determine special cases instead of relying on file system conventions. * Run lint with flag

Sebastian Markbåge committed May 28, 2020 at 15:04 UTC 60afa3c11761e62d98c90b036890372c61bcc4c9
6 files changed +161 -120
.circleci/config.yml
+15 -1
@@ -364,6 +364,20 @@ jobs:
364 - run: yarn lint-build
365 - run: scripts/circleci/check_minified_errors.sh
366
367 + RELEASE_CHANNEL_stable_yarn_lint_build:
368 + docker: *docker
369 + environment: *environment
370 + steps:
371 + - checkout
372 + - attach_workspace: *attach_workspace
373 + - *restore_yarn_cache
374 + - *run_yarn
375 + - run:
376 + environment:
377 + RELEASE_CHANNEL: stable
378 + command: yarn lint-build
379 + - run: scripts/circleci/check_minified_errors.sh
380 +
381 RELEASE_CHANNEL_stable_yarn_test_build:
382 docker: *docker
383 environment: *environment
@@ -500,7 +514,7 @@ workflows:
514 - sizebot_stable:
515 requires:
516 - RELEASE_CHANNEL_stable_yarn_build
503 - - yarn_lint_build:
517 + - RELEASE_CHANNEL_stable_yarn_lint_build:
518 requires:
519 - RELEASE_CHANNEL_stable_yarn_build
520 - RELEASE_CHANNEL_stable_yarn_test_build:
scripts/rollup/build.js
+7 -42
@@ -62,6 +62,8 @@ const {
62 RN_FB_PROFILING,
63 } = Bundles.bundleTypes;
64
65 +const {getFilename} = Bundles;
66 +
67 function parseRequestedNames(names, toCase) {
68 let result = [];
69 for (let i = 0; i < names.length; i++) {
@@ -258,37 +260,6 @@ function getFormat(bundleType) {
260 }
261 }
262
261 -function getFilename(name, globalName, bundleType) {
262 - // we do this to replace / to -, for react-dom/server
263 - name = name.replace('/index.', '.').replace('/', '-');
264 - switch (bundleType) {
265 - case UMD_DEV:
266 - return `${name}.development.js`;
267 - case UMD_PROD:
268 - return `${name}.production.min.js`;
269 - case UMD_PROFILING:
270 - return `${name}.profiling.min.js`;
271 - case NODE_DEV:
272 - return `${name}.development.js`;
273 - case NODE_PROD:
274 - return `${name}.production.min.js`;
275 - case NODE_PROFILING:
276 - return `${name}.profiling.min.js`;
277 - case FB_WWW_DEV:
278 - case RN_OSS_DEV:
279 - case RN_FB_DEV:
280 - return `${globalName}-dev.js`;
281 - case FB_WWW_PROD:
282 - case RN_OSS_PROD:
283 - case RN_FB_PROD:
284 - return `${globalName}-prod.js`;
285 - case FB_WWW_PROFILING:
286 - case RN_FB_PROFILING:
287 - case RN_OSS_PROFILING:
288 - return `${globalName}-profiling.js`;
289 - }
290 -}
291 -
263 function isProductionBundleType(bundleType) {
264 switch (bundleType) {
265 case UMD_DEV:
@@ -558,7 +529,7 @@ async function createBundle(bundle, bundleType) {
529 return;
530 }
531
561 - const filename = getFilename(bundle.entry, bundle.global, bundleType);
532 + const filename = getFilename(bundle, bundleType);
533 const logKey =
534 chalk.white.bold(filename) + chalk.dim(` (${bundleType.toLowerCase()})`);
535 const format = getFormat(bundleType);
@@ -765,17 +736,11 @@ async function buildEverything() {
736 [bundle, FB_WWW_PROFILING],
737 [bundle, RN_OSS_DEV],
738 [bundle, RN_OSS_PROD],
768 - [bundle, RN_OSS_PROFILING]
739 + [bundle, RN_OSS_PROFILING],
740 + [bundle, RN_FB_DEV],
741 + [bundle, RN_FB_PROD],
742 + [bundle, RN_FB_PROFILING]
743 );
770 -
771 - if (__EXPERIMENTAL__) {
772 - // FB-specific RN builds are experimental-only.
773 - bundles.push(
774 - [bundle, RN_FB_DEV],
775 - [bundle, RN_FB_PROD],
776 - [bundle, RN_FB_PROFILING]
777 - );
778 - }
744 }
745
746 if (!shouldExtractErrors && process.env.CIRCLE_NODE_TOTAL) {
scripts/rollup/bundles.js
+40 -2
@@ -356,7 +356,9 @@ const bundles = [
356
357 /******* React Native *******/
358 {
359 - bundleTypes: [RN_FB_DEV, RN_FB_PROD, RN_FB_PROFILING],
359 + bundleTypes: __EXPERIMENTAL__
360 + ? [RN_FB_DEV, RN_FB_PROD, RN_FB_PROFILING]
361 + : [],
362 moduleType: RENDERER,
363 entry: 'react-native-renderer',
364 global: 'ReactNativeRenderer',
@@ -384,7 +386,9 @@ const bundles = [
386
387 /******* React Native Fabric *******/
388 {
387 - bundleTypes: [RN_FB_DEV, RN_FB_PROD, RN_FB_PROFILING],
389 + bundleTypes: __EXPERIMENTAL__
390 + ? [RN_FB_DEV, RN_FB_PROD, RN_FB_PROFILING]
391 + : [],
392 moduleType: RENDERER,
393 entry: 'react-native-renderer/fabric',
394 global: 'ReactFabric',
@@ -793,9 +797,43 @@ deepFreeze(bundles);
797 deepFreeze(bundleTypes);
798 deepFreeze(moduleTypes);
799
800 +function getFilename(bundle, bundleType) {
801 + let name = bundle.entry;
802 + const globalName = bundle.global;
803 + // we do this to replace / to -, for react-dom/server
804 + name = name.replace('/index.', '.').replace('/', '-');
805 + switch (bundleType) {
806 + case UMD_DEV:
807 + return `${name}.development.js`;
808 + case UMD_PROD:
809 + return `${name}.production.min.js`;
810 + case UMD_PROFILING:
811 + return `${name}.profiling.min.js`;
812 + case NODE_DEV:
813 + return `${name}.development.js`;
814 + case NODE_PROD:
815 + return `${name}.production.min.js`;
816 + case NODE_PROFILING:
817 + return `${name}.profiling.min.js`;
818 + case FB_WWW_DEV:
819 + case RN_OSS_DEV:
820 + case RN_FB_DEV:
821 + return `${globalName}-dev.js`;
822 + case FB_WWW_PROD:
823 + case RN_OSS_PROD:
824 + case RN_FB_PROD:
825 + return `${globalName}-prod.js`;
826 + case FB_WWW_PROFILING:
827 + case RN_FB_PROFILING:
828 + case RN_OSS_PROFILING:
829 + return `${globalName}-profiling.js`;
830 + }
831 +}
832 +
833 module.exports = {
834 fbBundleExternalsMap,
835 bundleTypes,
836 moduleTypes,
837 bundles,
838 + getFilename,
839 };
scripts/rollup/validate/eslintignore deleted
-11
@@ -1,11 +0,0 @@
1 -# Don't validate noop renderer bundle.
2 -# Unlike others, it currently uses ES6 syntax (generators).
3 -# We also don't use or publish it.
4 -**/react-noop-renderer/**
5 -JestReact-prod.js
6 -JestReact-dev.js
7 -**/jest-react/**
8 -# ESLint ignores `node_modules/*` in subdirectories
9 -# So we have to add this to lint build files.
10 -# https://github.com/eslint/eslint/pull/12888
11 -!/build/node_modules/*
scripts/rollup/validate/eslintrc.cjs.js
+3
@@ -37,6 +37,9 @@ module.exports = {
37 // Flight Webpack
38 __webpack_chunk_load__: true,
39 __webpack_require__: true,
40 +
41 + // jest
42 + expect: true,
43 },
44 parserOptions: {
45 ecmaVersion: 5,
scripts/rollup/validate/index.js
+96 -64
@@ -1,78 +1,110 @@
1 'use strict';
2
3 -const chalk = require('chalk');
3 const path = require('path');
5 -const spawnSync = require('child_process').spawnSync;
6 -const glob = require('glob');
4
8 -const extension = process.platform === 'win32' ? '.cmd' : '';
5 +const {ESLint} = require('eslint');
6 +
7 +const {bundles, getFilename, bundleTypes} = require('../bundles');
8 +const Packaging = require('../packaging');
9 +
10 +const {
11 + UMD_DEV,
12 + UMD_PROD,
13 + UMD_PROFILING,
14 + NODE_DEV,
15 + NODE_PROD,
16 + NODE_PROFILING,
17 + FB_WWW_DEV,
18 + FB_WWW_PROD,
19 + FB_WWW_PROFILING,
20 + RN_OSS_DEV,
21 + RN_OSS_PROD,
22 + RN_OSS_PROFILING,
23 + RN_FB_DEV,
24 + RN_FB_PROD,
25 + RN_FB_PROFILING,
26 +} = bundleTypes;
27 +
28 +function getFormat(bundleType) {
29 + switch (bundleType) {
30 + case UMD_DEV:
31 + case UMD_PROD:
32 + case UMD_PROFILING:
33 + return 'umd';
34 + case NODE_DEV:
35 + case NODE_PROD:
36 + case NODE_PROFILING:
37 + return 'cjs';
38 + case FB_WWW_DEV:
39 + case FB_WWW_PROD:
40 + case FB_WWW_PROFILING:
41 + return 'fb';
42 + case RN_OSS_DEV:
43 + case RN_OSS_PROD:
44 + case RN_OSS_PROFILING:
45 + case RN_FB_DEV:
46 + case RN_FB_PROD:
47 + case RN_FB_PROFILING:
48 + return 'rn';
49 + }
50 + throw new Error('unknown bundleType');
51 +}
52 +
53 +function getESLintInstance(format) {
54 + return new ESLint({
55 + useEslintrc: false,
56 + overrideConfigFile: path.join(__dirname, `eslintrc.${format}.js`),
57 + ignore: false,
58 + });
59 +}
60 +
61 +const esLints = {
62 + cjs: getESLintInstance('cjs'),
63 + rn: getESLintInstance('rn'),
64 + fb: getESLintInstance('fb'),
65 + umd: getESLintInstance('umd'),
66 +};
67
68 // Performs sanity checks on bundles *built* by Rollup.
69 // Helps catch Rollup regressions.
12 -function lint({format, filePatterns}) {
13 - console.log(`Linting ${format} bundles...`);
14 - const result = spawnSync(
15 - path.join('node_modules', '.bin', 'eslint' + extension),
16 - [
17 - ...filePatterns,
18 - '--config',
19 - path.join(__dirname, `eslintrc.${format}.js`),
20 - // Disregard our ESLint rules that apply to the source.
21 - '--no-eslintrc',
22 - // Use a different ignore file.
23 - '--ignore-path',
24 - path.join(__dirname, 'eslintignore'),
25 - ],
26 - {
27 - // Allow colors to pass through
28 - stdio: 'inherit',
29 - }
70 +async function lint(bundle, bundleType) {
71 + const filename = getFilename(bundle, bundleType);
72 + const format = getFormat(bundleType);
73 + const eslint = esLints[format];
74 +
75 + const packageName = Packaging.getPackageName(bundle.entry);
76 + const mainOutputPath = Packaging.getBundleOutputPath(
77 + bundleType,
78 + filename,
79 + packageName
80 );
31 - if (result.status !== 0) {
32 - console.error(chalk.red(`Linting of ${format} bundles has failed.`));
33 - process.exit(result.status);
34 - } else {
35 - console.log(chalk.green(`Linted ${format} bundles successfully!`));
36 - console.log();
81 +
82 + const results = await eslint.lintFiles([mainOutputPath]);
83 + if (
84 + results.some(result => result.errorCount > 0 || result.warningCount > 0)
85 + ) {
86 + process.exitCode = 1;
87 + console.log(`Failed ${mainOutputPath}`);
88 + const formatter = await eslint.loadFormatter('stylish');
89 + const resultText = formatter.format(results);
90 + console.log(resultText);
91 }
92 }
93
40 -function checkFilesExist(bundle) {
41 - const {format, filePatterns} = bundle;
42 - filePatterns.forEach(pattern => {
43 - console.log(`Checking if files exist in ${pattern}...`);
44 - const files = glob.sync(pattern);
45 - if (files.length === 0) {
46 - console.error(chalk.red(`Found no ${format} bundles in ${pattern}`));
47 - process.exit(1);
48 - } else {
49 - console.log(chalk.green(`Found ${files.length} bundles.`));
50 - console.log();
94 +async function lintEverything() {
95 + console.log(`Linting known bundles...`);
96 + let promises = [];
97 + // eslint-disable-next-line no-for-of-loops/no-for-of-loops
98 + for (const bundle of bundles) {
99 + // eslint-disable-next-line no-for-of-loops/no-for-of-loops
100 + for (const bundleType of bundle.bundleTypes) {
101 + promises.push(lint(bundle, bundleType));
102 }
52 - });
53 - return bundle;
103 + }
104 + await Promise.all(promises);
105 }
106
56 -const bundles = [
57 - {
58 - format: 'rn',
59 - filePatterns: [`./build/react-native/implementations/*.js`],
60 - },
61 - {
62 - format: 'umd',
63 - filePatterns: [`./build/node_modules/*/umd/*.js`],
64 - },
65 - {
66 - format: 'cjs',
67 - filePatterns: [
68 - `./build/node_modules/*/*.js`,
69 - `./build/node_modules/*/cjs/*.js`,
70 - ],
71 - },
72 - {
73 - format: 'fb',
74 - filePatterns: [`./build/facebook-www/*.js`],
75 - },
76 -];
77 -
78 -bundles.map(checkFilesExist).map(lint);
107 +lintEverything().catch(error => {
108 + process.exitCode = 1;
109 + console.error(error);
110 +});