Skip to content

Commit 766b421

Browse files
committed
[server] Extend and fix context parser tests around prebuild discovery
1 parent 286b530 commit 766b421

File tree

4 files changed

+147
-47
lines changed

4 files changed

+147
-47
lines changed

components/server/src/prebuilds/incremental-workspace-service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export class IncrementalWorkspaceService {
6666
return history;
6767
}
6868

69-
public async findGoodBaseForIncrementalBuild(
69+
public async findBaseForIncrementalWorkspace(
7070
context: CommitContext,
7171
config: WorkspaceConfig,
7272
history: WithCommitHistory,

components/server/src/prebuilds/prebuild-manager.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ export class PrebuildManager {
407407
commitHistory: repoHist.commitHistory.slice(0, prebuildInterval),
408408
})),
409409
};
410-
const prebuild = await this.incrementalPrebuildsService.findGoodBaseForIncrementalBuild(
410+
const prebuild = await this.incrementalPrebuildsService.findBaseForIncrementalWorkspace(
411411
context,
412412
config,
413413
history,
@@ -416,6 +416,7 @@ export class PrebuildManager {
416416
true,
417417
);
418418
if (prebuild) {
419+
// TODO(gpl): Why not "done: prebuild.state === "available""?
419420
return { prebuildId: prebuild.id, wsid: prebuild.buildWorkspaceId, done: true };
420421
}
421422
}

components/server/src/workspace/context-service.spec.db.ts

Lines changed: 140 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ import {
1717
StartPrebuildResult,
1818
SnapshotContext,
1919
PrebuiltWorkspaceContext,
20+
Branch,
21+
CommitInfo,
22+
Repository,
23+
RepositoryInfo,
2024
} from "@gitpod/gitpod-protocol";
2125
import * as chai from "chai";
2226
import { Container } from "inversify";
@@ -36,6 +40,7 @@ import { HostContextProvider } from "../auth/host-context-provider";
3640
import { AuthProvider } from "../auth/auth-provider";
3741
import { Experiments } from "@gitpod/gitpod-protocol/lib/experiments/configcat-server";
3842
import { SYSTEM_USER } from "../authorization/authorizer";
43+
import { RepositoryProvider } from "../repohost";
3944

4045
const expect = chai.expect;
4146

@@ -54,14 +59,98 @@ const gitpodEmptyContext = {
5459
private: false,
5560
},
5661
normalizedContextURL: "https://github.com/gitpod-io/empty",
57-
revision: "asdf",
62+
revision: "123456",
5863
title: "gitpod-io/empty - main",
5964
};
6065

