Skip to content

Commit 18b92d8

Browse files
[.gitpod.yml] Introduce top-level env (#20339)
* [.gitpod.yml] Introduce top-level `env` * Update priority (prioritize User level vars)
1 parent c0c9b74 commit 18b92d8

File tree

7 files changed

+51
-14
lines changed

7 files changed

+51
-14
lines changed

components/gitpod-protocol/data/gitpod-schema.json

+7
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,13 @@
327327
"description": "the hard limit acts as a ceiling for the soft limit. For more details please check https://man7.org/linux/man-pages/man2/getrlimit.2.html"
328328
}
329329
}
330+
},
331+
"env": {
332+
"type": "object",
333+
"description": "Environment variables to set on the workspace.",
334+
"additionalProperties": {
335+
"type": "string"
336+
}
330337
}
331338
},
332339
"additionalProperties": false,

components/gitpod-protocol/go/gitpod-config-types.go

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/gitpod-protocol/src/protocol.ts

+1
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,7 @@ export interface WorkspaceConfig {
801801
jetbrains?: JetBrainsConfig;
802802
coreDump?: CoreDumpConfig;
803803
ideCredentials?: string;
804+
env?: { [env: string]: any };
804805

805806
/** deprecated. Enabled by default **/
806807
experimentalNetwork?: boolean;

components/server/src/user/env-var-service.spec.db.ts

+23-10
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
User,
1414
UserEnvVarValue,
1515
WithEnvvarsContext,
16+
WorkspaceConfig,
1617
} from "@gitpod/gitpod-protocol";
1718
import { Experiments } from "@gitpod/gitpod-protocol/lib/experiments/configcat-server";
1819
import * as chai from "chai";
@@ -43,36 +44,36 @@ const fooAnyUserEnvVar = {
4344
name: "foo",
4445
value: "any",
4546
repositoryPattern: "gitpod/*",
46-
};
47+
} as const;
4748

4849
const barUserCommitEnvVar = {
4950
name: "bar",
5051
value: "commit",
5152
repositoryPattern: "gitpod/gitpod-io",
52-
};
53+
} as const;
5354

5455
const barUserAnotherCommitEnvVar = {
5556
name: "bar",
5657
value: "commit",
5758
repositoryPattern: "gitpod/openvscode-server",
58-
};
59+
} as const;
5960

6061
const barProjectCensoredEnvVar = {
6162
name: "bar",
6263
censored: true,
6364
value: "project1",
64-
};
65+
} as const;
6566

6667
const bazProjectEnvVar = {
6768
name: "baz",
6869
censored: false,
6970
value: "project2",
70-
};
71+
} as const;
7172

7273
const barContextEnvVar = {
7374
name: "bar",
7475
value: "context",
75-
};
76+
} as const;
7677

7778
const contextEnvVars = {
7879
envvars: [barContextEnvVar],
@@ -299,15 +300,22 @@ describe("EnvVarService", async () => {
299300
});
300301
});
301302

