Skip to content

Commit

Permalink
Expand inter-MITTEN-t logic to account for confirm-failures. (#7773)
Browse files Browse the repository at this point in the history
  • Loading branch information
jmaher authored Sep 1, 2023
1 parent 1b0aa25 commit f61fe2f
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 6 deletions.
81 changes: 75 additions & 6 deletions ui/job-view/pushes/JobGroup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,85 @@ export class JobGroupComponent extends React.Component {
this.setState({ expanded: isExpanded });
}

getIntermittentJobTypeNames(groupJobs) {
const failedJobTypeNames = new Set();
getIntermittentJobTypeNames(groupJobs, confirmGroup) {
/* Given a set of jobs from a group and related confirmFailures:
* collect all failed jobs
* collect all confirm failure job names
* collect all confirm failure jobs that failed (i.e. confirmed)
* if job is retriggered, assuming >50% green == intermittent
* if job has confirm-failure: assuming green is intermittent, orange is failure
* if job has both cf and retrigger:
* confirm-failure is failed: mark as failed
* confirm-failure is green: add +1 to total success jobs
*/
const failedJobTypeNames = {};
const jobCountByConfirmName = {};
const jobCountByName = {};
const confirmedJobNames = [];

for (const job of groupJobs) {
if (!Object.keys(jobCountByName).includes(job.job_type_name)) {
jobCountByName[job.job_type_name] = 0;
}
jobCountByName[job.job_type_name]++;

// -cf group can have >1 job of each job_type_name and >1 type of job
if (
confirmGroup !== undefined &&
Object.keys(confirmGroup).includes('jobs')
) {
for (const sgjob of confirmGroup.jobs) {
if (sgjob.result === 'unknown') continue;

if (sgjob.job_type_name === job.job_type_name) {
if (
!Object.keys(jobCountByConfirmName).includes(sgjob.job_type_name)
) {
jobCountByConfirmName[sgjob.job_type_name] = 0;
}
jobCountByConfirmName[sgjob.job_type_name]++;

// if we find a failing -cf job, then this is a regression!
// TODO: we could fail for infra
if (sgjob.result === 'testfailed') {
confirmedJobNames.push(sgjob.job_type_name);
}
}
}
}

if (job.result === 'testfailed') {
failedJobTypeNames.add(job.job_type_name);
if (!Object.keys(failedJobTypeNames).includes(job.job_type_name)) {
failedJobTypeNames[job.job_type_name] = [];
}
// TODO: add list of failures here, specifically NEW failures
failedJobTypeNames[job.job_type_name].push(job.id);
}
}

const intermittentJobTypeNames = new Set();
const failedNames = Object.keys(failedJobTypeNames);
for (const job of groupJobs) {
if (
job.result === 'success' &&
failedJobTypeNames.has(job.job_type_name)
// if failed in -cf mode, do not consider as intermittent
if (confirmedJobNames.includes(job.job_type_name)) continue;

if (job.result === 'success' && failedNames.includes(job.job_type_name)) {
// TODO: make the default threshold lower, now 1/2 pass, ideally 2/3 pass
let threshold = 0.5;

// if -cf job exists (only here if green), then job is confirmed intermittent
if (jobCountByConfirmName[job.job_type_name] > 0) threshold = 1;

if (
failedJobTypeNames[job.job_type_name].length /
jobCountByName[job.job_type_name] <=
threshold
) {
intermittentJobTypeNames.add(job.job_type_name);
}
} else if (
// here if we have at least 1 green -cf job, we can mark the failures as intermittent
jobCountByConfirmName[job.job_type_name] > 0
) {
intermittentJobTypeNames.add(job.job_type_name);
}
Expand Down Expand Up @@ -162,12 +228,14 @@ export class JobGroupComponent extends React.Component {
jobs: groupJobs,
mapKey: groupMapKey,
},
confirmGroup,
runnableVisible,
} = this.props;
const { expanded } = this.state;
const { buttons, counts } = this.groupButtonsAndCounts(groupJobs, expanded);
const intermittentJobTypeNames = this.getIntermittentJobTypeNames(
groupJobs,
confirmGroup,
);
function isIntermittent(job) {
if (job.result !== 'testfailed') {
Expand Down Expand Up @@ -232,6 +300,7 @@ export class JobGroupComponent extends React.Component {

JobGroupComponent.propTypes = {
group: PropTypes.shape({}).isRequired,
confirmGroup: PropTypes.shape({}).isRequired,
repoName: PropTypes.string.isRequired,
filterModel: PropTypes.shape({}).isRequired,
filterPlatformCb: PropTypes.func.isRequired,
Expand Down
26 changes: 26 additions & 0 deletions ui/job-view/pushes/JobsAndGroups.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,27 @@ export default class JobsAndGroups extends React.Component {
toggleSelectedRunnableJob,
} = this.props;

const confirmGroups = {};
for (const g of groups) {
// group.mapKey == pushID groupSymbol Tier platform buildtype
// find matching group.mapKey
if (g.symbol.endsWith('-cf')) {
let foundTier = false;
let gname = '';
for (let tier = 1; tier <= 3; tier++) {
gname = g.mapKey.replace('-cf3', tier);
for (const t of groups) {
if (t.mapKey === gname) foundTier = true;
}
if (foundTier) break;
}

if (foundTier) {
confirmGroups[gname] = g;
}
}
}

return (
<td className="job-row">
{groups.map((group) => {
Expand All @@ -26,6 +47,11 @@ export default class JobsAndGroups extends React.Component {
group.visible && (
<JobGroup
group={group}
confirmGroup={
confirmGroups[group.mapKey] === undefined
? {}
: confirmGroups[group.mapKey]
}
repoName={repoName}
filterModel={filterModel}
filterPlatformCb={filterPlatformCb}
Expand Down

0 comments on commit f61fe2f

Please sign in to comment.