Skip to content

Commit aa7482e

Browse files
committed
Add default workspace image to org setting
1 parent 5cb145e commit aa7482e

File tree

15 files changed

+79
-19
lines changed

15 files changed

+79
-19
lines changed

components/gitpod-cli/cmd/validate.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClie
8888
var dockerContext string
8989
switch img := gitpodConfig.Image.(type) {
9090
case nil:
91+
// TODO: GET FROM SERVER
9192
image = "gitpod/workspace-full:latest"
9293
case string:
9394
image = img

components/gitpod-db/src/typeorm/entity/db-team-settings.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ export class DBOrgSettings implements OrganizationSettings {
1818
})
1919
workspaceSharingDisabled?: boolean;
2020

21+
@Column()
22+
defaultWorkspaceImage?: string; // TODO: migration
23+
2124
@Column()
2225
deleted: boolean;
2326
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,10 @@ export class TeamDBImpl extends TransactionalDBImpl<TeamDB> implements TeamDB {
368368

369369
public async findOrgSettings(orgId: string): Promise<OrganizationSettings | undefined> {
370370
const repo = await this.getOrgSettingsRepo();
371-
return repo.findOne({ where: { orgId, deleted: false }, select: ["orgId", "workspaceSharingDisabled"] });
371+
return repo.findOne({
372+
where: { orgId, deleted: false },
373+
select: ["orgId", "workspaceSharingDisabled", "defaultWorkspaceImage"],
374+
});
372375
}
373376

374377
public async setOrgSettings(orgId: string, settings: Partial<OrganizationSettings>): Promise<void> {
@@ -381,6 +384,7 @@ export class TeamDBImpl extends TransactionalDBImpl<TeamDB> implements TeamDB {
381384
});
382385
} else {
383386
team.workspaceSharingDisabled = settings.workspaceSharingDisabled;
387+
team.defaultWorkspaceImage = settings.defaultWorkspaceImage;
384388
repo.save(team);
385389
}
386390
}

components/gitpod-protocol/src/protocol.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,13 @@ export interface WorkspaceConfig {
972972
_featureFlags?: NamedWorkspaceFeatureFlag[];
973973
}
974974

