Add links to GitHub and include PR title on build info

This commit is contained in:
Tim Jacomb
2020-08-03 17:02:34 +01:00
committed by Fredrik Adelöw
parent ea15090bb3
commit c85e952300
4 changed files with 97 additions and 45 deletions
+66 -25
View File
@@ -49,22 +49,53 @@ export class JenkinsApi {
return lastBuild;
}
extractScmDetailsFromJob(jobDetails: any): any {
const scmInfo = jobDetails.actions
.filter(
(action: any) =>
action._class === 'jenkins.scm.api.metadata.ObjectMetadataAction',
)
.map((action: any) => {
return {
url: action?.objectUrl,
// https://javadoc.jenkins.io/plugin/scm-api/jenkins/scm/api/metadata/ObjectMetadataAction.html
// branch name for regular builds, pull request title on pull requests
displayName: action?.objectDisplayName,
};
})
.pop();
return scmInfo;
}
async getJob(jobName: string) {
return this.jenkins.job.get({
name: jobName,
depth: 1,
});
}
async getFolder(folderName: string) {
const folder = await this.jenkins.job.get(folderName);
const results = [];
for (const jobSummary of folder.jobs) {
const jobDetails = await this.jenkins.job.get(
`${folderName}/${jobSummary.name}`,
);
const jobDetails = await this.jenkins.job.get({
name: `${folderName}/${jobSummary.name}`,
depth: 1,
});
const jobScmInfo = this.extractScmDetailsFromJob(jobDetails);
if (jobDetails.jobs) {
// skipping folders inside folders for now
} else {
for (const buildDetails of jobDetails.builds) {
const build = await this.jenkins.build.get(
`${folderName}/${jobSummary.name}`,
buildDetails.number,
);
const ciTable = this.mapJenkinsBuildToCITable(build);
const build = await this.jenkins.build.get({
name: `${folderName}/${jobSummary.name}`,
number: buildDetails.number,
depth: 1,
});
const ciTable = this.mapJenkinsBuildToCITable(build, jobScmInfo);
results.push(ciTable);
}
}
@@ -72,22 +103,32 @@ export class JenkinsApi {
return results;
}
private mapJenkinsBuildToCITable(jenkinsResult: any): CITableBuildInfo {
const source = jenkinsResult.actions
.filter(
(action: any) => action._class === 'hudson.plugins.git.util.BuildData',
)
.map((action: any) => {
const [first]: any = Object.values(action.buildsByBranchName);
const branch = first.revision.branch[0];
return {
branchName: branch.name,
commit: {
hash: branch.SHA1.substring(0, 8),
},
};
})
.pop();
mapJenkinsBuildToCITable(
jenkinsResult: any,
jobScmInfo?: any,
): CITableBuildInfo {
const source =
jenkinsResult.actions
.filter(
(action: any) =>
action._class === 'hudson.plugins.git.util.BuildData',
)
.map((action: any) => {
const [first]: any = Object.values(action.buildsByBranchName);
const branch = first.revision.branch[0];
return {
branchName: branch.name,
commit: {
hash: branch.SHA1.substring(0, 8),
},
};
})
.pop() || {};
if (jobScmInfo) {
source.url = jobScmInfo?.url;
source.displayName = jobScmInfo?.displayName;
}
const path = new URL(jenkinsResult.url).pathname;
@@ -112,7 +153,7 @@ export class JenkinsApi {
return buildResult;
}
private extractJobDetailsFromBuildName(buildName: string) {
extractJobDetailsFromBuildName(buildName: string) {
const trimmedBuild = buildName.replace(/\/job/g, '').replace(/\/$/, '');
const split = trimmedBuild.split('/');
@@ -22,14 +22,18 @@ import { PluginHeader } from '../../components/PluginHeader';
import { ActionOutput } from './lib/ActionOutput/ActionOutput';
import { Layout } from '../../components/Layout';
import LaunchIcon from '@material-ui/icons/Launch';
import GitHubIcon from '@material-ui/icons/GitHub';
import { useBuildWithSteps } from '../../state/useBuildWithSteps';
const IconLink = IconButton as typeof Link;
const BuildName: FC<{ build?: any }> = ({ build }) => (
<Box display="flex" alignItems="center">
{build?.fullDisplayName}
<IconLink href={build?.url} target="_blank">
<LaunchIcon />
{build?.buildName}
<IconLink href={build?.url} target="_blank" title="View on Jenkins">
<LaunchIcon /> {/* TODO use Jenkins logo*/}
</IconLink>
<IconLink href={build?.source.url} target="_blank" title="View on GitHub">
<GitHubIcon />
</IconLink>
</Box>
);
@@ -111,10 +115,9 @@ const BuildWithStepsView = () => {
startPolling();
return () => stopPolling();
}, [buildPath, startPolling, stopPolling]);
return (
<>
<PluginHeader title="Build info" />
<PluginHeader title={value?.source.displayName || 'Build details'} />
<Grid container spacing={3} direction="column">
<Grid item>
@@ -18,11 +18,8 @@ import { Link, Typography, Box, IconButton } from '@material-ui/core';
import RetryIcon from '@material-ui/icons/Replay';
import GitHubIcon from '@material-ui/icons/GitHub';
import { Link as RouterLink } from 'react-router-dom';
import {
Table,
TableColumn,
} from '@backstage/core';
import {JenkinsRunStatus} from "../Status";
import { Table, TableColumn } from '@backstage/core';
import { JenkinsRunStatus } from '../Status';
export type CITableBuildInfo = {
id: string;
@@ -30,9 +27,10 @@ export type CITableBuildInfo = {
buildUrl?: string;
source: {
branchName: string;
url: string;
displayName: string;
commit: {
hash: string;
url: string;
};
};
status: string;
@@ -41,7 +39,7 @@ export type CITableBuildInfo = {
passed: number;
skipped: number;
failed: number;
testUrl: string; // fixme better name
testUrl: string;
};
onRestartClick: () => void;
};
@@ -61,19 +59,24 @@ const generatedColumns: TableColumn[] = [
title: 'Source',
render: (row: Partial<CITableBuildInfo>) => (
<>
<p>{row.source?.branchName}</p>
<p>{row.source?.commit.hash}</p>
<p>
<Link href={row.source?.url || ''} target="_blank">
{row.source?.branchName}
</Link>
</p>
<p>{row.source?.commit?.hash}</p>
</>
),
},
{
title: 'Status',
render: (row: Partial<CITableBuildInfo>) => {
render: (row: Partial<CITableBuildInfo>) => {
return (
<Box display="flex" alignItems="center">
<JenkinsRunStatus status={row.status} />
</Box>
)},
<Box display="flex" alignItems="center">
<JenkinsRunStatus status={row.status} />
</Box>
);
},
},
{
title: 'Actions',
@@ -27,7 +27,12 @@ export function useBuildWithSteps(buildName: string) {
const getBuildWithSteps = useCallback(async () => {
try {
const build = await api.getBuild(buildName);
return Promise.resolve(build);
const { jobName } = api.extractJobDetailsFromBuildName(buildName);
const job = await api.getJob(jobName);
const jobInfo = api.extractScmDetailsFromJob(job);
return Promise.resolve(api.mapJenkinsBuildToCITable(build, jobInfo));
} catch (e) {
errorApi.post(e);
return Promise.reject(e);