mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
* Remove the no longer used release-notes script * Commit missing file Co-authored-by: Tim Roes <tim.roes@elastic.co>
This commit is contained in:
parent
654548f6ad
commit
59efc977b7
25 changed files with 10 additions and 1508 deletions
|
@ -1,5 +1,4 @@
|
||||||
**/*.js.snap
|
**/*.js.snap
|
||||||
**/graphql/types.ts
|
|
||||||
/.es
|
/.es
|
||||||
/.chromium
|
/.chromium
|
||||||
/build
|
/build
|
||||||
|
|
24
package.json
24
package.json
|
@ -74,7 +74,6 @@
|
||||||
"**/deepmerge": "^4.2.2",
|
"**/deepmerge": "^4.2.2",
|
||||||
"**/fast-deep-equal": "^3.1.1",
|
"**/fast-deep-equal": "^3.1.1",
|
||||||
"globby/fast-glob": "3.2.5",
|
"globby/fast-glob": "3.2.5",
|
||||||
"**/graphql-toolkit/lodash": "^4.17.21",
|
|
||||||
"**/hoist-non-react-statics": "^3.3.2",
|
"**/hoist-non-react-statics": "^3.3.2",
|
||||||
"**/isomorphic-fetch/node-fetch": "^2.6.1",
|
"**/isomorphic-fetch/node-fetch": "^2.6.1",
|
||||||
"**/istanbul-instrumenter-loader/schema-utils": "1.0.0",
|
"**/istanbul-instrumenter-loader/schema-utils": "1.0.0",
|
||||||
|
@ -190,10 +189,10 @@
|
||||||
"compare-versions": "3.5.1",
|
"compare-versions": "3.5.1",
|
||||||
"concat-stream": "1.6.2",
|
"concat-stream": "1.6.2",
|
||||||
"constate": "^1.3.2",
|
"constate": "^1.3.2",
|
||||||
"cronstrue": "^1.51.0",
|
|
||||||
"content-disposition": "0.5.3",
|
"content-disposition": "0.5.3",
|
||||||
"copy-to-clipboard": "^3.0.8",
|
"copy-to-clipboard": "^3.0.8",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
|
"cronstrue": "^1.51.0",
|
||||||
"cytoscape": "^3.10.0",
|
"cytoscape": "^3.10.0",
|
||||||
"cytoscape-dagre": "^2.2.2",
|
"cytoscape-dagre": "^2.2.2",
|
||||||
"d3": "3.5.17",
|
"d3": "3.5.17",
|
||||||
|
@ -228,8 +227,6 @@
|
||||||
"glob": "^7.1.2",
|
"glob": "^7.1.2",
|
||||||
"glob-all": "^3.2.1",
|
"glob-all": "^3.2.1",
|
||||||
"globby": "^11.0.3",
|
"globby": "^11.0.3",
|
||||||
"graphql": "^0.13.2",
|
|
||||||
"graphql-tag": "^2.10.3",
|
|
||||||
"handlebars": "4.7.7",
|
"handlebars": "4.7.7",
|
||||||
"he": "^1.2.0",
|
"he": "^1.2.0",
|
||||||
"history": "^4.9.0",
|
"history": "^4.9.0",
|
||||||
|
@ -271,9 +268,9 @@
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lru-cache": "^4.1.5",
|
"lru-cache": "^4.1.5",
|
||||||
"lz-string": "^1.4.4",
|
"lz-string": "^1.4.4",
|
||||||
"markdown-it": "^10.0.0",
|
|
||||||
"mapbox-gl": "1.13.1",
|
"mapbox-gl": "1.13.1",
|
||||||
"mapbox-gl-draw-rectangle-mode": "^1.0.4",
|
"mapbox-gl-draw-rectangle-mode": "^1.0.4",
|
||||||
|
"markdown-it": "^10.0.0",
|
||||||
"md5": "^2.1.0",
|
"md5": "^2.1.0",
|
||||||
"memoize-one": "^5.0.0",
|
"memoize-one": "^5.0.0",
|
||||||
"mime": "^2.4.4",
|
"mime": "^2.4.4",
|
||||||
|
@ -295,12 +292,12 @@
|
||||||
"object-path-immutable": "^3.1.1",
|
"object-path-immutable": "^3.1.1",
|
||||||
"opn": "^5.5.0",
|
"opn": "^5.5.0",
|
||||||
"oppsy": "^2.0.0",
|
"oppsy": "^2.0.0",
|
||||||
|
"p-limit": "^3.0.1",
|
||||||
"p-map": "^4.0.0",
|
"p-map": "^4.0.0",
|
||||||
"p-retry": "^4.2.0",
|
"p-retry": "^4.2.0",
|
||||||
"papaparse": "^5.2.0",
|
"papaparse": "^5.2.0",
|
||||||
"pdfmake": "^0.1.65",
|
"pdfmake": "^0.1.65",
|
||||||
"pegjs": "0.10.0",
|
"pegjs": "0.10.0",
|
||||||
"p-limit": "^3.0.1",
|
|
||||||
"pluralize": "3.1.0",
|
"pluralize": "3.1.0",
|
||||||
"pngjs": "^3.4.0",
|
"pngjs": "^3.4.0",
|
||||||
"polished": "^1.9.2",
|
"polished": "^1.9.2",
|
||||||
|
@ -332,19 +329,19 @@
|
||||||
"react-monaco-editor": "^0.41.2",
|
"react-monaco-editor": "^0.41.2",
|
||||||
"react-popper-tooltip": "^2.10.1",
|
"react-popper-tooltip": "^2.10.1",
|
||||||
"react-query": "^3.13.10",
|
"react-query": "^3.13.10",
|
||||||
|
"react-redux": "^7.2.0",
|
||||||
|
"react-resizable": "^1.7.5",
|
||||||
"react-resize-detector": "^4.2.0",
|
"react-resize-detector": "^4.2.0",
|
||||||
"react-reverse-portal": "^1.0.4",
|
"react-reverse-portal": "^1.0.4",
|
||||||
|
"react-router": "^5.2.0",
|
||||||
|
"react-router-dom": "^5.2.0",
|
||||||
"react-router-redux": "^4.0.8",
|
"react-router-redux": "^4.0.8",
|
||||||
"react-shortcuts": "^2.0.0",
|
"react-shortcuts": "^2.0.0",
|
||||||
"react-sizeme": "^2.3.6",
|
"react-sizeme": "^2.3.6",
|
||||||
"react-syntax-highlighter": "^15.3.1",
|
"react-syntax-highlighter": "^15.3.1",
|
||||||
"react-redux": "^7.2.0",
|
|
||||||
"react-resizable": "^1.7.5",
|
|
||||||
"react-router": "^5.2.0",
|
|
||||||
"react-router-dom": "^5.2.0",
|
|
||||||
"react-tiny-virtual-list": "^2.2.0",
|
"react-tiny-virtual-list": "^2.2.0",
|
||||||
"react-virtualized": "^9.21.2",
|
|
||||||
"react-use": "^15.3.8",
|
"react-use": "^15.3.8",
|
||||||
|
"react-virtualized": "^9.21.2",
|
||||||
"react-vis": "^1.8.1",
|
"react-vis": "^1.8.1",
|
||||||
"react-visibility-sensor": "^5.1.1",
|
"react-visibility-sensor": "^5.1.1",
|
||||||
"reactcss": "1.2.3",
|
"reactcss": "1.2.3",
|
||||||
|
@ -373,8 +370,8 @@
|
||||||
"strip-ansi": "^6.0.0",
|
"strip-ansi": "^6.0.0",
|
||||||
"style-it": "^2.1.3",
|
"style-it": "^2.1.3",
|
||||||
"styled-components": "^5.1.0",
|
"styled-components": "^5.1.0",
|
||||||
"symbol-observable": "^1.2.0",
|
|
||||||
"suricata-sid-db": "^1.0.2",
|
"suricata-sid-db": "^1.0.2",
|
||||||
|
"symbol-observable": "^1.2.0",
|
||||||
"tabbable": "1.1.3",
|
"tabbable": "1.1.3",
|
||||||
"tar": "4.4.13",
|
"tar": "4.4.13",
|
||||||
"tinycolor2": "1.4.1",
|
"tinycolor2": "1.4.1",
|
||||||
|
@ -518,7 +515,6 @@
|
||||||
"@types/getos": "^3.0.0",
|
"@types/getos": "^3.0.0",
|
||||||
"@types/git-url-parse": "^9.0.0",
|
"@types/git-url-parse": "^9.0.0",
|
||||||
"@types/glob": "^7.1.2",
|
"@types/glob": "^7.1.2",
|
||||||
"@types/graphql": "^0.13.2",
|
|
||||||
"@types/gulp": "^4.0.6",
|
"@types/gulp": "^4.0.6",
|
||||||
"@types/gulp-zip": "^4.0.1",
|
"@types/gulp-zip": "^4.0.1",
|
||||||
"@types/hapi__cookie": "^10.1.1",
|
"@types/hapi__cookie": "^10.1.1",
|
||||||
|
@ -732,8 +728,8 @@
|
||||||
"jest-circus": "^26.6.3",
|
"jest-circus": "^26.6.3",
|
||||||
"jest-cli": "^26.6.3",
|
"jest-cli": "^26.6.3",
|
||||||
"jest-diff": "^26.6.2",
|
"jest-diff": "^26.6.2",
|
||||||
"jest-environment-jsdom-thirteen": "^1.0.1",
|
|
||||||
"jest-environment-jsdom": "^26.6.2",
|
"jest-environment-jsdom": "^26.6.2",
|
||||||
|
"jest-environment-jsdom-thirteen": "^1.0.1",
|
||||||
"jest-raw-loader": "^1.0.1",
|
"jest-raw-loader": "^1.0.1",
|
||||||
"jest-silent-reporter": "^0.2.1",
|
"jest-silent-reporter": "^0.2.1",
|
||||||
"jest-snapshot": "^26.6.2",
|
"jest-snapshot": "^26.6.2",
|
||||||
|
|
|
@ -6,5 +6,4 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export * from './release_notes';
|
|
||||||
export * from './api_docs';
|
export * from './api_docs';
|
||||||
|
|
|
@ -1,152 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Fs from 'fs';
|
|
||||||
import Path from 'path';
|
|
||||||
import { inspect } from 'util';
|
|
||||||
|
|
||||||
import { REPO_ROOT } from '@kbn/utils';
|
|
||||||
import { run, createFlagError, createFailError } from '@kbn/dev-utils';
|
|
||||||
|
|
||||||
import { FORMATS, SomeFormat } from './formats';
|
|
||||||
import {
|
|
||||||
PrApi,
|
|
||||||
Version,
|
|
||||||
ClassifiedPr,
|
|
||||||
streamFromIterable,
|
|
||||||
asyncPipeline,
|
|
||||||
IrrelevantPrSummary,
|
|
||||||
isPrRelevant,
|
|
||||||
classifyPr,
|
|
||||||
} from './lib';
|
|
||||||
|
|
||||||
const rootPackageJson = JSON.parse(
|
|
||||||
Fs.readFileSync(Path.resolve(REPO_ROOT, 'package.json'), 'utf8')
|
|
||||||
);
|
|
||||||
const extensions = FORMATS.map((f) => f.extension);
|
|
||||||
|
|
||||||
export function runReleaseNotesCli() {
|
|
||||||
run(
|
|
||||||
async ({ flags, log }) => {
|
|
||||||
const token = flags.token;
|
|
||||||
if (!token || typeof token !== 'string') {
|
|
||||||
throw createFlagError('--token must be defined');
|
|
||||||
}
|
|
||||||
const prApi = new PrApi(log, token);
|
|
||||||
|
|
||||||
const version = Version.fromFlag(flags.version);
|
|
||||||
if (!version) {
|
|
||||||
throw createFlagError('unable to parse --version, use format "v{major}.{minor}.{patch}"');
|
|
||||||
}
|
|
||||||
|
|
||||||
const includeVersions = Version.fromFlags(flags.include || []);
|
|
||||||
if (!includeVersions) {
|
|
||||||
throw createFlagError('unable to parse --include, use format "v{major}.{minor}.{patch}"');
|
|
||||||
}
|
|
||||||
|
|
||||||
const Formats: SomeFormat[] = [];
|
|
||||||
for (const flag of Array.isArray(flags.format) ? flags.format : [flags.format]) {
|
|
||||||
const Format = FORMATS.find((F) => F.extension === flag);
|
|
||||||
if (!Format) {
|
|
||||||
throw createFlagError(`--format must be one of "${extensions.join('", "')}"`);
|
|
||||||
}
|
|
||||||
Formats.push(Format);
|
|
||||||
}
|
|
||||||
|
|
||||||
const filename = flags.filename;
|
|
||||||
if (!filename || typeof filename !== 'string') {
|
|
||||||
throw createFlagError('--filename must be a string');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags['debug-pr']) {
|
|
||||||
const number = parseInt(String(flags['debug-pr']), 10);
|
|
||||||
if (Number.isNaN(number)) {
|
|
||||||
throw createFlagError('--debug-pr must be a pr number when specified');
|
|
||||||
}
|
|
||||||
|
|
||||||
const summary = new IrrelevantPrSummary(log);
|
|
||||||
const pr = await prApi.getPr(number);
|
|
||||||
log.success(
|
|
||||||
inspect(
|
|
||||||
{
|
|
||||||
version: version.label,
|
|
||||||
includeVersions: includeVersions.map((v) => v.label),
|
|
||||||
isPrRelevant: isPrRelevant(pr, version, includeVersions, summary),
|
|
||||||
...classifyPr(pr, log),
|
|
||||||
pr,
|
|
||||||
},
|
|
||||||
{ depth: 100 }
|
|
||||||
)
|
|
||||||
);
|
|
||||||
summary.logStats();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info(`Loading all PRs with label [${version.label}] to build release notes...`);
|
|
||||||
|
|
||||||
const summary = new IrrelevantPrSummary(log);
|
|
||||||
const prsToReport: ClassifiedPr[] = [];
|
|
||||||
const prIterable = prApi.iterRelevantPullRequests(version);
|
|
||||||
for await (const pr of prIterable) {
|
|
||||||
if (!isPrRelevant(pr, version, includeVersions, summary)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
prsToReport.push(classifyPr(pr, log));
|
|
||||||
}
|
|
||||||
summary.logStats();
|
|
||||||
|
|
||||||
if (!prsToReport.length) {
|
|
||||||
throw createFailError(
|
|
||||||
`All PRs with label [${version.label}] were filtered out by the config. Run again with --debug for more info.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info(`Found ${prsToReport.length} prs to report on`);
|
|
||||||
|
|
||||||
for (const Format of Formats) {
|
|
||||||
const format = new Format(version, prsToReport, log);
|
|
||||||
const outputPath = Path.resolve(`${filename}.${Format.extension}`);
|
|
||||||
await asyncPipeline(streamFromIterable(format.print()), Fs.createWriteStream(outputPath));
|
|
||||||
log.success(`[${Format.extension}] report written to ${outputPath}`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
usage: `node scripts/release_notes --token {token} --version {version}`,
|
|
||||||
flags: {
|
|
||||||
alias: {
|
|
||||||
version: 'v',
|
|
||||||
include: 'i',
|
|
||||||
},
|
|
||||||
string: ['token', 'version', 'format', 'filename', 'include', 'debug-pr'],
|
|
||||||
default: {
|
|
||||||
filename: 'report',
|
|
||||||
version: rootPackageJson.version,
|
|
||||||
format: extensions,
|
|
||||||
},
|
|
||||||
help: `
|
|
||||||
--token (required) The Github access token to use for requests
|
|
||||||
--version, -v The version to fetch PRs by, PRs with version labels prior to
|
|
||||||
this one will be ignored (see --include-version) (default ${
|
|
||||||
rootPackageJson.version
|
|
||||||
})
|
|
||||||
--include, -i A version that is before --version but shouldn't be considered
|
|
||||||
"released" and cause PRs with a matching label to be excluded from
|
|
||||||
release notes. Use this when PRs are labeled with a version that
|
|
||||||
is less that --version and is expected to be released after
|
|
||||||
--version, can be specified multiple times.
|
|
||||||
--format Only produce a certain format, options: "${extensions.join('", "')}"
|
|
||||||
--filename Output filename, defaults to "report"
|
|
||||||
--debug-pr Fetch and print the details for a single PR, disabling reporting
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
description: `
|
|
||||||
Fetch details from Github PRs for generating release notes
|
|
||||||
`,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import dedent from 'dedent';
|
|
||||||
|
|
||||||
import { Format } from './format';
|
|
||||||
import {
|
|
||||||
ASCIIDOC_SECTIONS,
|
|
||||||
UNKNOWN_ASCIIDOC_SECTION,
|
|
||||||
AREAS,
|
|
||||||
UNKNOWN_AREA,
|
|
||||||
} from '../release_notes_config';
|
|
||||||
|
|
||||||
function* lines(body: string) {
|
|
||||||
for (const line of dedent(body).split('\n')) {
|
|
||||||
yield `${line}\n`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AsciidocFormat extends Format {
|
|
||||||
static extension = 'asciidoc';
|
|
||||||
|
|
||||||
*print() {
|
|
||||||
const sortedAreas = [
|
|
||||||
...AREAS.slice().sort((a, b) => a.title.localeCompare(b.title)),
|
|
||||||
UNKNOWN_AREA,
|
|
||||||
];
|
|
||||||
|
|
||||||
yield* lines(`
|
|
||||||
[[release-notes-${this.version.label}]]
|
|
||||||
== ${this.version.label} Release Notes
|
|
||||||
|
|
||||||
Also see <<breaking-changes-${this.version.major}.${this.version.minor}>>.
|
|
||||||
`);
|
|
||||||
|
|
||||||
for (const section of [...ASCIIDOC_SECTIONS, UNKNOWN_ASCIIDOC_SECTION]) {
|
|
||||||
const prsInSection = this.prs.filter((pr) => pr.asciidocSection === section);
|
|
||||||
if (!prsInSection.length) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield '\n';
|
|
||||||
yield* lines(`
|
|
||||||
[float]
|
|
||||||
[[${section.id}-${this.version.label}]]
|
|
||||||
=== ${section.title}
|
|
||||||
`);
|
|
||||||
|
|
||||||
for (const area of sortedAreas) {
|
|
||||||
const prsInArea = prsInSection.filter((pr) => pr.area === area);
|
|
||||||
|
|
||||||
if (!prsInArea.length) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield `${area.title}::\n`;
|
|
||||||
for (const pr of prsInArea) {
|
|
||||||
const fixes = pr.fixes.length ? `[Fixes ${pr.fixes.join(', ')}] ` : '';
|
|
||||||
const strippedTitle = pr.title.replace(/^\s*\[[^\]]+\]\s*/, '');
|
|
||||||
yield `* ${fixes}${strippedTitle} {kibana-pull}${pr.number}[#${pr.number}]\n`;
|
|
||||||
if (pr.note) {
|
|
||||||
yield ` - ${pr.note}\n`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Format } from './format';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Escape a value to conform to field and header encoding defined at https://tools.ietf.org/html/rfc4180
|
|
||||||
*/
|
|
||||||
function esc(value: string | number) {
|
|
||||||
if (typeof value === 'number') {
|
|
||||||
return String(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value.includes(',') && !value.includes('\n') && !value.includes('"')) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `"${value.split('"').join('""')}"`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function row(...fields: Array<string | number>) {
|
|
||||||
return fields.map(esc).join(',') + '\r\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CsvFormat extends Format {
|
|
||||||
static extension = 'csv';
|
|
||||||
|
|
||||||
*print() {
|
|
||||||
// columns
|
|
||||||
yield row(
|
|
||||||
'areas',
|
|
||||||
'versions',
|
|
||||||
'user',
|
|
||||||
'title',
|
|
||||||
'number',
|
|
||||||
'url',
|
|
||||||
'date',
|
|
||||||
'fixes',
|
|
||||||
'labels',
|
|
||||||
'state'
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const pr of this.prs) {
|
|
||||||
yield row(
|
|
||||||
pr.area.title,
|
|
||||||
pr.versions.map((v) => v.label).join(', '),
|
|
||||||
pr.user.name || pr.user.login,
|
|
||||||
pr.title,
|
|
||||||
pr.number,
|
|
||||||
pr.url,
|
|
||||||
pr.mergedAt,
|
|
||||||
pr.fixes.join(', '),
|
|
||||||
pr.labels.join(', '),
|
|
||||||
pr.state
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ToolingLog } from '@kbn/dev-utils';
|
|
||||||
|
|
||||||
import { Version, ClassifiedPr } from '../lib';
|
|
||||||
|
|
||||||
export abstract class Format {
|
|
||||||
static extension: string;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
protected readonly version: Version,
|
|
||||||
protected readonly prs: ClassifiedPr[],
|
|
||||||
protected readonly log: ToolingLog
|
|
||||||
) {}
|
|
||||||
|
|
||||||
abstract print(): Iterator<string>;
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ArrayItem } from '../lib';
|
|
||||||
import { AsciidocFormat } from './asciidoc';
|
|
||||||
import { CsvFormat } from './csv';
|
|
||||||
|
|
||||||
export const FORMATS = [CsvFormat, AsciidocFormat] as const;
|
|
||||||
export type SomeFormat = ArrayItem<typeof FORMATS>;
|
|
|
@ -1,9 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export * from './cli';
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ToolingLog } from '@kbn/dev-utils';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Area,
|
|
||||||
AREAS,
|
|
||||||
UNKNOWN_AREA,
|
|
||||||
AsciidocSection,
|
|
||||||
ASCIIDOC_SECTIONS,
|
|
||||||
UNKNOWN_ASCIIDOC_SECTION,
|
|
||||||
} from '../release_notes_config';
|
|
||||||
import { PullRequest } from './pr_api';
|
|
||||||
|
|
||||||
export interface ClassifiedPr extends PullRequest {
|
|
||||||
area: Area;
|
|
||||||
asciidocSection: AsciidocSection;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function classifyPr(pr: PullRequest, log: ToolingLog): ClassifiedPr {
|
|
||||||
const filter = (a: Area | AsciidocSection) =>
|
|
||||||
a.labels.some((test) =>
|
|
||||||
typeof test === 'string' ? pr.labels.includes(test) : pr.labels.some((l) => l.match(test))
|
|
||||||
);
|
|
||||||
|
|
||||||
const areas = AREAS.filter(filter);
|
|
||||||
const asciidocSections = ASCIIDOC_SECTIONS.filter(filter);
|
|
||||||
|
|
||||||
const pickOne = <T extends Area | AsciidocSection>(name: string, options: T[]) => {
|
|
||||||
if (options.length > 1) {
|
|
||||||
const matches = options.map((o) => o.title).join(', ');
|
|
||||||
log.warning(`[${pr.terminalLink}] ambiguous ${name}, mulitple match [${matches}]`);
|
|
||||||
return options[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.length === 0) {
|
|
||||||
log.error(`[${pr.terminalLink}] unable to determine ${name} because none match`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return options[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
...pr,
|
|
||||||
area: pickOne('area', areas) || UNKNOWN_AREA,
|
|
||||||
asciidocSection: pickOne('asciidoc section', asciidocSections) || UNKNOWN_ASCIIDOC_SECTION,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { getFixReferences } from './get_fix_references';
|
|
||||||
|
|
||||||
it('returns all fixed issue mentions in the PR text', () => {
|
|
||||||
expect(
|
|
||||||
getFixReferences(`
|
|
||||||
clOses #1
|
|
||||||
closes: #2
|
|
||||||
clOse #3
|
|
||||||
close: #4
|
|
||||||
clOsed #5
|
|
||||||
closed: #6
|
|
||||||
fiX #7
|
|
||||||
fix: #8
|
|
||||||
fiXes #9
|
|
||||||
fixes: #10
|
|
||||||
fiXed #11
|
|
||||||
fixed: #12
|
|
||||||
reSolve #13
|
|
||||||
resolve: #14
|
|
||||||
reSolves #15
|
|
||||||
resolves: #16
|
|
||||||
reSolved #17
|
|
||||||
resolved: #18
|
|
||||||
fixed
|
|
||||||
#19
|
|
||||||
`)
|
|
||||||
).toMatchInlineSnapshot(`
|
|
||||||
Array [
|
|
||||||
"#1",
|
|
||||||
"#2",
|
|
||||||
"#3",
|
|
||||||
"#4",
|
|
||||||
"#5",
|
|
||||||
"#6",
|
|
||||||
"#7",
|
|
||||||
"#8",
|
|
||||||
"#9",
|
|
||||||
"#10",
|
|
||||||
"#11",
|
|
||||||
"#12",
|
|
||||||
"#13",
|
|
||||||
"#14",
|
|
||||||
"#15",
|
|
||||||
"#16",
|
|
||||||
"#17",
|
|
||||||
"#18",
|
|
||||||
]
|
|
||||||
`);
|
|
||||||
});
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const FIXES_RE = /(?:closes|close|closed|fix|fixes|fixed|resolve|resolves|resolved)[ :]*(#\d*)/gi;
|
|
||||||
|
|
||||||
export function getFixReferences(prText: string) {
|
|
||||||
const fixes: string[] = [];
|
|
||||||
let match;
|
|
||||||
while ((match = FIXES_RE.exec(prText))) {
|
|
||||||
fixes.push(match[1]);
|
|
||||||
}
|
|
||||||
return fixes;
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import MarkdownIt from 'markdown-it';
|
|
||||||
import dedent from 'dedent';
|
|
||||||
|
|
||||||
import { getNoteFromDescription } from './get_note_from_description';
|
|
||||||
|
|
||||||
it('extracts expected components from html', () => {
|
|
||||||
const mk = new MarkdownIt();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
getNoteFromDescription(
|
|
||||||
mk.render(dedent`
|
|
||||||
My PR description
|
|
||||||
|
|
||||||
Fixes: #1234
|
|
||||||
|
|
||||||
## Release Note:
|
|
||||||
|
|
||||||
Checkout this feature
|
|
||||||
`),
|
|
||||||
'release note'
|
|
||||||
)
|
|
||||||
).toMatchInlineSnapshot(`"Checkout this feature"`);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
getNoteFromDescription(
|
|
||||||
mk.render(dedent`
|
|
||||||
My PR description
|
|
||||||
|
|
||||||
Fixes: #1234
|
|
||||||
|
|
||||||
#### Dev docs:
|
|
||||||
|
|
||||||
We fixed an issue
|
|
||||||
`),
|
|
||||||
'dev docs'
|
|
||||||
)
|
|
||||||
).toMatchInlineSnapshot(`"We fixed an issue"`);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
getNoteFromDescription(
|
|
||||||
mk.render(dedent`
|
|
||||||
My PR description
|
|
||||||
|
|
||||||
Fixes: #1234
|
|
||||||
|
|
||||||
OTHER TITLE: Checkout feature foo
|
|
||||||
`),
|
|
||||||
'other title'
|
|
||||||
)
|
|
||||||
).toMatchInlineSnapshot(`"Checkout feature foo"`);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
getNoteFromDescription(
|
|
||||||
mk.render(dedent`
|
|
||||||
# Summary
|
|
||||||
|
|
||||||
My PR description
|
|
||||||
|
|
||||||
release note : bar
|
|
||||||
`),
|
|
||||||
'release note'
|
|
||||||
)
|
|
||||||
).toMatchInlineSnapshot(`"bar"`);
|
|
||||||
});
|
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cheerio from 'cheerio';
|
|
||||||
|
|
||||||
export function getNoteFromDescription(descriptionHtml: string, header: string) {
|
|
||||||
const re = new RegExp(`^(\\s*${header.toLowerCase()}(?:s)?\\s*:?\\s*)`, 'i');
|
|
||||||
const $ = cheerio.load(descriptionHtml);
|
|
||||||
for (const el of $('p,h1,h2,h3,h4,h5').toArray()) {
|
|
||||||
const text = $(el).text();
|
|
||||||
const match = text.match(re);
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const note = text.replace(match[1], '').trim();
|
|
||||||
return note || $(el).next().text().trim();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export * from './pr_api';
|
|
||||||
export * from './version';
|
|
||||||
export * from './is_pr_relevant';
|
|
||||||
export * from './streams';
|
|
||||||
export * from './type_helpers';
|
|
||||||
export * from './irrelevant_pr_summary';
|
|
||||||
export * from './classify_pr';
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ToolingLog } from '@kbn/dev-utils';
|
|
||||||
|
|
||||||
import { PullRequest } from './pr_api';
|
|
||||||
import { Version } from './version';
|
|
||||||
|
|
||||||
export class IrrelevantPrSummary {
|
|
||||||
private readonly stats = {
|
|
||||||
'skipped by label': new Map<string, number>(),
|
|
||||||
'skipped by label regexp': new Map<string, number>(),
|
|
||||||
'skipped by version': new Map<string, number>(),
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(private readonly log: ToolingLog) {}
|
|
||||||
|
|
||||||
skippedByLabel(pr: PullRequest, label: string) {
|
|
||||||
this.log.debug(`${pr.terminalLink} skipped, label [${label}] is ignored`);
|
|
||||||
this.increment('skipped by label', label);
|
|
||||||
}
|
|
||||||
|
|
||||||
skippedByLabelRegExp(pr: PullRequest, regexp: RegExp, label: string) {
|
|
||||||
this.log.debug(`${pr.terminalLink} skipped, label [${label}] matches regexp [${regexp}]`);
|
|
||||||
this.increment('skipped by label regexp', `${regexp}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
skippedByVersion(pr: PullRequest, earliestVersion: Version) {
|
|
||||||
this.log.debug(`${pr.terminalLink} skipped, earliest version is [${earliestVersion.label}]`);
|
|
||||||
this.increment('skipped by version', earliestVersion.label);
|
|
||||||
}
|
|
||||||
|
|
||||||
private increment(stat: keyof IrrelevantPrSummary['stats'], key: string) {
|
|
||||||
const n = this.stats[stat].get(key) || 0;
|
|
||||||
this.stats[stat].set(key, n + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
logStats() {
|
|
||||||
for (const [description, stats] of Object.entries(this.stats)) {
|
|
||||||
for (const [key, count] of stats) {
|
|
||||||
this.log.warning(`${count} ${count === 1 ? 'pr was' : 'prs were'} ${description} [${key}]`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Version } from './version';
|
|
||||||
import { PullRequest } from './pr_api';
|
|
||||||
import { IGNORE_LABELS } from '../release_notes_config';
|
|
||||||
import { IrrelevantPrSummary } from './irrelevant_pr_summary';
|
|
||||||
|
|
||||||
export function isPrRelevant(
|
|
||||||
pr: PullRequest,
|
|
||||||
version: Version,
|
|
||||||
includeVersions: Version[],
|
|
||||||
summary: IrrelevantPrSummary
|
|
||||||
) {
|
|
||||||
for (const label of IGNORE_LABELS) {
|
|
||||||
if (typeof label === 'string') {
|
|
||||||
if (pr.labels.includes(label)) {
|
|
||||||
summary.skippedByLabel(pr, label);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (label instanceof RegExp) {
|
|
||||||
const matching = pr.labels.find((l) => label.test(l));
|
|
||||||
if (matching) {
|
|
||||||
summary.skippedByLabelRegExp(pr, label, matching);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const [earliestVersion] = Version.sort(
|
|
||||||
// filter out `includeVersions` so that they won't be considered the "earliest version", only
|
|
||||||
// versions which are actually before the current `version` or the `version` itself are eligible
|
|
||||||
pr.versions.filter((v) => !includeVersions.includes(v)),
|
|
||||||
'asc'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (version !== earliestVersion) {
|
|
||||||
summary.skippedByVersion(pr, earliestVersion);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -1,222 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { inspect } from 'util';
|
|
||||||
|
|
||||||
import Axios from 'axios';
|
|
||||||
import gql from 'graphql-tag';
|
|
||||||
import * as GraphqlPrinter from 'graphql/language/printer';
|
|
||||||
import { DocumentNode } from 'graphql/language/ast';
|
|
||||||
import makeTerminalLink from 'terminal-link';
|
|
||||||
import { ToolingLog, isAxiosResponseError } from '@kbn/dev-utils';
|
|
||||||
|
|
||||||
import { Version } from './version';
|
|
||||||
import { getFixReferences } from './get_fix_references';
|
|
||||||
import { getNoteFromDescription } from './get_note_from_description';
|
|
||||||
|
|
||||||
const PrNodeFragment = gql`
|
|
||||||
fragment PrNode on PullRequest {
|
|
||||||
number
|
|
||||||
url
|
|
||||||
title
|
|
||||||
bodyText
|
|
||||||
bodyHTML
|
|
||||||
mergedAt
|
|
||||||
baseRefName
|
|
||||||
state
|
|
||||||
author {
|
|
||||||
login
|
|
||||||
... on User {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
labels(first: 100) {
|
|
||||||
nodes {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export interface PullRequest {
|
|
||||||
number: number;
|
|
||||||
url: string;
|
|
||||||
title: string;
|
|
||||||
targetBranch: string;
|
|
||||||
mergedAt: string;
|
|
||||||
state: string;
|
|
||||||
labels: string[];
|
|
||||||
fixes: string[];
|
|
||||||
user: {
|
|
||||||
name: string;
|
|
||||||
login: string;
|
|
||||||
};
|
|
||||||
versions: Version[];
|
|
||||||
terminalLink: string;
|
|
||||||
note?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PrApi {
|
|
||||||
constructor(private readonly log: ToolingLog, private readonly token: string) {}
|
|
||||||
|
|
||||||
async getPr(number: number) {
|
|
||||||
const resp = await this.gqlRequest(
|
|
||||||
gql`
|
|
||||||
query($number: Int!) {
|
|
||||||
repository(owner: "elastic", name: "kibana") {
|
|
||||||
pullRequest(number: $number) {
|
|
||||||
...PrNode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${PrNodeFragment}
|
|
||||||
`,
|
|
||||||
{
|
|
||||||
number,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const node = resp.data?.repository?.pullRequest;
|
|
||||||
if (!node) {
|
|
||||||
throw new Error(`unexpected github response, unable to fetch PR: ${inspect(resp)}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.parsePullRequestNode(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterate all of the PRs which have the `version` label
|
|
||||||
*/
|
|
||||||
async *iterRelevantPullRequests(version: Version) {
|
|
||||||
let nextCursor: string | undefined;
|
|
||||||
let hasNextPage = true;
|
|
||||||
|
|
||||||
while (hasNextPage) {
|
|
||||||
const resp = await this.gqlRequest(
|
|
||||||
gql`
|
|
||||||
query($cursor: String, $labels: [String!]) {
|
|
||||||
repository(owner: "elastic", name: "kibana") {
|
|
||||||
pullRequests(first: 100, after: $cursor, labels: $labels, states: MERGED) {
|
|
||||||
pageInfo {
|
|
||||||
hasNextPage
|
|
||||||
endCursor
|
|
||||||
}
|
|
||||||
nodes {
|
|
||||||
...PrNode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${PrNodeFragment}
|
|
||||||
`,
|
|
||||||
{
|
|
||||||
cursor: nextCursor,
|
|
||||||
labels: [version.label],
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const pullRequests = resp.data?.repository?.pullRequests;
|
|
||||||
if (!pullRequests) {
|
|
||||||
throw new Error(`unexpected github response, unable to fetch PRs: ${inspect(resp)}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
hasNextPage = pullRequests.pageInfo?.hasNextPage;
|
|
||||||
nextCursor = pullRequests.pageInfo?.endCursor;
|
|
||||||
|
|
||||||
if (hasNextPage === undefined || (hasNextPage && !nextCursor)) {
|
|
||||||
throw new Error(
|
|
||||||
`github response does not include valid pagination information: ${inspect(resp)}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const node of pullRequests.nodes) {
|
|
||||||
yield this.parsePullRequestNode(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the Github API response into the structure used by this tool
|
|
||||||
*
|
|
||||||
* @param node A GraphQL response from Github using the PrNode fragment
|
|
||||||
*/
|
|
||||||
private parsePullRequestNode(node: any): PullRequest {
|
|
||||||
const terminalLink = makeTerminalLink(`#${node.number}`, node.url);
|
|
||||||
|
|
||||||
const labels: string[] = node.labels.nodes.map((l: { name: string }) => l.name);
|
|
||||||
|
|
||||||
return {
|
|
||||||
number: node.number,
|
|
||||||
url: node.url,
|
|
||||||
terminalLink,
|
|
||||||
title: node.title,
|
|
||||||
targetBranch: node.baseRefName,
|
|
||||||
state: node.state,
|
|
||||||
mergedAt: node.mergedAt,
|
|
||||||
labels,
|
|
||||||
fixes: getFixReferences(node.bodyText),
|
|
||||||
user: {
|
|
||||||
login: node.author?.login || 'deleted user',
|
|
||||||
name: node.author?.name,
|
|
||||||
},
|
|
||||||
versions: labels
|
|
||||||
.map((l) => Version.fromLabel(l))
|
|
||||||
.filter((v): v is Version => v instanceof Version),
|
|
||||||
note:
|
|
||||||
getNoteFromDescription(node.bodyHTML, 'release note') ||
|
|
||||||
getNoteFromDescription(node.bodyHTML, 'dev docs'),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a single request to the Github v4 GraphQL API
|
|
||||||
*/
|
|
||||||
private async gqlRequest(query: DocumentNode, variables: Record<string, unknown> = {}) {
|
|
||||||
let attempt = 0;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
attempt += 1;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const resp = await Axios.request({
|
|
||||||
url: 'https://api.github.com/graphql',
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'user-agent': '@kbn/release-notes',
|
|
||||||
authorization: `bearer ${this.token}`,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
query: GraphqlPrinter.print(query),
|
|
||||||
variables,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return resp.data;
|
|
||||||
} catch (error) {
|
|
||||||
if (!isAxiosResponseError(error) || error.response.status < 500) {
|
|
||||||
// rethrow error unless it is a 500+ response from github
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { status, data } = error.response;
|
|
||||||
const resp = inspect(data);
|
|
||||||
|
|
||||||
if (attempt === 5) {
|
|
||||||
throw new Error(
|
|
||||||
`${status} response from Github, attempted request ${attempt} times: [${resp}]`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const delay = attempt * 2000;
|
|
||||||
this.log.debug(`Github responded with ${status}, retrying in ${delay} ms: [${resp}]`);
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { promisify } from 'util';
|
|
||||||
import { Readable, pipeline } from 'stream';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @types/node still doesn't have this method that was added
|
|
||||||
* in 10.17.0 https://nodejs.org/api/stream.html#stream_stream_readable_from_iterable_options
|
|
||||||
*/
|
|
||||||
export function streamFromIterable(
|
|
||||||
iter: Iterable<string | Buffer> | AsyncIterable<string | Buffer>
|
|
||||||
): Readable {
|
|
||||||
// @ts-ignore
|
|
||||||
return Readable.from(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const asyncPipeline = promisify(pipeline);
|
|
|
@ -1,9 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export type ArrayItem<T extends readonly any[]> = T extends ReadonlyArray<infer X> ? X : never;
|
|
|
@ -1,135 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Version } from './version';
|
|
||||||
|
|
||||||
it('parses version labels, returns null on failure', () => {
|
|
||||||
expect(Version.fromLabel('v1.0.2')).toMatchInlineSnapshot(`
|
|
||||||
Version {
|
|
||||||
"label": "v1.0.2",
|
|
||||||
"major": 1,
|
|
||||||
"minor": 0,
|
|
||||||
"patch": 2,
|
|
||||||
"tag": undefined,
|
|
||||||
"tagNum": undefined,
|
|
||||||
"tagOrder": Infinity,
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
expect(Version.fromLabel('v1.0.0')).toMatchInlineSnapshot(`
|
|
||||||
Version {
|
|
||||||
"label": "v1.0.0",
|
|
||||||
"major": 1,
|
|
||||||
"minor": 0,
|
|
||||||
"patch": 0,
|
|
||||||
"tag": undefined,
|
|
||||||
"tagNum": undefined,
|
|
||||||
"tagOrder": Infinity,
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
expect(Version.fromLabel('v9.0.2')).toMatchInlineSnapshot(`
|
|
||||||
Version {
|
|
||||||
"label": "v9.0.2",
|
|
||||||
"major": 9,
|
|
||||||
"minor": 0,
|
|
||||||
"patch": 2,
|
|
||||||
"tag": undefined,
|
|
||||||
"tagNum": undefined,
|
|
||||||
"tagOrder": Infinity,
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
expect(Version.fromLabel('v9.0.2-alpha0')).toMatchInlineSnapshot(`
|
|
||||||
Version {
|
|
||||||
"label": "v9.0.2-alpha0",
|
|
||||||
"major": 9,
|
|
||||||
"minor": 0,
|
|
||||||
"patch": 2,
|
|
||||||
"tag": "alpha",
|
|
||||||
"tagNum": 0,
|
|
||||||
"tagOrder": 1,
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
expect(Version.fromLabel('v9.0.2-beta1')).toMatchInlineSnapshot(`
|
|
||||||
Version {
|
|
||||||
"label": "v9.0.2-beta1",
|
|
||||||
"major": 9,
|
|
||||||
"minor": 0,
|
|
||||||
"patch": 2,
|
|
||||||
"tag": "beta",
|
|
||||||
"tagNum": 1,
|
|
||||||
"tagOrder": 2,
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
expect(Version.fromLabel('v9.0')).toMatchInlineSnapshot(`undefined`);
|
|
||||||
expect(Version.fromLabel('some:area')).toMatchInlineSnapshot(`undefined`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sorts versions in ascending order', () => {
|
|
||||||
const versions = [
|
|
||||||
'v1.7.3',
|
|
||||||
'v1.7.0',
|
|
||||||
'v1.5.0',
|
|
||||||
'v2.7.0',
|
|
||||||
'v7.0.0-beta2',
|
|
||||||
'v7.0.0-alpha1',
|
|
||||||
'v2.0.0',
|
|
||||||
'v0.0.0',
|
|
||||||
'v7.0.0-beta1',
|
|
||||||
'v7.0.0',
|
|
||||||
].map((l) => Version.fromLabel(l)!);
|
|
||||||
|
|
||||||
const sorted = Version.sort(versions);
|
|
||||||
|
|
||||||
expect(sorted.map((v) => v.label)).toMatchInlineSnapshot(`
|
|
||||||
Array [
|
|
||||||
"v0.0.0",
|
|
||||||
"v1.5.0",
|
|
||||||
"v1.7.0",
|
|
||||||
"v1.7.3",
|
|
||||||
"v2.0.0",
|
|
||||||
"v2.7.0",
|
|
||||||
"v7.0.0-alpha1",
|
|
||||||
"v7.0.0-beta1",
|
|
||||||
"v7.0.0-beta2",
|
|
||||||
"v7.0.0",
|
|
||||||
]
|
|
||||||
`);
|
|
||||||
|
|
||||||
// ensure versions was not mutated
|
|
||||||
expect(sorted).not.toEqual(versions);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sorts versions in decending order', () => {
|
|
||||||
const versions = [
|
|
||||||
'v1.7.3',
|
|
||||||
'v1.7.0',
|
|
||||||
'v1.5.0',
|
|
||||||
'v7.0.0-beta1',
|
|
||||||
'v2.7.0',
|
|
||||||
'v2.0.0',
|
|
||||||
'v0.0.0',
|
|
||||||
'v7.0.0',
|
|
||||||
].map((l) => Version.fromLabel(l)!);
|
|
||||||
|
|
||||||
const sorted = Version.sort(versions, 'desc');
|
|
||||||
|
|
||||||
expect(sorted.map((v) => v.label)).toMatchInlineSnapshot(`
|
|
||||||
Array [
|
|
||||||
"v7.0.0",
|
|
||||||
"v7.0.0-beta1",
|
|
||||||
"v2.7.0",
|
|
||||||
"v2.0.0",
|
|
||||||
"v1.7.3",
|
|
||||||
"v1.7.0",
|
|
||||||
"v1.5.0",
|
|
||||||
"v0.0.0",
|
|
||||||
]
|
|
||||||
`);
|
|
||||||
|
|
||||||
// ensure versions was not mutated
|
|
||||||
expect(sorted).not.toEqual(versions);
|
|
||||||
});
|
|
|
@ -1,112 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const LABEL_RE = /^v(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta)(\d+))?$/;
|
|
||||||
|
|
||||||
const versionCache = new Map<string, Version>();
|
|
||||||
|
|
||||||
const multiCompare = (...diffs: number[]) => {
|
|
||||||
for (const diff of diffs) {
|
|
||||||
if (diff !== 0) {
|
|
||||||
return diff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class Version {
|
|
||||||
static fromFlag(flag: string | string[] | boolean | undefined) {
|
|
||||||
if (typeof flag !== 'string') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Version.fromLabel(flag) || Version.fromLabel(`v${flag}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
static fromFlags(flag: string | string[] | boolean | undefined) {
|
|
||||||
const flags = Array.isArray(flag) ? flag : [flag];
|
|
||||||
const versions: Version[] = [];
|
|
||||||
|
|
||||||
for (const f of flags) {
|
|
||||||
const version = Version.fromFlag(f);
|
|
||||||
if (!version) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
versions.push(version);
|
|
||||||
}
|
|
||||||
|
|
||||||
return versions;
|
|
||||||
}
|
|
||||||
|
|
||||||
static fromLabel(label: string) {
|
|
||||||
const match = label.match(LABEL_RE);
|
|
||||||
if (!match) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cached = versionCache.get(label);
|
|
||||||
if (cached) {
|
|
||||||
return cached;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [, major, minor, patch, tag, tagNum] = match;
|
|
||||||
const version = new Version(
|
|
||||||
parseInt(major, 10),
|
|
||||||
parseInt(minor, 10),
|
|
||||||
parseInt(patch, 10),
|
|
||||||
tag as 'alpha' | 'beta' | undefined,
|
|
||||||
tagNum ? parseInt(tagNum, 10) : undefined
|
|
||||||
);
|
|
||||||
|
|
||||||
versionCache.set(label, version);
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
static sort(versions: Version[], dir: 'asc' | 'desc' = 'asc') {
|
|
||||||
const order = dir === 'asc' ? 1 : -1;
|
|
||||||
|
|
||||||
return versions.slice().sort((a, b) => a.compare(b) * order);
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly label = `v${this.major}.${this.minor}.${this.patch}${
|
|
||||||
this.tag ? `-${this.tag}${this.tagNum}` : ''
|
|
||||||
}`;
|
|
||||||
private readonly tagOrder: number;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public readonly major: number,
|
|
||||||
public readonly minor: number,
|
|
||||||
public readonly patch: number,
|
|
||||||
public readonly tag: 'alpha' | 'beta' | undefined,
|
|
||||||
public readonly tagNum: number | undefined
|
|
||||||
) {
|
|
||||||
switch (tag) {
|
|
||||||
case undefined:
|
|
||||||
this.tagOrder = Infinity;
|
|
||||||
break;
|
|
||||||
case 'alpha':
|
|
||||||
this.tagOrder = 1;
|
|
||||||
break;
|
|
||||||
case 'beta':
|
|
||||||
this.tagOrder = 2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error('unexpected tag');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compare(other: Version) {
|
|
||||||
return multiCompare(
|
|
||||||
this.major - other.major,
|
|
||||||
this.minor - other.minor,
|
|
||||||
this.patch - other.patch,
|
|
||||||
this.tagOrder - other.tagOrder,
|
|
||||||
(this.tagNum ?? 0) - (other.tagNum ?? 0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,283 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exclude any PR from release notes that has a matching label. String
|
|
||||||
* labels must match exactly, for more complicated use a RegExp
|
|
||||||
*/
|
|
||||||
export const IGNORE_LABELS: Array<RegExp | string> = [
|
|
||||||
'Team:Docs',
|
|
||||||
':KibanaApp/fix-it-week',
|
|
||||||
'reverted',
|
|
||||||
/^test/,
|
|
||||||
'non-issue',
|
|
||||||
'jenkins',
|
|
||||||
'build',
|
|
||||||
'chore',
|
|
||||||
'backport',
|
|
||||||
'release_note:skip',
|
|
||||||
'release_note:dev_docs',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define areas that are used to categorize changes in the release notes
|
|
||||||
* based on the labels a PR has. the `labels` array can contain strings, which
|
|
||||||
* are matched exactly, or regular expressions. The first area, in definition
|
|
||||||
* order, which has a `label` which matches and label on a PR is the area
|
|
||||||
* assigned to that PR.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export interface Area {
|
|
||||||
title: string;
|
|
||||||
labels: Array<string | RegExp>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const AREAS: Area[] = [
|
|
||||||
{
|
|
||||||
title: 'Design',
|
|
||||||
labels: ['Team:Design', 'Project:Accessibility'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Logstash',
|
|
||||||
labels: ['App:Logstash', 'Feature:Logstash Pipelines'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Management',
|
|
||||||
labels: [
|
|
||||||
'Feature:license',
|
|
||||||
'Feature:Console',
|
|
||||||
'Feature:Search Profiler',
|
|
||||||
'Feature:watcher',
|
|
||||||
'Feature:Index Patterns',
|
|
||||||
'Feature:Kibana Management',
|
|
||||||
'Feature:Dev Tools',
|
|
||||||
'Feature:Inspector',
|
|
||||||
'Feature:Index Management',
|
|
||||||
'Feature:Snapshot and Restore',
|
|
||||||
'Team:Elasticsearch UI',
|
|
||||||
'Feature:FieldFormatters',
|
|
||||||
'Feature:CCR',
|
|
||||||
'Feature:ILM',
|
|
||||||
'Feature:Transforms',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Monitoring',
|
|
||||||
labels: ['Team:Monitoring', 'Feature:Telemetry', 'Feature:Stack Monitoring'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Operations',
|
|
||||||
labels: ['Team:Operations', 'Feature:License'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Kibana UI',
|
|
||||||
labels: ['Kibana UI', 'Team:Core UI', 'Feature:Header'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Platform',
|
|
||||||
labels: [
|
|
||||||
'Team:Platform',
|
|
||||||
'Feature:Plugins',
|
|
||||||
'Feature:New Platform',
|
|
||||||
'Project:i18n',
|
|
||||||
'Feature:ExpressionLanguage',
|
|
||||||
'Feature:Saved Objects',
|
|
||||||
'Team:Stack Services',
|
|
||||||
'Feature:NP Migration',
|
|
||||||
'Feature:Task Manager',
|
|
||||||
'Team:Pulse',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Machine Learning',
|
|
||||||
labels: [
|
|
||||||
':ml',
|
|
||||||
'Feature:Anomaly Detection',
|
|
||||||
'Feature:Data Frames',
|
|
||||||
'Feature:File Data Viz',
|
|
||||||
'Feature:ml-results',
|
|
||||||
'Feature:Data Frame Analytics',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Maps',
|
|
||||||
labels: ['Team:Geo'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'QA',
|
|
||||||
labels: ['Team:QA'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Security',
|
|
||||||
labels: [
|
|
||||||
'Team:Security',
|
|
||||||
'Feature:Security/Spaces',
|
|
||||||
'Feature:users and roles',
|
|
||||||
'Feature:Security/Authentication',
|
|
||||||
'Feature:Security/Authorization',
|
|
||||||
'Feature:Security/Feature Controls',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Canvas',
|
|
||||||
labels: ['Feature:Canvas'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Dashboard',
|
|
||||||
labels: ['Feature:Dashboard', 'Feature:Drilldowns'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Discover',
|
|
||||||
labels: ['Feature:Discover'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Kibana Home & Add Data',
|
|
||||||
labels: ['Feature:Add Data', 'Feature:Home'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Querying & Filtering',
|
|
||||||
labels: [
|
|
||||||
'Feature:Query Bar',
|
|
||||||
'Feature:Courier',
|
|
||||||
'Feature:Filters',
|
|
||||||
'Feature:Timepicker',
|
|
||||||
'Feature:Highlight',
|
|
||||||
'Feature:KQL',
|
|
||||||
'Feature:Rollups',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Reporting',
|
|
||||||
labels: ['Feature:Reporting', 'Team:Reporting Services'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Sharing',
|
|
||||||
labels: ['Feature:Embedding', 'Feature:SharingURLs'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Visualizations',
|
|
||||||
labels: [
|
|
||||||
'Feature:Timelion',
|
|
||||||
'Feature:TSVB',
|
|
||||||
'Feature:Coordinate Map',
|
|
||||||
'Feature:Region Map',
|
|
||||||
'Feature:Vega',
|
|
||||||
'Feature:Gauge Vis',
|
|
||||||
'Feature:Tagcloud',
|
|
||||||
'Feature:Vis Loader',
|
|
||||||
'Feature:Vislib',
|
|
||||||
'Feature:Vis Editor',
|
|
||||||
'Feature:Aggregations',
|
|
||||||
'Feature:Input Control',
|
|
||||||
'Feature:Visualizations',
|
|
||||||
'Feature:Markdown',
|
|
||||||
'Feature:Data Table',
|
|
||||||
'Feature:Heatmap',
|
|
||||||
'Feature:Pie Chart',
|
|
||||||
'Feature:XYAxis',
|
|
||||||
'Feature:Graph',
|
|
||||||
'Feature:New Feature',
|
|
||||||
'Feature:MetricVis',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'SIEM',
|
|
||||||
labels: ['Team:SIEM'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Code',
|
|
||||||
labels: ['Team:Code'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Infrastructure',
|
|
||||||
labels: ['App:Infrastructure', 'Feature:Infra UI', 'Feature:Service Maps'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Logs',
|
|
||||||
labels: ['App:Logs', 'Feature:Logs UI'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Uptime',
|
|
||||||
labels: ['App:Uptime', 'Feature:Uptime', 'Team:uptime'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Beats Management',
|
|
||||||
labels: ['App:Beats', 'Feature:beats-cm', 'Team:Beats'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'APM',
|
|
||||||
labels: ['Team:apm', /^apm[:\-]/],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Lens',
|
|
||||||
labels: ['App:Lens', 'Feature:Lens'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Alerting',
|
|
||||||
labels: ['App:Alerting', 'Feature:Alerting', 'Team:Alerting Services', 'Feature:Actions'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Metrics',
|
|
||||||
labels: ['App:Metrics', 'Feature:Metrics UI', 'Team:logs-metrics-ui'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Data ingest',
|
|
||||||
labels: ['Ingest', 'Feature:Ingest Node Pipelines'],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const UNKNOWN_AREA: Area = {
|
|
||||||
title: 'Unknown',
|
|
||||||
labels: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define the sections that will be assigned to PRs when generating the
|
|
||||||
* asciidoc formatted report. The order of the sections determines the
|
|
||||||
* order they will be rendered in the report
|
|
||||||
*/
|
|
||||||
|
|
||||||
export interface AsciidocSection {
|
|
||||||
title: string;
|
|
||||||
labels: Array<string | RegExp>;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ASCIIDOC_SECTIONS: AsciidocSection[] = [
|
|
||||||
{
|
|
||||||
id: 'enhancement',
|
|
||||||
title: 'Enhancements',
|
|
||||||
labels: ['release_note:enhancement'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'bug',
|
|
||||||
title: 'Bug fixes',
|
|
||||||
labels: ['release_note:fix'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'roadmap',
|
|
||||||
title: 'Roadmap',
|
|
||||||
labels: ['release_note:roadmap'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'deprecation',
|
|
||||||
title: 'Deprecations',
|
|
||||||
labels: ['release_note:deprecation'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'breaking',
|
|
||||||
title: 'Breaking Changes',
|
|
||||||
labels: ['release_note:breaking'],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const UNKNOWN_ASCIIDOC_SECTION: AsciidocSection = {
|
|
||||||
id: 'unknown',
|
|
||||||
title: 'Unknown',
|
|
||||||
labels: [],
|
|
||||||
};
|
|
|
@ -1,10 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
require('../src/setup_node_env/no_transpilation');
|
|
||||||
require('@kbn/docs-utils').runReleaseNotesCli();
|
|
22
yarn.lock
22
yarn.lock
|
@ -4881,11 +4881,6 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/graphql@^0.13.2":
|
|
||||||
version "0.13.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.13.4.tgz#55ae9c29f0fd6b85ee536f5c72b4769d5c5e06b1"
|
|
||||||
integrity sha512-B4yel4ro2nTb3v0pYO8vO6SjgvFJSrwUY+IO6TUSLdOSB+gQFslylrhRCHxvXMIhxB71mv5PEE9dAX+24S8sew==
|
|
||||||
|
|
||||||
"@types/gulp-zip@^4.0.1":
|
"@types/gulp-zip@^4.0.1":
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/gulp-zip/-/gulp-zip-4.0.1.tgz#96cd0b994219f9ae3bbbec7ec3baa043fba9d9ef"
|
resolved "https://registry.yarnpkg.com/@types/gulp-zip/-/gulp-zip-4.0.1.tgz#96cd0b994219f9ae3bbbec7ec3baa043fba9d9ef"
|
||||||
|
@ -14705,18 +14700,6 @@ graphlib@^2.1.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
lodash "^4.17.15"
|
lodash "^4.17.15"
|
||||||
|
|
||||||
graphql-tag@^2.10.3:
|
|
||||||
version "2.10.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.3.tgz#ea1baba5eb8fc6339e4c4cf049dabe522b0edf03"
|
|
||||||
integrity sha512-4FOv3ZKfA4WdOKJeHdz6B3F/vxBLSgmBcGeAFPf4n1F64ltJUvOOerNj0rsJxONQGdhUMynQIvd6LzB+1J5oKA==
|
|
||||||
|
|
||||||
graphql@^0.13.2:
|
|
||||||
version "0.13.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.13.2.tgz#4c740ae3c222823e7004096f832e7b93b2108270"
|
|
||||||
integrity sha512-QZ5BL8ZO/B20VA8APauGBg3GyEgZ19eduvpLWoq5x7gMmWnHoy8rlQWPLmWgFvo1yNgjSEFMesmS4R6pPr7xog==
|
|
||||||
dependencies:
|
|
||||||
iterall "^1.2.1"
|
|
||||||
|
|
||||||
grid-index@^1.1.0:
|
grid-index@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/grid-index/-/grid-index-1.1.0.tgz#97f8221edec1026c8377b86446a7c71e79522ea7"
|
resolved "https://registry.yarnpkg.com/grid-index/-/grid-index-1.1.0.tgz#97f8221edec1026c8377b86446a7c71e79522ea7"
|
||||||
|
@ -16770,11 +16753,6 @@ istanbul-reports@^3.0.2:
|
||||||
html-escaper "^2.0.0"
|
html-escaper "^2.0.0"
|
||||||
istanbul-lib-report "^3.0.0"
|
istanbul-lib-report "^3.0.0"
|
||||||
|
|
||||||
iterall@^1.2.1:
|
|
||||||
version "1.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea"
|
|
||||||
integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==
|
|
||||||
|
|
||||||
iterate-iterator@^1.0.1:
|
iterate-iterator@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/iterate-iterator/-/iterate-iterator-1.0.1.tgz#1693a768c1ddd79c969051459453f082fe82e9f6"
|
resolved "https://registry.yarnpkg.com/iterate-iterator/-/iterate-iterator-1.0.1.tgz#1693a768c1ddd79c969051459453f082fe82e9f6"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue