Support rebuilding a build

Note that like the previous implementation, this actually triggers a build of the project, not a re-build of a given build.

Signed-off-by: Andrew Shirley <andrew.shirley@sainsburys.co.uk>
Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
Andrew Shirley
2021-06-02 18:55:25 +01:00
committed by blam
parent 64b279a55b
commit 79593909c9
5 changed files with 67 additions and 26 deletions
+29 -9
View File
@@ -62,7 +62,7 @@ export interface Project {
inQueue: string;
// added by us
status: string; // == inQueue ? 'queued' : lastBuild.building ? 'running' : lastBuild.result,
onRestartClick: () => void; // TODO handle.* ?
onRestartClick: () => Promise<void>; // TODO rename to handle.* ? also, should this be on lastBuild?
}
export interface JenkinsApi {
@@ -98,7 +98,11 @@ export interface JenkinsApi {
buildNumber: string,
): Promise<Build>;
retry(entity: EntityName, jobName: string, buildNumber: string): Promise<any>;
retry(
entity: EntityName,
jobName: string,
buildNumber: string,
): Promise<void>;
}
export class JenkinsApiImpl implements JenkinsApi {
@@ -135,7 +139,14 @@ export class JenkinsApiImpl implements JenkinsApi {
},
});
return (await response.json()).projects;
return (
(await response.json()).projects?.map((p: Project) => ({
...p,
onRestartClick: async () => {
await this.retry(entity, p.fullName, String(p.lastBuild.number));
},
})) || []
);
}
async getBuild(
@@ -160,14 +171,23 @@ export class JenkinsApiImpl implements JenkinsApi {
return (await response.json()).build;
}
retry(
// @ts-ignore unused because unimplemented
async retry(
entity: EntityName,
// @ts-ignore unused because unimplemented
jobName: string,
// @ts-ignore unused because unimplemented
buildNumber: string,
): Promise<any> {
return Promise.resolve(undefined);
): Promise<void> {
const url = `${await this.discoveryApi.getBaseUrl('jenkins')}/v1/entity/${
entity.namespace
}/${entity.kind}/${entity.name}/job/${encodeURIComponent(
jobName,
)}/${buildNumber}:rebuild`;
const idToken = await this.identityApi.getIdToken();
await fetch(url, {
method: 'POST',
headers: {
...(idToken && { Authorization: `Bearer ${idToken}` }),
},
});
}
}
@@ -48,6 +48,7 @@ const useStyles = makeStyles(theme => ({
}));
const BuildWithStepsView = () => {
// TODO: Add a test that react-router decodes this (even though `generatePath` doesn't encode it for you!)
const { jobName, buildNumber } = useRouteRefParams(buildRouteRef);
const classes = useStyles();
@@ -100,11 +100,11 @@ const generatedColumns: TableColumn[] = [
<Link
component={RouterLink}
to={generatePath(buildRouteRef.path, {
jobName: row.fullName,
buildNumber: row.lastBuild?.number.toString(),
jobName: encodeURIComponent(row.fullName),
buildNumber: String(row.lastBuild?.number),
})}
>
{row.fullName}
{row.fullDisplayName}
</Link>
);
},
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useCallback } from 'react';
import { useCallback, useMemo } from 'react';
import { useAsyncRetry } from 'react-use';
import { jenkinsApiRef } from '../api';
import { useAsyncPolling } from './useAsyncPolling';
@@ -32,7 +32,7 @@ export function useBuildWithSteps(jobName: string, buildNumber: string) {
const api = useApi(jenkinsApiRef);
const errorApi = useApi(errorApiRef);
const { entity } = useEntity();
const entityName = getEntityName(entity);
const entityName = useMemo(() => getEntityName(entity), [entity]);
const getBuildWithSteps = useCallback(async () => {
try {
@@ -43,14 +43,6 @@ export function useBuildWithSteps(jobName: string, buildNumber: string) {
}
}, [buildNumber, jobName, entityName, api, errorApi]);
const restartBuild = async () => {
try {
await api.retry(entityName, jobName, buildNumber);
} catch (e) {
errorApi.post(e);
}
};
const { loading, value, retry } = useAsyncRetry(() => getBuildWithSteps(), [
getBuildWithSteps,
]);
@@ -63,7 +55,6 @@ export function useBuildWithSteps(jobName: string, buildNumber: string) {
return [
{ loading, value, retry },
{
restartBuild,
getBuildWithSteps,
startPolling,
stopPolling,