Commit bab02ee7 authored by Mike Greiling's avatar Mike Greiling

Merge branch '201869-run-jest-in-parallel-in-ci' into 'master'

Resolve "Run jest in parallel in CI"

Closes #201869

See merge request gitlab-org/gitlab!25104
parents 7b208ba2 53ac64da
......@@ -207,11 +207,11 @@ karma-as-if-foss:
extends: .frontend-job-base
script:
- date
- yarn jest --ci --coverage
- yarn jest --ci --coverage --testSequencer ./scripts/frontend/parallel_ci_sequencer.js
cache:
key: jest
paths:
- tmp/jest/jest/
- tmp/cache/jest/
policy: pull-push
jest:
......@@ -229,6 +229,7 @@ jest:
- tmp/tests/frontend/
reports:
junit: junit_jest.xml
parallel: 2
jest-as-if-foss:
extends:
......@@ -239,6 +240,26 @@ jest-as-if-foss:
cache:
policy: pull
coverage-frontend:
extends:
- .default-tags
- .default-retry
- .frontend:rules:default-frontend-jobs
needs: ["jest"]
stage: post-test
before_script:
- yarn install --frozen-lockfile --cache-folder .yarn-cache --prefer-offline
script:
- yarn node scripts/frontend/merge_coverage_frontend.js
artifacts:
name: coverage-frontend
expire_in: 31d
paths:
- coverage-frontend/
cache:
paths:
- .yarn-cache/
.qa-frontend-node:
extends:
- .default-tags
......
......@@ -146,6 +146,7 @@ graph RL;
U2["frontend-fixtures-as-if-foss<br/>(EE default refs only)"];
V["webpack-dev-server, static-analysis"];
M[coverage];
O[coverage-frontend];
N["pages (master only)"];
Q[package-and-qa];
S["RSpec<br/>(e.g. rspec unit pg9)"]
......@@ -190,6 +191,7 @@ subgraph "`test` stage"
subgraph "`post-test` stage"
M --> |happens after| S
O --> |needs `jest`| I
end
subgraph "`review-prepare` stage"
......
......@@ -55,6 +55,14 @@ if (IS_EE) {
collectCoverageFrom.push(rootDirEE.replace('$1', '/**/*.{js,vue}'));
}
const coverageDirectory = () => {
if (process.env.CI_NODE_INDEX && process.env.CI_NODE_TOTAL) {
return `<rootDir>/coverage-frontend/jest-${process.env.CI_NODE_INDEX}-${process.env.CI_NODE_TOTAL}`;
}
return '<rootDir>/coverage-frontend/';
};
// eslint-disable-next-line import/no-commonjs
module.exports = {
clearMocks: true,
......@@ -62,7 +70,7 @@ module.exports = {
moduleFileExtensions: ['js', 'json', 'vue'],
moduleNameMapper,
collectCoverageFrom,
coverageDirectory: '<rootDir>/coverage-frontend/',
coverageDirectory: coverageDirectory(),
coverageReporters: ['json', 'lcov', 'text-summary', 'clover'],
cacheDirectory: '<rootDir>/tmp/cache/jest',
modulePathIgnorePatterns: ['<rootDir>/.yarn-cache/'],
......
const { create } = require('istanbul-reports');
const { createCoverageMap } = require('istanbul-lib-coverage');
const { createContext } = require('istanbul-lib-report');
const { resolve } = require('path');
const { sync } = require('glob');
const coverageMap = createCoverageMap();
const coverageDir = resolve(__dirname, '../../coverage-frontend');
const reportFiles = sync(`${coverageDir}/*/coverage-final.json`);
// Normalize coverage report generated by jest that has additional "data" key
// https://github.com/facebook/jest/issues/2418#issuecomment-423806659
const normalizeReport = report => {
const normalizedReport = Object.assign({}, report);
Object.entries(normalizedReport).forEach(([k, v]) => {
if (v.data) normalizedReport[k] = v.data;
});
return normalizedReport;
};
reportFiles
.map(reportFile => require(reportFile))
.map(normalizeReport)
.forEach(report => coverageMap.merge(report));
const context = createContext({ coverageMap: coverageMap, dir: 'coverage-frontend' });
['json', 'lcov', 'text-summary', 'clover'].forEach(reporter => {
create(reporter, {}).execute(context);
});
const Sequencer = require('@jest/test-sequencer').default;
class ParallelCISequencer extends Sequencer {
constructor() {
super();
this.ciNodeIndex = Number(process.env.CI_NODE_INDEX || '1');
this.ciNodeTotal = Number(process.env.CI_NODE_TOTAL || '1');
}
sort(tests) {
const sortedTests = this.sortByPath(tests);
const testsForThisRunner = this.distributeAcrossCINodes(sortedTests);
console.log(`CI_NODE_INDEX: ${this.ciNodeIndex}`);
console.log(`CI_NODE_TOTAL: ${this.ciNodeTotal}`);
console.log(`Total number of tests: ${tests.length}`);
console.log(`Total number of tests for this runner: ${testsForThisRunner.length}`);
return testsForThisRunner;
}
sortByPath(tests) {
return tests.sort((test1, test2) => {
if (test1.path < test2.path) {
return -1;
}
if (test1.path > test2.path) {
return 1;
}
return 0;
});
}
distributeAcrossCINodes(tests) {
return tests.filter((test, index) => {
return index % this.ciNodeTotal === this.ciNodeIndex - 1;
});
}
}
module.exports = ParallelCISequencer;
......@@ -5418,6 +5418,11 @@ has-flag@^3.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
has-flag@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has-symbols@^1.0.0, has-symbols@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
......@@ -5552,6 +5557,11 @@ html-entities@^1.2.1:
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=
html-escaper@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.0.tgz#71e87f931de3fe09e56661ab9a29aadec707b491"
integrity sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==
html-minifier@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-4.0.0.tgz#cca9aad8bce1175e02e17a8c33e46d8988889f56"
......@@ -6283,6 +6293,11 @@ istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.5:
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49"
integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==
istanbul-lib-coverage@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec"
integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==
istanbul-lib-hook@^2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz#c95695f383d4f8f60df1f04252a9550e15b5b133"
......@@ -6312,6 +6327,15 @@ istanbul-lib-report@^2.0.4, istanbul-lib-report@^2.0.8:
make-dir "^2.1.0"
supports-color "^6.1.0"
istanbul-lib-report@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6"
integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==
dependencies:
istanbul-lib-coverage "^3.0.0"
make-dir "^3.0.0"
supports-color "^7.1.0"
istanbul-lib-source-maps@^3.0.1, istanbul-lib-source-maps@^3.0.6:
version "3.0.6"
resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8"
......@@ -6330,6 +6354,14 @@ istanbul-reports@^2.1.1, istanbul-reports@^2.2.4:
dependencies:
handlebars "^4.1.2"
istanbul-reports@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.0.tgz#d4d16d035db99581b6194e119bbf36c963c5eb70"
integrity sha512-2osTcC8zcOSUkImzN2EWQta3Vdi4WjjKw99P2yWx5mLnigAM0Rd5uYFn1cf2i/Ois45GkNjaoTqc5CxgMSX80A==
dependencies:
html-escaper "^2.0.0"
istanbul-lib-report "^3.0.0"
istextorbinary@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.2.1.tgz#a5231a08ef6dd22b268d0895084cf8d58b5bec53"
......@@ -10836,6 +10868,13 @@ supports-color@^5.2.0, supports-color@^5.3.0, supports-color@^5.4.0:
dependencies:
has-flag "^3.0.0"
supports-color@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
dependencies:
has-flag "^4.0.0"
svg-tags@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment