From c3b7ef17a294155559458331cba2213701a518c6 Mon Sep 17 00:00:00 2001 From: patrickm68 Date: Sat, 18 Aug 2018 05:34:09 +0800 Subject: [PATCH] ci: tweak patterns, improve markdown output New format is in https://github.com/nodejs/reliability/issues/14 Added a few more patterns and linkify the machine names as well as console of example stacks --- lib/ci/ci_failure_parser.js | 24 ++++---- lib/ci/ci_result_parser.js | 56 ++++++++++++++----- .../jenkins/git-failure-2/expected.json | 4 +- 3 files changed, 58 insertions(+), 26 deletions(-) diff --git a/lib/ci/ci_failure_parser.js b/lib/ci/ci_failure_parser.js index 42a86cd..e6e14f1 100644 --- a/lib/ci/ci_failure_parser.js +++ b/lib/ci/ci_failure_parser.js @@ -152,13 +152,17 @@ const FAILURE_FILTERS = [{ } }, { filter(ctx, text) { - const pattern = - /Changes not staged for commit:[\s\S]+no changes added to commit/mg; - const matches = text.match(pattern); - if (!matches) { - return null; - } - return new GitFailure(ctx, matches[0]); + const patterns = [{ + pattern: + /Changes not staged for commit:[\s\S]+no changes added to commit/mg, + context: { index: 0, contextBefore: 0, contextAfter: 0 } + }, { + pattern: + // eslint-disable-next-line max-len + /error: Your local changes to the following files[\s\S]+Failed to merge in the changes./g, + context: { index: 0, contextBefore: 0, contextAfter: 0 } + }]; + return failureMatcher(GitFailure, patterns, ctx, text); } }, { filter(ctx, text) { @@ -174,6 +178,9 @@ const FAILURE_FILTERS = [{ }, { filter(ctx, text) { const patterns = [{ + pattern: /bash: line /g, + context: { index: 0, contextBefore: 0, contextAfter: 1 } + }, { pattern: /ERROR: .+/g, // Pick the last one context: { index: -1, contextBefore: 0, contextAfter: 5 } @@ -197,9 +204,6 @@ const FAILURE_FILTERS = [{ }, { filter(ctx, text) { const patterns = [{ - pattern: /bash: line /g, - context: { index: 0, contextBefore: 0, contextAfter: 1 } - }, { pattern: /FATAL: .+/g, context: { index: -1, contextBefore: 0, contextAfter: 5 } }, { diff --git a/lib/ci/ci_result_parser.js b/lib/ci/ci_result_parser.js index 8236f1e..43cdde7 100644 --- a/lib/ci/ci_result_parser.js +++ b/lib/ci/ci_result_parser.js @@ -29,8 +29,6 @@ const FAILURE = 'FAILURE'; const ABORTED = 'ABORTED'; const UNSTABLE = 'UNSTABLE'; -const SEP_LENGTH = 120; - const TEST_PHASE = 'Binary Tests'; // com.tikal.jenkins.plugins.multijob.MultiJobBuild const BUILD_FIELDS = 'builtOn,buildNumber,jobName,result,url'; @@ -247,7 +245,7 @@ class TestBuild extends Job { displayHeader() { const { cli, result, change } = this; - cli.separator('Summary', SEP_LENGTH); + cli.separator('Summary'); cli.table('Result', resultName(result)); cli.table('URL', this.jobUrl); cli.table('Source', this.sourceURL); @@ -259,7 +257,7 @@ class TestBuild extends Job { displayFailure(failure) { const { cli } = this; const { url, reason } = failure; - cli.separator(getNodeName(url), SEP_LENGTH); + cli.separator(getNodeName(url)); cli.table('URL', url); if (failure.type) { cli.table('Type', failure.type); @@ -284,7 +282,7 @@ class TestBuild extends Job { for (const failure of failures) { this.displayFailure(failure); } - cli.separator('Other builds', SEP_LENGTH); + cli.separator('Other builds'); for (const aborted of builds.aborted) { cli.table('Aborted', getUrl(aborted.url)); } @@ -336,7 +334,14 @@ function getHighlight(f) { .replace( /'JNLP4-connect connection from .+?'/, 'JNLP4-connect connection from ...' ) - .replace(/FATAL: Could not checkout \w+/, 'FATAL: Could not checkout ...'); + .replace(/FATAL: Could not checkout \w+/, 'FATAL: Could not checkout ...') + .replace( + /error: pathspec .+ did not match any file\(s\) known to git/, + 'error: pathspec ... did not match any file(s) known to git') + .replace( + /failed: no workspace for .+/, + 'failed: no workspace for ...' + ); } function markdownRow(...args) { @@ -347,6 +352,10 @@ function markdownRow(...args) { return result + '|\n'; } +function getMachineUrl(name) { + return `[${name}](https://${CI_DOMAIN}/computer/${name}/)`; +} + class FailureAggregator { constructor(cli, failures) { this.cli = cli; @@ -392,29 +401,48 @@ class FailureAggregator { aggregates = this.aggregates = this.aggregate(); } - let output = ''; + const last = parseJobFromURL(this.failures[0].upstream); + const first = parseJobFromURL( + this.failures[this.failures.length - 1].upstream + ); + const jobName = CI_TYPES.get(first.type).jobName; + let output = 'Failures in '; + output += `[${jobName}/${first.jobid}](${first.link}) to `; + output += `[${jobName}/${last.jobid}](${last.link}) `; + output += `that failed more than 2 PRs\n`; + const todo = []; for (const type of Object.keys(aggregates)) { output += `\n### ${FAILURE_TYPES_NAME[type]}\n\n`; for (const item of aggregates[type]) { const { reason, type, prs, failures, machines } = item; if (prs.length < 2) { continue; } - output += markdownRow('Reason', `\`${reason}\``); + todo.push(reason); + output += markdownRow('Reason', `${reason}`); output += markdownRow('-', ':-'); output += markdownRow('Type', type); const source = prs.map(f => f.source); output += markdownRow( 'Failed PR', `${source.length} (${source.join(', ')})` ); - output += markdownRow('Appeared', machines.join(', ')); + output += markdownRow( + 'Appeared', machines.map(getMachineUrl).join(', ') + ); if (prs.length > 1) { output += markdownRow('First CI', `${prs[0].upstream}`); } output += markdownRow('Last CI', `${prs[prs.length - 1].upstream}`); - output += '\n' + fold('Example', failures[0].reason) + '\n'; - output += '\n-------\n\n'; + output += '\n'; + output += fold( + `Example`, + failures[0].reason + ); + output += '\n\n-------\n\n'; } } - return output; + + output += '### Progress\n\n'; + output += todo.map(i => `- \`${i}\``).join('\n'); + return output + '\n'; } display() { @@ -440,7 +468,7 @@ class FailureAggregator { cli.table('First CI', `${prs[0].upstream}`); } cli.table('Last CI', `${prs[prs.length - 1].upstream}`); - cli.log('\n' + chalk.bold('Example:') + '\n'); + cli.log('\n' + chalk.bold('Example: ') + `${failures[0].url}\n`); const example = failures[0].reason; cli.log(example.length > 512 ? example.slice(0, 512) + '...' : example); cli.separator(); @@ -802,7 +830,7 @@ class BenchmarkRun extends Job { display() { const { cli, results, significantResults } = this; cli.log(results); - cli.separator('significant results', SEP_LENGTH); + cli.separator('significant results'); cli.log(significantResults); } diff --git a/test/fixtures/jenkins/git-failure-2/expected.json b/test/fixtures/jenkins/git-failure-2/expected.json index f478c43..4a2c39e 100644 --- a/test/fixtures/jenkins/git-failure-2/expected.json +++ b/test/fixtures/jenkins/git-failure-2/expected.json @@ -1,7 +1,7 @@ -{ +[{ "url": "https://ci.nodejs.org/job/node-test-commit-linuxone/nodes=rhel72-s390x/3915/console", "builtOn": "test-linuxonecc-rhel72-s390x-3", "reason": "Changes not staged for commit:\n19:15:57 # (use \"git add ...\" to update what will be committed)\n19:15:57 # (use \"git checkout -- ...\" to discard changes in working directory)\n19:15:57 #\n19:15:57 #\tmodified: deps/v8/third_party/jinja2/LICENSE\n19:15:57 #\n19:15:57 # Untracked files:\n19:15:57 # (use \"git add ...\" to include in what will be committed)\n19:15:57 #\n19:15:57 #\tbuild/\n19:15:57 no changes added to commit", "highlight": 0, "type": "GIT_FAILURE" -} +}]