Skip to content

Commit 3c2d7d3

Browse files
committed
[server] Refactor setProjectConfiguration + updateProjectSettings → updateProjectPartial
1 parent b404e72 commit 3c2d7d3

File tree

8 files changed

+52
-57
lines changed

8 files changed

+52
-57
lines changed

components/dashboard/src/projects/ProjectSettings.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,12 @@ export default function () {
7070
}
7171
setIsLoading(true);
7272
try {
73-
await getGitpodService().server.updateProjectSettings(project.id, { useIncrementalPrebuilds: !isIncrementalPrebuildsEnabled });
73+
await getGitpodService().server.updateProjectPartial({
74+
id: project.id,
75+
settings: {
76+
useIncrementalPrebuilds: !isIncrementalPrebuildsEnabled,
77+
}
78+
});
7479
setIsIncrementalPrebuildsEnabled(!isIncrementalPrebuildsEnabled);
7580
} finally {
7681
setIsLoading(false);

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* See License.enterprise.txt in the project root folder.
55
*/
66

7-
import { Project, ProjectConfig, ProjectSettings } from "@gitpod/gitpod-protocol";
7+
import { PartialProject, Project } from "@gitpod/gitpod-protocol";
88

99
export const ProjectDB = Symbol('ProjectDB');
1010
export interface ProjectDB {
@@ -14,7 +14,6 @@ export interface ProjectDB {
1414
findTeamProjects(teamId: string): Promise<Project[]>;
1515
findUserProjects(userId: string): Promise<Project[]>;
1616
storeProject(project: Project): Promise<Project>;
17-
setProjectConfiguration(projectId: string, config: ProjectConfig): Promise<void>;
18-
setProjectSettings(projectId: string, settings: ProjectSettings): Promise<void>;
17+
updateProject(partialProject: PartialProject): Promise<void>;
1918
markDeleted(projectId: string): Promise<void>;
2019
}

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

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { TypeORM } from "./typeorm";
99
import { Repository } from "typeorm";
1010
import { ProjectDB } from "../project-db";
1111
import { DBProject } from "./entity/db-project";
12-
import { Project, ProjectConfig, ProjectSettings } from "@gitpod/gitpod-protocol";
12+
import { PartialProject, Project } from "@gitpod/gitpod-protocol";
1313

1414
@injectable()
1515
export class ProjectDBImpl implements ProjectDB {
@@ -60,24 +60,13 @@ export class ProjectDBImpl implements ProjectDB {
6060
return repo.save(project);
6161
}
6262

63-
public async setProjectConfiguration(projectId: string, config: ProjectConfig): Promise<void> {
63+
public async updateProject(partialProject: PartialProject): Promise<void> {
6464
const repo = await this.getRepo();
65-
const project = await repo.findOne({ id: projectId, markedDeleted: false });
66-
if (!project) {
65+
const count = await repo.count({ id: partialProject.id, markedDeleted: false });
66+
if (count < 1) {
6767
throw new Error('A project with this ID could not be found');
6868
}
69-
project.config = config;
70-
await repo.save(project);
71-
}
72-
73-
public async setProjectSettings(projectId: string, settings: ProjectSettings): Promise<void> {
74-
const repo = await this.getRepo();
75-
const project = await repo.findOne({ id: projectId, markedDeleted: false });
76-
if (!project) {
77-
throw new Error('A project with this ID could not be found');
78-
}
79-
project.settings = settings;
80-
await repo.save(project);
69+
await repo.update(partialProject.id, partialProject);
8170
}
8271

8372
public async markDeleted(projectId: string): Promise<void> {

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
} from './protocol';
1414
import {
1515
Team, TeamMemberInfo,
16-
TeamMembershipInvite, Project, TeamMemberRole, PrebuildWithStatus, StartPrebuildResult, ProjectSettings
16+
TeamMembershipInvite, Project, TeamMemberRole, PrebuildWithStatus, StartPrebuildResult, PartialProject
1717
} from './teams-projects-protocol';
1818
import { JsonRpcProxy, JsonRpcServer } from './messaging/proxy-factory';
1919
import { Disposable, CancellationTokenSource } from 'vscode-jsonrpc';
@@ -136,12 +136,12 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
136136
findPrebuilds(params: FindPrebuildsParams): Promise<PrebuildWithStatus[]>;
137137
triggerPrebuild(projectId: string, branchName: string | null): Promise<StartPrebuildResult>;
138138
cancelPrebuild(projectId: string, prebuildId: string): Promise<void>;
139-
setProjectConfiguration(projectId: string, configString: string): Promise<void>;
140139
fetchProjectRepositoryConfiguration(projectId: string): Promise<string | undefined>;
141140
guessProjectConfiguration(projectId: string): Promise<string | undefined>;
142141
fetchRepositoryConfiguration(cloneUrl: string): Promise<string | undefined>;
143142
guessRepositoryConfiguration(cloneUrl: string): Promise<string | undefined>;
144-
updateProjectSettings(projectId: string, partialSettings: Partial<ProjectSettings>): Promise<void>;
143+
setProjectConfiguration(projectId: string, configString: string): Promise<void>;
144+
updateProjectPartial(partialProject: PartialProject): Promise<void>;
145145

146146
// content service
147147
getContentBlobUploadUrl(name: string): Promise<string>

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import { PrebuiltWorkspaceState } from "./protocol";
88
import { v4 as uuidv4 } from 'uuid';
9+
import { DeepPartial } from "./util/deep-partial";
910

1011
export interface ProjectConfig {
1112
'.gitpod.yml': string;
@@ -60,6 +61,8 @@ export namespace Project {
6061
}
6162
}
6263

64+
export type PartialProject = DeepPartial<Project> & Pick<Project, 'id'>;
65+
6366
export interface PrebuildWithStatus {
6467
info: PrebuildInfo;
6568
status: PrebuiltWorkspaceState;

components/server/src/auth/rate-limiter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,12 @@ function getConfig(config: RateLimiterConfig): RateLimiterConfig {
9898
"getProjectOverview": { group: "default", points: 1 },
9999
"triggerPrebuild": { group: "default", points: 1 },
100100
"cancelPrebuild": { group: "default", points: 1 },
101-
"setProjectConfiguration": { group: "default", points: 1 },
102101
"fetchProjectRepositoryConfiguration": { group: "default", points: 1 },
103102
"guessProjectConfiguration": { group: "default", points: 1 },
104103
"fetchRepositoryConfiguration": { group: "default", points: 1 },
105104
"guessRepositoryConfiguration": { group: "default", points: 1 },
106-
"updateProjectSettings": { group: "default", points: 1 },
105+
"setProjectConfiguration": { group: "default", points: 1 },
106+
"updateProjectPartial": { group: "default", points: 1 },
107107
"getContentBlobUploadUrl": { group: "default", points: 1 },
108108
"getContentBlobDownloadUrl": { group: "default", points: 1 },
109109
"getGitpodTokens": { group: "default", points: 1 },

components/server/src/projects/projects-service.ts

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66

77
import { inject, injectable } from "inversify";
88
import { DBWithTracing, ProjectDB, TeamDB, TracedWorkspaceDB, UserDB, WorkspaceDB } from "@gitpod/gitpod-db/lib";
9-
import { Branch, CommitContext, PrebuildWithStatus, CreateProjectParams, FindPrebuildsParams, Project, ProjectConfig, User, WorkspaceConfig, ProjectSettings } from "@gitpod/gitpod-protocol";
9+
import { Branch, CommitContext, PrebuildWithStatus, CreateProjectParams, FindPrebuildsParams, Project, User, WorkspaceConfig } from "@gitpod/gitpod-protocol";
1010
import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing";
1111
import { HostContextProvider } from "../auth/host-context-provider";
1212
import { FileProvider, RepoURL } from "../repohost";
1313
import { log } from '@gitpod/gitpod-protocol/lib/util/logging';
1414
import { ContextParser } from "../workspace/context-parser-service";
1515
import { ConfigInferrer } from "./config-inferrer";
16+
import { PartialProject } from "@gitpod/gitpod-protocol/src/teams-projects-protocol";
1617

1718
@injectable()
1819
export class ProjectsService {
@@ -178,10 +179,6 @@ export class ProjectsService {
178179
return result;
179180
}
180181

181-
async setProjectConfiguration(projectId: string, config: ProjectConfig): Promise<void> {
182-
return this.projectDB.setProjectConfiguration(projectId, config);
183-
}
184-
185182
protected async getRepositoryFileProviderAndCommitContext(ctx: TraceContext, user: User, cloneUrl: string): Promise<{fileProvider: FileProvider, commitContext: CommitContext}> {
186183
const normalizedContextUrl = this.contextParser.normalizeContextURL(cloneUrl);
187184
const commitContext = (await this.contextParser.handle(ctx, user, normalizedContextUrl)) as CommitContext;
@@ -229,17 +226,8 @@ export class ProjectsService {
229226
return configString;
230227
}
231228

232-
async updateProjectSettings(projectId: string, partialSettings: Partial<ProjectSettings>): Promise<void> {
233-
const project = await this.getProject(projectId);
234-
if (!project) {
235-
throw new Error("Project not found");
236-
}
237-
const settings = project.settings || {};
238-
let key: keyof ProjectSettings;
239-
for (key in partialSettings) {
240-
settings[key] = partialSettings[key];
241-
}
242-
return this.projectDB.setProjectSettings(projectId, settings);
229+
async updateProjectPartial(partialProject: PartialProject): Promise<void> {
230+
return this.projectDB.updateProject(partialProject);
243231
}
244232

245233
}

components/server/src/workspace/gitpod-server-impl.ts

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import { LocalMessageBroker } from "../messaging/local-message-broker";
5353
import { CachingBlobServiceClientProvider } from '@gitpod/content-service/lib/sugar';
5454
import { IDEOptions } from '@gitpod/gitpod-protocol/lib/ide-protocol';
5555
import { IDEConfigService } from '../ide-config';
56-
import { ProjectSettings } from '@gitpod/gitpod-protocol/src/teams-projects-protocol';
56+
import { PartialProject } from '@gitpod/gitpod-protocol/src/teams-projects-protocol';
5757

5858
// shortcut
5959
export const traceWI = (ctx: TraceContext, wi: Omit<LogContext, "userId">) => TraceContext.setOWI(ctx, wi); // userId is already taken care of in WebsocketConnectionManager
@@ -1636,18 +1636,6 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
16361636
throw new ResponseError(ErrorCodes.EE_FEATURE, `Cancelling Prebuilds is implemented in Gitpod's Enterprise Edition`);
16371637
}
16381638

1639-
public async setProjectConfiguration(ctx: TraceContext, projectId: string, configString: string): Promise<void> {
1640-
traceAPIParams(ctx, { projectId }); // filter configString because of size
1641-
1642-
const user = this.checkAndBlockUser("setProjectConfiguration");
1643-
await this.guardProjectOperation(user, projectId, "update");
1644-
const parseResult = this.gitpodParser.parse(configString);
1645-
if (parseResult.validationErrors) {
1646-
throw new Error(`This configuration could not be parsed: ${parseResult.validationErrors.join(', ')}`);
1647-
}
1648-
await this.projectsService.setProjectConfiguration(projectId, { '.gitpod.yml': configString });
1649-
}
1650-
16511639
public async fetchRepositoryConfiguration(ctx: TraceContext, cloneUrl: string): Promise<string | undefined> {
16521640
traceAPIParams(ctx, { cloneUrl });
16531641
const user = this.checkUser("fetchRepositoryConfiguration");
@@ -1714,10 +1702,33 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
17141702
}
17151703
}
17161704

1717-
public async updateProjectSettings(ctx: TraceContext, projectId: string, partialSettings: Partial<ProjectSettings>): Promise<void> {
1718-
const user = this.checkUser("updateProjectSettings");
1705+
public async setProjectConfiguration(ctx: TraceContext, projectId: string, configString: string): Promise<void> {
1706+
traceAPIParams(ctx, { projectId }); // filter configString because of size
1707+
1708+
const user = this.checkAndBlockUser("setProjectConfiguration");
17191709
await this.guardProjectOperation(user, projectId, "update");
1720-
await this.projectsService.updateProjectSettings(projectId, partialSettings);
1710+
const parseResult = this.gitpodParser.parse(configString);
1711+
if (parseResult.validationErrors) {
1712+
throw new Error(`This configuration could not be parsed: ${parseResult.validationErrors.join(', ')}`);
1713+
}
1714+
await this.projectsService.updateProjectPartial({
1715+
id: projectId,
1716+
config: { '.gitpod.yml': configString },
1717+
});
1718+
}
1719+
1720+
public async updateProjectPartial(ctx: TraceContext, partialProject: PartialProject): Promise<void> {
1721+
const user = this.checkUser("updateProjectPartial");
1722+
await this.guardProjectOperation(user, partialProject.id, "update");
1723+
1724+
const partial: PartialProject = { id: partialProject.id };
1725+
const allowedFields: (keyof Project)[] = ['settings']; // Don't add 'config' here! Please use `setProjectConfiguration` instead to parse & validate configs
1726+
for (const f of allowedFields) {
1727+
if (f in partialProject) {
1728+
(partial[f] as any) = partialProject[f];
1729+
}
1730+
}
1731+
await this.projectsService.updateProjectPartial(partial);
17211732
}
17221733

17231734
public async getContentBlobUploadUrl(ctx: TraceContext, name: string): Promise<string> {

0 commit comments

Comments
 (0)