Skip to content

Implement a 'Use Last Successful Prebuild' workspace creation mode #13801

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion components/dashboard/src/contexts/FeatureFlagContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ interface FeatureFlagConfig {
const FeatureFlagContext = createContext<{
showPersistentVolumeClaimUI: boolean;
showUsageView: boolean;
showUseLastSuccessfulPrebuild: boolean;
}>({
showPersistentVolumeClaimUI: false,
showUsageView: false,
showUseLastSuccessfulPrebuild: false,
});

const FeatureFlagContextProvider: React.FC = ({ children }) => {
Expand All @@ -31,13 +33,15 @@ const FeatureFlagContextProvider: React.FC = ({ children }) => {
const team = getCurrentTeam(location, teams);
const [showPersistentVolumeClaimUI, setShowPersistentVolumeClaimUI] = useState<boolean>(false);
const [showUsageView, setShowUsageView] = useState<boolean>(false);
const [showUseLastSuccessfulPrebuild, setShowUseLastSuccessfulPrebuild] = useState<boolean>(false);

useEffect(() => {
if (!user) return;
(async () => {
const featureFlags: FeatureFlagConfig = {
persistent_volume_claim: { defaultValue: true, setter: setShowPersistentVolumeClaimUI },
usage_view: { defaultValue: false, setter: setShowUsageView },
showUseLastSuccessfulPrebuild: { defaultValue: false, setter: setShowUseLastSuccessfulPrebuild },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the current pattern we want to use for Feature Flag names? I thought it'd be snake_case? But might be wrong! 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a debate (internal) about this currently 🙂

};
for (const [flagName, config] of Object.entries(featureFlags)) {
if (teams) {
Expand Down Expand Up @@ -69,7 +73,9 @@ const FeatureFlagContextProvider: React.FC = ({ children }) => {
}, [user, teams, team, project]);

return (
<FeatureFlagContext.Provider value={{ showPersistentVolumeClaimUI, showUsageView }}>
<FeatureFlagContext.Provider
value={{ showPersistentVolumeClaimUI, showUsageView, showUseLastSuccessfulPrebuild }}
>
{children}
</FeatureFlagContext.Provider>
);
Expand Down
14 changes: 14 additions & 0 deletions components/dashboard/src/start/CreateWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { BillingAccountSelector } from "../components/BillingAccountSelector";
import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution";
import { TeamsContext } from "../teams/teams-context";
import Alert from "../components/Alert";
import { FeatureFlagContext } from "../contexts/FeatureFlagContext";

export interface CreateWorkspaceProps {
contextUrl: string;
Expand Down Expand Up @@ -269,6 +270,9 @@ export default class CreateWorkspace extends React.Component<CreateWorkspaceProp
return (
<RunningPrebuildView
runningPrebuild={result.runningWorkspacePrebuild}
onUseLastSuccessfulPrebuild={() =>
this.createWorkspace(CreateWorkspaceMode.UseLastSuccessfulPrebuild)
}
onIgnorePrebuild={() => this.createWorkspace(CreateWorkspaceMode.ForceNew)}
onPrebuildSucceeded={() => this.createWorkspace(CreateWorkspaceMode.UsePrebuild)}
/>
Expand Down Expand Up @@ -531,12 +535,14 @@ interface RunningPrebuildViewProps {
starting: RunningWorkspacePrebuildStarting;
sameCluster: boolean;
};
onUseLastSuccessfulPrebuild: () => void;
onIgnorePrebuild: () => void;
onPrebuildSucceeded: () => void;
}

function RunningPrebuildView(props: RunningPrebuildViewProps) {
const workspaceId = props.runningPrebuild.workspaceID;
const { showUseLastSuccessfulPrebuild } = useContext(FeatureFlagContext);

useEffect(() => {
const disposables = new DisposableCollection();
Expand Down Expand Up @@ -565,6 +571,14 @@ function RunningPrebuildView(props: RunningPrebuildViewProps) {
{/* TODO(gpl) Copied around in Start-/CreateWorkspace. This should properly go somewhere central. */}
<div className="h-full mt-6 w-11/12 lg:w-3/5">
<PrebuildLogs workspaceId={workspaceId} onIgnorePrebuild={props.onIgnorePrebuild}>
{showUseLastSuccessfulPrebuild && (
<button
className="secondary"
onClick={() => props.onUseLastSuccessfulPrebuild && props.onUseLastSuccessfulPrebuild()}
>
Use Last Successful Prebuild
</button>
)}
<button className="secondary" onClick={() => props.onIgnorePrebuild && props.onIgnorePrebuild()}>
Skip Prebuild
</button>
Expand Down
1 change: 0 additions & 1 deletion components/gitpod-protocol/src/experiments/configcat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export const USER_ID_ATTRIBUTE = "user_id";
export const PROJECT_ID_ATTRIBUTE = "project_id";
export const TEAM_ID_ATTRIBUTE = "team_id";
export const TEAM_NAME_ATTRIBUTE = "team_name";
export const TEAM_NAMES_ATTRIBUTE = "team_names";
export const BILLING_TIER_ATTRIBUTE = "billing_tier";

export class ConfigCatClient implements Client {
Expand Down
9 changes: 7 additions & 2 deletions components/gitpod-protocol/src/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1111,13 +1111,16 @@ export namespace SnapshotContext {
}
}

export interface StartPrebuildContext extends WorkspaceContext {
actual: WorkspaceContext;
export interface WithCommitHistory {
commitHistory?: string[];
additionalRepositoryCommitHistories?: {
cloneUrl: string;
commitHistory: string[];
}[];
}

export interface StartPrebuildContext extends WorkspaceContext, WithCommitHistory {
actual: WorkspaceContext;
project?: Project;
branch?: string;
}
Expand Down Expand Up @@ -1382,6 +1385,8 @@ export enum CreateWorkspaceMode {
UsePrebuild = "use-prebuild",
// SelectIfRunning returns a list of currently running workspaces for the context URL if there are any, otherwise falls back to Default mode
SelectIfRunning = "select-if-running",
// UseLastSuccessfulPrebuild returns ...
UseLastSuccessfulPrebuild = "use-last-successful-prebuild",
}

export namespace WorkspaceCreationResult {
Expand Down
2 changes: 2 additions & 0 deletions components/server/ee/src/container-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { PrebuildStatusMaintainer } from "./prebuilds/prebuilt-status-maintainer
import { GitLabApp } from "./prebuilds/gitlab-app";
import { BitbucketApp } from "./prebuilds/bitbucket-app";
import { GitHubEnterpriseApp } from "./prebuilds/github-enterprise-app";
import { IncrementalPrebuildsService } from "./prebuilds/incremental-prebuilds-service";
import { IPrefixContextParser } from "../../src/workspace/context-parser";
import { StartPrebuildContextParser } from "./prebuilds/start-prebuild-context-parser";
import { WorkspaceFactory } from "../../src/workspace/workspace-factory";
Expand Down Expand Up @@ -83,6 +84,7 @@ export const productionEEContainerModule = new ContainerModule((bind, unbind, is
bind(BitbucketAppSupport).toSelf().inSingletonScope();
bind(GitHubEnterpriseApp).toSelf().inSingletonScope();
bind(BitbucketServerApp).toSelf().inSingletonScope();
bind(IncrementalPrebuildsService).toSelf().inSingletonScope();

bind(UserCounter).toSelf().inSingletonScope();

Expand Down
175 changes: 175 additions & 0 deletions components/server/ee/src/prebuilds/incremental-prebuilds-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jankeromnes Any changes in this file? Or is it a "pure move"? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new file, composed of 3 pre-existing code sections. Here are the relevant diffs:

getCommitHistoryForContext diff
--- get-commit-history-1        2022-10-18 09:42:59.685989248 +0000
+++ get-commit-history-2        2022-10-18 09:41:19.713994670 +0000
@@ -1,18 +1,18 @@
 const maxDepth = this.config.incrementalPrebuilds.commitHistory;
 const hostContext = this.hostContextProvider.get(context.repository.host);
 const repoProvider = hostContext?.services?.repositoryProvider;
-if (repoProvider) {
-    prebuildContext.commitHistory = await repoProvider.getCommitHistory(
+if (!repoProvider) {
+    return {};
+}
+const history: WithCommitHistory = {};
+history.commitHistory = await repoProvider.getCommitHistory(
         user,
         context.repository.owner,
         context.repository.name,
         context.revision,
         maxDepth,
     );
-    if (
-        context.additionalRepositoryCheckoutInfo &&
-        context.additionalRepositoryCheckoutInfo.length > 0
-    ) {
+if (context.additionalRepositoryCheckoutInfo && context.additionalRepositoryCheckoutInfo.length > 0) {
         const histories = context.additionalRepositoryCheckoutInfo.map(async (info) => {
             const commitHistory = await repoProvider.getCommitHistory(
                 user,
@@ -26,5 +26,6 @@ if (repoProvider) {
                 commitHistory,
             };
         });
-        prebuildContext.additionalRepositoryCommitHistories = await Promise.all(histories);
+    history.additionalRepositoryCommitHistories = await Promise.all(histories);
     }
findGoodBaseForIncrementalBuild diff
--- find-good-base-1    2022-10-18 09:51:32.557961085 +0000
+++ find-good-base-2    2022-10-18 09:41:40.157993561 +0000
@@ -1,23 +1,23 @@
-if (context.commitHistory && context.commitHistory.length > 0) {
+if (!history.commitHistory || history.commitHistory.length < 1) {
+    return;
+}
+
+const { config } = await this.configProvider.fetchConfig({}, user, context);
+const imageSource = await this.imageSourceProvider.getImageSource({}, user, context, config);
+
     // Note: This query returns only not-garbage-collected prebuilds in order to reduce cardinality
     // (e.g., at the time of writing, the Gitpod repository has 16K+ prebuilds, but only ~300 not-garbage-collected)
-    const recentPrebuilds = await this.db.trace({ span }).findPrebuildsWithWorkpace(commitContext.repository.cloneUrl);
-    const loggedContext = filterForLogging(context);
+const recentPrebuilds = await this.workspaceDB.findPrebuildsWithWorkpace(context.repository.cloneUrl);
     for (const recentPrebuild of recentPrebuilds) {
         if (
-            !(await this.isGoodBaseforIncrementalPrebuild(
-                context,
+        await this.isGoodBaseforIncrementalBuild(
+            history,
                 config,
                 imageSource,
                 recentPrebuild.prebuild,
                 recentPrebuild.workspace,
-            ))
+        )
         ) {
-            log.debug({ userId: user.id }, "Not using incremental prebuild base", {
-                candidatePrebuildId: recentPrebuild.prebuild.id,
-                context: loggedContext,
-            });
-            continue;
-        }
+        return recentPrebuild.prebuild;
     }
 }
isGoodBaseForIncrementalBuild diff
--- is-good-base-1      2022-10-18 09:44:50.477983240 +0000
+++ is-good-base-2      2022-10-18 09:42:00.273992470 +0000
@@ -1,7 +1,7 @@
-if (!context.commitHistory || context.commitHistory.length === 0) {
+if (!history.commitHistory || history.commitHistory.length === 0) {
     return false;
 }
-if (!CommitContext.is(candidate.context)) {
+if (!CommitContext.is(candidateWorkspace.context)) {
     return false;
 }
 
@@ -11,23 +11,26 @@ if (candidatePrebuild.state !== "availab
 }
 
 // we are only considering full prebuilds
-if (!!candidate.basedOnPrebuildId) {
+if (!!candidateWorkspace.basedOnPrebuildId) {
     return false;
 }
 
-const candidateCtx = candidate.context;
-if (candidateCtx.additionalRepositoryCheckoutInfo?.length !== context.additionalRepositoryCommitHistories?.length) {
+if (
+    candidateWorkspace.context.additionalRepositoryCheckoutInfo?.length !==
+    history.additionalRepositoryCommitHistories?.length
+) {
     // different number of repos
     return false;
 }
 
-if (!context.commitHistory.some((sha) => sha === candidateCtx.revision)) {
+const candidateCtx = candidateWorkspace.context;
+if (!history.commitHistory.some((sha) => sha === candidateCtx.revision)) {
     return false;
 }
 
 // check the commits are included in the commit history
-for (const subRepo of candidateCtx.additionalRepositoryCheckoutInfo || []) {
-    const matchIngRepo = context.additionalRepositoryCommitHistories?.find(
+for (const subRepo of candidateWorkspace.context.additionalRepositoryCheckoutInfo || []) {
+    const matchIngRepo = history.additionalRepositoryCommitHistories?.find(
         (repo) => repo.cloneUrl === subRepo.repository.cloneUrl,
     );
     if (!matchIngRepo || !matchIngRepo.commitHistory.some((sha) => sha === subRepo.revision)) {
@@ -36,10 +39,10 @@ for (const subRepo of candidateCtx.addit
 }
 
 // ensure the image source hasn't changed (skips older images)
-if (JSON.stringify(imageSource) !== JSON.stringify(candidate.imageSource)) {
+if (JSON.stringify(imageSource) !== JSON.stringify(candidateWorkspace.imageSource)) {
     log.debug(`Skipping parent prebuild: Outdated image`, {
         imageSource,
-        parentImageSource: candidate.imageSource,
+        parentImageSource: candidateWorkspace.imageSource,
     });
     return false;
 }
@@ -55,7 +58,7 @@ const filterPrebuildTasks = (tasks: Task
         )
         .filter((task) => Object.keys(task).length > 0);
 const prebuildTasks = filterPrebuildTasks(config.tasks);
-const parentPrebuildTasks = filterPrebuildTasks(candidate.config.tasks);
+const parentPrebuildTasks = filterPrebuildTasks(candidateWorkspace.config.tasks);
 if (JSON.stringify(prebuildTasks) !== JSON.stringify(parentPrebuildTasks)) {
     log.debug(`Skipping parent prebuild: Outdated prebuild tasks`, {
         prebuildTasks,

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would have been great to see this diff surfaced in the PR, ideally by making the move a separate PR, or at least a separate commit. 😕
Only now I notice that fetchConfig was pulled into findGoodBaseForIncrementalBuild, which feels a bit strange, because now there is a disconnect between these two lines [1, 2]. 🤔

Something for a follow-up?

Copy link
Contributor Author

@jankeromnes jankeromnes Oct 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @geropl!

Would have been great to see this diff surfaced in the PR, ideally by making the move a separate PR, or at least a separate commit. 😕

True, I agree that code moves and code changes would ideally be made in separate commits. 💯 (But unfortunately, I squashed my commits, to make resolving some merge conflicts easier.)

Only now I notice that fetchConfig was pulled into findGoodBaseForIncrementalBuild, which feels a bit strange, because now there is a disconnect between these two lines [1, 2]. 🤔

Indeed, you're right about the fetchConfig being moved. And this has the unfortunate consequence of calling fetchConfig twice now [1, 2]. This could be resolved by allowing to pass an optional config to findGoodBaseForIncrementalBuild.

However, I don't understand what you mean by "disconnect". These two lines still do what was intended, right? (I.e., we fetch the config for the current context, then we find a potentially older prebuild, but we "fix" the created workspace by forcing its config back to the most recent state.)

FYI, this was done to fix a bug where, during incremental prebuilds, a prebuild somehow got a config with an outdated command, and the new workspace would run the outdated command on start-up even though the .gitpod.yml in the workspace and Git history both had the more recent command.

I think that bug is still adequately handled in the new version of the code. Does this explanation resolve the "disconnect" you saw?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With "disconnect" I mean that we should be using the exact same config being used for the prebuild and for identifying the prebuild.
Now that we're doing it twice that might for some CommitContexts (e.g., PR/branch context) lead to situations where config is out of sync here. This a) makes it harder to reason about the code, and b) opens up possibility for current (or future) bugs.

Copy link
Contributor Author

@jankeromnes jankeromnes Oct 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explaining! I don't fully understand how the configs could get out-of-sync (because we only fetch a read-only config, i.e. a .gitpod.yml from the repo, for the single context that we currently want to open, regardless of which prebuild or incremental prebuild we end up using -- we do occasionally fetch the same config multiple times, but we never modify it).

Maybe, going back to fetching it just once here, and passing it along to findGoodBaseForIncrementalBuild would solve your concern? (I.e. then we keep exactly one config object in this flow as before.)

* Copyright (c) 2022 Gitpod GmbH. All rights reserved.
* Licensed under the GNU Affero General Public License (AGPL).
* See License-AGPL.txt in the project root for license information.
*/

import { inject, injectable } from "inversify";
import {
CommitContext,
PrebuiltWorkspace,
TaskConfig,
User,
Workspace,
WorkspaceConfig,
WorkspaceImageSource,
} from "@gitpod/gitpod-protocol";
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
import { WithCommitHistory } from "@gitpod/gitpod-protocol/src/protocol";
import { WorkspaceDB } from "@gitpod/gitpod-db/lib";
import { Config } from "../../../src/config";
import { ConfigProvider } from "../../../src/workspace/config-provider";
import { HostContextProvider } from "../../../src/auth/host-context-provider";
import { ImageSourceProvider } from "../../../src/workspace/image-source-provider";

@injectable()
export class IncrementalPrebuildsService {
@inject(Config) protected readonly config: Config;
@inject(ConfigProvider) protected readonly configProvider: ConfigProvider;
@inject(HostContextProvider) protected readonly hostContextProvider: HostContextProvider;
@inject(ImageSourceProvider) protected readonly imageSourceProvider: ImageSourceProvider;
@inject(WorkspaceDB) protected readonly workspaceDB: WorkspaceDB;

public async getCommitHistoryForContext(context: CommitContext, user: User): Promise<WithCommitHistory> {
const maxDepth = this.config.incrementalPrebuilds.commitHistory;
const hostContext = this.hostContextProvider.get(context.repository.host);
const repoProvider = hostContext?.services?.repositoryProvider;
if (!repoProvider) {
return {};
}
const history: WithCommitHistory = {};
history.commitHistory = await repoProvider.getCommitHistory(
user,
context.repository.owner,
context.repository.name,
context.revision,
maxDepth,
);
if (context.additionalRepositoryCheckoutInfo && context.additionalRepositoryCheckoutInfo.length > 0) {
const histories = context.additionalRepositoryCheckoutInfo.map(async (info) => {
const commitHistory = await repoProvider.getCommitHistory(
user,
info.repository.owner,
info.repository.name,
info.revision,
maxDepth,
);
return {
cloneUrl: info.repository.cloneUrl,
commitHistory,
};
});
history.additionalRepositoryCommitHistories = await Promise.all(histories);
}
return history;
}

public async findGoodBaseForIncrementalBuild(
context: CommitContext,
history: WithCommitHistory,
user: User,
): Promise<PrebuiltWorkspace | undefined> {
if (!history.commitHistory || history.commitHistory.length < 1) {
return;
}

const { config } = await this.configProvider.fetchConfig({}, user, context);
const imageSource = await this.imageSourceProvider.getImageSource({}, user, context, config);

// Note: This query returns only not-garbage-collected prebuilds in order to reduce cardinality
// (e.g., at the time of writing, the Gitpod repository has 16K+ prebuilds, but only ~300 not-garbage-collected)
const recentPrebuilds = await this.workspaceDB.findPrebuildsWithWorkpace(context.repository.cloneUrl);
for (const recentPrebuild of recentPrebuilds) {
if (
await this.isGoodBaseforIncrementalBuild(
history,
config,
imageSource,
recentPrebuild.prebuild,
recentPrebuild.workspace,
)
) {
return recentPrebuild.prebuild;
}
}
}

protected async isGoodBaseforIncrementalBuild(
history: WithCommitHistory,
config: WorkspaceConfig,
imageSource: WorkspaceImageSource,
candidatePrebuild: PrebuiltWorkspace,
candidateWorkspace: Workspace,
): Promise<boolean> {
if (!history.commitHistory || history.commitHistory.length === 0) {
return false;
}
if (!CommitContext.is(candidateWorkspace.context)) {
return false;
}

// we are only considering available prebuilds
if (candidatePrebuild.state !== "available") {
return false;
}

// we are only considering full prebuilds
if (!!candidateWorkspace.basedOnPrebuildId) {
return false;
}

if (
candidateWorkspace.context.additionalRepositoryCheckoutInfo?.length !==
history.additionalRepositoryCommitHistories?.length
) {
// different number of repos
return false;
}

const candidateCtx = candidateWorkspace.context;
if (!history.commitHistory.some((sha) => sha === candidateCtx.revision)) {
return false;
}

// check the commits are included in the commit history
for (const subRepo of candidateWorkspace.context.additionalRepositoryCheckoutInfo || []) {
const matchIngRepo = history.additionalRepositoryCommitHistories?.find(
(repo) => repo.cloneUrl === subRepo.repository.cloneUrl,
);
if (!matchIngRepo || !matchIngRepo.commitHistory.some((sha) => sha === subRepo.revision)) {
return false;
}
}

// ensure the image source hasn't changed (skips older images)
if (JSON.stringify(imageSource) !== JSON.stringify(candidateWorkspace.imageSource)) {
log.debug(`Skipping parent prebuild: Outdated image`, {
imageSource,
parentImageSource: candidateWorkspace.imageSource,
});
return false;
}

// ensure the tasks haven't changed
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 prebuildTasks = filterPrebuildTasks(config.tasks);
const parentPrebuildTasks = filterPrebuildTasks(candidateWorkspace.config.tasks);
if (JSON.stringify(prebuildTasks) !== JSON.stringify(parentPrebuildTasks)) {
log.debug(`Skipping parent prebuild: Outdated prebuild tasks`, {
prebuildTasks,
parentPrebuildTasks,
});
return false;
}

return true;
}
}
41 changes: 11 additions & 30 deletions components/server/ee/src/prebuilds/prebuild-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { inject, injectable } from "inversify";
import * as opentracing from "opentracing";
import { StopWorkspacePolicy } from "@gitpod/ws-manager/lib";
import { error } from "console";
import { IncrementalPrebuildsService } from "./incremental-prebuilds-service";

export class WorkspaceRunningError extends Error {
constructor(msg: string, public instance: WorkspaceInstance) {
Expand All @@ -59,6 +60,7 @@ export class PrebuildManager {
@inject(ConfigProvider) protected readonly configProvider: ConfigProvider;
@inject(Config) protected readonly config: Config;
@inject(ProjectsService) protected readonly projectService: ProjectsService;
@inject(IncrementalPrebuildsService) protected readonly incrementalPrebuildsService: IncrementalPrebuildsService;

async abortPrebuildsForBranch(ctx: TraceContext, project: Project, user: User, branch: string): Promise<void> {
const span = TraceContext.startSpan("abortPrebuildsForBranch", ctx);
Expand Down Expand Up @@ -172,36 +174,15 @@ export class PrebuildManager {
};

if (this.shouldPrebuildIncrementally(context.repository.cloneUrl, project)) {
const maxDepth = this.config.incrementalPrebuilds.commitHistory;
const hostContext = this.hostContextProvider.get(context.repository.host);
const repoProvider = hostContext?.services?.repositoryProvider;
if (repoProvider) {
prebuildContext.commitHistory = await repoProvider.getCommitHistory(
user,
context.repository.owner,
context.repository.name,
context.revision,
maxDepth,
);
if (
context.additionalRepositoryCheckoutInfo &&
context.additionalRepositoryCheckoutInfo.length > 0
) {
const histories = context.additionalRepositoryCheckoutInfo.map(async (info) => {
const commitHistory = await repoProvider.getCommitHistory(
user,
info.repository.owner,
info.repository.name,
info.revision,
maxDepth,
);
return {
cloneUrl: info.repository.cloneUrl,
commitHistory,
};
});
prebuildContext.additionalRepositoryCommitHistories = await Promise.all(histories);
}
// We store the commit histories in the `StartPrebuildContext` in order to pass them down to
// `WorkspaceFactoryEE.createForStartPrebuild`.
const { commitHistory, additionalRepositoryCommitHistories } =
await this.incrementalPrebuildsService.getCommitHistoryForContext(context, user);
if (commitHistory) {
prebuildContext.commitHistory = commitHistory;
}
if (additionalRepositoryCommitHistories) {
prebuildContext.additionalRepositoryCommitHistories = additionalRepositoryCommitHistories;
}
}

Expand Down
Loading