Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
11f1d3b
feat(ci): add e2e duration charts
universal-itengineer May 18, 2026
7d9ca7c
fix(ci): log chart render errors and tighten e2e report install
universal-itengineer May 18, 2026
1c4ff6b
fix(ci, observability): keep Loop thread reply when chart upload fails
universal-itengineer May 18, 2026
de29f30
refactor(ci, observability): align messenger report with main + chart…
universal-itengineer May 18, 2026
4aa3c99
fix adding graph for report
universal-itengineer May 19, 2026
dc1e31f
feat(ci, observability): replace e2e cluster chart set with five new …
universal-itengineer May 20, 2026
1a60728
refactor(ci, observability): focus e2e charts on failures and durations
universal-itengineer May 20, 2026
a0f72c6
refactor(ci, observability): remove duplicate e2e failed-slow chart
universal-itengineer May 20, 2026
be86fdd
refactor(ci, observability): use duration gradient for slowest specs …
universal-itengineer May 20, 2026
158606d
refactor(ci, observability): clarify e2e chart titles and layout
universal-itengineer May 20, 2026
09ac020
refactor(ci, observability): widen slowest specs chart output
universal-itengineer May 20, 2026
05dd800
refactor(ci, observability): add margin to slowest specs chart
universal-itengineer May 20, 2026
32e634a
fix(ci, observability): keep small duration bucket counts visible
universal-itengineer May 20, 2026
e0e0ab7
refactor(ci, observability): separate slowest e2e charts from messenger
universal-itengineer May 21, 2026
0d26cdb
fix(ci, observability): write slowest charts to tmp charts
universal-itengineer May 21, 2026
59d33cc
refactor(ci, observability): move e2e charts to python
universal-itengineer May 22, 2026
06f0156
fix(ci, observability): apply e2e chart review fixes
universal-itengineer May 22, 2026
397c15b
fix formatting
universal-itengineer May 22, 2026
acf2e1b
fix formatting 2
universal-itengineer May 22, 2026
dbdffac
fix formatting 3
universal-itengineer May 22, 2026
be84683
resovle comments
universal-itengineer May 25, 2026
1476bfd
rm tmp folder
universal-itengineer May 26, 2026
aee0e72
resolve comments
universal-itengineer May 26, 2026
b7ecaa8
fix cunstruct url
universal-itengineer May 26, 2026
0f52433
fix url api
universal-itengineer May 26, 2026
ee1d454
refactor(ci): e2e reports
universal-itengineer May 26, 2026
b2d0bb4
fix gh wf
universal-itengineer May 26, 2026
3a51d8f
refactor(ci): polish Loop info logs and dedupe failedTests derivation
universal-itengineer May 26, 2026
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
3 changes: 3 additions & 0 deletions .github/scripts/js/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"printWidth": 120
}
84 changes: 26 additions & 58 deletions .github/scripts/js/e2e/report/cluster-report.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@
const fs = require("fs");

