mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Ingest code coverage (#62336)
This commit is contained in:
parent
30e305eb00
commit
4853f24705
36 changed files with 28300 additions and 81 deletions
|
@ -5,89 +5,26 @@ kibanaLibrary.load() // load from the Jenkins instance
|
|||
|
||||
kibanaPipeline(timeoutMinutes: 240) {
|
||||
catchErrors {
|
||||
def timestamp = new Date(currentBuild.startTimeInMillis).format("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone("UTC"))
|
||||
withEnv([
|
||||
'CODE_COVERAGE=1', // Needed for multiple ci scripts, such as remote.ts, test/scripts/*.sh, schema.js, etc.
|
||||
"TIME_STAMP=${timestamp}",
|
||||
'CODE_COVERAGE=1', // Enables coverage. Needed for multiple ci scripts, such as remote.ts, test/scripts/*.sh, schema.js, etc.
|
||||
]) {
|
||||
parallel([
|
||||
'kibana-intake-agent': workers.intake('kibana-intake', './test/scripts/jenkins_unit.sh'),
|
||||
'x-pack-intake-agent': {
|
||||
withEnv([
|
||||
'NODE_ENV=test' // Needed for jest tests only
|
||||
]) {
|
||||
workers.intake('x-pack-intake', './test/scripts/jenkins_xpack.sh')()
|
||||
}
|
||||
},
|
||||
'kibana-oss-agent': workers.functional('kibana-oss-tests', { kibanaPipeline.buildOss() }, [
|
||||
'oss-ciGroup1': kibanaPipeline.ossCiGroupProcess(1),
|
||||
'oss-ciGroup2': kibanaPipeline.ossCiGroupProcess(2),
|
||||
'oss-ciGroup3': kibanaPipeline.ossCiGroupProcess(3),
|
||||
'oss-ciGroup4': kibanaPipeline.ossCiGroupProcess(4),
|
||||
'oss-ciGroup5': kibanaPipeline.ossCiGroupProcess(5),
|
||||
'oss-ciGroup6': kibanaPipeline.ossCiGroupProcess(6),
|
||||
'oss-ciGroup7': kibanaPipeline.ossCiGroupProcess(7),
|
||||
'oss-ciGroup8': kibanaPipeline.ossCiGroupProcess(8),
|
||||
'oss-ciGroup9': kibanaPipeline.ossCiGroupProcess(9),
|
||||
'oss-ciGroup10': kibanaPipeline.ossCiGroupProcess(10),
|
||||
'oss-ciGroup11': kibanaPipeline.ossCiGroupProcess(11),
|
||||
'oss-ciGroup12': kibanaPipeline.ossCiGroupProcess(12),
|
||||
]),
|
||||
'kibana-xpack-agent': workers.functional('kibana-xpack-tests', { kibanaPipeline.buildXpack() }, [
|
||||
'xpack-ciGroup1': kibanaPipeline.xpackCiGroupProcess(1),
|
||||
'xpack-ciGroup2': kibanaPipeline.xpackCiGroupProcess(2),
|
||||
'xpack-ciGroup3': kibanaPipeline.xpackCiGroupProcess(3),
|
||||
'xpack-ciGroup4': kibanaPipeline.xpackCiGroupProcess(4),
|
||||
'xpack-ciGroup5': kibanaPipeline.xpackCiGroupProcess(5),
|
||||
'xpack-ciGroup6': kibanaPipeline.xpackCiGroupProcess(6),
|
||||
'xpack-ciGroup7': kibanaPipeline.xpackCiGroupProcess(7),
|
||||
'xpack-ciGroup8': kibanaPipeline.xpackCiGroupProcess(8),
|
||||
'xpack-ciGroup9': kibanaPipeline.xpackCiGroupProcess(9),
|
||||
'xpack-ciGroup10': kibanaPipeline.xpackCiGroupProcess(10),
|
||||
]),
|
||||
])
|
||||
workers.base(name: 'coverage-worker', size: 'l', ramDisk: false, bootstrapped: false) {
|
||||
kibanaPipeline.downloadCoverageArtifacts()
|
||||
kibanaPipeline.bash(
|
||||
'''
|
||||
# bootstrap from x-pack folder
|
||||
source src/dev/ci_setup/setup_env.sh
|
||||
cd x-pack
|
||||
yarn kbn bootstrap --prefer-offline
|
||||
cd ..
|
||||
# extract archives
|
||||
mkdir -p /tmp/extracted_coverage
|
||||
echo extracting intakes
|
||||
tar -xzf /tmp/downloaded_coverage/coverage/kibana-intake/kibana-coverage.tar.gz -C /tmp/extracted_coverage
|
||||
tar -xzf /tmp/downloaded_coverage/coverage/x-pack-intake/kibana-coverage.tar.gz -C /tmp/extracted_coverage
|
||||
echo extracting kibana-oss-tests
|
||||
tar -xzf /tmp/downloaded_coverage/coverage/kibana-oss-tests/kibana-coverage.tar.gz -C /tmp/extracted_coverage
|
||||
echo extracting kibana-xpack-tests
|
||||
tar -xzf /tmp/downloaded_coverage/coverage/kibana-xpack-tests/kibana-coverage.tar.gz -C /tmp/extracted_coverage
|
||||
# replace path in json files to have valid html report
|
||||
pwd=$(pwd)
|
||||
du -sh /tmp/extracted_coverage/target/kibana-coverage/
|
||||
echo replacing path in json files
|
||||
for i in {1..9}; do
|
||||
sed -i "s|/dev/shm/workspace/kibana|$pwd|g" /tmp/extracted_coverage/target/kibana-coverage/functional/${i}*.json &
|
||||
done
|
||||
wait
|
||||
# merge oss & x-pack reports
|
||||
echo merging coverage reports
|
||||
yarn nyc report --temp-dir /tmp/extracted_coverage/target/kibana-coverage/jest --report-dir target/kibana-coverage/jest-combined --reporter=html --reporter=json-summary
|
||||
yarn nyc report --temp-dir /tmp/extracted_coverage/target/kibana-coverage/functional --report-dir target/kibana-coverage/functional-combined --reporter=html --reporter=json-summary
|
||||
echo copy mocha reports
|
||||
mkdir -p target/kibana-coverage/mocha-combined
|
||||
cp -r /tmp/extracted_coverage/target/kibana-coverage/mocha target/kibana-coverage/mocha-combined
|
||||
''',
|
||||
"run `yarn kbn bootstrap && merge coverage`"
|
||||
)
|
||||
sh 'tar -czf kibana-jest-coverage.tar.gz target/kibana-coverage/jest-combined/*'
|
||||
kibanaPipeline.uploadCoverageArtifacts("coverage/jest-combined", 'kibana-jest-coverage.tar.gz')
|
||||
sh 'tar -czf kibana-functional-coverage.tar.gz target/kibana-coverage/functional-combined/*'
|
||||
kibanaPipeline.uploadCoverageArtifacts("coverage/functional-combined", 'kibana-functional-coverage.tar.gz')
|
||||
sh 'tar -czf kibana-mocha-coverage.tar.gz target/kibana-coverage/mocha-combined/*'
|
||||
kibanaPipeline.uploadCoverageArtifacts("coverage/mocha-combined", 'kibana-mocha-coverage.tar.gz')
|
||||
kibanaCoverage.runTests()
|
||||
handleIngestion(TIME_STAMP)
|
||||
}
|
||||
}
|
||||
kibanaPipeline.sendMail()
|
||||
}
|
||||
kibanaPipeline.sendMail()
|
||||
}
|
||||
|
||||
def handleIngestion(timestamp) {
|
||||
kibanaPipeline.downloadCoverageArtifacts()
|
||||
kibanaCoverage.prokLinks("### Process HTML Links")
|
||||
kibanaCoverage.collectVcsInfo("### Collect VCS Info")
|
||||
kibanaCoverage.ingest(timestamp, '### Injest && Upload')
|
||||
kibanaCoverage.uploadCoverageStaticSite(timestamp)
|
||||
}
|
||||
|
||||
|
||||
|
|
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
|
@ -128,6 +128,9 @@
|
|||
/src/legacy/server/utils/ @elastic/kibana-operations
|
||||
/src/legacy/server/warnings/ @elastic/kibana-operations
|
||||
|
||||
# Quality Assurance
|
||||
/src/dev/code_coverage @elastic/kibana-qa
|
||||
|
||||
# Platform
|
||||
/src/core/ @elastic/kibana-platform
|
||||
/config/kibana.yml @elastic/kibana-platform
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -46,4 +46,6 @@ npm-debug.log*
|
|||
.tern-project
|
||||
x-pack/plugins/apm/tsconfig.json
|
||||
apm.tsconfig.json
|
||||
/x-pack/legacy/plugins/apm/e2e/snapshots.js
|
||||
/x-pack/plugins/apm/e2e/snapshots.js
|
||||
.nyc_output
|
||||
|
|
|
@ -72,7 +72,8 @@
|
|||
"spec_to_console": "node scripts/spec_to_console",
|
||||
"backport-skip-ci": "backport --prDescription \"[skip-ci]\"",
|
||||
"storybook": "node scripts/storybook",
|
||||
"cover:report": "nyc report --temp-dir target/kibana-coverage/functional --report-dir target/coverage/report --reporter=lcov && open ./target/coverage/report/lcov-report/index.html"
|
||||
"cover:report": "nyc report --temp-dir target/kibana-coverage/functional --report-dir target/coverage/report --reporter=lcov && open ./target/coverage/report/lcov-report/index.html",
|
||||
"cover:functional:merge": "nyc report --temp-dir target/kibana-coverage/functional --report-dir target/coverage/report/functional --reporter=json-summary"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
21
scripts/ingest_coverage.js
Normal file
21
scripts/ingest_coverage.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
require('../src/setup_node_env');
|
||||
require('../src/dev/code_coverage/ingest_coverage').runCoverageIngestionCli();
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { ciRunUrl } from '../transforms';
|
||||
|
||||
describe(`Transform fn`, () => {
|
||||
describe(`ciRunUrl`, () => {
|
||||
it(`should add the url when present in the environment`, () => {
|
||||
process.env.CI_RUN_URL = 'blah';
|
||||
expect(ciRunUrl()).to.have.property('ciRunUrl', 'blah');
|
||||
});
|
||||
it(`should not include the url if not present in the environment`, () => {
|
||||
process.env.CI_RUN_URL = void 0;
|
||||
expect(ciRunUrl({ a: 'a' })).not.to.have.property('ciRunUrl');
|
||||
});
|
||||
});
|
||||
});
|
22
src/dev/code_coverage/ingest_coverage/constants.js
Normal file
22
src/dev/code_coverage/ingest_coverage/constants.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export const STATIC_SITE_URL_PROP_NAME = 'staticSiteUrl';
|
||||
export const COVERAGE_INDEX = process.env.COVERAGE_INDEX || 'kibana_code_coverage';
|
||||
export const TOTALS_INDEX = process.env.TOTALS_INDEX || `kibana_total_code_coverage`;
|
62
src/dev/code_coverage/ingest_coverage/either.js
Normal file
62
src/dev/code_coverage/ingest_coverage/either.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/* eslint new-cap: 0 */
|
||||
/* eslint no-unused-vars: 0 */
|
||||
|
||||
export const Right = x => ({
|
||||
chain: f => f(x),
|
||||
map: f => Right(f(x)),
|
||||
fold: (f, g) => g(x),
|
||||
inspect: () => `Right(${x})`,
|
||||
});
|
||||
|
||||
Right.of = function of(x) {
|
||||
return Right(x);
|
||||
};
|
||||
|
||||
export function right(x) {
|
||||
return Right.of(x);
|
||||
}
|
||||
|
||||
export const Left = x => ({
|
||||
chain: f => Left(x),
|
||||
map: f => Left(x),
|
||||
fold: (f, g) => f(x),
|
||||
inspect: () => `Left(${x})`,
|
||||
});
|
||||
|
||||
Left.of = function of(x) {
|
||||
return Left(x);
|
||||
};
|
||||
|
||||
export function left(x) {
|
||||
return Left.of(x);
|
||||
}
|
||||
|
||||
export const fromNullable = x =>
|
||||
x !== null && x !== undefined && x !== false && x !== 'undefined' ? Right(x) : Left(null);
|
||||
|
||||
export const tryCatch = f => {
|
||||
try {
|
||||
return Right(f());
|
||||
} catch (e) {
|
||||
return Left(e);
|
||||
}
|
||||
};
|
61
src/dev/code_coverage/ingest_coverage/index.js
Normal file
61
src/dev/code_coverage/ingest_coverage/index.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { resolve } from 'path';
|
||||
import { prok } from './process';
|
||||
import { run, createFlagError } from '@kbn/dev-utils';
|
||||
|
||||
const ROOT = resolve(__dirname, '../../../..');
|
||||
const flags = {
|
||||
string: ['path', 'verbose', 'vcsInfoPath'],
|
||||
help: `
|
||||
--path Required, path to the file to extract coverage data
|
||||
--vcsInfoPath Required, path to the git info file (branch, sha, author, & commit msg)
|
||||
`,
|
||||
};
|
||||
|
||||
export function runCoverageIngestionCli() {
|
||||
run(
|
||||
({ flags, log }) => {
|
||||
if (flags.path === '') throw createFlagError('please provide a single --path flag');
|
||||
if (flags.vcsInfoPath === '')
|
||||
throw createFlagError('please provide a single --vcsInfoPath flag');
|
||||
if (flags.verbose) log.verbose(`Verbose logging enabled`);
|
||||
|
||||
const resolveRoot = resolve.bind(null, ROOT);
|
||||
const jsonSummaryPath = resolveRoot(flags.path);
|
||||
const vcsInfoFilePath = resolveRoot(flags.vcsInfoPath);
|
||||
prok({ jsonSummaryPath, vcsInfoFilePath }, log);
|
||||
},
|
||||
{
|
||||
description: `
|
||||
|
||||
Post code coverage in json-summary format to an ES index.
|
||||
Note: You probably should create the index first.
|
||||
Two indexes are needed, see README.md.
|
||||
|
||||
Examples:
|
||||
|
||||
See 'ingest_code_coverage_readme.md'
|
||||
|
||||
`,
|
||||
flags,
|
||||
}
|
||||
);
|
||||
}
|
194
src/dev/code_coverage/ingest_coverage/index_mapping.md
Normal file
194
src/dev/code_coverage/ingest_coverage/index_mapping.md
Normal file
|
@ -0,0 +1,194 @@
|
|||
# Create index mapping
|
||||
|
||||
This is usually done in Kibana's dev tools ui.
|
||||
|
||||
```
|
||||
"mappings" : {
|
||||
"properties" : {
|
||||
"@timestamp" : {
|
||||
"type" : "date"
|
||||
},
|
||||
"BUILD_ID" : {
|
||||
"type" : "text",
|
||||
"fields" : {
|
||||
"keyword" : {
|
||||
"type" : "keyword",
|
||||
"ignore_above" : 256
|
||||
}
|
||||
}
|
||||
},
|
||||
"branches" : {
|
||||
"properties" : {
|
||||
"covered" : {
|
||||
"type" : "long"
|
||||
},
|
||||
"pct" : {
|
||||
"type" : "long"
|
||||
},
|
||||
"skipped" : {
|
||||
"type" : "long"
|
||||
},
|
||||
"total" : {
|
||||
"type" : "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ciRunUrl" : {
|
||||
"type" : "text",
|
||||
"fields" : {
|
||||
"keyword" : {
|
||||
"type" : "keyword",
|
||||
"ignore_above" : 256
|
||||
}
|
||||
}
|
||||
},
|
||||
"coveredFilePath" : {
|
||||
"type" : "text",
|
||||
"fields" : {
|
||||
"keyword" : {
|
||||
"type" : "keyword",
|
||||
"ignore_above" : 256
|
||||
}
|
||||
}
|
||||
},
|
||||
"functions" : {
|
||||
"properties" : {
|
||||
"covered" : {
|
||||
"type" : "long"
|
||||
},
|
||||
"pct" : {
|
||||
"type" : "long"
|
||||
},
|
||||
"skipped" : {
|
||||
"type" : "long"
|
||||
},
|
||||
"total" : {
|
||||
"type" : "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"isTotal" : {
|
||||
"type" : "boolean"
|
||||
},
|
||||
"jsonSummaryPath" : {
|
||||
"type" : "text",
|
||||
"fields" : {
|
||||
"keyword" : {
|
||||
"type" : "keyword",
|
||||
"ignore_above" : 256
|
||||
}
|
||||
}
|
||||
},
|
||||
"lines" : {
|
||||
"properties" : {
|
||||
"covered" : {
|
||||
"type" : "long"
|
||||
},
|
||||
"pct" : {
|
||||
"type" : "long"
|
||||
},
|
||||
"skipped" : {
|
||||
"type" : "long"
|
||||
},
|
||||
"total" : {
|
||||
"type" : "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"path" : {
|
||||
"type" : "text",
|
||||
"fields" : {
|
||||
"keyword" : {
|
||||
"type" : "keyword",
|
||||
"ignore_above" : 256
|
||||
}
|
||||
}
|
||||
},
|
||||
"statements" : {
|
||||
"properties" : {
|
||||
"covered" : {
|
||||
"type" : "long"
|
||||
},
|
||||
"pct" : {
|
||||
"type" : "long"
|
||||
},
|
||||
"skipped" : {
|
||||
"type" : "long"
|
||||
},
|
||||
"total" : {
|
||||
"type" : "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"staticSiteUrl" : {
|
||||
"type" : "text",
|
||||
"fields" : {
|
||||
"keyword" : {
|
||||
"type" : "keyword",
|
||||
"ignore_above" : 256
|
||||
}
|
||||
}
|
||||
},
|
||||
"testRunnerType" : {
|
||||
"type" : "text",
|
||||
"fields" : {
|
||||
"keyword" : {
|
||||
"type" : "keyword",
|
||||
"ignore_above" : 256
|
||||
}
|
||||
}
|
||||
},
|
||||
"vcs" : {
|
||||
"properties" : {
|
||||
"author" : {
|
||||
"type" : "text",
|
||||
"fields" : {
|
||||
"keyword" : {
|
||||
"type" : "keyword",
|
||||
"ignore_above" : 256
|
||||
}
|
||||
}
|
||||
},
|
||||
"branch" : {
|
||||
"type" : "text",
|
||||
"fields" : {
|
||||
"keyword" : {
|
||||
"type" : "keyword",
|
||||
"ignore_above" : 256
|
||||
}
|
||||
}
|
||||
},
|
||||
"commitMsg" : {
|
||||
"type" : "text",
|
||||
"fields" : {
|
||||
"keyword" : {
|
||||
"type" : "keyword",
|
||||
"ignore_above" : 256
|
||||
}
|
||||
}
|
||||
},
|
||||
"sha" : {
|
||||
"type" : "text",
|
||||
"fields" : {
|
||||
"keyword" : {
|
||||
"type" : "keyword",
|
||||
"ignore_above" : 256
|
||||
}
|
||||
}
|
||||
},
|
||||
"vcsUrl" : {
|
||||
"type" : "text",
|
||||
"fields" : {
|
||||
"keyword" : {
|
||||
"type" : "keyword",
|
||||
"ignore_above" : 256
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
_The main portion of the above mapping, is the timestamp-date mapping._
|
103
src/dev/code_coverage/ingest_coverage/ingest.js
Normal file
103
src/dev/code_coverage/ingest_coverage/ingest.js
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
const { Client } = require('@elastic/elasticsearch');
|
||||
import { createFailError } from '@kbn/dev-utils';
|
||||
import chalk from 'chalk';
|
||||
import { green, always } from './utils';
|
||||
import { fromNullable } from './either';
|
||||
import { COVERAGE_INDEX, TOTALS_INDEX } from './constants';
|
||||
|
||||
const node = process.env.ES_HOST || 'http://localhost:9200';
|
||||
const redacted = redact(node);
|
||||
const client = new Client({ node });
|
||||
|
||||
const indexName = body => (body.isTotal ? TOTALS_INDEX : COVERAGE_INDEX);
|
||||
|
||||
export const ingest = log => async body => {
|
||||
const index = indexName(body);
|
||||
|
||||
if (process.env.NODE_ENV === 'integration_test') {
|
||||
log.debug(`### Just Logging, ${green('NOT actually sending')} to [${green(index)}]`);
|
||||
logSuccess(log, index, body);
|
||||
} else {
|
||||
try {
|
||||
log.debug(`### Actually sending to: ${green(index)}`);
|
||||
await client.index({ index, body });
|
||||
logSuccess(log, index, body);
|
||||
} catch (e) {
|
||||
throw createFailError(errMsg(index, body, e));
|
||||
}
|
||||
}
|
||||
};
|
||||
function logSuccess(log, index, body) {
|
||||
const logShort = () => `### Sent:
|
||||
### ES HOST (redacted): ${redacted}
|
||||
### Index: ${green(index)}`;
|
||||
|
||||
logShort();
|
||||
log.verbose(pretty(body));
|
||||
|
||||
const { staticSiteUrl } = body;
|
||||
|
||||
logShort();
|
||||
log.debug(`### staticSiteUrl: ${staticSiteUrl}`);
|
||||
}
|
||||
function errMsg(index, body, e) {
|
||||
const orig = fromNullable(e.body).fold(
|
||||
always(''),
|
||||
() => `### Orig Err:\n${pretty(e.body.error)}`
|
||||
);
|
||||
|
||||
const red = color('red');
|
||||
|
||||
return `
|
||||
### ES HOST (redacted): \n\t${red(redacted)}
|
||||
### INDEX: \n\t${red(index)}
|
||||
### Partial orig err stack: \n\t${partial(e.stack)}
|
||||
### Item BODY:\n${pretty(body)}
|
||||
${orig}
|
||||
|
||||
### Troubleshooting Hint:
|
||||
${red('Perhaps the coverage data was not merged properly?\n')}
|
||||
`;
|
||||
}
|
||||
|
||||
function partial(x) {
|
||||
return x
|
||||
.split('\n')
|
||||
.splice(0, 2)
|
||||
.join('\n');
|
||||
}
|
||||
function redact(x) {
|
||||
const url = new URL(x);
|
||||
if (url.password) {
|
||||
return `${url.protocol}//${url.host}`;
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
function color(whichColor) {
|
||||
return function colorInner(x) {
|
||||
return chalk[whichColor].bgWhiteBright(x);
|
||||
};
|
||||
}
|
||||
function pretty(x) {
|
||||
return JSON.stringify(x, null, 2);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
# Convert Code Coverage Json Summary and Send to ES
|
||||
|
||||
|
||||
## How it works
|
||||
|
||||
It starts with this jenkins pipeline file:
|
||||
|
||||
.ci/Jenkinsfile_coverage#L60
|
||||
|
||||
```
|
||||
src/dev/code_coverage/shell_scripts/ingest_coverage.sh ${BUILD_NUMBER} ${env.BUILD_URL}
|
||||
```
|
||||
|
||||
The ingestion system is hard coded to look for 3 coverage summary files...all json.
|
||||
|
||||
From there, an event stream is created, that massages the data to an output format in json that is ingested.
|
||||
|
||||
## Configuration
|
||||
|
||||
There is really only one config step.
|
||||
The index [mapping](src/dev/code_coverage/ingest_coverage/index_mapping.md) for one of
|
||||
of the indexes has to be manually created.
|
||||
Currently, we just add it using Kibana's Dev Tools.
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { spawn } from 'child_process';
|
||||
import { resolve } from 'path';
|
||||
import { green, always } from '../utils';
|
||||
|
||||
import { STATIC_SITE_URL_PROP_NAME, COVERAGE_INDEX } from '../constants';
|
||||
|
||||
const ROOT_DIR = resolve(__dirname, '../../../../..');
|
||||
const MOCKS_DIR = resolve(__dirname, './mocks');
|
||||
const staticSiteUrlRegexes = {
|
||||
staticHostIncluded: /https:\/\/kibana-coverage\.elastic\.dev/,
|
||||
timeStampIncluded: /\d{4}-\d{2}-\d{2}T\d{2}.*\d{2}.*\d{2}Z/,
|
||||
folderStructureIncluded: /(?:.*|.*-combined)\//,
|
||||
};
|
||||
const env = {
|
||||
BUILD_ID: 407,
|
||||
CI_RUN_URL: 'https://kibana-ci.elastic.co/job/elastic+kibana+code-coverage/407/',
|
||||
STATIC_SITE_URL_BASE: 'https://kibana-coverage.elastic.dev',
|
||||
TIME_STAMP: '2020-03-02T21:11:47Z',
|
||||
ES_HOST: 'https://super:changeme@some.fake.host:9243',
|
||||
NODE_ENV: 'integration_test',
|
||||
COVERAGE_INGESTION_KIBANA_ROOT: '/var/lib/jenkins/workspace/elastic+kibana+code-coverage/kibana',
|
||||
};
|
||||
const includesSiteUrlPredicate = x => x.includes(STATIC_SITE_URL_PROP_NAME);
|
||||
const siteUrlLines = specificLinesOnly(includesSiteUrlPredicate);
|
||||
const splitByNewLine = x => x.split('\n');
|
||||
const siteUrlsSplitByNewLine = siteUrlLines(splitByNewLine);
|
||||
const siteUrlsSplitByNewLineWithoutBlanks = siteUrlsSplitByNewLine(notBlankLines);
|
||||
|
||||
describe('Ingesting Coverage to Cluster', () => {
|
||||
const verboseArgs = [
|
||||
'scripts/ingest_coverage.js',
|
||||
'--verbose',
|
||||
'--vcsInfoPath',
|
||||
'src/dev/code_coverage/ingest_coverage/integration_tests/mocks/VCS_INFO.txt',
|
||||
'--path',
|
||||
];
|
||||
|
||||
const noTotalsPath = 'jest-combined/coverage-summary-NO-total.json';
|
||||
const bothIndexesPath = 'jest-combined/coverage-summary-manual-mix.json';
|
||||
|
||||
describe('with NODE_ENV set to "integration_test"', () => {
|
||||
describe(`and debug || verbose turned on`, () => {
|
||||
describe(`to the [${COVERAGE_INDEX}] index`, () => {
|
||||
const mutableCoverageIndexChunks = [];
|
||||
|
||||
beforeAll(done => {
|
||||
const ingestAndMutateAsync = ingestAndMutate(done);
|
||||
const ingestAndMutateAsyncWithPath = ingestAndMutateAsync(noTotalsPath);
|
||||
const verboseIngestAndMutateAsyncWithPath = ingestAndMutateAsyncWithPath(verboseArgs);
|
||||
verboseIngestAndMutateAsyncWithPath(mutableCoverageIndexChunks);
|
||||
});
|
||||
|
||||
it(
|
||||
'should result in every posted item having a site url that meets all regex assertions',
|
||||
always(
|
||||
siteUrlsSplitByNewLineWithoutBlanks(mutableCoverageIndexChunks).forEach(
|
||||
expectAllRegexesToPass({
|
||||
...staticSiteUrlRegexes,
|
||||
endsInDotJsDotHtml: /.js.html$/,
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
describe(`to both indexes in the same push`, () => {
|
||||
const mutableBothIndexesChunks = [];
|
||||
|
||||
beforeAll(done => {
|
||||
const ingestAndMutateAsync = ingestAndMutate(done);
|
||||
const ingestAndMutateAsyncWithPath = ingestAndMutateAsync(bothIndexesPath);
|
||||
const verboseIngestAndMutateAsyncWithPath = ingestAndMutateAsyncWithPath(verboseArgs);
|
||||
verboseIngestAndMutateAsyncWithPath(mutableBothIndexesChunks);
|
||||
});
|
||||
|
||||
it(
|
||||
'should result in every posted item having a site url that meets all regex assertions',
|
||||
always(
|
||||
siteUrlsSplitByNewLineWithoutBlanks(mutableBothIndexesChunks).forEach(
|
||||
expectAllRegexesToPass(staticSiteUrlRegexes)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
it('should result in the "just logging" message being present in the log', () => {
|
||||
expect(mutableBothIndexesChunks.some(x => x.includes('Just Logging'))).to.be(true);
|
||||
});
|
||||
it('should result in the "actually sending" message NOT being present in the log', () => {
|
||||
expect(mutableBothIndexesChunks.every(x => !x.includes('Actually sending...'))).to.be(
|
||||
true
|
||||
);
|
||||
});
|
||||
describe(`with provided vcs info file`, () => {
|
||||
const filterZero = xs => included => xs.filter(x => x.includes(included))[0];
|
||||
const filteredWith = filterZero(mutableBothIndexesChunks);
|
||||
it('should have a vcs block', () => {
|
||||
const vcs = 'vcs';
|
||||
const portion = filteredWith(vcs);
|
||||
expect(portion).to.contain(vcs);
|
||||
});
|
||||
it(`should have a branch`, () => {
|
||||
const branch = `"branch":`;
|
||||
const portion = filteredWith(branch);
|
||||
expect(portion).to.contain(branch);
|
||||
expect(portion).to.contain(`"origin/ingest-code-coverage"`);
|
||||
});
|
||||
it(`should have a sha`, () => {
|
||||
const sha = `"sha":`;
|
||||
const portion = filteredWith(sha);
|
||||
expect(portion).to.contain(sha);
|
||||
expect(portion).to.contain(`"f07b34f6206"`);
|
||||
});
|
||||
it(`should have an author`, () => {
|
||||
const author = `"author":`;
|
||||
const portion = filteredWith(author);
|
||||
expect(portion).to.contain(author);
|
||||
expect(portion).to.contain(`"Tre' Seymour"`);
|
||||
});
|
||||
it(`should have a commit msg, truncated`, () => {
|
||||
const commitMsg = `"commitMsg":`;
|
||||
const portion = filteredWith(commitMsg);
|
||||
expect(portion).to.contain(commitMsg);
|
||||
expect(portion).to.contain(`"Lorem :) ipsum Tre' λ dolor sit amet, consectetur ..."`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function ingestAndMutate(done) {
|
||||
return summaryPathSuffix => args => xs => {
|
||||
const coverageSummaryPath = resolve(MOCKS_DIR, summaryPathSuffix);
|
||||
const opts = [...args, coverageSummaryPath];
|
||||
const ingest = spawn(process.execPath, opts, { cwd: ROOT_DIR, env });
|
||||
|
||||
ingest.stdout.on('data', x => xs.push(x + ''));
|
||||
ingest.on('close', done);
|
||||
};
|
||||
}
|
||||
|
||||
function specificLinesOnly(predicate) {
|
||||
return splitByNewLine => notBlankLines => xs =>
|
||||
xs.filter(predicate).map(x => splitByNewLine(x).reduce(notBlankLines));
|
||||
}
|
||||
|
||||
function notBlankLines(acc, item) {
|
||||
if (item !== '') return item;
|
||||
return acc;
|
||||
}
|
||||
|
||||
function expectAllRegexesToPass(staticSiteUrlRegexes) {
|
||||
return urlLine =>
|
||||
Object.entries(staticSiteUrlRegexes).forEach(regexTuple => {
|
||||
if (!regexTuple[1].test(urlLine))
|
||||
throw new Error(
|
||||
`\n### ${green('FAILED')}\nAsserting: [\n\t${green(
|
||||
regexTuple[0]
|
||||
)}\n]\nAgainst: [\n\t${urlLine}\n]`
|
||||
);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
origin/ingest-code-coverage
|
||||
f07b34f6206
|
||||
Tre' Seymour
|
||||
Lorem :) ipsum Tre' λ dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
|
||||
Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris. Integer in mauris eu nibh euismod gravida. Duis ac tellus et risus vulputate vehicula. Donec lobortis risus a elit. Etiam tempor. Ut ullamcorper, ligula eu tempor congue, eros est euismod turpis, id tincidunt sapien risus a quam. Maecenas fermentum consequat mi. Donec fermentum. Pellentesque malesuada nulla a mi. Duis sapien sem, aliquet nec, commodo eget, consequat quis, neque. Aliquam faucibus, elit ut dictum aliquet, felis nisl adipiscing sapien, sed malesuada diam lacus eget erat. Cras mollis scelerisque nunc. Nullam arcu. Aliquam consequat. Curabitur augue lorem, dapibus quis, laoreet et, pretium ac, nisi. Aenean magna nisl, mollis quis, molestie eu, feugiat in, orci. In hac habitasse platea dictumst.
|
||||
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,158 @@
|
|||
{
|
||||
"total": {
|
||||
"lines": {
|
||||
"total": 14817,
|
||||
"covered": 3377,
|
||||
"skipped": 0,
|
||||
"pct": 22.79
|
||||
},
|
||||
"statements": {
|
||||
"total": 15507,
|
||||
"covered": 3453,
|
||||
"skipped": 0,
|
||||
"pct": 22.27
|
||||
},
|
||||
"functions": {
|
||||
"total": 3286,
|
||||
"covered": 654,
|
||||
"skipped": 0,
|
||||
"pct": 19.9
|
||||
},
|
||||
"branches": {
|
||||
"total": 8060,
|
||||
"covered": 1439,
|
||||
"skipped": 0,
|
||||
"pct": 17.85
|
||||
}
|
||||
},
|
||||
"/var/lib/jenkins/workspace/elastic+kibana+code-coverage/kibana/x-pack/legacy/plugins/reporting/server/browsers/extract/unzip.js": {
|
||||
"lines": {
|
||||
"total": 4,
|
||||
"covered": 4,
|
||||
"skipped": 0,
|
||||
"pct": 100
|
||||
},
|
||||
"functions": {
|
||||
"total": 1,
|
||||
"covered": 1,
|
||||
"skipped": 0,
|
||||
"pct": 100
|
||||
},
|
||||
"statements": {
|
||||
"total": 4,
|
||||
"covered": 4,
|
||||
"skipped": 0,
|
||||
"pct": 100
|
||||
},
|
||||
"branches": {
|
||||
"total": 0,
|
||||
"covered": 0,
|
||||
"skipped": 0,
|
||||
"pct": 100
|
||||
}
|
||||
},
|
||||
"total": {
|
||||
"lines": {
|
||||
"total": 14817,
|
||||
"covered": 3377,
|
||||
"skipped": 0,
|
||||
"pct": 22.79
|
||||
},
|
||||
"statements": {
|
||||
"total": 15507,
|
||||
"covered": 3453,
|
||||
"skipped": 0,
|
||||
"pct": 22.27
|
||||
},
|
||||
"functions": {
|
||||
"total": 3286,
|
||||
"covered": 654,
|
||||
"skipped": 0,
|
||||
"pct": 19.9
|
||||
},
|
||||
"branches": {
|
||||
"total": 8060,
|
||||
"covered": 1439,
|
||||
"skipped": 0,
|
||||
"pct": 17.85
|
||||
}
|
||||
},
|
||||
"/var/lib/jenkins/workspace/elastic+kibana+code-coverage/kibana/packages/kbn-ui-framework/src/components/button/button.js": {
|
||||
"lines": {
|
||||
"total": 33,
|
||||
"covered": 28,
|
||||
"skipped": 0,
|
||||
"pct": 84.85
|
||||
},
|
||||
"functions": {
|
||||
"total": 7,
|
||||
"covered": 6,
|
||||
"skipped": 0,
|
||||
"pct": 85.71
|
||||
},
|
||||
"statements": {
|
||||
"total": 33,
|
||||
"covered": 28,
|
||||
"skipped": 0,
|
||||
"pct": 84.85
|
||||
},
|
||||
"branches": {
|
||||
"total": 21,
|
||||
"covered": 16,
|
||||
"skipped": 0,
|
||||
"pct": 76.19
|
||||
}
|
||||
},
|
||||
"total": {
|
||||
"lines": {
|
||||
"total": 14817,
|
||||
"covered": 3377,
|
||||
"skipped": 0,
|
||||
"pct": 22.79
|
||||
},
|
||||
"statements": {
|
||||
"total": 15507,
|
||||
"covered": 3453,
|
||||
"skipped": 0,
|
||||
"pct": 22.27
|
||||
},
|
||||
"functions": {
|
||||
"total": 3286,
|
||||
"covered": 654,
|
||||
"skipped": 0,
|
||||
"pct": 19.9
|
||||
},
|
||||
"branches": {
|
||||
"total": 8060,
|
||||
"covered": 1439,
|
||||
"skipped": 0,
|
||||
"pct": 17.85
|
||||
}
|
||||
},
|
||||
"/var/lib/jenkins/workspace/elastic+kibana+code-coverage/kibana/packages/kbn-ui-framework/src/components/button/button_icon/button_icon.js": {
|
||||
"lines": {
|
||||
"total": 6,
|
||||
"covered": 6,
|
||||
"skipped": 0,
|
||||
"pct": 100
|
||||
},
|
||||
"functions": {
|
||||
"total": 1,
|
||||
"covered": 1,
|
||||
"skipped": 0,
|
||||
"pct": 100
|
||||
},
|
||||
"statements": {
|
||||
"total": 6,
|
||||
"covered": 6,
|
||||
"skipped": 0,
|
||||
"pct": 100
|
||||
},
|
||||
"branches": {
|
||||
"total": 0,
|
||||
"covered": 0,
|
||||
"skipped": 0,
|
||||
"pct": 100
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1 @@
|
|||
2e51fdb932
|
23
src/dev/code_coverage/ingest_coverage/json_stream.js
Normal file
23
src/dev/code_coverage/ingest_coverage/json_stream.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import oboe from 'oboe';
|
||||
import { createReadStream } from 'fs';
|
||||
|
||||
export default jsonSummaryPath => oboe(createReadStream(jsonSummaryPath));
|
104
src/dev/code_coverage/ingest_coverage/process.js
Normal file
104
src/dev/code_coverage/ingest_coverage/process.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { fromEventPattern, of, fromEvent } from 'rxjs';
|
||||
import { concatMap, delay, map, takeUntil } from 'rxjs/operators';
|
||||
import jsonStream from './json_stream';
|
||||
import { pipe, noop, green, always } from './utils';
|
||||
import { ingest } from './ingest';
|
||||
import {
|
||||
staticSite,
|
||||
statsAndstaticSiteUrl,
|
||||
addJsonSummaryPath,
|
||||
testRunner,
|
||||
addTimeStamp,
|
||||
buildId,
|
||||
coveredFilePath,
|
||||
ciRunUrl,
|
||||
itemizeVcs,
|
||||
} from './transforms';
|
||||
import { resolve } from 'path';
|
||||
import { createReadStream } from 'fs';
|
||||
import readline from 'readline';
|
||||
|
||||
const ROOT = '../../../..';
|
||||
const COVERAGE_INGESTION_KIBANA_ROOT =
|
||||
process.env.COVERAGE_INGESTION_KIBANA_ROOT || resolve(__dirname, ROOT);
|
||||
const ms = process.env.DELAY || 0;
|
||||
const staticSiteUrlBase = process.env.STATIC_SITE_URL_BASE || 'https://kibana-coverage.elastic.dev';
|
||||
const addPrePopulatedTimeStamp = addTimeStamp(process.env.TIME_STAMP);
|
||||
const preamble = pipe(statsAndstaticSiteUrl, rootDirAndOrigPath, buildId, addPrePopulatedTimeStamp);
|
||||
const addTestRunnerAndStaticSiteUrl = pipe(testRunner, staticSite(staticSiteUrlBase));
|
||||
|
||||
const transform = jsonSummaryPath => log => vcsInfo => {
|
||||
const objStream = jsonStream(jsonSummaryPath).on('done', noop);
|
||||
const itemizeVcsInfo = itemizeVcs(vcsInfo);
|
||||
|
||||
const jsonSummary$ = _ => objStream.on('node', '!.*', _);
|
||||
|
||||
fromEventPattern(jsonSummary$)
|
||||
.pipe(
|
||||
map(preamble),
|
||||
map(coveredFilePath),
|
||||
map(itemizeVcsInfo),
|
||||
map(ciRunUrl),
|
||||
map(addJsonSummaryPath(jsonSummaryPath)),
|
||||
map(addTestRunnerAndStaticSiteUrl),
|
||||
concatMap(x => of(x).pipe(delay(ms)))
|
||||
)
|
||||
.subscribe(ingest(log));
|
||||
};
|
||||
|
||||
function rootDirAndOrigPath(obj) {
|
||||
return {
|
||||
...obj,
|
||||
originalFilePath: obj.staticSiteUrl,
|
||||
COVERAGE_INGESTION_KIBANA_ROOT,
|
||||
};
|
||||
}
|
||||
|
||||
const mutateVcsInfo = vcsInfo => x => vcsInfo.push(x.trimStart().trimEnd());
|
||||
const vcsInfoLines$ = vcsInfoFilePath => {
|
||||
const rl = readline.createInterface({ input: createReadStream(vcsInfoFilePath) });
|
||||
return fromEvent(rl, 'line').pipe(takeUntil(fromEvent(rl, 'close')));
|
||||
};
|
||||
|
||||
export const prok = ({ jsonSummaryPath, vcsInfoFilePath }, log) => {
|
||||
validateRoot(COVERAGE_INGESTION_KIBANA_ROOT, log);
|
||||
logAll(jsonSummaryPath, log);
|
||||
|
||||
const xformWithPath = transform(jsonSummaryPath)(log); // On complete
|
||||
|
||||
const vcsInfo = [];
|
||||
vcsInfoLines$(vcsInfoFilePath).subscribe(
|
||||
mutateVcsInfo(vcsInfo),
|
||||
err => log.error(err),
|
||||
always(xformWithPath(vcsInfo))
|
||||
);
|
||||
};
|
||||
|
||||
function logAll(jsonSummaryPath, log) {
|
||||
log.debug(`### Code coverage ingestion set to delay for: ${green(ms)} ms`);
|
||||
log.debug(`### COVERAGE_INGESTION_KIBANA_ROOT: \n\t${green(COVERAGE_INGESTION_KIBANA_ROOT)}`);
|
||||
log.debug(`### Ingesting from summary json: \n\t[${green(jsonSummaryPath)}]`);
|
||||
}
|
||||
|
||||
function validateRoot(x, log) {
|
||||
return /kibana$/.test(x) ? noop() : log.warning(`✖✖✖ 'kibana' NOT FOUND in ROOT: ${x}\n`);
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
String path = doc['coveredFilePath.keyword'].value;
|
||||
if (path.contains('/apm')) return "APM";
|
||||
else if (path.contains('/canvas')) return "Canvas";
|
||||
else if (path.contains('/maps')) return "Maps";
|
||||
else if (path.contains('map_')) return "Maps";
|
||||
else if (path.contains('/ml')) return "ML";
|
||||
else if (path.contains('/transform')) return "ML";
|
||||
else if (path.contains('/infra')) return "Infra";
|
||||
else if (path.contains('/siem')) return "SIEM";
|
||||
else if (path.contains('/endpoint')) return "Endpoint";
|
||||
else if (path.contains('logstash')) return "Logstash";
|
||||
else if (path.contains('beat')) return "Beats";
|
||||
else if (path.contains('uptime')) return "Observability";
|
||||
else if (path.contains('observability')) return "Observability";
|
||||
else if (path.contains('tutorials')) return "Observability";
|
||||
else if (path.contains('/code')) return "Code";
|
||||
else if (path.contains('/cross_cluster_replication')) return "Elasticsearch UI";
|
||||
else if (path.contains('/index_lifecycle_management')) return "Elasticsearch UI";
|
||||
else if (path.contains('/index_management')) return "Elasticsearch UI";
|
||||
else if (path.contains('/license_management')) return "Elasticsearch UI";
|
||||
else if (path.contains('/management')) return "Elasticsearch UI";
|
||||
else if (path.contains('/licensing')) return "Elasticsearch UI";
|
||||
else if (path.contains('/public/management'))return "Elasticsearch UI";
|
||||
else if (path.contains('/remote_clusters')) return "Elasticsearch UI";
|
||||
else if (path.contains('/searchprofiler')) return "Elasticsearch UI";
|
||||
else if (path.contains('/searchprofiler')) return "Elasticsearch UI";
|
||||
else if (path.contains('/snapshot_restore')) return "Elasticsearch UI";
|
||||
else if (path.contains('/rollup')) return "Elasticsearch UI";
|
||||
else if (path.contains('/watcher')) return "Elasticsearch UI";
|
||||
else if (path.contains('/watcher')) return "Elasticsearch UI";
|
||||
else if (path.contains('/file_upload')) return "Elasticsearch UI";
|
||||
else if (path.contains('grokdebugger')) return "Elasticsearch UI";
|
||||
else if (path.contains('es_ui_shared')) return "Elasticsearch UI";
|
||||
else if (path.contains('kibana/x-pack/legacy/server/lib')) return "Elasticsearch UI";
|
||||
else if (path.contains('/public/field_editor')) return "Kibana App";
|
||||
else if (path.contains('dashboard')) return "Kibana App";
|
||||
else if (path.contains('discover')) return "Kibana App";
|
||||
else if (path.contains('graph')) return "Kibana App";
|
||||
else if (path.contains('timelion')) return "Kibana App";
|
||||
else if (path.contains('/lens/')) return "Kibana App";
|
||||
else if (path.contains('/core_plugins')) return "Kibana App";
|
||||
else if (path.contains('/vislib')) return "Kibana App";
|
||||
else if (path.contains('/visualize')) return "Kibana App";
|
||||
else if (path.contains('/public/vis/')) return "Kibana App";
|
||||
else if (path.contains('/kbn-es')) return "Kibana App";
|
||||
else if (path.contains('kuery')) return "Kibana App";
|
||||
else if (path.contains('url_shortening')) return "Kibana App";
|
||||
else if (path.contains('sample_data')) return "Kibana App";
|
||||
else if (path.contains('/home')) return "Kibana App";
|
||||
else if (path.contains('/accessibility')) return "Kibana App";
|
||||
else if (path.contains('/timeseries')) return "Kibana App";
|
||||
else if (path.contains('/point_series')) return "Kibana App";
|
||||
else if (path.contains('security')) return "Kibana Security";
|
||||
else if (path.contains('privilege')) return "Kibana Security";
|
||||
else if (path.contains('/spaces')) return "Kibana Security";
|
||||
else if (path.contains('monitoring')) return "Stack Monitoring";
|
||||
else if (path.contains('/es_archiver')) return "Kibana Operations";
|
||||
else if (path.contains('/dev/build')) return "Kibana Operations";
|
||||
else if (path.contains('/kbn-test')) return "Kibana Operations";
|
||||
else if (path.contains('upgrade')) return "Kibana Operations";
|
||||
else if (path.contains('/kbn-dev-utils')) return "Kibana Operations";
|
||||
else if (path.contains('optimize')) return "Kibana Operations";
|
||||
else if (path.contains('test_utils')) return "Kibana Operations";
|
||||
else if (path.contains('kbn-babel-preset')) return "Kibana Operations";
|
||||
else if (path.contains('kibana/server/routes')) return "Kibana Operations";
|
||||
else if (path.contains('kibana/src/legacy/server/')) return "Kibana Operations";
|
||||
else if (path.contains('kibana/scripts/')) return "Kibana Operations";
|
||||
else if (path.contains('kibana/packages/')) return "Kibana Operations";
|
||||
else if (path.contains('kibana/src/setup_node_env')) return "Kibana Operations";
|
||||
else if (path.contains('/kbn-ui-framework')) return "Kibana Design";
|
||||
else if (path.contains('/ui/ui')) return "Kibana Design";
|
||||
else if (path.contains('/eui')) return "Kibana Design";
|
||||
else if (path.contains('/kbn-es-query')) return "Kibana App Arch";
|
||||
else if (path.contains('/kbn-ui-framework')) return "Kibana App Arch";
|
||||
else if (path.contains('/kbn-interpreter')) return "Kibana App Arch";
|
||||
else if (path.contains('courier')) return "Kibana App Arch";
|
||||
else if (path.contains('kbn-config-schema')) return "Kibana Platform";
|
||||
else if (path.contains('kibana/src/legacy/utils')) return "Kibana Platform";
|
||||
else if (path.contains('saved_objects')) return "Kibana Platform";
|
||||
else if (path.contains('/reporting')) return "Kibana Stack Services";
|
||||
else if (path.contains('telemetry')) return "Kibana Stack Services";
|
||||
else if (path.contains('/kbn-i18n')) return "Kibana Stack Services";
|
||||
else if (path.contains('/kbn-analytics')) return "Kibana Stack Services";
|
||||
else if (path.contains('/task_manager')) return "Kibana Stack Services";
|
||||
else if (path.contains('alert')) return "Kibana Stack Services";
|
||||
else if (path.contains('actions')) return "Kibana Stack Services";
|
||||
else return "unknown";
|
148
src/dev/code_coverage/ingest_coverage/transforms.js
Normal file
148
src/dev/code_coverage/ingest_coverage/transforms.js
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { left, right, fromNullable } from './either';
|
||||
import { always, id, noop } from './utils';
|
||||
|
||||
const maybeTotal = x => (x === 'total' ? left(x) : right(x));
|
||||
|
||||
const trimLeftFrom = (text, x) => x.substr(x.indexOf(text));
|
||||
|
||||
export const statsAndstaticSiteUrl = (...xs) => {
|
||||
const [staticSiteUrl] = xs[0][1];
|
||||
const [stats] = xs[0];
|
||||
return {
|
||||
staticSiteUrl,
|
||||
...stats,
|
||||
};
|
||||
};
|
||||
|
||||
export const addJsonSummaryPath = jsonSummaryPath => obj => ({
|
||||
jsonSummaryPath: trimLeftFrom('target', jsonSummaryPath),
|
||||
...obj,
|
||||
});
|
||||
|
||||
export const truncate = text => obj => {
|
||||
const { staticSiteUrl } = obj;
|
||||
if (staticSiteUrl.includes(text)) obj.staticSiteUrl = trimLeftFrom(text, staticSiteUrl);
|
||||
return obj;
|
||||
};
|
||||
|
||||
export const addTimeStamp = ts => obj => ({
|
||||
...obj,
|
||||
'@timestamp': ts,
|
||||
});
|
||||
|
||||
const setTotal = x => obj => (obj.isTotal = x);
|
||||
const mutateTrue = setTotal(true);
|
||||
const mutateFalse = setTotal(false);
|
||||
|
||||
const root = urlBase => ts => testRunnerType =>
|
||||
`${urlBase}/${ts}/${testRunnerType.toLowerCase()}-combined`;
|
||||
|
||||
const prokForTotalsIndex = mutateTrue => urlRoot => obj =>
|
||||
right(obj)
|
||||
.map(mutateTrue)
|
||||
.map(always(`${urlRoot}/index.html`))
|
||||
.fold(noop, id);
|
||||
|
||||
const prokForCoverageIndex = root => mutateFalse => urlRoot => obj => siteUrl =>
|
||||
right(siteUrl)
|
||||
.map(x => {
|
||||
mutateFalse(obj);
|
||||
return x;
|
||||
})
|
||||
.map(x => x.replace(root, ''))
|
||||
.map(x => `${urlRoot}${x}.html`)
|
||||
.fold(noop, id);
|
||||
|
||||
export const staticSite = urlBase => obj => {
|
||||
const { staticSiteUrl, testRunnerType, COVERAGE_INGESTION_KIBANA_ROOT } = obj;
|
||||
const ts = obj['@timestamp'];
|
||||
const urlRoot = root(urlBase)(ts)(testRunnerType);
|
||||
const prokTotal = prokForTotalsIndex(mutateTrue)(urlRoot);
|
||||
const prokCoverage = prokForCoverageIndex(COVERAGE_INGESTION_KIBANA_ROOT)(mutateFalse)(urlRoot)(
|
||||
obj
|
||||
);
|
||||
const prokForBoth = always(maybeTotal(staticSiteUrl).fold(always(prokTotal(obj)), prokCoverage));
|
||||
|
||||
return { ...obj, staticSiteUrl: prokForBoth() };
|
||||
};
|
||||
|
||||
export const coveredFilePath = obj => {
|
||||
const { staticSiteUrl, COVERAGE_INGESTION_KIBANA_ROOT } = obj;
|
||||
|
||||
const withoutCoveredFilePath = always(obj);
|
||||
const leadingSlashRe = /^\//;
|
||||
const maybeDropLeadingSlash = x => (leadingSlashRe.test(x) ? right(x) : left(x));
|
||||
const dropLeadingSlash = x => x.replace(leadingSlashRe, '');
|
||||
const dropRoot = root => x =>
|
||||
maybeDropLeadingSlash(x.replace(root, '')).fold(id, dropLeadingSlash);
|
||||
return maybeTotal(staticSiteUrl)
|
||||
.map(dropRoot(COVERAGE_INGESTION_KIBANA_ROOT))
|
||||
.fold(withoutCoveredFilePath, coveredFilePath => ({ ...obj, coveredFilePath }));
|
||||
};
|
||||
|
||||
export const ciRunUrl = obj =>
|
||||
fromNullable(process.env.CI_RUN_URL).fold(always(obj), ciRunUrl => ({ ...obj, ciRunUrl }));
|
||||
|
||||
const size = 50;
|
||||
const truncateCommitMsg = x => (x.length > size ? `${x.slice(0, 50)}...` : x);
|
||||
|
||||
export const itemizeVcs = vcsInfo => obj => {
|
||||
const [branch, sha, author, commitMsg] = vcsInfo;
|
||||
return {
|
||||
...obj,
|
||||
vcs: {
|
||||
branch,
|
||||
sha,
|
||||
author,
|
||||
commitMsg: truncateCommitMsg(commitMsg),
|
||||
vcsUrl: `https://github.com/elastic/kibana/commit/${sha}`,
|
||||
},
|
||||
};
|
||||
};
|
||||
export const testRunner = obj => {
|
||||
const { jsonSummaryPath } = obj;
|
||||
|
||||
let testRunnerType = 'other';
|
||||
|
||||
const upperTestRunnerType = x => {
|
||||
if (jsonSummaryPath.includes(x)) {
|
||||
testRunnerType = x.toUpperCase();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
['mocha', 'jest', 'functional'].forEach(upperTestRunnerType);
|
||||
|
||||
return {
|
||||
testRunnerType,
|
||||
...obj,
|
||||
};
|
||||
};
|
||||
|
||||
export const buildId = obj => {
|
||||
const { env } = process;
|
||||
if (env.BUILD_ID) obj.BUILD_ID = env.BUILD_ID;
|
||||
|
||||
return {
|
||||
...obj,
|
||||
};
|
||||
};
|
27
src/dev/code_coverage/ingest_coverage/utils.js
Normal file
27
src/dev/code_coverage/ingest_coverage/utils.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import chalk from 'chalk';
|
||||
|
||||
export const pipe = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)));
|
||||
export const noop = () => {};
|
||||
export const green = x => chalk.greenBright.bold(x);
|
||||
export const id = x => x;
|
||||
export const always = x => () => x;
|
||||
export const pretty = x => JSON.stringify(x, null, 2);
|
10
src/dev/code_coverage/shell_scripts/copy_mocha_reports.sh
Normal file
10
src/dev/code_coverage/shell_scripts/copy_mocha_reports.sh
Normal file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
EXTRACT_START_DIR=tmp/extracted_coverage
|
||||
EXTRACT_END_DIR=target/kibana-coverage
|
||||
COMBINED_EXRACT_DIR=/${EXTRACT_START_DIR}/${EXTRACT_END_DIR}
|
||||
|
||||
|
||||
echo "### Copy mocha reports"
|
||||
mkdir -p $EXTRACT_END_DIR/mocha-combined
|
||||
cp -r $COMBINED_EXRACT_DIR/mocha/. $EXTRACT_END_DIR/mocha-combined/
|
12
src/dev/code_coverage/shell_scripts/extract_archives.sh
Normal file
12
src/dev/code_coverage/shell_scripts/extract_archives.sh
Normal file
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
DOWNLOAD_DIR=/tmp/downloaded_coverage
|
||||
EXTRACT_DIR=/tmp/extracted_coverage
|
||||
|
||||
mkdir -p $EXTRACT_DIR
|
||||
|
||||
echo "### Extracting downloaded artifacts"
|
||||
for x in kibana-intake x-pack-intake kibana-oss-tests kibana-xpack-tests; do
|
||||
tar -xzf $DOWNLOAD_DIR/coverage/${x}/kibana-coverage.tar.gz -C $EXTRACT_DIR || echo "### Error 'tarring': ${x}"
|
||||
done
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
DOWNLOAD_DIR=/tmp/downloaded_coverage
|
||||
EXTRACT_DIR=/tmp/extracted_coverage
|
||||
|
||||
echo "### Extracting kibana-xpack-tests"
|
||||
tar -xzf $DOWNLOAD_DIR/coverage/kibana-xpack-tests/kibana-coverage.tar.gz -C $EXTRACT_DIR
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
EXTRACT_START_DIR=tmp/extracted_coverage
|
||||
EXTRACT_END_DIR=target/kibana-coverage
|
||||
COMBINED_EXRACT_DIR=/${EXTRACT_START_DIR}/${EXTRACT_END_DIR}
|
||||
|
||||
PWD=$(pwd)
|
||||
du -sh $COMBINED_EXRACT_DIR
|
||||
|
||||
echo "### Replacing path in json files"
|
||||
for i in {1..9}; do
|
||||
sed -i "s|/dev/shm/workspace/kibana|${PWD}|g" $COMBINED_EXRACT_DIR/functional/${i}*.json &
|
||||
done
|
||||
wait
|
29
src/dev/code_coverage/shell_scripts/ingest_coverage.sh
Normal file
29
src/dev/code_coverage/shell_scripts/ingest_coverage.sh
Normal file
|
@ -0,0 +1,29 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "### Ingesting Code Coverage"
|
||||
echo ""
|
||||
|
||||
|
||||
BUILD_ID=$1
|
||||
export BUILD_ID
|
||||
|
||||
CI_RUN_URL=$2
|
||||
export CI_RUN_URL
|
||||
echo "### debug CI_RUN_URL: ${CI_RUN_URL}"
|
||||
|
||||
ES_HOST="https://${USER_FROM_VAULT}:${PASS_FROM_VAULT}@${HOST_FROM_VAULT}"
|
||||
export ES_HOST
|
||||
|
||||
STATIC_SITE_URL_BASE='https://kibana-coverage.elastic.dev'
|
||||
export STATIC_SITE_URL_BASE
|
||||
|
||||
for x in jest functional mocha; do
|
||||
echo "### Ingesting coverage for ${x}"
|
||||
|
||||
COVERAGE_SUMMARY_FILE=target/kibana-coverage/${x}-combined/coverage-summary.json
|
||||
|
||||
node scripts/ingest_coverage.js --verbose --path ${COVERAGE_SUMMARY_FILE} --vcsInfoPath ./VCS_INFO.txt
|
||||
done
|
||||
|
||||
echo "### Ingesting Code Coverage - Complete"
|
||||
echo ""
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
EXTRACT_START_DIR=tmp/extracted_coverage
|
||||
EXTRACT_END_DIR=target/kibana-coverage
|
||||
COMBINED_EXTRACT_DIR=/${EXTRACT_START_DIR}/${EXTRACT_END_DIR}
|
||||
|
||||
echo "### Merge coverage reports"
|
||||
for x in jest functional; do
|
||||
yarn nyc report --temp-dir $COMBINED_EXTRACT_DIR/${x} --report-dir $EXTRACT_END_DIR/${x}-combined --reporter=html --reporter=json-summary
|
||||
done
|
16
src/dev/code_coverage/www/404.html
Normal file
16
src/dev/code_coverage/www/404.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Static Code Coverage"
|
||||
/>
|
||||
<title>Not Found</title>
|
||||
</head>
|
||||
<body>
|
||||
Requested Resource NOT FOUND
|
||||
</body>
|
||||
</html>
|
23
src/dev/code_coverage/www/index_partial.html
Normal file
23
src/dev/code_coverage/www/index_partial.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>KBN - Code Coverage</title>
|
||||
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
|
||||
|
||||
|
||||
|
||||
<style>
|
||||
</style>
|
||||
</head>
|
||||
<body class="text-center">
|
||||
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
|
||||
<header class="masthead mb-auto">
|
||||
<div class="inner">
|
||||
<h3 class="masthead-brand">Kibana Code Coverage</h3>
|
||||
<nav class="nav nav-masthead justify-content-center">
|
||||
<a class="nav-link active" href="https://kibana-stats.elastic.dev/">Home</a>
|
||||
<a class="nav-link" href="https://kibana-stats.elastic.dev/app/kibana#/discover/fd694ed0-62f8-11ea-8312-7f2d69b79843?_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-7d%2Cto%3Anow))">Discover</a>
|
0
src/dev/code_coverage/www/index_partial_2.html
Normal file
0
src/dev/code_coverage/www/index_partial_2.html
Normal file
|
@ -37,6 +37,7 @@ export default {
|
|||
'<rootDir>/packages',
|
||||
'<rootDir>/src/test_utils',
|
||||
'<rootDir>/test/functional/services/remote',
|
||||
'<rootDir>/src/dev/code_coverage/ingest_coverage',
|
||||
],
|
||||
collectCoverageFrom: [
|
||||
'src/plugins/**/*.{ts,tsx}',
|
||||
|
|
|
@ -42,6 +42,7 @@ export const IGNORE_FILE_GLOBS = [
|
|||
'**/{webpackShims,__mocks__}/**/*',
|
||||
'x-pack/docs/**/*',
|
||||
'src/core/server/core_app/assets/fonts/**/*',
|
||||
'src/dev/code_coverage/ingest_coverage/integration_tests/mocks/**/*',
|
||||
'packages/kbn-utility-types/test-d/**/*',
|
||||
'**/Jenkinsfile*',
|
||||
'Dockerfile*',
|
||||
|
|
|
@ -31,4 +31,4 @@ else
|
|||
mkdir -p ../kibana/target/kibana-coverage/functional
|
||||
mv target/kibana-coverage/functional/* ../kibana/target/kibana-coverage/functional/
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
|
189
vars/kibanaCoverage.groovy
Normal file
189
vars/kibanaCoverage.groovy
Normal file
|
@ -0,0 +1,189 @@
|
|||
def uploadCoverageStaticSite(timestamp) {
|
||||
def uploadPrefix = "gs://elastic-bekitzur-kibana-coverage-live/"
|
||||
def uploadPrefixWithTimeStamp = "${uploadPrefix}${timestamp}/"
|
||||
|
||||
uploadBaseWebsiteFiles(uploadPrefix)
|
||||
uploadCoverageHtmls(uploadPrefixWithTimeStamp)
|
||||
}
|
||||
|
||||
def uploadBaseWebsiteFiles(prefix) {
|
||||
[
|
||||
'src/dev/code_coverage/www/index.html',
|
||||
'src/dev/code_coverage/www/404.html'
|
||||
].each { uploadWithVault(prefix, it) }
|
||||
}
|
||||
|
||||
def uploadCoverageHtmls(prefix) {
|
||||
[
|
||||
'target/kibana-coverage/functional-combined',
|
||||
'target/kibana-coverage/jest-combined',
|
||||
'target/kibana-coverage/mocha-combined',
|
||||
].each { uploadWithVault(prefix, it) }
|
||||
}
|
||||
|
||||
def uploadWithVault(prefix, path) {
|
||||
def vaultSecret = 'secret/gce/elastic-bekitzur/service-account/kibana'
|
||||
|
||||
withGcpServiceAccount.fromVaultSecret(vaultSecret, 'value') {
|
||||
kibanaPipeline.bash("""
|
||||
gsutil -m cp -r -a public-read -z js,css,html ${path} '${prefix}'
|
||||
""", "### Upload files to GCS with vault, path: ${path}")
|
||||
}
|
||||
}
|
||||
|
||||
def prokLinks(title) {
|
||||
kibanaPipeline.bash('''
|
||||
cat << EOF > src/dev/code_coverage/www/index_partial_2.html
|
||||
<a class="nav-link" href="https://kibana-coverage.elastic.dev/${TIME_STAMP}/jest-combined/index.html">Latest Jest</a>
|
||||
<a class="nav-link" href="https://kibana-coverage.elastic.dev/${TIME_STAMP}/mocha-combined/index.html">Latest Mocha</a>
|
||||
<a class="nav-link" href="https://kibana-coverage.elastic.dev/${TIME_STAMP}/functional-combined/index.html">Latest FTR</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main role="main" class="inner cover">
|
||||
<!-- <h1 class="cover-heading"> - Master Branch</h1>-->
|
||||
<p class="lead">Use Kibana Stats to mine coverage data</p>
|
||||
<p class="lead">
|
||||
<a href="https://kibana-stats.elastic.dev/app/kibana#/dashboard/58b8db70-62f9-11ea-8312-7f2d69b79843?_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-7d%2Cto%3Anow))" class="btn btn-lg btn-primary">Dashboard</a>
|
||||
</p>
|
||||
</main>
|
||||
|
||||
<footer class="mastfoot mt-auto">
|
||||
<div class="inner">
|
||||
<p>Please slack us at <a href="https://app.slack.com/client/T0CUZ52US/C0TR0FAET">#kibana-qa</a> if you've questions</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
''', title)
|
||||
kibanaPipeline.bash('''
|
||||
cat src/dev/code_coverage/www/index_partial.html > src/dev/code_coverage/www/index.html
|
||||
cat src/dev/code_coverage/www/index_partial_2.html >> src/dev/code_coverage/www/index.html
|
||||
|
||||
echo "### Prok'd Index File: ..."
|
||||
cat src/dev/code_coverage/www/index.html
|
||||
''', "### Combine Index Partials")
|
||||
}
|
||||
def collectVcsInfo(title) {
|
||||
kibanaPipeline.bash('''
|
||||
predicate() {
|
||||
x=$1
|
||||
if [ -n "$x" ]; then
|
||||
return
|
||||
else
|
||||
echo "### 1 or more variables that Code Coverage needs, are undefined"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
CMD="git log --pretty=format"
|
||||
XS=("${GIT_BRANCH}" \
|
||||
"$(${CMD}":%h" -1)" \
|
||||
"$(${CMD}":%an" -1)" \
|
||||
"$(${CMD}":%s" -1)")
|
||||
touch VCS_INFO.txt
|
||||
for X in "${!XS[@]}"; do
|
||||
{
|
||||
predicate "${XS[X]}"
|
||||
echo "${XS[X]}" >> VCS_INFO.txt
|
||||
}
|
||||
done
|
||||
echo "### VCS_INFO:"
|
||||
cat VCS_INFO.txt
|
||||
''', title
|
||||
)
|
||||
}
|
||||
|
||||
def bootMergeAndIngest(buildNum, buildUrl, title) {
|
||||
kibanaPipeline.bash("""
|
||||
source src/dev/ci_setup/setup_env.sh
|
||||
# bootstrap from x-pack folder
|
||||
cd x-pack
|
||||
yarn kbn bootstrap --prefer-offline
|
||||
# Return to project root
|
||||
cd ..
|
||||
. src/dev/code_coverage/shell_scripts/extract_archives.sh
|
||||
. src/dev/code_coverage/shell_scripts/fix_html_reports_parallel.sh
|
||||
. src/dev/code_coverage/shell_scripts/merge_jest_and_functional.sh
|
||||
. src/dev/code_coverage/shell_scripts/copy_mocha_reports.sh
|
||||
. src/dev/code_coverage/shell_scripts/ingest_coverage.sh ${buildNum} ${buildUrl}
|
||||
""", title)
|
||||
}
|
||||
|
||||
def ingestWithVault(buildNum, buildUrl, title) {
|
||||
def vaultSecret = 'secret/kibana-issues/prod/coverage/elasticsearch'
|
||||
withVaultSecret(secret: vaultSecret, secret_field: 'host', variable_name: 'HOST_FROM_VAULT') {
|
||||
withVaultSecret(secret: vaultSecret, secret_field: 'username', variable_name: 'USER_FROM_VAULT') {
|
||||
withVaultSecret(secret: vaultSecret, secret_field: 'password', variable_name: 'PASS_FROM_VAULT') {
|
||||
bootMergeAndIngest(buildNum, buildUrl, title)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def ingest(timestamp, title) {
|
||||
withEnv([
|
||||
"TIME_STAMP=${timestamp}",
|
||||
]) {
|
||||
ingestWithVault(BUILD_NUMBER, BUILD_URL, title)
|
||||
}
|
||||
}
|
||||
|
||||
def runTests() {
|
||||
parallel([
|
||||
'kibana-intake-agent': workers.intake('kibana-intake', './test/scripts/jenkins_unit.sh'),
|
||||
'x-pack-intake-agent': {
|
||||
withEnv([
|
||||
'NODE_ENV=test' // Needed for jest tests only
|
||||
]) {
|
||||
workers.intake('x-pack-intake', './test/scripts/jenkins_xpack.sh')()
|
||||
}
|
||||
},
|
||||
'kibana-oss-agent' : workers.functional(
|
||||
'kibana-oss-tests',
|
||||
{ kibanaPipeline.buildOss() },
|
||||
ossProks()
|
||||
),
|
||||
'kibana-xpack-agent' : workers.functional(
|
||||
'kibana-xpack-tests',
|
||||
{ kibanaPipeline.buildXpack() },
|
||||
xpackProks()
|
||||
),
|
||||
])
|
||||
}
|
||||
|
||||
def ossProks() {
|
||||
return [
|
||||
'oss-ciGroup1' : kibanaPipeline.ossCiGroupProcess(1),
|
||||
'oss-ciGroup2' : kibanaPipeline.ossCiGroupProcess(2),
|
||||
'oss-ciGroup3' : kibanaPipeline.ossCiGroupProcess(3),
|
||||
'oss-ciGroup4' : kibanaPipeline.ossCiGroupProcess(4),
|
||||
'oss-ciGroup5' : kibanaPipeline.ossCiGroupProcess(5),
|
||||
'oss-ciGroup6' : kibanaPipeline.ossCiGroupProcess(6),
|
||||
'oss-ciGroup7' : kibanaPipeline.ossCiGroupProcess(7),
|
||||
'oss-ciGroup8' : kibanaPipeline.ossCiGroupProcess(8),
|
||||
'oss-ciGroup9' : kibanaPipeline.ossCiGroupProcess(9),
|
||||
'oss-ciGroup10': kibanaPipeline.ossCiGroupProcess(10),
|
||||
'oss-ciGroup11': kibanaPipeline.ossCiGroupProcess(11),
|
||||
'oss-ciGroup12': kibanaPipeline.ossCiGroupProcess(12),
|
||||
]
|
||||
}
|
||||
|
||||
def xpackProks() {
|
||||
return [
|
||||
'xpack-ciGroup1' : kibanaPipeline.xpackCiGroupProcess(1),
|
||||
'xpack-ciGroup2' : kibanaPipeline.xpackCiGroupProcess(2),
|
||||
'xpack-ciGroup3' : kibanaPipeline.xpackCiGroupProcess(3),
|
||||
'xpack-ciGroup4' : kibanaPipeline.xpackCiGroupProcess(4),
|
||||
'xpack-ciGroup5' : kibanaPipeline.xpackCiGroupProcess(5),
|
||||
'xpack-ciGroup6' : kibanaPipeline.xpackCiGroupProcess(6),
|
||||
'xpack-ciGroup7' : kibanaPipeline.xpackCiGroupProcess(7),
|
||||
'xpack-ciGroup8' : kibanaPipeline.xpackCiGroupProcess(8),
|
||||
'xpack-ciGroup9' : kibanaPipeline.xpackCiGroupProcess(9),
|
||||
'xpack-ciGroup10': kibanaPipeline.xpackCiGroupProcess(10),
|
||||
]
|
||||
}
|
||||
|
||||
return this
|
Loading…
Add table
Add a link
Reference in a new issue