Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,6 @@ run(
return;
}

// Scout test failures reporting
await generateScoutTestFailureArtifacts({ log, bkMeta });

if (reportPaths.length) {
log.info('found', reportPaths.length, 'reports', reportPaths);

Expand Down Expand Up @@ -137,6 +134,9 @@ run(

// Process Scout reports
await processScoutReports(scoutReports, processParams);

// Generate Scout test failure artifacts after reports are updated (GH issue info, html reports, etc.)
await generateScoutTestFailureArtifacts({ log, bkMeta });
}
} finally {
await CiStatsReporter.fromEnv(log).metrics([
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import fs from 'fs';
import os from 'os';
import Path from 'path';

import { ToolingLog } from '@kbn/tooling-log';

import type { ScoutTestFailureExtended } from './get_scout_failures';
import { updateScoutHtmlReport } from './process_scout_reports';

const createFailure = (
overrides: Partial<ScoutTestFailureExtended> = {}
): ScoutTestFailureExtended => {
return {
id: 'failure-id',
target: 'serverless-oblt',
location: 'x-pack/test.ts',
duration: 1234,
owners: 'team:test',
classname: 'suite name',
name: 'test name',
time: '1.23',
failure: 'error message',
likelyIrrelevant: false,
...overrides,
};
};

describe('updateScoutHtmlReport', () => {
it('updates the tracked branches line when a GitHub issue exists', () => {
const tempDir = fs.mkdtempSync(Path.join(os.tmpdir(), 'scout-html-'));
const htmlPath = Path.join(tempDir, 'failure-id.html');
const htmlTemplate = `
<html>
<body>
<div class="section" id="tracked-branches-status">
<strong>No failures found in tracked branches</strong>
</div>
</body>
</html>
`;
fs.writeFileSync(htmlPath, htmlTemplate.trim(), 'utf-8');

const failure = createFailure({
githubIssue: 'https://github.com/elastic/kibana/issues/123',
failureCount: 6,
});

updateScoutHtmlReport({
log: new ToolingLog(),
reportDir: tempDir,
failure,
reportUpdate: true,
});

const updatedContent = fs.readFileSync(htmlPath, 'utf-8');
expect(updatedContent).toContain('Failures in tracked branches');
expect(updatedContent).toContain('id="failure-count">6<');
expect(updatedContent).toContain('https://github.com/elastic/kibana/issues/123');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,58 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import fs from 'fs';
import { escape } from 'he';
import Path from 'path';
import { getScoutFailures, type ScoutTestFailureExtended } from './get_scout_failures';
import type { ProcessReportsParams } from './process_reports_types';
import { createFailureIssue, updateFailureIssue } from './report_failure';
import { reportFailuresToEs } from './report_failures_to_es';
import { reportFailuresToFile } from './report_failures_to_file';

export const updateScoutHtmlReport = ({
log,
reportDir,
failure,
reportUpdate,
}: {
log: ProcessReportsParams['log'];
reportDir: string;
failure: ScoutTestFailureExtended;
reportUpdate: boolean;
}) => {
const htmlReportPath = Path.join(reportDir, `${failure.id}.html`);
if (!fs.existsSync(htmlReportPath)) {
log.warning(`Scout HTML report not found: ${htmlReportPath}`);
return;
}

const fileContent = fs.readFileSync(htmlReportPath, 'utf-8');
const failureCount = failure.failureCount ?? 0;
const githubIssue = failure.githubIssue ? escape(failure.githubIssue) : undefined;

let updatedContent = fileContent;
if (githubIssue) {
const badgeHtml = `<span class="badge rounded-pill bg-danger" id="failure-count">${failureCount}</span>`;
const issueLinkHtml = `<a id="github-issue-link" href="${githubIssue}" target="_blank">${githubIssue}</a>`;
const trackedBranchesLine = `<strong>Failures in tracked branches</strong>: ${badgeHtml} ${issueLinkHtml}`;

updatedContent = updatedContent.replace(
/<div[^>]*id="tracked-branches-status"[^>]*>[\s\S]*?<\/div>/,
`<div class="section" id="tracked-branches-status">${trackedBranchesLine}</div>`
);
}

if (updatedContent === fileContent) {
return;
}

if (!reportUpdate) {
log.info(`Report update disabled, skipping HTML update for ${htmlReportPath}`);
return;
}

fs.writeFileSync(htmlReportPath, updatedContent, 'utf-8');
};

export async function processScoutReports(
reportPaths: string[],
Expand All @@ -27,7 +74,7 @@ export async function processScoutReports(
prependTitle,
updateGithub,
indexInEs,
bkMeta,
reportUpdate,
} = params;

for (const reportPath of reportPaths) {
Expand All @@ -47,6 +94,8 @@ export async function processScoutReports(
await reportFailuresToEs(log, failures);
}

const reportDir = Path.dirname(reportPath);

for (const failure of failures) {
if (failure.likelyIrrelevant) {
log.info(`Scout failure is likely irrelevant: ${failure.classname} - ${failure.name}`);
Expand All @@ -68,6 +117,7 @@ export async function processScoutReports(
failure.githubIssue = url;
failure.failureCount = updateGithub ? newCount : newCount - 1;
log.info(`Updated existing Scout issue: ${url} (fail count: ${newCount})`);
updateScoutHtmlReport({ log, reportDir, failure, reportUpdate });
continue;
}

Expand All @@ -85,9 +135,7 @@ export async function processScoutReports(
failure.githubIssue = newIssue.html_url;
}
failure.failureCount = updateGithub ? 1 : 0;
updateScoutHtmlReport({ log, reportDir, failure, reportUpdate });
}

// Generate Scout failure artifacts (similar to JUnit report processing)
await reportFailuresToFile(log, failures, bkMeta, {});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -375,16 +375,8 @@ export const buildFailureHtml = (testFailure: TestFailure): string => {
<pre>${errorStackTrace}</pre>
</div>

<div>
<details>
<summary>
<strong>Failures in tracked branches</strong>:
<span class="badge rounded-pill bg-danger" id="failure-count">0</span>
</summary>
<div id="github-issue-section" style="display: none;">
<a id="github-issue-link" href="" target="_blank"></a>
</div>
</details>
<div class="section" id="tracked-branches-status">
<strong>No failures found in tracked branches</strong>
</div>

<div class="section">
Expand Down