66+
// MockRepositoryProvider is a class implementing the RepositoryProvider interface, which allows to pass in commitHistory and commitInfo as needed
67+
class MockRepositoryProvider implements RepositoryProvider {
68+
branches: Map<string, { branch: Branch; commits: CommitInfo[] }> = new Map();
69+
70+
addBranch(branch: Omit<Branch, "commit">, commits: CommitInfo[]) {
71+
this.branches.set(branch.name, {
72+
branch: {
73+
...branch,
74+
commit: {
75+
sha: head(commits).sha,
76+
author: head(commits).author,
77+
commitMessage: head(commits).commitMessage,
78+
},
79+
},
80+
commits,
81+
});
82+
}
83+
84+
async hasReadAccess(user: any, owner: string, repo: string): Promise<boolean> {
85+
return true;
86+
}
87+
async getBranch(user: User, owner: string, repo: string, branchName: string): Promise<Branch> {
88+
const branch = this.branches.get(branchName);
89+
if (!branch) {
90+
throw new Error("branch not found");
91+
}
92+
return branch.branch;
93+
}
94+
async getRepo(user: User, owner: string, repo: string): Promise<Repository> {
95+
return {
96+
host: "github.com",
97+
owner: "gitpod-io",
98+
name: "empty",
99+
cloneUrl: "https://github.com/gitpod-io/empty.git",
100+
defaultBranch: "main",
101+
};
102+
}
103+
async getCommitHistory(user: User, owner: string, repo: string, ref: string, maxDepth: number): Promise<string[]> {
104+
const branch = this.branches.get(ref);
105+
if (branch) {
106+
return branch.commits.map((c) => c.sha);
107+
}
108+
109+
for (const b of this.branches.values()) {
110+
for (const [i, c] of b.commits.entries()) {
111+
if (c.sha === ref) {
112+
// this commit, and everything before it
113+
return b.commits.slice(0, i + 1).map((c) => c.sha);
114+
}
115+
}
116+
}
117+
throw new Error(`ref ${ref} not found`);
118+
}
119+
async getCommitInfo(user: User, owner: string, repo: string, ref: string): Promise<CommitInfo | undefined> {
120+
return headu(this.branches.get(ref)?.commits);
121+
}
122+
123+
async getBranches(user: User, owner: string, repo: string): Promise<Branch[]> {
124+
return Array.from(this.branches.values()).map((b) => b.branch);
125+
}
126+
127+
async getUserRepos(user: User): Promise<RepositoryInfo[]> {
128+
return [];
129+
}
130+
async searchRepos(user: User, searchString: string, limit: number): Promise<RepositoryInfo[]> {
131+
return [];
132+
}
133+
}
134+
135+
function headu<T>(arr: T[] | undefined): T | undefined {
136+
if (!arr || arr.length === 0) {
137+
return undefined;
138+
}
139+
return arr[arr.length - 1];
140+
}
141+
142+
function head<T>(arr: T[]): T {
143+
if (arr.length === 0) {
144+
throw new Error("empty array");
145+
}
146+
return arr[arr.length - 1];
147+
}
148+
61149
const SNAPSHOT_BUCKET = "https://gitpod.io/none-bucket";
62150

