diff --git a/components/dashboard/src/projects/Prebuild.tsx b/components/dashboard/src/projects/Prebuild.tsx index c36ffd7e58987d..e46ad41e96f455 100644 --- a/components/dashboard/src/projects/Prebuild.tsx +++ b/components/dashboard/src/projects/Prebuild.tsx @@ -156,39 +156,42 @@ export default function () {
- {["aborted", "timeout", "failed"].includes(prebuild?.status || "") || !!prebuild?.error ? ( - - ) : ["building", "queued"].includes(prebuild?.status || "") ? ( + {["building", "queued"].includes(prebuild?.status || "") ? ( - ) : prebuild?.status === "available" ? ( - - - ) : ( - + <> + + {prebuild?.status === "available" ? ( + + + + ) : ( + + )} + )}
diff --git a/components/dashboard/src/projects/Prebuilds.tsx b/components/dashboard/src/projects/Prebuilds.tsx index e86d47e1698dd5..570e5145b5fb4b 100644 --- a/components/dashboard/src/projects/Prebuilds.tsx +++ b/components/dashboard/src/projects/Prebuilds.tsx @@ -39,6 +39,7 @@ export default function (props: { project?: Project; isAdminDashboard?: boolean const [isLoadingPrebuilds, setIsLoadingPrebuilds] = useState(true); const [prebuilds, setPrebuilds] = useState([]); + const [isRunningPrebuild, setIsRunningPrebuild] = useState(false); useEffect(() => { let registration: Disposable; @@ -139,11 +140,18 @@ export default function (props: { project?: Project; isAdminDashboard?: boolean return -1; }; - const triggerPrebuild = (branchName: string | null) => { + const runPrebuild = async (branchName: string | null) => { if (!project) { return; } - getGitpodService().server.triggerPrebuild(project.id, branchName); + setIsRunningPrebuild(true); + try { + await getGitpodService().server.triggerPrebuild(project.id, branchName); + } catch (error) { + console.error("Could not run prebuild", error); + } finally { + setIsRunningPrebuild(false); + } }; const formatDate = (date: string | undefined) => { @@ -182,9 +190,16 @@ export default function (props: { project?: Project; isAdminDashboard?: boolean
- {!isLoadingPrebuilds && prebuilds.length === 0 && !props.isAdminDashboard && ( - )} diff --git a/components/dashboard/src/projects/Project.tsx b/components/dashboard/src/projects/Project.tsx index a39d64aa916c5b..99e3bf7324dae0 100644 --- a/components/dashboard/src/projects/Project.tsx +++ b/components/dashboard/src/projects/Project.tsx @@ -388,20 +388,7 @@ export default function () { triggerPrebuild(branch), - }, - ] - : prebuild.status === "building" + prebuild?.status === "queued" || prebuild?.status === "building" ? [ { title: "Cancel Prebuild", @@ -411,7 +398,14 @@ export default function () { prebuild && cancelPrebuild(prebuild.info.id), }, ] - : [] + : [ + { + title: `${prebuild ? "Rerun" : "Run"} Prebuild (${ + branch.name + })`, + onClick: () => triggerPrebuild(branch), + }, + ] } /> diff --git a/components/server/ee/src/prebuilds/prebuild-manager.ts b/components/server/ee/src/prebuilds/prebuild-manager.ts index 167ed9f1d4a6bc..be6ba74e81ab12 100644 --- a/components/server/ee/src/prebuilds/prebuild-manager.ts +++ b/components/server/ee/src/prebuilds/prebuild-manager.ts @@ -134,34 +134,37 @@ export class PrebuildManager { `Running prebuilds without a project is no longer supported. Please add '${cloneURL}' as a project in a Gitpod team.`, ); } - const existingPB = await this.findNonFailedPrebuiltWorkspace({ span }, cloneURL, commitSHAIdentifier); - // If the existing prebuild is failed, it will be retriggered in the afterwards const config = await this.fetchConfig({ span }, user, context); - if (existingPB) { - // If the existing prebuild is based on an outdated project config, we also want to retrigger it. - const existingPBWS = await this.workspaceDB.trace({ span }).findById(existingPB.buildWorkspaceId); - const existingConfig = existingPBWS?.config; - log.debug( - `startPrebuild | commits: ${commitSHAIdentifier}, existingPB: ${ - existingPB.id - }, existingConfig: ${JSON.stringify(existingConfig)}, newConfig: ${JSON.stringify(config)}}`, - ); - const filterPrebuildTasks = (tasks: TaskConfig[] = []) => - tasks - .map((task) => - Object.keys(task) - .filter((key) => ["before", "init", "prebuild"].includes(key)) - // @ts-ignore - .reduce((obj, key) => ({ ...obj, [key]: task[key] }), {}), - ) - .filter((task) => Object.keys(task).length > 0); - const isSameConfig = - JSON.stringify(filterPrebuildTasks(existingConfig?.tasks)) === - JSON.stringify(filterPrebuildTasks(config?.tasks)); - // If there is an existing prebuild that isn't failed and it's based on the current config, we return it here instead of triggering a new prebuild. - if (isSameConfig) { - return { prebuildId: existingPB.id, wsid: existingPB.buildWorkspaceId, done: true }; + + if (!forcePrebuild) { + // Check for an existing, successful prebuild, before triggering a new one. + const existingPB = await this.findNonFailedPrebuiltWorkspace({ span }, cloneURL, commitSHAIdentifier); + if (existingPB) { + // But if the existing prebuild is failed, or based on an outdated config, it will still be retriggered below. + const existingPBWS = await this.workspaceDB.trace({ span }).findById(existingPB.buildWorkspaceId); + const existingConfig = existingPBWS?.config; + log.debug( + `startPrebuild | commits: ${commitSHAIdentifier}, existingPB: ${ + existingPB.id + }, existingConfig: ${JSON.stringify(existingConfig)}, newConfig: ${JSON.stringify(config)}}`, + ); + const filterPrebuildTasks = (tasks: TaskConfig[] = []) => + tasks + .map((task) => + Object.keys(task) + .filter((key) => ["before", "init", "prebuild"].includes(key)) + // @ts-ignore + .reduce((obj, key) => ({ ...obj, [key]: task[key] }), {}), + ) + .filter((task) => Object.keys(task).length > 0); + const isSameConfig = + JSON.stringify(filterPrebuildTasks(existingConfig?.tasks)) === + JSON.stringify(filterPrebuildTasks(config?.tasks)); + // If there is an existing prebuild that isn't failed and it's based on the current config, we return it here instead of triggering a new prebuild. + if (isSameConfig) { + return { prebuildId: existingPB.id, wsid: existingPB.buildWorkspaceId, done: true }; + } } } if (project && context.ref && !project.settings?.keepOutdatedPrebuildsRunning) {