const { findSingleMatchingFile } = require("./shared/fs-utils");
const {
parseGinkgoOutput,
parseGinkgoReport,
} = require("./shared/ginkgo-report-utils");
const { parseGinkgoOutput, parseGinkgoReport } = require("./shared/ginkgo-report-utils");
const {
archivedReportPattern,
buildClusterStatus,
Expand Down Expand Up @@ -69,11 +66,11 @@ const {
*/

const workflowStages = [
{ name: "bootstrap", displayName: "Bootstrap cluster", needsJobId: "bootstrap" },
{ name: "configure-sdn", displayName: "Configure SDN", needsJobId: "configure-sdn" },
{ name: "storage-setup", displayName: "Configure storage", needsJobId: "configure-storage" },
{ name: "bootstrap", displayName: "Bootstrap cluster", needsJobId: "bootstrap" },
{ name: "configure-sdn", displayName: "Configure SDN", needsJobId: "configure-sdn" },
{ name: "storage-setup", displayName: "Configure storage", needsJobId: "configure-storage" },
{ name: "virtualization-setup", displayName: "Configure Virtualization", needsJobId: "configure-virtualization" },
{ name: "e2e-test", displayName: "E2E test", needsJobId: "e2e-test" },
{ name: "e2e-test", displayName: "E2E test", needsJobId: "e2e-test" },
];

function readClusterReportConfigFromEnv(env = process.env) {
Expand Down Expand Up @@ -178,6 +175,8 @@ async function readStageJobUrlsFromApi(github, context, config, core) {
* metrics: ReturnType<typeof zeroMetrics>,
* failedTests: string[],
* failedTestDetails: Array<{name: string, reason: string}>,
* specTimings: Array<Record<string, any>>,
* suiteTotalMs: number,
* startedAt: null,
* source: string,
* }} Empty parsed-report payload.
Expand All @@ -187,6 +186,8 @@ function emptyParsedReport(source) {
metrics: zeroMetrics(),
failedTests: [],
failedTestDetails: [],
specTimings: [],
suiteTotalMs: 0,
startedAt: null,
source,
};
Expand Down Expand Up @@ -217,6 +218,8 @@ const ginkgoOutputSource = {
* metrics: ReturnType<typeof zeroMetrics>,
* failedTests: string[],
* failedTestDetails: Array<{name: string, reason: string}>,
* specTimings: Array<Record<string, any>>,
* suiteTotalMs: number,
* startedAt: string|null,
* }} parse Parser function for the source content.
* @property {function(string): RegExp} pattern Builds the file-name regex for the source.
Expand All @@ -232,11 +235,7 @@ const ginkgoOutputSource = {
* @returns {string|null} Path to the source file, or null when none exists.
*/
function findGinkgoSource(config, source) {
return findSingleMatchingFile(
config.reportsDir,
source.pattern(config.storageType),
source.label
);
return findSingleMatchingFile(config.reportsDir, source.pattern(config.storageType), source.label);
}

/**
Expand All @@ -252,6 +251,8 @@ function findGinkgoSource(config, source) {
* metrics: ReturnType<typeof zeroMetrics>,
* failedTests: string[],
* failedTestDetails: Array<{name: string, reason: string}>,
* specTimings: Array<Record<string, any>>,
* suiteTotalMs: number,
* startedAt: string|null,
* source: string,
* }} Parsed report payload with a source tag.
Expand All @@ -268,38 +269,21 @@ function parseGinkgoFile(filePath, core, source) {
source: source.okSource,
};
} catch (error) {
core.warning(
`Unable to parse ${source.label} ${filePath}: ${error.message}`
);
core.warning(`Unable to parse ${source.label} ${filePath}: ${error.message}`);
return emptyParsedReport(source.invalidSource);
}
}

function buildReportPayload({
config,
context,
fallbackWorkflowRunUrl,
branchName,
parsedReport,
sourcePath,
}) {
function buildReportPayload({ config, context, fallbackWorkflowRunUrl, branchName, parsedReport, sourcePath }) {
const clusterStatus = buildClusterStatus(config.stageResults);
const testStatus = buildTestStatus(
config.stageResults["e2e-test"],
parsedReport.source,
clusterStatus,
parsedReport.metrics
);
const reportSummary = buildReportSummary(
config.storageType,
clusterStatus,
testStatus
);
const workflowRunUrl = getReportJobUrl(
reportSummary,
config.stageJobUrls,
fallbackWorkflowRunUrl
);
const reportSummary = buildReportSummary(config.storageType, clusterStatus, testStatus);
const workflowRunUrl = getReportJobUrl(reportSummary, config.stageJobUrls, fallbackWorkflowRunUrl);

return {
schemaVersion: 1,
Expand All @@ -320,16 +304,14 @@ function buildReportPayload({
metrics: parsedReport.metrics,
failedTests: parsedReport.failedTests,
failedTestDetails: parsedReport.failedTestDetails,
specTimings: parsedReport.specTimings || [],
suiteTotalMs: parsedReport.suiteTotalMs || 0,
sourceReport: sourcePath,
reportSource: parsedReport.source,
};
}

function getReportJobUrl(
reportSummary,
stageJobUrls = {},
fallbackWorkflowRunUrl
) {
function getReportJobUrl(reportSummary, stageJobUrls = {}, fallbackWorkflowRunUrl) {
if (reportSummary.failedStage && stageJobUrls[reportSummary.failedStage]) {
return stageJobUrls[reportSummary.failedStage];
}
Expand Down Expand Up @@ -367,29 +349,20 @@ function setReportOutputs(report, reportFile, core) {
* @throws {Error} If config is incomplete or the report file cannot be written.
*/
async function buildClusterReport({ core, context, github, config } = {}) {
const resolvedConfig = requireClusterReportConfig(
config || readClusterReportConfigFromEnv()
);
const resolvedConfig = requireClusterReportConfig(config || readClusterReportConfigFromEnv());

if (!resolvedConfig.stageResults) {
resolvedConfig.stageResults = readStageResultsFromEnv();
}

if (!resolvedConfig.stageJobUrls && github) {
resolvedConfig.stageJobUrls = await readStageJobUrlsFromApi(
github,
context,
resolvedConfig,
core
);
resolvedConfig.stageJobUrls = await readStageJobUrlsFromApi(github, context, resolvedConfig, core);
}

const fallbackWorkflowRunUrl = getWorkflowRunUrl(context);
const branchName = getBranchName(context);
const rawReportPath = findGinkgoSource(resolvedConfig, ginkgoJsonSource);
const outputPath = rawReportPath
? null
: findGinkgoSource(resolvedConfig, ginkgoOutputSource);
const outputPath = rawReportPath ? null : findGinkgoSource(resolvedConfig, ginkgoOutputSource);
const sourcePath = rawReportPath || outputPath;
const sourceDescriptor = rawReportPath ? ginkgoJsonSource : ginkgoOutputSource;

Expand All @@ -410,14 +383,9 @@ async function buildClusterReport({ core, context, github, config } = {}) {
});

try {
fs.writeFileSync(
resolvedConfig.reportFile,
`${JSON.stringify(report, null, 2)}\n`
);
fs.writeFileSync(resolvedConfig.reportFile, `${JSON.stringify(report, null, 2)}\n`);
} catch (error) {
throw new Error(
`Unable to write cluster report file ${resolvedConfig.reportFile}: ${error.message}`
);
throw new Error(`Unable to write cluster report file ${resolvedConfig.reportFile}: ${error.message}`);
}

setReportOutputs(report, resolvedConfig.reportFile, core);
Expand Down
Loading
Loading