975+
// WorkspaceConfigContext is the context to help parse/generate workspace config
976+
export interface WorkspaceConfigContext {
977+
// organizationId is used to find organization related workspace config settings,
978+
// - defaultWorkspaceImage: it will affect `image` field
979+
organizationId?: string;
980+
}
981+
975982
export interface GithubAppConfig {
976983
prebuilds?: GithubAppPrebuildConfig;
977984
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ export interface Organization {
148148

149149
export interface OrganizationSettings {
150150
workspaceSharingDisabled?: boolean;
151+
defaultWorkspaceImage?: string;
151152
}
152153

153154
export type TeamMemberRole = OrgMemberRole;

components/server/src/prebuilds/bitbucket-app.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ export class BitbucketApp {
134134
branch: context.ref,
135135
commit: context.revision,
136136
});
137-
const config = await this.prebuildManager.fetchConfig({ span }, user, context);
137+
const config = await this.prebuildManager.fetchConfig({ span }, user, context, {
138+
organizationId: projectAndOwner.project?.teamId,
139+
});
138140
if (!this.prebuildManager.shouldPrebuild(config)) {
139141
console.log("Bitbucket push event: No config. No prebuild.");
140142
await this.webhookEvents.updateEvent(event.id, {

components/server/src/prebuilds/bitbucket-server-app.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,18 @@ export class BitbucketServerApp {
128128
})
129129
.catch((err) => log.error("cannot update project usage", err));
130130
}
131+
// handle context again with organization settings
132+
const commitContext = (await this.contextParser.handle({ span }, user, contextUrl)) as CommitContext;
131133
await this.webhookEvents.updateEvent(event.id, {
132134
authorizedUserId: user.id,
133135
projectId: projectAndOwner?.project?.id,
134136
cloneUrl,
135-
branch: context.ref,
136-
commit: context.revision,
137+
branch: commitContext.ref,
138+
commit: commitContext.revision,
139+
});
140+
const config = await this.prebuildManager.fetchConfig({ span }, user, commitContext, {
141+
organizationId: projectAndOwner.project?.teamId,
137142
});
138-
const config = await this.prebuildManager.fetchConfig({ span }, user, context);
139143
if (!this.prebuildManager.shouldPrebuild(config)) {
140144
log.info("Bitbucket push event: No config. No prebuild.");
141145
await this.webhookEvents.updateEvent(event.id, {
@@ -154,7 +158,7 @@ export class BitbucketServerApp {
154158
{
155159
user: projectAndOwner.user,
156160
project: projectAndOwner?.project,
157-
context,
161+
context: commitContext,
158162
commitInfo,
159163
},
160164
);

components/server/src/prebuilds/github-app.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,9 @@ export class GithubApp {
295295
span.setTag("contextURL", contextURL);
296296

297297
const context = (await this.contextParser.handle({ span }, user, contextURL)) as CommitContext;
298-
const config = await this.prebuildManager.fetchConfig({ span }, user, context);
298+
const config = await this.prebuildManager.fetchConfig({ span }, user, context, {
299+
organizationId: project?.teamId,
300+
});
299301

300302
const r = await this.ensureMainProjectAndUser(user, project, context, installationId);
301303
user = r.user;
@@ -435,7 +437,9 @@ export class GithubApp {
435437
}
436438

437439
const context = (await this.contextParser.handle({ span }, user, contextURL)) as CommitContext;
438-
const config = await this.prebuildManager.fetchConfig({ span }, user, context);
440+
const config = await this.prebuildManager.fetchConfig({ span }, user, context, {
441+
organizationId: project?.teamId,
442+
});
439443

440444
const r = await this.ensureMainProjectAndUser(user, project, context, installationId);
441445
user = r.user;

components/server/src/prebuilds/github-enterprise-app.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,9 @@ export class GitHubEnterpriseApp {
168168
commit: context.revision,
169169
});
170170

171-
const config = await this.prebuildManager.fetchConfig({ span }, user, context);
171+
const config = await this.prebuildManager.fetchConfig({ span }, user, context, {
172+
organizationId: projectAndOwner.project?.teamId,
173+
});
172174
if (
173175
!this.prebuildManager.shouldPrebuild(config) ||
174176
!this.appRules.shouldRunPrebuild(config, context.ref === context.repository.defaultBranch, false, false)

components/server/src/prebuilds/gitlab-app.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,9 @@ export class GitLabApp {
158158
commit: context.revision,
159159
});
160160

161-
const config = await this.prebuildManager.fetchConfig({ span }, user, context);
161+
const config = await this.prebuildManager.fetchConfig({ span }, user, context, {
162+
organizationId: projectAndOwner.project?.teamId,
163+
});
162164
if (!this.prebuildManager.shouldPrebuild(config)) {
163165
log.debug({ userId: user.id }, "GitLab push hook: There is no prebuild config.", {
164166
context: body,

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
User,
1717
Workspace,
1818
WorkspaceConfig,
19+
WorkspaceConfigContext,
1920
WorkspaceInstance,
2021
} from "@gitpod/gitpod-protocol";
2122
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
@@ -137,7 +138,9 @@ export class PrebuildManager {
137138
}
138139
await this.checkUsageLimitReached(user, project.teamId); // throws if out of credits
139140

140-
const config = await this.fetchConfig({ span }, user, context);
141+
const config = await this.fetchConfig({ span }, user, context, {
142+
organizationId: project.teamId,
143+
});
141144

142145
if (!forcePrebuild) {
143146
// Check for an existing, successful prebuild, before triggering a new one.
@@ -366,10 +369,15 @@ export class PrebuildManager {
366369
return this.config.incrementalPrebuilds.repositoryPasslist.some((url) => trimRepoUrl(url) === repoUrl);
367370
}
368371

369-
async fetchConfig(ctx: TraceContext, user: User, context: CommitContext): Promise<WorkspaceConfig> {
372+
async fetchConfig(
373+
ctx: TraceContext,
374+
user: User,
375+
context: CommitContext,
376+
configContext: WorkspaceConfigContext,
377+
): Promise<WorkspaceConfig> {
370378
const span = TraceContext.startSpan("fetchConfig", ctx);
371379
try {
372-
return (await this.configProvider.fetchConfig({ span }, user, context)).config;
380+
return (await this.configProvider.fetchConfig({ span }, user, context, configContext)).config;
373381
} catch (err) {
374382
TraceContext.setError({ span }, err);
375383
throw err;

components/server/src/workspace/config-provider.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import {
2222
AdditionalContentContext,
2323
WithDefaultConfig,
2424
ProjectConfig,
25+
OrganizationSettings,
26+
WorkspaceConfigContext,
2527
} from "@gitpod/gitpod-protocol";
2628
import { GitpodFileParser } from "@gitpod/gitpod-protocol/lib/gitpod-file-parser";
2729

@@ -49,6 +51,7 @@ export class ConfigProvider {
4951
ctx: TraceContext,
5052
user: User,
5153
commit: CommitContext,
54+
configContext: WorkspaceConfigContext,
5255
): Promise<{ config: WorkspaceConfig; literalConfig?: ProjectConfig }> {
5356
const span = TraceContext.startSpan("fetchConfig", ctx);
5457
span.addTags({
@@ -59,6 +62,11 @@ export class ConfigProvider {
5962
try {
6063
let customConfig: WorkspaceConfig | undefined;
6164
let literalConfig: ProjectConfig | undefined;
65+
let orgSettings: OrganizationSettings | undefined;
66+
67+
if (configContext.organizationId) {
68+
orgSettings = await this.teamDB.findOrgSettings(configContext.organizationId);
69+
}
6270

6371
if (!WithDefaultConfig.is(commit)) {
6472
const cc = await this.fetchCustomConfig(ctx, user, commit);
@@ -78,13 +86,16 @@ export class ConfigProvider {
7886
if (!ImageConfigString.is(config.image)) {
7987
throw new Error(`Default config must contain a base image!`);
8088
}
89+
if (orgSettings?.defaultWorkspaceImage) {
90+
config.image = orgSettings.defaultWorkspaceImage;
91+
}
8192
config._origin = "default";
8293
return { config, literalConfig };
8394
}
8495

8596
const config = customConfig;
8697
if (!config.image) {
87-
config.image = this.config.workspaceDefaults.workspaceImage;
98+
config.image = orgSettings?.defaultWorkspaceImage ?? this.config.workspaceDefaults.workspaceImage;
8899
} else if (ImageConfigFile.is(config.image)) {
89100
const dockerfilePath = [configBasePath, config.image.file].filter((s) => !!s).join("/");
90101
const repo = commit.repository;

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ export class ContextParser {
117117
}
118118
const span = TraceContext.startSpan("ContextParser.handleMultiRepositoryContext", ctx);
119119
try {
120-
let config = await this.configProvider.fetchConfig({ span }, user, context);
120+
// Note: we only care about repo related stuff in this function.
121+
// Fields like `config.image` will not be exposed, so pass an empty WorkspaceConfigContext here
122+
let config = await this.configProvider.fetchConfig({ span }, user, context, {});
121123
let mainRepoContext: WorkspaceContext | undefined;
122124
if (config.config.mainConfiguration) {
123125
mainRepoContext = await this.internalHandleWithoutPrefix(
@@ -130,7 +132,9 @@ export class ContextParser {
130132
`Cannot find main repository '${config.config.mainConfiguration}'.`,
131133
]);
132134
}
133-
config = await this.configProvider.fetchConfig({ span }, user, mainRepoContext);
135+
// Note: we only care about repo related stuff in this function.
136+
// Fields like `config.image` will not be exposed, so pass an empty WorkspaceConfigContext here
137+
config = await this.configProvider.fetchConfig({ span }, user, mainRepoContext, {});
134138
}
135139

136140
if (config.config.additionalRepositories && config.config.additionalRepositories.length > 0) {

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ import {
132132
ProjectEnvVar,
133133
UserEnvVar,
134134
UserFeatureSettings,
135+
WorkspaceConfigContext,
135136
WorkspaceTimeoutSetting,
136137
} from "@gitpod/gitpod-protocol/lib/protocol";
137138
import { ListUsageRequest, ListUsageResponse } from "@gitpod/gitpod-protocol/lib/usage";
@@ -330,6 +331,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
330331
parentCtx: TraceContext,
331332
user: User,
332333
context: WorkspaceContext,
334+
configContext: WorkspaceConfigContext,
333335
ignoreRunningPrebuild?: boolean,
334336
allowUsingPreviousPrebuilds?: boolean,
335337
): Promise<WorkspaceCreationResult | PrebuiltWorkspaceContext | undefined> {
@@ -366,7 +368,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
366368
.trace(ctx)
367369
.findPrebuiltWorkspaceByCommit(cloneUrl, commitSHAs);
368370
if (!prebuiltWorkspace && allowUsingPreviousPrebuilds) {
369-
const { config } = await this.configProvider.fetchConfig({}, user, context);
371+
const { config } = await this.configProvider.fetchConfig({}, user, context, configContext);
370372
const history = await this.incrementalPrebuildsService.getCommitHistoryForContext(context, user);
371373
prebuiltWorkspace = await this.incrementalPrebuildsService.findGoodBaseForIncrementalBuild(
372374
context,
@@ -1344,6 +1346,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
13441346
ctx,
13451347
user,
13461348
context,
1349+
{ organizationId: options.organizationId },
13471350
options.ignoreRunningPrebuild,
13481351
options.allowUsingPreviousPrebuilds || project?.settings?.allowUsingPreviousPrebuilds,
13491352
);

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,9 @@ export class WorkspaceFactory {
110110

111111
await assertNoPrebuildIsRunningForSameCommit();
112112

113-
const { config } = await this.configProvider.fetchConfig({ span }, user, context.actual);
113+
const { config } = await this.configProvider.fetchConfig({ span }, user, context.actual, {
114+
organizationId,
115+
});
114116

115117
// If an incremental prebuild was requested, see if we can find a recent prebuild to act as a base.
116118
let ws;
@@ -371,7 +373,9 @@ export class WorkspaceFactory {
371373
const span = TraceContext.startSpan("createForCommit", ctx);
372374

373375
try {
374-
const { config, literalConfig } = await this.configProvider.fetchConfig({ span }, user, context);
376+
const { config, literalConfig } = await this.configProvider.fetchConfig({ span }, user, context, {
377+
organizationId,
378+
});
375379
const imageSource = await this.imageSourceProvider.getImageSource(ctx, user, context, config);
376380
if (config._origin === "derived" && literalConfig) {
377381
(context as any as AdditionalContentContext).additionalFiles = { ...literalConfig };

0 commit comments

Comments
 (0)