Skip to content

Commit 14a21a7

Browse files
authored
[projects] lookup projects by id not cloneURL (#18774)
1 parent d464ef8 commit 14a21a7

19 files changed

+612
-761
lines changed

components/dashboard/src/projects/new-project/NewProjectRepoList.tsx

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ export const NewProjectRepoList: FC<Props> = ({ filteredRepos, noReposAvailable,
2929
<div className="flex-grow">
3030
<div
3131
className={
32-
"text-base text-gray-900 dark:text-gray-50 font-medium rounded-xl whitespace-nowrap" +
33-
(r.inUse ? " text-gray-400 dark:text-gray-500" : "text-gray-700")
32+
"text-base text-gray-900 dark:text-gray-50 font-medium rounded-xl whitespace-nowrap text-gray-700"
3433
}
3534
>
3635
{toSimpleName(r)}
@@ -39,17 +38,9 @@ export const NewProjectRepoList: FC<Props> = ({ filteredRepos, noReposAvailable,
3938
</div>
4039
<div className="flex justify-end">
4140
<div className="h-full my-auto flex self-center opacity-0 group-hover:opacity-100 items-center mr-2 text-right">
42-
{!r.inUse ? (
43-
<Button onClick={() => onRepoSelected(r)} loading={isCreating}>
44-
Select
45-
</Button>
46-
) : (
47-
<p className="text-gray-500">
48-
Project already
49-
<br />
50-
exists.
51-
</p>
52-
)}
41+
<Button onClick={() => onRepoSelected(r)} loading={isCreating}>
42+
Select
43+
</Button>
5344
</div>
5445
</div>
5546
</div>

components/dashboard/src/workspaces/CreateWorkspacePage.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ export function CreateWorkspacePage() {
237237
const result = await createWorkspaceMutation.createWorkspace({
238238
contextUrl: contextURL,
239239
organizationId,
240+
projectId: selectedProjectID,
240241
...opts,
241242
});
242243
await storeAutoStartOptions();
@@ -263,6 +264,7 @@ export function CreateWorkspacePage() {
263264
selectedIde,
264265
useLatestIde,
265266
createWorkspaceMutation,
267+
selectedProjectID,
266268
storeAutoStartOptions,
267269
history,
268270
autostart,

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import { TransactionalDB } from "./typeorm/transactional-db-impl";
1010
export const ProjectDB = Symbol("ProjectDB");
1111
export interface ProjectDB extends TransactionalDB<ProjectDB> {
1212
findProjectById(projectId: string): Promise<Project | undefined>;
13-
findProjectByCloneUrl(cloneUrl: string): Promise<Project | undefined>;
14-
findProjectsByCloneUrls(cloneUrls: string[]): Promise<(Project & { teamOwners?: string[] })[]>;
13+
findProjectsByCloneUrl(cloneUrl: string): Promise<Project[]>;
1514
findProjects(orgID: string): Promise<Project[]>;
1615
findProjectsBySearchTerm(
1716
offset: number,

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

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import { PartialProject, Project, ProjectEnvVar, ProjectEnvVarWithValue, ProjectUsage } from "@gitpod/gitpod-protocol";
88
import { EncryptionService } from "@gitpod/gitpod-protocol/lib/encryption/encryption-service";
99
import { inject, injectable, optional } from "inversify";
10-
import { EntityManager, Repository } from "typeorm";
10+
import { EntityManager, FindConditions, Repository } from "typeorm";
1111
import { v4 as uuidv4 } from "uuid";
1212
import { ProjectDB } from "../project-db";
1313
import { DBProject } from "./entity/db-project";
@@ -58,46 +58,10 @@ export class ProjectDBImpl extends TransactionalDBImpl<ProjectDB> implements Pro
5858
return repo.findOne({ id: projectId, markedDeleted: false });
5959
}
6060

61-
public async findProjectByCloneUrl(cloneUrl: string): Promise<Project | undefined> {
61+
public async findProjectsByCloneUrl(cloneUrl: string): Promise<Project[]> {
6262
const repo = await this.getRepo();
63-
return repo.findOne({ cloneUrl, markedDeleted: false });
64-
}
65-
66-
public async findProjectsByCloneUrls(cloneUrls: string[]): Promise<(Project & { teamOwners?: string[] })[]> {
67-
if (cloneUrls.length === 0) {
68-
return [];
69-
}
70-
const repo = await this.getRepo();
71-
const q = repo
72-
.createQueryBuilder("project")
73-
.where("project.markedDeleted = false")
74-
.andWhere(`project.cloneUrl in (${cloneUrls.map((u) => `'${u}'`).join(", ")})`);
75-
const projects = await q.getMany();
76-
77-
const teamIds = Array.from(new Set(projects.map((p) => p.teamId).filter((id) => !!id)));
78-
79-
const teamIdsAndOwners =
80-
teamIds.length === 0
81-
? []
82-
: ((await (
83-
await this.getEntityManager()
84-
).query(`
85-
SELECT member.teamId AS teamId, user.name AS owner FROM d_b_user AS user
86-
LEFT JOIN d_b_team_membership AS member ON (user.id = member.userId)
87-
WHERE member.teamId IN (${teamIds.map((id) => `'${id}'`).join(", ")})
88-
AND member.deleted = 0
89-
AND member.role = 'owner'
90-
`)) as { teamId: string; owner: string }[]);
91-
92-
const result: (Project & { teamOwners?: string[] })[] = [];
93-
for (const project of projects) {
94-
result.push({
95-
...project,
96-
teamOwners: teamIdsAndOwners.filter((i) => i.teamId === project.teamId).map((i) => i.owner),
97-
});
98-
}
99-
100-
return result;
63+
const conditions: FindConditions<DBProject> = { cloneUrl, markedDeleted: false };
64+
return repo.find(conditions);
10165
}
10266

10367
public async findProjects(orgId: string): Promise<Project[]> {

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

Lines changed: 12 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import {
5757
} from "./metrics";
5858
import { TransactionalDBImpl } from "./transactional-db-impl";
5959
import { TypeORM } from "./typeorm";
60+
import { ApplicationError, ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error";
6061

6162
type RawTo<T> = (instance: WorkspaceInstance, ws: Workspace) => T;
6263
interface OrderBy {
@@ -710,16 +711,19 @@ export class TypeORMWorkspaceDBImpl extends TransactionalDBImpl<WorkspaceDB> imp
710711

711712
// Find the (last triggered) prebuild for a given commit
712713
public async findPrebuiltWorkspaceByCommit(
713-
cloneURL: string,
714+
projectId: string,
714715
commit: string,
715716
): Promise<PrebuiltWorkspace | undefined> {
716-
if (!commit || !cloneURL) {
717-
return undefined;
717+
if (!commit || !projectId) {
718+
throw new ApplicationError(ErrorCodes.INTERNAL_SERVER_ERROR, "Illegal arguments", { projectId, commit });
718719
}
719720
const repo = await this.getPrebuiltWorkspaceRepo();
720721
return await repo
721722
.createQueryBuilder("pws")
722-
.where("pws.cloneURL = :cloneURL AND pws.commit LIKE :commit", { cloneURL, commit: commit + "%" })
723+
.where("pws.projectId = :projectId AND pws.commit LIKE :commit", {
724+
projectId,
725+
commit: commit + "%",
726+
})
723727
.orderBy("pws.creationTime", "DESC")
724728
.innerJoinAndMapOne(
725729
"pws.workspace",
@@ -770,19 +774,12 @@ export class TypeORMWorkspaceDBImpl extends TransactionalDBImpl<WorkspaceDB> imp
770774
const repo = await this.getPrebuiltWorkspaceRepo();
771775
return await repo.findOne(pwsid);
772776
}
773-
public async countRunningPrebuilds(cloneURL: string): Promise<number> {
774-
const repo = await this.getPrebuiltWorkspaceRepo();
775-
return await repo
776-
.createQueryBuilder("pws")
777-
.where('pws.cloneURL = :cloneURL AND state = "building"', { cloneURL })
778-
.getCount();
779-
}
780777

781-
public async findPrebuildsWithWorkpace(cloneURL: string): Promise<PrebuildWithWorkspace[]> {
778+
public async findPrebuildsWithWorkspace(projectId: string): Promise<PrebuildWithWorkspace[]> {
782779
const repo = await this.getPrebuiltWorkspaceRepo();
783780

784781
let query = repo.createQueryBuilder("pws");
785-
query = query.where("pws.cloneURL = :cloneURL", { cloneURL });
782+
query = query.where("pws.projectId = :projectId", { projectId });
786783
query = query.orderBy("pws.creationTime", "DESC");
787784
query = query.innerJoinAndMapOne("pws.workspace", DBWorkspace, "ws", "pws.buildWorkspaceId = ws.id");
788785
query = query.andWhere("ws.deleted = false");
@@ -798,37 +795,17 @@ export class TypeORMWorkspaceDBImpl extends TransactionalDBImpl<WorkspaceDB> imp
798795
});
799796
}
800797

801-
public async countUnabortedPrebuildsSince(cloneURL: string, date: Date): Promise<number> {
798+
public async countUnabortedPrebuildsSince(projectId: string, date: Date): Promise<number> {
802799
const abortedState: PrebuiltWorkspaceState = "aborted";
803800
const repo = await this.getPrebuiltWorkspaceRepo();
804801

805802
let query = repo.createQueryBuilder("pws");
806-
query = query.where("pws.cloneURL = :cloneURL", { cloneURL });
803+
query = query.where("pws.projectId != :projectId", { projectId });
807804
query = query.andWhere("pws.creationTime >= :time", { time: date.toISOString() });
808805
query = query.andWhere("pws.state != :state", { state: abortedState });
809806
return query.getCount();
810807
}
811808

812-
public async findQueuedPrebuilds(cloneURL?: string): Promise<PrebuildWithWorkspace[]> {
813-
const repo = await this.getPrebuiltWorkspaceRepo();
814-
815-
let query = await repo.createQueryBuilder("pws");
816-
query = query.where('state = "queued"');
817-
if (cloneURL) {
818-
query = query.andWhere("pws.cloneURL = :cloneURL", { cloneURL });
819-
}
820-
query = query.orderBy("pws.creationTime", "ASC");
821-
query = query.innerJoinAndMapOne("pws.workspace", DBWorkspace, "ws", "pws.buildWorkspaceId = ws.id");
822-
823-
const res = await query.getMany();
824-
return res.map((r) => {
825-
const withWorkspace: PrebuiltWorkspace & { workspace: Workspace } = r as any;
826-
return {
827-
prebuild: r,
828-
workspace: withWorkspace.workspace,
829-
};
830-
});
831-
}
832809
public async attachUpdatableToPrebuild(pwsid: string, update: PrebuiltWorkspaceUpdatable): Promise<void> {
833810
const repo = await this.getPrebuiltWorkspaceUpdatableRepo();
834811
await repo.save(update);

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { TypeORM } from "./typeorm/typeorm";
1616
import { DBPrebuiltWorkspace } from "./typeorm/entity/db-prebuilt-workspace";
1717
import { secondsBefore } from "@gitpod/gitpod-protocol/lib/util/timeutil";
1818
import { resetDB } from "./test/reset-db";
19+
import { v4 } from "uuid";
1920

2021
@suite
2122
class WorkspaceDBSpec {
@@ -508,6 +509,7 @@ class WorkspaceDBSpec {
508509
public async testCountUnabortedPrebuildsSince() {
509510
const now = new Date();
510511
const cloneURL = "https://github.com/gitpod-io/gitpod";
512+
const projectId = v4();
511513

512514
await Promise.all([
513515
// Created now, and queued
@@ -516,6 +518,7 @@ class WorkspaceDBSpec {
516518
buildWorkspaceId: "apples",
517519
creationTime: now.toISOString(),
518520
cloneURL: cloneURL,
521+
projectId,
519522
commit: "",
520523
state: "queued",
521524
statusVersion: 0,
@@ -526,6 +529,7 @@ class WorkspaceDBSpec {
526529
buildWorkspaceId: "bananas",
527530
creationTime: now.toISOString(),
528531
cloneURL: cloneURL,
532+
projectId,
529533
commit: "",
530534
state: "aborted",
531535
statusVersion: 0,
@@ -536,14 +540,26 @@ class WorkspaceDBSpec {
536540
buildWorkspaceId: "oranges",
537541
creationTime: secondsBefore(now.toISOString(), 62),
538542
cloneURL: cloneURL,
543+
projectId,
539544
commit: "",
540545
state: "available",
541546
statusVersion: 0,
542547
}),
548+
// different project now and queued
549+
this.storePrebuiltWorkspace({
550+
id: "prebuild123-other",
551+
buildWorkspaceId: "apples",
552+
creationTime: now.toISOString(),
553+
cloneURL: cloneURL,
554+
projectId: "other-projectId",
555+
commit: "",
556+
state: "queued",
557+
statusVersion: 0,
558+
}),
543559
]);
544560

545561
const minuteAgo = secondsBefore(now.toISOString(), 60);
546-
const unabortedCount = await this.db.countUnabortedPrebuildsSince(cloneURL, new Date(minuteAgo));
562+
const unabortedCount = await this.db.countUnabortedPrebuildsSince(projectId, new Date(minuteAgo));
547563
expect(unabortedCount).to.eq(1);
548564
}
549565

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ export interface WorkspaceDB {
133133
findInstancesByPhase(phases: string[]): Promise<WorkspaceInstance[]>;
134134

135135
getWorkspaceCount(type?: String): Promise<Number>;
136-
getWorkspaceCountByCloneURL(cloneURL: string, sinceLastDays?: number, type?: string): Promise<number>;
137136
getInstanceCount(type?: string): Promise<number>;
138137

139138
findRegularRunningInstances(userId?: string): Promise<WorkspaceInstance[]>;
@@ -158,17 +157,15 @@ export interface WorkspaceDB {
158157
updateSnapshot(snapshot: DeepPartial<Snapshot> & Pick<Snapshot, "id">): Promise<void>;
159158

160159
storePrebuiltWorkspace(pws: PrebuiltWorkspace): Promise<PrebuiltWorkspace>;
161-
findPrebuiltWorkspaceByCommit(cloneURL: string, commit: string): Promise<PrebuiltWorkspace | undefined>;
160+
findPrebuiltWorkspaceByCommit(projectId: string, commit: string): Promise<PrebuiltWorkspace | undefined>;
162161
findActivePrebuiltWorkspacesByBranch(
163162
projectId: string,
164163
branch: string,
165164
): Promise<PrebuildWithWorkspaceAndInstances[]>;
166-
findPrebuildsWithWorkpace(cloneURL: string): Promise<PrebuildWithWorkspace[]>;
165+
findPrebuildsWithWorkspace(projectId: string): Promise<PrebuildWithWorkspace[]>;
167166
findPrebuildByWorkspaceID(wsid: string): Promise<PrebuiltWorkspace | undefined>;
168167
findPrebuildByID(pwsid: string): Promise<PrebuiltWorkspace | undefined>;
169-
countRunningPrebuilds(cloneURL: string): Promise<number>;
170-
countUnabortedPrebuildsSince(cloneURL: string, date: Date): Promise<number>;
171-
findQueuedPrebuilds(cloneURL?: string): Promise<PrebuildWithWorkspace[]>;
168+
countUnabortedPrebuildsSince(projectId: string, date: Date): Promise<number>;
172169
attachUpdatableToPrebuild(pwsid: string, update: PrebuiltWorkspaceUpdatable): Promise<void>;
173170
findUpdatablesForPrebuild(pwsid: string): Promise<PrebuiltWorkspaceUpdatable[]>;
174171
markUpdatableResolved(updatableId: string): Promise<void>;

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,8 +323,6 @@ export interface ProviderRepository {
323323
updatedAt?: string;
324324
installationId?: number;
325325
installationUpdatedAt?: string;
326-
327-
inUse?: { userName: string };
328326
}
329327

330328
export interface ClientHeaderFields {
@@ -416,6 +414,7 @@ export namespace GitpodServer {
416414
export interface CreateWorkspaceOptions extends StartWorkspaceOptions {
417415
contextUrl: string;
418416
organizationId: string;
417+
projectId?: string;
419418

420419
// whether running workspaces on the same context should be ignored. If false (default) users will be asked.
421420
//TODO(se) remove this option and let clients do that check if they like. The new create workspace page does it already

0 commit comments

Comments
 (0)