Skip to content

Commit 6ed7198

Browse files
committed
wip prebuild events
1 parent c638804 commit 6ed7198

File tree

14 files changed

+311
-32
lines changed

14 files changed

+311
-32
lines changed

components/dashboard/src/projects/Prebuilds.tsx

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ export default function () {
2424
const projectName = match?.params?.resource;
2525
const team = getCurrentTeam(location, teams);
2626

27-
// @ts-ignore
2827
const [project, setProject] = useState<Project | undefined>();
2928
const [defaultBranch, setDefaultBranch] = useState<string | undefined>();
3029

@@ -33,6 +32,34 @@ export default function () {
3332

3433
const [prebuilds, setPrebuilds] = useState<PrebuildInfo[]>([]);
3534

35+
useEffect(() => {
36+
if (!project) {
37+
return;
38+
}
39+
const registration = getGitpodService().registerClient({
40+
onPrebuildUpdate: (update) => {
41+
42+
if (!project) {
43+
return;
44+
}
45+
if (update.prebuildInfo.projectId === project.id) {
46+
// TODO(at) create a proper model to update the state
47+
setPrebuilds((prev) => {
48+
const existingPrebuild = prev.find(p => p.id);
49+
if (existingPrebuild) {
50+
existingPrebuild.status = update.status;
51+
return [...prev];
52+
}
53+
return [update.prebuildInfo, ...prev];
54+
})
55+
}
56+
}
57+
})
58+
return () => {
59+
registration.dispose();
60+
}
61+
}, [ project ]);
62+
3663
useEffect(() => {
3764
if (!teams) {
3865
return;
@@ -42,21 +69,23 @@ export default function () {
4269
? await getGitpodService().server.getTeamProjects(team.id)
4370
: await getGitpodService().server.getUserProjects());
4471

45-
const project = projectName && projects.find(p => p.name === projectName);
46-
if (project) {
47-
setProject(project);
72+
const newProject = projectName && projects.find(p => p.name === projectName);
73+
if (newProject) {
74+
setProject(newProject);
4875

49-
const prebuilds = await getGitpodService().server.findPrebuilds({ projectId: project.id });
76+
const prebuilds = await getGitpodService().server.findPrebuilds({ projectId: newProject.id });
5077
setPrebuilds(prebuilds);
5178

52-
const details = await getGitpodService().server.getProjectOverview(project.id);
79+
const details = await getGitpodService().server.getProjectOverview(newProject.id);
5380
if (details?.branches) {
5481
setDefaultBranch(details.branches.find(b => b.isDefault)?.name);
5582
}
5683
}
5784
})();
5885
}, [ teams, team ]);
5986

87+
88+
6089
const prebuildContextMenu = (p: PrebuildInfo) => {
6190
const running = p.status === "building";
6291
const entries: ContextMenuEntry[] = [];
@@ -102,8 +131,6 @@ export default function () {
102131
return true;
103132
}
104133

105-
const filteredPrebuilds = prebuilds.filter(filter);
106-
107134
const openPrebuild = (pb: PrebuildInfo) => {
108135
history.push(`/${!!team ? team.slug : 'projects'}/${projectName}/${pb.id}`);
109136
}
@@ -147,7 +174,7 @@ export default function () {
147174
<ItemFieldContextMenu />
148175
</ItemField>
149176
</Item>
150-
{filteredPrebuilds.map((p: PrebuildInfo) => <Item className="grid grid-cols-3">
177+
{prebuilds.filter(filter).map((p: PrebuildInfo) => <Item key={`prebuild-${p.id}`} className="grid grid-cols-3">
151178
<ItemField className="flex items-center">
152179
<div className="cursor-pointer" onClick={() => openPrebuild(p)}>
153180
<div className="text-base text-gray-900 dark:text-gray-50 font-medium uppercase mb-1">
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* Copyright (c) 2021 Gitpod GmbH. All rights reserved.
3+
* Licensed under the Gitpod Enterprise Source Code License,
4+
* See License.enterprise.txt in the project root folder.
5+
*/
6+
7+
import { Entity, Column, PrimaryColumn } from "typeorm";
8+
import { PrebuildInfo } from "@gitpod/gitpod-protocol";
9+
10+
import { TypeORM } from "../../typeorm/typeorm";
11+
12+
@Entity()
13+
export class DBPrebuildInfo {
14+
15+
@PrimaryColumn(TypeORM.UUID_COLUMN_TYPE)
16+
prebuildId: string;
17+
18+
@Column({
19+
type: 'simple-json',
20+
transformer: (() => {
21+
return {
22+
to(value: any): any {
23+
return JSON.stringify(value);
24+
},
25+
from(value: any): any {
26+
try {
27+
const obj = JSON.parse(value);
28+
return PrebuildInfo.is(obj) ? obj : undefined;
29+
} catch (error) {
30+
}
31+
}
32+
};
33+
})()
34+
})
35+
info: PrebuildInfo;
36+
37+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Copyright (c) 2021 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License-AGPL.txt in the project root for license information.
5+
*/
6+
7+
import {MigrationInterface, QueryRunner} from "typeorm";
8+
9+
export class AddPrebuildInfo1628160315471 implements MigrationInterface {
10+
11+
public async up(queryRunner: QueryRunner): Promise<any> {
12+
await queryRunner.query("CREATE TABLE IF NOT EXISTS `d_b_prebuild_info` ( `prebuildId` char(36) NOT NULL, `info` text NOT NULL, `deleted` tinyint(4) NOT NULL DEFAULT '0', `_lastModified` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), PRIMARY KEY (`prebuildId`), KEY `ind_dbsync` (`_lastModified`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
13+
}
14+
15+
public async down(queryRunner: QueryRunner): Promise<any> {
16+
}
17+
18+
}

components/gitpod-db/src/typeorm/workspace-db-impl.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import { injectable, inject } from "inversify";
88
import { Repository, EntityManager, DeepPartial, UpdateQueryBuilder } from "typeorm";
99
import { MaybeWorkspace, MaybeWorkspaceInstance, WorkspaceDB, FindWorkspacesOptions, PrebuiltUpdatableAndWorkspace, WorkspaceInstanceSessionWithWorkspace, PrebuildWithWorkspace, WorkspaceAndOwner, WorkspacePortsAuthData, WorkspaceOwnerAndSoftDeleted } from "../workspace-db";
10-
import { Workspace, WorkspaceInstance, WorkspaceInfo, WorkspaceInstanceUser, WhitelistedRepository, Snapshot, LayoutData, PrebuiltWorkspace, RunningWorkspaceInfo, PrebuiltWorkspaceUpdatable, WorkspaceAndInstance, WorkspaceType } from "@gitpod/gitpod-protocol";
10+
import { Workspace, WorkspaceInstance, WorkspaceInfo, WorkspaceInstanceUser, WhitelistedRepository, Snapshot, LayoutData, PrebuiltWorkspace, RunningWorkspaceInfo, PrebuiltWorkspaceUpdatable, WorkspaceAndInstance, WorkspaceType, PrebuildInfo } from "@gitpod/gitpod-protocol";
1111
import { TypeORM } from "./typeorm";
1212
import { DBWorkspace } from "./entity/db-workspace";
1313
import { DBWorkspaceInstance } from "./entity/db-workspace-instance";
@@ -19,6 +19,7 @@ import { log } from '@gitpod/gitpod-protocol/lib/util/logging';
1919
import { DBPrebuiltWorkspace } from "./entity/db-prebuilt-workspace";
2020
import { DBPrebuiltWorkspaceUpdatable } from "./entity/db-prebuilt-workspace-updatable";
2121
import { BUILTIN_WORKSPACE_PROBE_USER_NAME } from "../user-db";
22+
import { DBPrebuildInfo } from "./entity/db-prebuild-info-entry";
2223

2324
type RawTo<T> = (instance: WorkspaceInstance, ws: Workspace) => T;
2425
interface OrderBy {
@@ -55,6 +56,10 @@ export abstract class AbstractTypeORMWorkspaceDBImpl implements WorkspaceDB {
5556
return await (await this.getManager()).getRepository<DBPrebuiltWorkspace>(DBPrebuiltWorkspace);
5657
}
5758

59+
protected async getPrebuildInfoRepo(): Promise<Repository<DBPrebuildInfo>> {
60+
return await (await this.getManager()).getRepository<DBPrebuildInfo>(DBPrebuildInfo);
61+
}
62+
5863
protected async getPrebuiltWorkspaceUpdatableRepo(): Promise<Repository<DBPrebuiltWorkspaceUpdatable>> {
5964
return await (await this.getManager()).getRepository<DBPrebuiltWorkspaceUpdatable>(DBPrebuiltWorkspaceUpdatable);
6065
}
@@ -826,7 +831,7 @@ export abstract class AbstractTypeORMWorkspaceDBImpl implements WorkspaceDB {
826831
const repo = await this.getPrebuiltWorkspaceRepo();
827832

828833
const query = repo.createQueryBuilder('pws')
829-
.orderBy('pws.creationTime', 'ASC')
834+
.orderBy('pws.creationTime', 'DESC')
830835
.innerJoinAndMapOne('pws.workspace', DBWorkspace, 'ws', 'pws.buildWorkspaceId = ws.id')
831836
.andWhere('pws.projectId = :projectId', { projectId });
832837

@@ -845,13 +850,31 @@ export abstract class AbstractTypeORMWorkspaceDBImpl implements WorkspaceDB {
845850
const repo = await this.getPrebuiltWorkspaceRepo();
846851

847852
const query = repo.createQueryBuilder('pws')
848-
.orderBy('pws.creationTime', 'ASC')
853+
.orderBy('pws.creationTime', 'DESC')
849854
.innerJoinAndMapOne('pws.workspace', DBWorkspace, 'ws', 'pws.buildWorkspaceId = ws.id')
850855
.andWhere('pws.id = :id', { id });
851856

852857
return query.getOne();
853858
}
854859

860+
async storePrebuildInfo(prebuildInfo: PrebuildInfo): Promise<void> {
861+
const repo = await this.getPrebuildInfoRepo();
862+
await repo.save({
863+
prebuildId: prebuildInfo.id,
864+
info: prebuildInfo
865+
});
866+
}
867+
868+
async findPrebuildInfo(prebuildId: string): Promise<PrebuildInfo | undefined>{
869+
const repo = await this.getPrebuildInfoRepo();
870+
871+
const query = repo.createQueryBuilder('pi')
872+
.andWhere('pi.prebuildId = :prebuildId', { prebuildId });
873+
874+
const entry = await query.getOne();
875+
return entry?.info;
876+
}
877+
855878
}
856879

857880
@injectable()

components/gitpod-db/src/workspace-db.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import { DeepPartial } from 'typeorm';
88

9-
import { Workspace, WorkspaceInfo, WorkspaceInstance, WorkspaceInstanceUser, WhitelistedRepository, Snapshot, LayoutData, PrebuiltWorkspace, PrebuiltWorkspaceUpdatable, RunningWorkspaceInfo, WorkspaceAndInstance, WorkspaceType } from '@gitpod/gitpod-protocol';
9+
import { Workspace, WorkspaceInfo, WorkspaceInstance, WorkspaceInstanceUser, WhitelistedRepository, Snapshot, LayoutData, PrebuiltWorkspace, PrebuiltWorkspaceUpdatable, RunningWorkspaceInfo, WorkspaceAndInstance, WorkspaceType, PrebuildInfo } from '@gitpod/gitpod-protocol';
1010

1111
export type MaybeWorkspace = Workspace | undefined;
1212
export type MaybeWorkspaceInstance = WorkspaceInstance | undefined;
@@ -115,4 +115,7 @@ export interface WorkspaceDB {
115115

116116
findPrebuiltWorkspacesByProject(projectId: string, branch?: string, limit?: number): Promise<PrebuiltWorkspace[]>;
117117
findPrebuiltWorkspacesById(prebuildId: string): Promise<PrebuiltWorkspace | undefined>;
118+
119+
storePrebuildInfo(prebuildInfo: PrebuildInfo): Promise<void>;
120+
findPrebuildInfo(prebuildId: string): Promise<PrebuildInfo | undefined>;
118121
}

components/gitpod-protocol/src/gitpod-service.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
} from './protocol';
1414
import {
1515
Team, TeamMemberInfo,
16-
TeamMembershipInvite, Project, PrebuildInfo, TeamMemberRole
16+
TeamMembershipInvite, Project, PrebuildInfo, TeamMemberRole, PrebuildUpdate
1717
} from './teams-projects-protocol';
1818
import { JsonRpcProxy, JsonRpcServer } from './messaging/proxy-factory';
1919
import { Disposable, CancellationTokenSource } from 'vscode-jsonrpc';
@@ -34,6 +34,8 @@ export interface GitpodClient {
3434
onInstanceUpdate(instance: WorkspaceInstance): void;
3535
onWorkspaceImageBuildLogs: WorkspaceImageBuild.LogCallback;
3636

37+
onPrebuildUpdate(update: PrebuildUpdate): void;
38+
3739
onCreditAlert(creditAlert: CreditAlert): void;
3840

3941
//#region propagating reconnection to iframe
@@ -376,6 +378,18 @@ export class GitpodCompositeClient<Client extends GitpodClient> implements Gitpo
376378
}
377379
}
378380

381+
onPrebuildUpdate(update: PrebuildUpdate): void {
382+
for (const client of this.clients) {
383+
if (client.onPrebuildUpdate) {
384+
try {
385+
client.onPrebuildUpdate(update);
386+
} catch (error) {
387+
console.error(error)
388+
}
389+
}
390+
}
391+
}
392+
379393
onWorkspaceImageBuildLogs(info: WorkspaceImageBuild.StateInfo, content: WorkspaceImageBuild.LogContent | undefined): void {
380394
for (const client of this.clients) {
381395
if (client.onWorkspaceImageBuildLogs) {

components/gitpod-protocol/src/teams-projects-protocol.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,24 @@ export namespace Project {
5454
}
5555
}
5656

57+
export interface PrebuildUpdate {
58+
prebuildInfo: PrebuildInfo;
59+
status: PrebuiltWorkspaceState;
60+
}
61+
5762
export interface PrebuildInfo {
5863
id: string;
59-
teamId: string;
64+
buildWorkspaceId: string;
65+
66+
teamId?: string;
67+
userId?: string;
68+
69+
projectId: string;
6070
projectName: string;
71+
6172
cloneUrl: string;
6273
branch: string;
6374
branchPrebuildNumber: string;
64-
buildWorkspaceId: string;
6575

6676
startedAt: string;
6777
startedBy: string;
@@ -75,6 +85,11 @@ export interface PrebuildInfo {
7585
changeUrl?: string;
7686
changeHash: string;
7787
}
88+
export namespace PrebuildInfo {
89+
export function is(data?: any): data is PrebuildInfo {
90+
return typeof data === "object" && ["id", "buildWorkspaceId", "projectId", "branch"].every(p => p in data);
91+
}
92+
}
7893

7994
export interface Team {
8095
id: string;

components/server/ee/src/workspace/workspace-factory.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@ import { Feature } from '@gitpod/licensor/lib/api';
1515
import { ResponseError } from 'vscode-jsonrpc';
1616
import { ErrorCodes } from '@gitpod/gitpod-protocol/lib/messaging/error';
1717
import { generateWorkspaceID } from '@gitpod/gitpod-protocol/lib/util/generate-workspace-id';
18+
import { HostContextProvider } from '../../../src/auth/host-context-provider';
19+
import { parseRepoUrl } from '../../../src/repohost';
1820

1921
@injectable()
2022
export class WorkspaceFactoryEE extends WorkspaceFactory {
2123

2224
@inject(LicenseEvaluator) protected readonly licenseEvaluator: LicenseEvaluator;
25+
@inject(HostContextProvider) protected readonly hostContextProvider: HostContextProvider;
2326

2427
protected requireEELicense(feature: Feature) {
2528
if (!this.licenseEvaluator.isEnabled(feature)) {
@@ -127,6 +130,47 @@ export class WorkspaceFactoryEE extends WorkspaceFactory {
127130
branch
128131
});
129132

133+
134+
{ // TODO(at) store prebuild info
135+
if (project) {
136+
const { userId, teamId, name: projectName, id: projectId } = project;
137+
const prebuild = pws;
138+
const parsedUrl = parseRepoUrl(project.cloneUrl);
139+
if (parsedUrl) {
140+
const { owner, repo, host } = parsedUrl;
141+
const repositoryProvider = this.hostContextProvider.get(host)?.services?.repositoryProvider;
142+
if (repositoryProvider) {
143+
const commit = await repositoryProvider.getCommitInfo(user, owner, repo, prebuild.commit);
144+
if (commit) {
145+
await this.db.trace({span}).storePrebuildInfo({
146+
id: prebuild.id,
147+
status: prebuild.state,
148+
buildWorkspaceId: prebuild.buildWorkspaceId,
149+
teamId,
150+
userId,
151+
projectName,
152+
projectId,
153+
startedAt: prebuild.creationTime,
154+
startedBy: "", // TODO
155+
startedByAvatar: "", // TODO
156+
cloneUrl: prebuild.cloneURL,
157+
branch: prebuild.branch || "unknown",
158+
branchPrebuildNumber: "42", // TODO
159+
changeAuthor: commit.author,
160+
changeAuthorAvatar: commit.authorAvatarUrl,
161+
changeDate: commit.authorDate || "",
162+
changeHash: commit.sha,
163+
changeTitle: commit.commitMessage,
164+
// changePR
165+
// changeUrl
166+
});
167+
}
168+
}
169+
}
170+
}
171+
}
172+
173+
130174
log.debug({ userId: user.id, workspaceId: ws.id }, `Registered workspace prebuild: ${pws.id} for ${commitContext.repository.cloneUrl}:${commitContext.revision}`);
131175

132176
return ws;

0 commit comments

Comments
 (0)