diff --git a/lib/ci/ci_failure_parser.js b/lib/ci/ci_failure_parser.js
index 42a86cd7..e6e14f13 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 8236f1eb..43cdde7b 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 f478c43f..4a2c39ec 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"
-}
+}]