63151
describe("ContextService", async () => {
64152
let container: Container;
153+
let mockRepositoryProvider: MockRepositoryProvider;
65154
let owner: User;
66155
let member: User;
67156
let stranger: User;
@@ -91,41 +180,73 @@ describe("ContextService", async () => {
91180
normalizeContextURL: function (contextURL: string): string {
92181
return contextURL + "normalizeContextURL";
93182
},
94-
handle: function (ctx: TraceContext, user: User, contextURL: string): Promise<WorkspaceContext> {
183+
handle: async function (ctx: TraceContext, user: User, contextURL: string): Promise<WorkspaceContext> {
95184
const url = contextURL.replace("normalizeContextURL", "");
96-
switch (url) {
97-
case "https://github.com/gitpod-io/empty":
98-
return gitpodEmptyContext as any;
99-
case `open-prebuild/${prebuild.prebuildId}/https://github.com/gitpod-io/empty/tree/main`:
100-
return {
101-
...gitpodEmptyContext,
102-
openPrebuildID: prebuild.prebuildId,
103-
} as any;
104-
case `snapshot/${snapshot.id}`: {
185+
186+
const cases = new Map<string, () => WorkspaceContext>();
187+
cases.set("https://github.com/gitpod-io/empty", () => {
188+
return gitpodEmptyContext as any;
189+
});
190+
191+
if (prebuild) {
192+
cases.set(
193+
`open-prebuild/${prebuild.prebuildId}/https://github.com/gitpod-io/empty/tree/main`,
194+
() => {
195+
return {
196+
...gitpodEmptyContext,
197+
openPrebuildID: prebuild.prebuildId,
198+
} as any;
199+
},
200+
);
201+
}
202+
if (snapshot) {
203+
cases.set(`snapshot/${snapshot.id}`, () => {
105204
return {
106205
...gitpodEmptyContext,
107206
snapshotId: snapshot.id,
108207
snapshotBucketId: SNAPSHOT_BUCKET,
109208
} as any;
110-
}
111-
case `snapshot/${snapshot_stranger.id}`: {
209+
});
210+
}
211+
if (snapshot_stranger) {
212+
cases.set(`snapshot/${snapshot_stranger.id}`, () => {
112213
return {
113214
...gitpodEmptyContext,
114215
snapshotId: snapshot_stranger.id,
115216
snapshotBucketId: SNAPSHOT_BUCKET,
116217
} as any;
117-
}
118-
default:
119-
return {
120-
ref: "master",
121-
} as any;
218+
});
219+
}
220+
const c = cases.get(url);
221+
if (c) {
222+
return c();
122223
}
224+
225+
const mainBranch = await mockRepositoryProvider.getBranch(user, "gitpod-io", "empty", "main");
226+
const r: CommitContext = {
227+
title: mainBranch.commit.commitMessage,
228+
ref: mainBranch.name,
229+
refType: "branch",
230+
revision: mainBranch.commit.sha,
231+
repository: await mockRepositoryProvider.getRepo(user, "gitpod-io", "empty"),
232+
normalizedContextURL: mainBranch.htmlUrl,
233+
};
234+
return r;
123235
},
124236
} as any as ContextParser);
125237
};
126238

127239
bindContextParser();
128240

241+
mockRepositoryProvider = new MockRepositoryProvider();
242+
mockRepositoryProvider.addBranch({ name: "main", htmlUrl: "https://github.com/gitpod-io/empty/tree/main" }, [
243+
{
244+
sha: gitpodEmptyContext.revision,
245+
author: "some-dude",
246+
commitMessage: "some message",
247+
},
248+
]);
249+
129250
container.rebind(HostContextProvider).toConstantValue({
130251
get: () => {
131252
const authProviderId = "Public-GitHub";
@@ -138,30 +259,7 @@ describe("ContextService", async () => {
138259
},
139260
},
140261
services: {
141-
repositoryProvider: {
142-
hasReadAccess: async (user: any, owner: string, repo: string) => {
143-
return true;
144-
},
145-
getBranch: () => {
146-
return {
147-
url: "https://github.com/gitpod-io/empty.git",
148-
name: "main",
149-
htmlUrl: "https://github.com/gitpod-io/empty",
150-
commit: {},
151-
};
152-
},
153-
getRepo: () => {
154-
return {
155-
defaultBranch: "main",
156-
};
157-
},
158-
getCommitHistory: () => {
159-
return [];
160-
},
161-
getCommitInfo: () => {
162-
return undefined;
163-
},
164-
},
262+
repositoryProvider: mockRepositoryProvider,
165263
},
166264
};
167265
},

components/server/src/workspace/context-service.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class ContextService {
2929
constructor(
3030
@inject(TracedWorkspaceDB) private readonly workspaceDb: DBWithTracing<WorkspaceDB>,
3131
@inject(ContextParser) private contextParser: ContextParser,
32-
@inject(IncrementalWorkspaceService) private readonly incrementalPrebuildsService: IncrementalWorkspaceService,
32+
@inject(IncrementalWorkspaceService) private readonly incrementalWorkspaceService: IncrementalWorkspaceService,
3333
@inject(ConfigProvider) private readonly configProvider: ConfigProvider,
3434

3535
@inject(ProjectsService) private readonly projectsService: ProjectsService,
@@ -57,14 +57,15 @@ export class ContextService {
5757
}
5858
} else {
5959
const configPromise = this.configProvider.fetchConfig({}, user, context, organizationId);
60-
const history = await this.incrementalPrebuildsService.getCommitHistoryForContext(context, user);
60+
const history = await this.incrementalWorkspaceService.getCommitHistoryForContext(context, user);
6161
const { config } = await configPromise;
62-
prebuiltWorkspace = await this.incrementalPrebuildsService.findGoodBaseForIncrementalBuild(
62+
prebuiltWorkspace = await this.incrementalWorkspaceService.findBaseForIncrementalWorkspace(
6363
context,
6464
config,
6565
history,
6666
user,
6767
projectId,
68+
false,
6869
);
6970
}
7071
if (!prebuiltWorkspace?.projectId) {

0 commit comments

Comments
 (0)