302-
it("should resolve env variables regular projext", async () => {
303+
it("should resolve env variables regular project", async () => {
303304
await es.addUserEnvVar(member.id, member.id, fooAnyUserEnvVar);
304305
await es.addUserEnvVar(member.id, member.id, barUserCommitEnvVar);
305306
await es.addUserEnvVar(member.id, member.id, barUserAnotherCommitEnvVar);
306307

307308
await es.addProjectEnvVar(owner.id, project.id, barProjectCensoredEnvVar);
308309
await es.addProjectEnvVar(owner.id, project.id, bazProjectEnvVar);
309310

310-
const envVars = await es.resolveEnvVariables(member.id, project.id, "regular", commitContext);
311+
const workspaceConfig: WorkspaceConfig = {
312+
env: {
313+
foobar: "yes please",
314+
[fooAnyUserEnvVar.name]: "overridden_by_user_var",
315+
},
316+
};
317+
318+
const envVars = await es.resolveEnvVariables(member.id, project.id, "regular", commitContext, workspaceConfig);
311319
envVars.project.forEach((e) => {
312320
delete (e as any).id;
313321
delete (e as any).projectId;
@@ -327,10 +335,15 @@ describe("EnvVarService", async () => {
327335
censored: e.censored,
328336
})),
329337
);
330-
expect(envVars.workspace).to.have.deep.members([fooAnyUserEnvVar, barUserCommitEnvVar, bazProjectEnvVar]);
338+
expect(envVars.workspace).to.have.deep.members([
339+
fooAnyUserEnvVar,
340+
barUserCommitEnvVar,
341+
bazProjectEnvVar,
342+
{ name: "foobar", value: "yes please" },
343+
]);
331344
});
332345

333-
it("should resolve env variables prebuild with projext ", async () => {
346+
it("should resolve env variables prebuild with project", async () => {
334347
await es.addUserEnvVar(member.id, member.id, fooAnyUserEnvVar);
335348
await es.addUserEnvVar(member.id, member.id, barUserCommitEnvVar);
336349
await es.addUserEnvVar(member.id, member.id, barUserAnotherCommitEnvVar);

components/server/src/user/env-var-service.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
UserEnvVar,
1414
UserEnvVarValue,
1515
WithEnvvarsContext,
16+
WorkspaceConfig,
1617
WorkspaceContext,
1718
WorkspaceType,
1819
} from "@gitpod/gitpod-protocol";
@@ -231,6 +232,7 @@ export class EnvVarService {
231232
projectId: string | undefined,
232233
wsType: WorkspaceType,
233234
wsContext: WorkspaceContext,
235+
wsConfig?: WorkspaceConfig,
234236
): Promise<ResolvedEnvVars> {
235237
await this.auth.checkPermissionOnUser(requestorId, "read_env_var", requestorId);
236238
if (projectId) {
@@ -249,7 +251,7 @@ export class EnvVarService {
249251
: [];
250252

251253
if (wsType === "prebuild") {
252-
// prebuild does not have access to user env vars and cannot be started via prewfix URL
254+
// prebuild does not have access to user env vars and cannot be started via prefix URL
253255
const withValues = await this.projectDB.getProjectEnvironmentVariableValues(projectEnvVars);
254256
merge(withValues);
255257
return {
@@ -258,14 +260,23 @@ export class EnvVarService {
258260
};
259261
}
260262

261-
// 1. first merge user envs
263+
// 1. first merge the `env` in the .gitpod.yml
264+
if (wsConfig?.env) {
265+
const configEnvVars = Object.entries(wsConfig.env as Record<string, string>).map(([name, value]) => ({
266+
name,
267+
value,
268+
}));
269+
merge(configEnvVars);
270+
}
271+
272+
// 2. then user envs
262273
if (CommitContext.is(wsContext)) {
263274
// this is a commit context, thus we can filter the env vars
264275
const userEnvVars = await this.userDB.getEnvVars(requestorId);
265276
merge(UserEnvVar.filter(userEnvVars, wsContext.repository.owner, wsContext.repository.name));
266277
}
267278

268-
// 2. then from the project
279+
// 3. then from the project
269280
if (projectEnvVars.length) {
270281
// Instead of using an access guard for Project environment variables, we let Project owners decide whether
271282
// a variable should be:
@@ -276,7 +287,7 @@ export class EnvVarService {
276287
merge(withValues);
277288
}
278289

279-
// 3. then parsed from the context URL
290+
// 4. then parsed from the context URL
280291
if (WithEnvvarsContext.is(wsContext)) {
281292
merge(wsContext.envvars);
282293
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
12261226
workspace.projectId,
12271227
workspace.type,
12281228
workspace.context,
1229+
workspace.config,
12291230
);
12301231

12311232
const result: EnvVarWithValue[] = [];

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

+1
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ export class WorkspaceStarter {
402402
workspace.projectId,
403403
workspace.type,
404404
workspace.context,
405+
workspace.config,
405406
);
406407

407408
await this.actuallyStartWorkspace(ctx, instance, workspace, user, envVars);

0 commit comments

Comments
 (0)