isMain: false,
mergeBranch: 'master',
name: 'foo',
- status: { bugs: 0, codeSmells: 0, vulnerabilities: 0 },
+ status: { bugs: 0, codeSmells: 0, qualityGateStatus: 'OK', vulnerabilities: 0 },
type: BranchType.SHORT
};
const component = {} as Component;
isOrphan,
mergeBranch: 'master',
name,
- status: { bugs: 0, codeSmells: 0, vulnerabilities: 0 },
+ status: { bugs: 0, codeSmells: 0, qualityGateStatus: 'OK', vulnerabilities: 0 },
type: BranchType.SHORT
};
}
base: 'master',
branch: 'feature',
key: '1234',
- status: { bugs: 0, codeSmells: 0, vulnerabilities: 0 },
+ status: { bugs: 0, codeSmells: 0, qualityGateStatus: 'OK', vulnerabilities: 0 },
title
};
}
isMain: false,
mergeBranch: 'master',
name: 'foo',
- status: { bugs: 1, codeSmells: 2, vulnerabilities: 3 },
+ status: { bugs: 1, codeSmells: 2, qualityGateStatus: 'ERROR', vulnerabilities: 3 },
type: BranchType.SHORT
};
isMain: false,
mergeBranch: 'master',
name: 'feature',
- status: { bugs: 0, codeSmells: 2, vulnerabilities: 3 },
+ status: { bugs: 0, codeSmells: 2, qualityGateStatus: 'ERROR', vulnerabilities: 3 },
type: BranchType.SHORT
};
expect(
base: 'master',
branch: 'feature',
key: '1234',
- status: { bugs: 0, codeSmells: 2, vulnerabilities: 3 },
+ status: { bugs: 0, codeSmells: 2, qualityGateStatus: 'ERROR', vulnerabilities: 3 },
title: 'Feature PR',
url: 'https://example.com/pull/1234'
};
"status": Object {
"bugs": 0,
"codeSmells": 0,
+ "qualityGateStatus": "OK",
"vulnerabilities": 0,
},
"type": "SHORT",
"status": Object {
"bugs": 0,
"codeSmells": 0,
+ "qualityGateStatus": "OK",
"vulnerabilities": 0,
},
"title": "qux",
"status": Object {
"bugs": 0,
"codeSmells": 0,
+ "qualityGateStatus": "OK",
"vulnerabilities": 0,
},
"type": "SHORT",
"status": Object {
"bugs": 0,
"codeSmells": 0,
+ "qualityGateStatus": "OK",
"vulnerabilities": 0,
},
"type": "SHORT",
"status": Object {
"bugs": 0,
"codeSmells": 0,
+ "qualityGateStatus": "OK",
"vulnerabilities": 0,
},
"type": "SHORT",
"status": Object {
"bugs": 0,
"codeSmells": 0,
+ "qualityGateStatus": "OK",
"vulnerabilities": 0,
},
"type": "SHORT",
"status": Object {
"bugs": 1,
"codeSmells": 2,
+ "qualityGateStatus": "ERROR",
"vulnerabilities": 3,
},
"type": "SHORT",
"status": Object {
"bugs": 1,
"codeSmells": 2,
+ "qualityGateStatus": "ERROR",
"vulnerabilities": 3,
},
"type": "SHORT",
"status": Object {
"bugs": 1,
"codeSmells": 2,
+ "qualityGateStatus": "ERROR",
"vulnerabilities": 3,
},
"type": "SHORT",
"status": Object {
"bugs": 1,
"codeSmells": 2,
+ "qualityGateStatus": "ERROR",
"vulnerabilities": 3,
},
"type": "SHORT",
"status": Object {
"bugs": 0,
"codeSmells": 2,
+ "qualityGateStatus": "ERROR",
"vulnerabilities": 3,
},
"title": "Feature PR",
"status": Object {
"bugs": 0,
"codeSmells": 2,
+ "qualityGateStatus": "ERROR",
"vulnerabilities": 3,
},
"type": "SHORT",
status?: {
bugs: number;
codeSmells: number;
+ qualityGateStatus: string;
vulnerabilities: number;
};
title: string;
status?: {
bugs: number;
codeSmells: number;
+ qualityGateStatus: string;
vulnerabilities: number;
};
type: BranchType.SHORT;
import Level from '../ui/Level';
import BugIcon from '../icons-components/BugIcon';
import CodeSmellIcon from '../icons-components/CodeSmellIcon';
+import HelpIcon from '../icons-components/HelpIcon';
+import Tooltip from '../controls/Tooltip';
import VulnerabilityIcon from '../icons-components/VulnerabilityIcon';
import { BranchLike } from '../../app/types';
import { isShortLivingBranch, isPullRequest, isLongLivingBranch } from '../../helpers/branches';
+import { translateWithParameters } from '../../helpers/l10n';
import './BranchStatus.css';
interface Props {
const totalIssues =
branchLike.status.bugs + branchLike.status.vulnerabilities + branchLike.status.codeSmells;
-
- const indicatorColor = totalIssues > 0 ? 'red' : 'green';
+ const indicatorColor = getQualityGateColor(branchLike.status.qualityGateStatus);
+ const shouldDisplayHelper = branchLike.status.qualityGateStatus === 'OK' && totalIssues > 0;
return concise ? (
<ul className="branch-status">
</ul>
) : (
<ul className="branch-status">
- <li className="spacer-right">
+ <li className="little-spacer-right">
<StatusIndicator color={indicatorColor} size="small" />
</li>
<li className="spacer-left">
{branchLike.status.bugs}
- <BugIcon />
+ <BugIcon className="little-spacer-left" />
</li>
<li className="spacer-left">
{branchLike.status.vulnerabilities}
- <VulnerabilityIcon />
+ <VulnerabilityIcon className="little-spacer-left" />
</li>
<li className="spacer-left">
{branchLike.status.codeSmells}
- <CodeSmellIcon />
+ <CodeSmellIcon className="little-spacer-left" />
</li>
+ {shouldDisplayHelper && (
+ <Tooltip
+ overlay={translateWithParameters(
+ 'branches.short_lived.quality_gate.description',
+ totalIssues
+ )}
+ placement="right">
+ <li className="spacer-left">
+ <HelpIcon className="text-info" />
+ </li>
+ </Tooltip>
+ )}
</ul>
);
} else if (isLongLivingBranch(branchLike)) {
return null;
}
}
+
+function getQualityGateColor(status: string) {
+ let indicatorColor = 'gray';
+ if (status === 'ERROR') {
+ indicatorColor = 'red';
+ } else if (status === 'WARN') {
+ indicatorColor = 'orange';
+ } else if (status === 'OK') {
+ indicatorColor = 'green';
+ }
+ return indicatorColor;
+}
.status-indicator.green {
background-color: var(--green);
}
+
+.status-indicator.orange {
+ background-color: var(--orange);
+}
+
+.status-indicator.gray {
+ background-color: var(--gray71);
+}
import { BranchType, LongLivingBranch, ShortLivingBranch } from '../../../app/types';
it('renders status of short-living branches', () => {
- checkShort(0, 0, 0);
- checkShort(0, 1, 0);
- checkShort(7, 3, 6);
+ checkShort('OK', 0, 0, 0);
+ checkShort('WARN', 0, 1, 0);
+ checkShort('ERROR', 7, 3, 6);
+ checkShort('OK', 0, 0, 1);
- function checkShort(bugs: number, codeSmells: number, vulnerabilities: number) {
+ function checkShort(
+ qualityGateStatus: string,
+ bugs: number,
+ codeSmells: number,
+ vulnerabilities: number
+ ) {
const shortBranch: ShortLivingBranch = {
isMain: false,
mergeBranch: 'master',
name: 'foo',
- status: { bugs, codeSmells, vulnerabilities },
+ status: { bugs, codeSmells, qualityGateStatus, vulnerabilities },
type: BranchType.SHORT
};
expect(shallow(<BranchStatus branchLike={shortBranch} />)).toMatchSnapshot();
className="branch-status"
>
<li
- className="spacer-right"
+ className="little-spacer-right"
>
<StatusIndicator
color="green"
className="spacer-left"
>
0
- <BugIcon />
+ <BugIcon
+ className="little-spacer-left"
+ />
</li>
<li
className="spacer-left"
>
0
- <VulnerabilityIcon />
+ <VulnerabilityIcon
+ className="little-spacer-left"
+ />
</li>
<li
className="spacer-left"
>
0
- <CodeSmellIcon />
+ <CodeSmellIcon
+ className="little-spacer-left"
+ />
</li>
</ul>
`;
className="branch-status"
>
<li
- className="spacer-right"
+ className="little-spacer-right"
>
<StatusIndicator
- color="red"
+ color="orange"
size="small"
/>
</li>
className="spacer-left"
>
0
- <BugIcon />
+ <BugIcon
+ className="little-spacer-left"
+ />
</li>
<li
className="spacer-left"
>
0
- <VulnerabilityIcon />
+ <VulnerabilityIcon
+ className="little-spacer-left"
+ />
</li>
<li
className="spacer-left"
>
1
- <CodeSmellIcon />
+ <CodeSmellIcon
+ className="little-spacer-left"
+ />
</li>
</ul>
`;
className="branch-status"
>
<li
- className="spacer-right"
+ className="little-spacer-right"
>
<StatusIndicator
color="red"
className="spacer-left"
>
7
- <BugIcon />
+ <BugIcon
+ className="little-spacer-left"
+ />
</li>
<li
className="spacer-left"
>
6
- <VulnerabilityIcon />
+ <VulnerabilityIcon
+ className="little-spacer-left"
+ />
</li>
<li
className="spacer-left"
>
3
- <CodeSmellIcon />
+ <CodeSmellIcon
+ className="little-spacer-left"
+ />
+ </li>
+</ul>
+`;
+
+exports[`renders status of short-living branches 4`] = `
+<ul
+ className="branch-status"
+>
+ <li
+ className="little-spacer-right"
+ >
+ <StatusIndicator
+ color="green"
+ size="small"
+ />
</li>
+ <li
+ className="spacer-left"
+ >
+ 0
+ <BugIcon
+ className="little-spacer-left"
+ />
+ </li>
+ <li
+ className="spacer-left"
+ >
+ 1
+ <VulnerabilityIcon
+ className="little-spacer-left"
+ />
+ </li>
+ <li
+ className="spacer-left"
+ >
+ 0
+ <CodeSmellIcon
+ className="little-spacer-left"
+ />
+ </li>
+ <Tooltip
+ overlay="branches.short_lived.quality_gate.description.1"
+ placement="right"
+ >
+ <li
+ className="spacer-left"
+ >
+ <HelpIcon
+ className="text-info"
+ />
+ </li>
+ </Tooltip>
</ul>
`;
});
it('compares pull requests', () => {
- expect(isSameBranchLike(pullRequest({ key: '1234' }), pullRequest({ key: '1234' }))).toBeTruthy();
- expect(isSameBranchLike(pullRequest({ key: '1234' }), pullRequest({ key: '5678' }))).toBeFalsy();
+ expect(
+ isSameBranchLike(pullRequest({ key: '1234' }), pullRequest({ key: '1234' }))
+ ).toBeTruthy();
+ expect(
+ isSameBranchLike(pullRequest({ key: '1234' }), pullRequest({ key: '5678' }))
+ ).toBeFalsy();
});
it('compares branches', () => {
}
function shortLivingBranch(overrides?: Partial<ShortLivingBranch>): ShortLivingBranch {
- const status = { bugs: 0, codeSmells: 0, vulnerabilities: 0 };
+ const status = { bugs: 0, codeSmells: 0, qualityGateStatus: 'OK', vulnerabilities: 0 };
return {
isMain: false,
mergeBranch: 'master',
}
function pullRequest(overrides?: Partial<PullRequest>): PullRequest {
- const status = { bugs: 0, codeSmells: 0, vulnerabilities: 0 };
+ const status = { bugs: 0, codeSmells: 0, qualityGateStatus: 'OK', vulnerabilities: 0 };
return {
base: 'master',
branch: 'feature',
branches.no_support.header.text=Analyze each branch of your project separately with the Developer Edition.
branches.search_for_branches=Search for branches...
branches.pull_requests=Pull Requests
+branches.short_lived.quality_gate.description=The branch status is passed because there are no open issue. The remaining {0} issue(s) have been confirmed.
branches.short_lived_branches=Short-lived branches
branches.pull_request.for_merge_into_x_from_y=for merge into {base} from {branch}
branches.see_the_pr=See the PR