Skip to content

Commit

Permalink
[prebuild] Support opening a specfic prebuild
Browse files Browse the repository at this point in the history
  • Loading branch information
csweichel committed Oct 13, 2022
1 parent 6fb1ac0 commit a8bb384
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 7 deletions.
8 changes: 5 additions & 3 deletions components/dashboard/src/projects/Prebuild.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,14 @@ export default function () {
) : prebuild?.status === "available" ? (
<a
className="my-auto"
href={gitpodHostUrl.withContext(`${prebuild?.info.changeUrl}`).toString()}
href={gitpodHostUrl
.withContext(`open-prebuild/${prebuild?.info.id}/${prebuild?.info.changeUrl}`)
.toString()}
>
<button>New Workspace ({prebuild?.info.branch})</button>
<button>New Workspace (with this prebuild)</button>
</a>
) : (
<button disabled={true}>New Workspace ({prebuild?.info.branch})</button>
<button disabled={true}>New Workspace (with this prebuild)</button>
)}
</PrebuildLogs>
</div>
Expand Down
10 changes: 10 additions & 0 deletions components/gitpod-protocol/src/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,16 @@ export namespace AdditionalContentContext {
}
}

export interface OpenPrebuildContext extends WorkspaceContext {
openPrebuildID: string;
}

export namespace OpenPrebuildContext {
export function is(ctx: any): ctx is OpenPrebuildContext {
return "openPrebuildID" in ctx;
}
}

export interface CommitContext extends WorkspaceContext, GitCheckoutInfo {
/** @deprecated Moved to .repository.cloneUrl, left here for backwards-compatibility for old workspace contextes in the DB */
cloneUrl?: string;
Expand Down
19 changes: 15 additions & 4 deletions components/server/ee/src/workspace/gitpod-server-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
TeamMemberRole,
WORKSPACE_TIMEOUT_DEFAULT_SHORT,
PrebuildEvent,
OpenPrebuildContext,
} from "@gitpod/gitpod-protocol";
import { ResponseError } from "vscode-jsonrpc";
import {
Expand Down Expand Up @@ -963,9 +964,19 @@ export class GitpodServerEEImpl extends GitpodServerImpl {

const logCtx: LogContext = { userId: user.id };
const cloneUrl = context.repository.cloneUrl;
const prebuiltWorkspace = await this.workspaceDb
.trace(ctx)
.findPrebuiltWorkspaceByCommit(cloneUrl, commitSHAs);
let prebuiltWorkspace: PrebuiltWorkspace | undefined;
if (OpenPrebuildContext.is(context)) {
prebuiltWorkspace = await this.workspaceDb.trace(ctx).findPrebuildByID(context.openPrebuildID);
if (prebuiltWorkspace?.cloneURL !== cloneUrl) {
// prevent users from opening arbitrary prebuilds this way - they must match the clone URL so that the resource guards are correct.
return;
}
} else {
prebuiltWorkspace = await this.workspaceDb
.trace(ctx)
.findPrebuiltWorkspaceByCommit(cloneUrl, commitSHAs);
}

const logPayload = { mode, cloneUrl, commit: commitSHAs, prebuiltWorkspace };
log.debug(logCtx, "Looking for prebuilt workspace: ", logPayload);
if (!prebuiltWorkspace) {
Expand Down Expand Up @@ -994,7 +1005,7 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
const makeResult = (instanceID: string): WorkspaceCreationResult => {
return <WorkspaceCreationResult>{
runningWorkspacePrebuild: {
prebuildID: prebuiltWorkspace.id,
prebuildID: prebuiltWorkspace!.id,
workspaceID,
instanceID,
starting: "queued",
Expand Down
13 changes: 13 additions & 0 deletions components/server/ee/src/workspace/workspace-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
PrebuiltWorkspace,
WorkspaceConfig,
WorkspaceImageSource,
OpenPrebuildContext,
} from "@gitpod/gitpod-protocol";
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
import { LicenseEvaluator } from "@gitpod/licensor/lib";
Expand Down Expand Up @@ -373,6 +374,18 @@ export class WorkspaceFactoryEE extends WorkspaceFactory {
config._featureFlags = (config._featureFlags || []).concat(["persistent_volume_claim"]);
}

if (OpenPrebuildContext.is(context.originalContext)) {
// Because of incremental prebuilds, createForContext will take over the original context.
// To ensure we get the right commit when forcing a prebuild, we force the context here.
context.originalContext = buildWorkspace.context;

if (CommitContext.is(context.originalContext)) {
// We force the checkout of the revision rather than the ref/branch.
// Otherwise we'd the correct prebuild with the "wrong" Git status.
delete context.originalContext.ref;
}
}

const id = await this.generateWorkspaceID(context);
const newWs: Workspace = {
id,
Expand Down
2 changes: 2 additions & 0 deletions components/server/src/container-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ import { LivenessController } from "./liveness/liveness-controller";
import { IDEServiceClient, IDEServiceDefinition } from "@gitpod/ide-service-api/lib/ide.pb";
import { prometheusClientMiddleware } from "@gitpod/gitpod-protocol/lib/util/nice-grpc";
import { UsageService } from "./user/usage-service";
import { OpenPrebuildPrefixContextParser } from "./workspace/open-prebuild-prefix-context-parser";

export const productionContainerModule = new ContainerModule((bind, unbind, isBound, rebind) => {
bind(Config).toConstantValue(ConfigFile.fromFile());
Expand Down Expand Up @@ -189,6 +190,7 @@ export const productionContainerModule = new ContainerModule((bind, unbind, isBo
bind(IPrefixContextParser).to(EnvvarPrefixParser).inSingletonScope();
bind(IPrefixContextParser).to(ImageBuildPrefixContextParser).inSingletonScope();
bind(IPrefixContextParser).to(AdditionalContentPrefixContextParser).inSingletonScope();
bind(IPrefixContextParser).to(OpenPrebuildPrefixContextParser).inSingletonScope();

bind(GitTokenScopeGuesser).toSelf().inSingletonScope();
bind(GitTokenValidator).toSelf().inSingletonScope();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright (c) 2021 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 { User, WorkspaceContext } from "@gitpod/gitpod-protocol";
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
import { OpenPrebuildContext } from "@gitpod/gitpod-protocol/src/protocol";
import { inject, injectable } from "inversify";
import { Config } from "../config";
import { IPrefixContextParser } from "./context-parser";

@injectable()
export class OpenPrebuildPrefixContextParser implements IPrefixContextParser {
@inject(Config) protected readonly config: Config;
static PREFIX = /^\/?open-prebuild\/([^\/]*)\//;

findPrefix(user: User, context: string): string | undefined {
const result = OpenPrebuildPrefixContextParser.PREFIX.exec(context);
if (!result) {
return undefined;
}
return result[0];
}

public async handle(user: User, prefix: string, context: WorkspaceContext): Promise<WorkspaceContext> {
const match = OpenPrebuildPrefixContextParser.PREFIX.exec(prefix);
if (!match) {
log.error("Could not parse prefix " + prefix);
return context;
}

(context as OpenPrebuildContext).openPrebuildID = match[1];
return context;
}
}

0 comments on commit a8bb384

Please sign in to comment.