@gitpod/gitpod-protocol 0.1.5-sje-pacman.1 → 0.1.5-sje-kots-node-reqs.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/gitpod-schema.json +153 -2
- package/lib/accounting-protocol.d.ts +7 -0
- package/lib/accounting-protocol.d.ts.map +1 -1
- package/lib/accounting-protocol.js +8 -1
- package/lib/accounting-protocol.js.map +1 -1
- package/lib/admin-protocol.d.ts +4 -0
- package/lib/admin-protocol.d.ts.map +1 -1
- package/lib/admin-protocol.js.map +1 -1
- package/lib/attribution.d.ts +20 -0
- package/lib/attribution.d.ts.map +1 -0
- package/lib/attribution.js +40 -0
- package/lib/attribution.js.map +1 -0
- package/lib/blocked-repositories-protocol.d.ts +13 -0
- package/lib/blocked-repositories-protocol.d.ts.map +1 -0
- package/lib/blocked-repositories-protocol.js +8 -0
- package/lib/blocked-repositories-protocol.js.map +1 -0
- package/lib/context-url.js +1 -1
- package/lib/context-url.js.map +1 -1
- package/lib/env.d.ts +0 -5
- package/lib/env.d.ts.map +1 -1
- package/lib/env.js +1 -20
- package/lib/env.js.map +1 -1
- package/lib/experiments/always-default.d.ts +8 -0
- package/lib/experiments/always-default.d.ts.map +1 -0
- package/lib/experiments/always-default.js +20 -0
- package/lib/experiments/always-default.js.map +1 -0
- package/lib/experiments/configcat-server.d.ts +8 -0
- package/lib/experiments/configcat-server.d.ts.map +1 -0
- package/lib/experiments/configcat-server.js +35 -0
- package/lib/experiments/configcat-server.js.map +1 -0
- package/lib/experiments/configcat.d.ts +22 -0
- package/lib/experiments/configcat.d.ts.map +1 -0
- package/lib/experiments/configcat.js +53 -0
- package/lib/experiments/configcat.js.map +1 -0
- package/lib/experiments/types.d.ts +23 -0
- package/lib/experiments/types.d.ts.map +1 -0
- package/lib/experiments/types.js +10 -0
- package/lib/experiments/types.js.map +1 -0
- package/lib/gitpod-service.d.ts +29 -5
- package/lib/gitpod-service.d.ts.map +1 -1
- package/lib/gitpod-service.js +20 -10
- package/lib/gitpod-service.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/installation-admin-protocol.d.ts +3 -0
- package/lib/installation-admin-protocol.d.ts.map +1 -1
- package/lib/installation-admin-protocol.js +1 -0
- package/lib/installation-admin-protocol.js.map +1 -1
- package/lib/license-protocol.d.ts +7 -0
- package/lib/license-protocol.d.ts.map +1 -1
- package/lib/license-protocol.js.map +1 -1
- package/lib/messaging/error.d.ts +2 -0
- package/lib/messaging/error.d.ts.map +1 -1
- package/lib/messaging/error.js +4 -0
- package/lib/messaging/error.js.map +1 -1
- package/lib/protocol.d.ts +86 -4
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +183 -12
- package/lib/protocol.js.map +1 -1
- package/lib/protocol.spec.d.ts +7 -0
- package/lib/protocol.spec.d.ts.map +1 -0
- package/lib/protocol.spec.js +127 -0
- package/lib/protocol.spec.js.map +1 -0
- package/lib/team-subscription-protocol.d.ts +16 -0
- package/lib/team-subscription-protocol.d.ts.map +1 -1
- package/lib/team-subscription-protocol.js +12 -1
- package/lib/team-subscription-protocol.js.map +1 -1
- package/lib/teams-projects-protocol.d.ts +18 -0
- package/lib/teams-projects-protocol.d.ts.map +1 -1
- package/lib/teams-projects-protocol.js.map +1 -1
- package/lib/usage.d.ts +22 -0
- package/lib/usage.d.ts.map +1 -0
- package/lib/usage.js +115 -0
- package/lib/usage.js.map +1 -0
- package/lib/util/debug-app.d.ts +25 -0
- package/lib/util/debug-app.d.ts.map +1 -0
- package/lib/util/debug-app.js +100 -0
- package/lib/util/debug-app.js.map +1 -0
- package/lib/util/generate-workspace-id.d.ts +5 -0
- package/lib/util/generate-workspace-id.d.ts.map +1 -1
- package/lib/util/generate-workspace-id.js +12 -8
- package/lib/util/generate-workspace-id.js.map +1 -1
- package/lib/util/generate-workspace-id.spec.js +10 -3
- package/lib/util/generate-workspace-id.spec.js.map +1 -1
- package/lib/util/logging.d.ts.map +1 -1
- package/lib/util/logging.js +9 -2
- package/lib/util/logging.js.map +1 -1
- package/lib/util/timeutil.d.ts +1 -0
- package/lib/util/timeutil.d.ts.map +1 -1
- package/lib/util/timeutil.js +7 -1
- package/lib/util/timeutil.js.map +1 -1
- package/lib/util/tracing.d.ts.map +1 -1
- package/lib/util/tracing.js +8 -10
- package/lib/util/tracing.js.map +1 -1
- package/lib/webhook-event.d.ts +44 -0
- package/lib/webhook-event.d.ts.map +1 -0
- package/lib/webhook-event.js +8 -0
- package/lib/webhook-event.js.map +1 -0
- package/lib/workspace-cluster.d.ts +5 -7
- package/lib/workspace-cluster.d.ts.map +1 -1
- package/lib/workspace-cluster.js.map +1 -1
- package/lib/workspace-instance.d.ts +17 -1
- package/lib/workspace-instance.d.ts.map +1 -1
- package/lib/wsready.js +1 -1
- package/package.json +9 -6
- package/pkg-yarn.lock +7 -5
- package/provenance-bundle.jsonl +1 -1
- package/src/accounting-protocol.ts +10 -0
- package/src/admin-protocol.ts +7 -0
- package/src/attribution.ts +48 -0
- package/src/blocked-repositories-protocol.ts +13 -0
- package/src/context-url.ts +1 -1
- package/src/env.ts +0 -22
- package/src/experiments/always-default.ts +24 -0
- package/src/experiments/configcat-server.ts +38 -0
- package/src/experiments/configcat.ts +58 -0
- package/src/experiments/types.ts +35 -0
- package/src/gitpod-service.ts +54 -11
- package/src/index.ts +1 -0
- package/src/installation-admin-protocol.ts +3 -0
- package/src/license-protocol.ts +7 -0
- package/src/messaging/error.ts +6 -0
- package/src/protocol.spec.ts +97 -0
- package/src/protocol.ts +258 -13
- package/src/team-subscription-protocol.ts +24 -0
- package/src/teams-projects-protocol.ts +20 -0
- package/src/usage.ts +146 -0
- package/src/util/debug-app.ts +81 -0
- package/src/util/generate-workspace-id.spec.ts +10 -3
- package/src/util/generate-workspace-id.ts +9 -3
- package/src/util/logging.ts +11 -3
- package/src/util/timeutil.ts +6 -0
- package/src/util/tracing.ts +8 -10
- package/src/webhook-event.ts +55 -0
- package/src/workspace-cluster.ts +2 -4
- package/src/workspace-instance.ts +30 -1
- package/src/wsready.ts +1 -1
package/src/protocol.ts
CHANGED
|
@@ -68,13 +68,22 @@ export namespace User {
|
|
|
68
68
|
});
|
|
69
69
|
return res;
|
|
70
70
|
}
|
|
71
|
-
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Returns the stored email or if it doesn't exist returns the primaryEmail of the first identity this user signed up with.
|
|
74
|
+
* @param user
|
|
75
|
+
* @returns A primaryEmail, or undefined if there is none.
|
|
76
|
+
*/
|
|
77
|
+
export function getPrimaryEmail(user: User): string | undefined {
|
|
78
|
+
if (user.additionalData?.profile?.emailAddress) {
|
|
79
|
+
return user.additionalData?.profile?.emailAddress;
|
|
80
|
+
}
|
|
72
81
|
const identities = user.identities.filter((i) => !!i.primaryEmail);
|
|
73
82
|
if (identities.length <= 0) {
|
|
74
|
-
|
|
83
|
+
return undefined;
|
|
75
84
|
}
|
|
76
85
|
|
|
77
|
-
return identities[0].primaryEmail
|
|
86
|
+
return identities[0].primaryEmail || undefined;
|
|
78
87
|
}
|
|
79
88
|
export function getName(user: User): string | undefined {
|
|
80
89
|
const name = user.fullName || user.name;
|
|
@@ -89,6 +98,91 @@ export namespace User {
|
|
|
89
98
|
}
|
|
90
99
|
return undefined;
|
|
91
100
|
}
|
|
101
|
+
|
|
102
|
+
export function hasPreferredIde(user: User) {
|
|
103
|
+
return (
|
|
104
|
+
typeof user?.additionalData?.ideSettings?.defaultIde !== "undefined" ||
|
|
105
|
+
typeof user?.additionalData?.ideSettings?.useLatestVersion !== "undefined"
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function isOnboardingUser(user: User) {
|
|
110
|
+
return !hasPreferredIde(user);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function migrationIDESettings(user: User) {
|
|
114
|
+
if (
|
|
115
|
+
!user?.additionalData?.ideSettings ||
|
|
116
|
+
Object.keys(user.additionalData.ideSettings).length === 0 ||
|
|
117
|
+
user.additionalData.ideSettings.settingVersion === "2.0"
|
|
118
|
+
) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const newIDESettings: IDESettings = {
|
|
122
|
+
settingVersion: "2.0",
|
|
123
|
+
};
|
|
124
|
+
const ideSettings = user.additionalData.ideSettings;
|
|
125
|
+
if (ideSettings.useDesktopIde) {
|
|
126
|
+
if (ideSettings.defaultDesktopIde === "code-desktop") {
|
|
127
|
+
newIDESettings.defaultIde = "code-desktop";
|
|
128
|
+
} else if (ideSettings.defaultDesktopIde === "code-desktop-insiders") {
|
|
129
|
+
newIDESettings.defaultIde = "code-desktop";
|
|
130
|
+
newIDESettings.useLatestVersion = true;
|
|
131
|
+
} else {
|
|
132
|
+
newIDESettings.defaultIde = ideSettings.defaultDesktopIde;
|
|
133
|
+
newIDESettings.useLatestVersion = ideSettings.useLatestVersion;
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
const useLatest = ideSettings.defaultIde === "code-latest";
|
|
137
|
+
newIDESettings.defaultIde = "code";
|
|
138
|
+
newIDESettings.useLatestVersion = useLatest;
|
|
139
|
+
}
|
|
140
|
+
user.additionalData.ideSettings = newIDESettings;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function getProfile(user: User): Profile {
|
|
144
|
+
return {
|
|
145
|
+
name: User.getName(user!) || "",
|
|
146
|
+
email: User.getPrimaryEmail(user!) || "",
|
|
147
|
+
company: user?.additionalData?.profile?.companyName,
|
|
148
|
+
avatarURL: user?.avatarUrl,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function setProfile(user: User, profile: Profile): User {
|
|
153
|
+
user.fullName = profile.name;
|
|
154
|
+
user.avatarUrl = profile.avatarURL;
|
|
155
|
+
|
|
156
|
+
if (!user.additionalData) {
|
|
157
|
+
user.additionalData = {};
|
|
158
|
+
}
|
|
159
|
+
if (!user.additionalData.profile) {
|
|
160
|
+
user.additionalData.profile = {};
|
|
161
|
+
}
|
|
162
|
+
user.additionalData.profile.emailAddress = profile.email;
|
|
163
|
+
user.additionalData.profile.companyName = profile.company;
|
|
164
|
+
user.additionalData.profile.lastUpdatedDetailsNudge = new Date().toISOString();
|
|
165
|
+
|
|
166
|
+
return user;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// The actual Profile of a User
|
|
170
|
+
export interface Profile {
|
|
171
|
+
name: string;
|
|
172
|
+
email: string;
|
|
173
|
+
company?: string;
|
|
174
|
+
avatarURL?: string;
|
|
175
|
+
}
|
|
176
|
+
export namespace Profile {
|
|
177
|
+
export function hasChanges(before: Profile, after: Profile) {
|
|
178
|
+
return (
|
|
179
|
+
before.name !== after.name ||
|
|
180
|
+
before.email !== after.email ||
|
|
181
|
+
before.company !== after.company ||
|
|
182
|
+
before.avatarURL !== after.avatarURL
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
92
186
|
}
|
|
93
187
|
|
|
94
188
|
export interface AdditionalUserData {
|
|
@@ -103,9 +197,24 @@ export interface AdditionalUserData {
|
|
|
103
197
|
oauthClientsApproved?: { [key: string]: string };
|
|
104
198
|
// to remember GH Orgs the user installed/updated the GH App for
|
|
105
199
|
knownGitHubOrgs?: string[];
|
|
106
|
-
|
|
107
200
|
// Git clone URL pointing to the user's dotfile repo
|
|
108
201
|
dotfileRepo?: string;
|
|
202
|
+
// Identifies an explicit team or user ID to which all the user's workspace usage should be attributed to (e.g. for billing purposes)
|
|
203
|
+
usageAttributionId?: string;
|
|
204
|
+
// preferred workspace classes
|
|
205
|
+
workspaceClasses?: WorkspaceClasses;
|
|
206
|
+
// additional user profile data
|
|
207
|
+
profile?: ProfileDetails;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// The format in which we store User Profiles in
|
|
211
|
+
export interface ProfileDetails {
|
|
212
|
+
// when was the last time the user updated their profile information or has been nudged to do so.
|
|
213
|
+
lastUpdatedDetailsNudge?: string;
|
|
214
|
+
// the user's company name
|
|
215
|
+
companyName?: string;
|
|
216
|
+
// the user's email
|
|
217
|
+
emailAddress?: string;
|
|
109
218
|
}
|
|
110
219
|
|
|
111
220
|
export interface EmailNotificationSettings {
|
|
@@ -115,12 +224,20 @@ export interface EmailNotificationSettings {
|
|
|
115
224
|
}
|
|
116
225
|
|
|
117
226
|
export type IDESettings = {
|
|
227
|
+
settingVersion?: string;
|
|
118
228
|
defaultIde?: string;
|
|
229
|
+
// DEPRECATED: Use defaultIde after `settingVersion: 2.0`, no more specialify desktop or browser.
|
|
119
230
|
useDesktopIde?: boolean;
|
|
231
|
+
// DEPRECATED: Same with useDesktopIde.
|
|
120
232
|
defaultDesktopIde?: string;
|
|
121
233
|
useLatestVersion?: boolean;
|
|
122
234
|
};
|
|
123
235
|
|
|
236
|
+
export interface WorkspaceClasses {
|
|
237
|
+
regular: string;
|
|
238
|
+
prebuild: string;
|
|
239
|
+
}
|
|
240
|
+
|
|
124
241
|
export interface UserPlatform {
|
|
125
242
|
uid: string;
|
|
126
243
|
userAgent: string;
|
|
@@ -151,7 +268,12 @@ export interface UserFeatureSettings {
|
|
|
151
268
|
* The values of this type MUST MATCH enum values in WorkspaceFeatureFlag from ws-manager/client/core_pb.d.ts
|
|
152
269
|
* If they don't we'll break things during workspace startup.
|
|
153
270
|
*/
|
|
154
|
-
export const WorkspaceFeatureFlags = {
|
|
271
|
+
export const WorkspaceFeatureFlags = {
|
|
272
|
+
full_workspace_backup: undefined,
|
|
273
|
+
fixed_resources: undefined,
|
|
274
|
+
persistent_volume_claim: undefined,
|
|
275
|
+
protected_secrets: undefined,
|
|
276
|
+
};
|
|
155
277
|
export type NamedWorkspaceFeatureFlag = keyof typeof WorkspaceFeatureFlags;
|
|
156
278
|
|
|
157
279
|
export interface EnvVarWithValue {
|
|
@@ -178,6 +300,45 @@ export interface UserEnvVar extends UserEnvVarValue {
|
|
|
178
300
|
}
|
|
179
301
|
|
|
180
302
|
export namespace UserEnvVar {
|
|
303
|
+
/**
|
|
304
|
+
* @param variable
|
|
305
|
+
* @returns Either a string containing an error message or undefined.
|
|
306
|
+
*/
|
|
307
|
+
export function validate(variable: UserEnvVarValue): string | undefined {
|
|
308
|
+
const name = variable.name;
|
|
309
|
+
const pattern = variable.repositoryPattern;
|
|
310
|
+
if (name.trim() === "") {
|
|
311
|
+
return "Name must not be empty.";
|
|
312
|
+
}
|
|
313
|
+
if (name.length > 255) {
|
|
314
|
+
return "Name too long. Maximum name length is 255 characters.";
|
|
315
|
+
}
|
|
316
|
+
if (!/^[a-zA-Z_]+[a-zA-Z0-9_]*$/.test(name)) {
|
|
317
|
+
return "Name must match /^[a-zA-Z_]+[a-zA-Z0-9_]*$/.";
|
|
318
|
+
}
|
|
319
|
+
if (variable.value.trim() === "") {
|
|
320
|
+
return "Value must not be empty.";
|
|
321
|
+
}
|
|
322
|
+
if (variable.value.length > 32767) {
|
|
323
|
+
return "Value too long. Maximum value length is 32767 characters.";
|
|
324
|
+
}
|
|
325
|
+
if (pattern.trim() === "") {
|
|
326
|
+
return "Scope must not be empty.";
|
|
327
|
+
}
|
|
328
|
+
const split = pattern.split("/");
|
|
329
|
+
if (split.length < 2) {
|
|
330
|
+
return "A scope must use the form 'organization/repo'.";
|
|
331
|
+
}
|
|
332
|
+
for (const name of split) {
|
|
333
|
+
if (name !== "*") {
|
|
334
|
+
if (!/^[a-zA-Z0-9_\-.\*]+$/.test(name)) {
|
|
335
|
+
return "Invalid scope segment. Only ASCII characters, numbers, -, _, . or * are allowed.";
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return undefined;
|
|
340
|
+
}
|
|
341
|
+
|
|
181
342
|
// DEPRECATED: Use ProjectEnvVar instead of repositoryPattern - https://github.com/gitpod-com/gitpod/issues/5322
|
|
182
343
|
export function normalizeRepoPattern(pattern: string) {
|
|
183
344
|
return pattern.toLocaleLowerCase();
|
|
@@ -263,6 +424,68 @@ export namespace UserEnvVar {
|
|
|
263
424
|
}
|
|
264
425
|
}
|
|
265
426
|
|
|
427
|
+
export interface SSHPublicKeyValue {
|
|
428
|
+
name: string;
|
|
429
|
+
key: string;
|
|
430
|
+
}
|
|
431
|
+
export interface UserSSHPublicKey extends SSHPublicKeyValue {
|
|
432
|
+
id: string;
|
|
433
|
+
key: string;
|
|
434
|
+
userId: string;
|
|
435
|
+
fingerprint: string;
|
|
436
|
+
creationTime: string;
|
|
437
|
+
lastUsedTime?: string;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export type UserSSHPublicKeyValue = Omit<UserSSHPublicKey, "key" | "userId">;
|
|
441
|
+
|
|
442
|
+
export namespace SSHPublicKeyValue {
|
|
443
|
+
export function validate(value: SSHPublicKeyValue): string | undefined {
|
|
444
|
+
if (value.name.length === 0) {
|
|
445
|
+
return "Title must not be empty.";
|
|
446
|
+
}
|
|
447
|
+
if (value.name.length > 255) {
|
|
448
|
+
return "Title too long. Maximum value length is 255 characters.";
|
|
449
|
+
}
|
|
450
|
+
if (value.key.length === 0) {
|
|
451
|
+
return "Key must not be empty.";
|
|
452
|
+
}
|
|
453
|
+
try {
|
|
454
|
+
getData(value);
|
|
455
|
+
} catch (e) {
|
|
456
|
+
return "Key is invalid. You must supply a key in OpenSSH public key format.";
|
|
457
|
+
}
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
export function getData(value: SSHPublicKeyValue) {
|
|
462
|
+
// Begins with 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'ssh-ed25519', 'sk-ecdsa-sha2-nistp256@openssh.com', or 'sk-ssh-ed25519@openssh.com'.
|
|
463
|
+
const regex =
|
|
464
|
+
/^(?<type>ssh-rsa|ecdsa-sha2-nistp256|ecdsa-sha2-nistp384|ecdsa-sha2-nistp521|ssh-ed25519|sk-ecdsa-sha2-nistp256@openssh\.com|sk-ssh-ed25519@openssh\.com) (?<key>.*?)( (?<email>.*?))?$/;
|
|
465
|
+
const resultGroup = regex.exec(value.key.trim());
|
|
466
|
+
if (!resultGroup) {
|
|
467
|
+
throw new Error("Key is invalid.");
|
|
468
|
+
}
|
|
469
|
+
return {
|
|
470
|
+
type: resultGroup.groups?.["type"] as string,
|
|
471
|
+
key: resultGroup.groups?.["key"] as string,
|
|
472
|
+
email: resultGroup.groups?.["email"] || undefined,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
export function getFingerprint(value: SSHPublicKeyValue) {
|
|
477
|
+
const data = getData(value);
|
|
478
|
+
let buf = Buffer.from(data.key, "base64");
|
|
479
|
+
// gitlab style
|
|
480
|
+
// const hash = createHash("md5").update(buf).digest("hex");
|
|
481
|
+
// github style
|
|
482
|
+
const hash = createHash("sha256").update(buf).digest("base64");
|
|
483
|
+
return hash;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
export const MAXIMUM_KEY_LENGTH = 5;
|
|
487
|
+
}
|
|
488
|
+
|
|
266
489
|
export interface GitpodToken {
|
|
267
490
|
/** Hash value (SHA256) of the token (primary key). */
|
|
268
491
|
tokenHash: string;
|
|
@@ -395,6 +618,13 @@ export interface Snapshot {
|
|
|
395
618
|
message?: string;
|
|
396
619
|
}
|
|
397
620
|
|
|
621
|
+
export interface VolumeSnapshot {
|
|
622
|
+
id: string;
|
|
623
|
+
workspaceId: string;
|
|
624
|
+
creationTime: string;
|
|
625
|
+
volumeHandle: string;
|
|
626
|
+
}
|
|
627
|
+
|
|
398
628
|
export type SnapshotState = "pending" | "available" | "error";
|
|
399
629
|
|
|
400
630
|
export interface LayoutData {
|
|
@@ -464,7 +694,7 @@ export interface Workspace {
|
|
|
464
694
|
|
|
465
695
|
export type WorkspaceSoftDeletion = "user" | "gc";
|
|
466
696
|
|
|
467
|
-
export type WorkspaceType = "regular" | "prebuild" | "probe";
|
|
697
|
+
export type WorkspaceType = "regular" | "prebuild" | "probe"; // TODO(gpl) Removed prove here
|
|
468
698
|
|
|
469
699
|
export namespace Workspace {
|
|
470
700
|
export function getFullRepositoryName(ws: Workspace): string | undefined {
|
|
@@ -532,6 +762,20 @@ export interface VSCodeConfig {
|
|
|
532
762
|
extensions?: string[];
|
|
533
763
|
}
|
|
534
764
|
|
|
765
|
+
export interface JetBrainsConfig {
|
|
766
|
+
intellij?: JetBrainsProductConfig;
|
|
767
|
+
goland?: JetBrainsProductConfig;
|
|
768
|
+
pycharm?: JetBrainsProductConfig;
|
|
769
|
+
phpstorm?: JetBrainsProductConfig;
|
|
770
|
+
}
|
|
771
|
+
export interface JetBrainsProductConfig {
|
|
772
|
+
prebuilds?: JetBrainsPrebuilds;
|
|
773
|
+
vmoptions?: string;
|
|
774
|
+
}
|
|
775
|
+
export interface JetBrainsPrebuilds {
|
|
776
|
+
version?: "stable" | "latest" | "both";
|
|
777
|
+
}
|
|
778
|
+
|
|
535
779
|
export interface RepositoryCloneInformation {
|
|
536
780
|
url: string;
|
|
537
781
|
checkoutLocation?: string;
|
|
@@ -548,6 +792,7 @@ export interface WorkspaceConfig {
|
|
|
548
792
|
gitConfig?: { [config: string]: string };
|
|
549
793
|
github?: GithubAppConfig;
|
|
550
794
|
vscode?: VSCodeConfig;
|
|
795
|
+
jetbrains?: JetBrainsConfig;
|
|
551
796
|
|
|
552
797
|
/** deprecated. Enabled by default **/
|
|
553
798
|
experimentalNetwork?: boolean;
|
|
@@ -634,13 +879,16 @@ export interface PrebuiltWorkspace {
|
|
|
634
879
|
buildWorkspaceId: string;
|
|
635
880
|
creationTime: string;
|
|
636
881
|
state: PrebuiltWorkspaceState;
|
|
882
|
+
statusVersion: number;
|
|
637
883
|
error?: string;
|
|
638
884
|
snapshot?: string;
|
|
639
885
|
}
|
|
640
886
|
|
|
641
887
|
export namespace PrebuiltWorkspace {
|
|
642
888
|
export function isDone(pws: PrebuiltWorkspace) {
|
|
643
|
-
return
|
|
889
|
+
return (
|
|
890
|
+
pws.state === "available" || pws.state === "timeout" || pws.state === "aborted" || pws.state === "failed"
|
|
891
|
+
);
|
|
644
892
|
}
|
|
645
893
|
|
|
646
894
|
export function isAvailable(pws: PrebuiltWorkspace) {
|
|
@@ -764,6 +1012,7 @@ export namespace ExternalImageConfigFile {
|
|
|
764
1012
|
|
|
765
1013
|
export interface WorkspaceContext {
|
|
766
1014
|
title: string;
|
|
1015
|
+
ref?: string;
|
|
767
1016
|
/** This contains the URL portion of the contextURL (which might contain other modifiers as well). It's optional because it's not set for older workspaces. */
|
|
768
1017
|
normalizedContextURL?: string;
|
|
769
1018
|
forceCreateNewWorkspace?: boolean;
|
|
@@ -1015,6 +1264,8 @@ export interface Repository {
|
|
|
1015
1264
|
owner: string;
|
|
1016
1265
|
name: string;
|
|
1017
1266
|
cloneUrl: string;
|
|
1267
|
+
/* Optional kind to differentiate between repositories of orgs/groups/projects and personal repos. */
|
|
1268
|
+
repoKind?: string;
|
|
1018
1269
|
description?: string;
|
|
1019
1270
|
avatarUrl?: string;
|
|
1020
1271
|
webUrl?: string;
|
|
@@ -1143,12 +1394,6 @@ export interface AuthProviderInfo {
|
|
|
1143
1394
|
};
|
|
1144
1395
|
}
|
|
1145
1396
|
|
|
1146
|
-
export namespace AuthProviderInfo {
|
|
1147
|
-
export function isGitHubEnterprise(info?: AuthProviderInfo): boolean {
|
|
1148
|
-
return !!info && info.authProviderType === "GitHub" && info.host !== "github.com";
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
1397
|
export interface AuthProviderEntry {
|
|
1153
1398
|
readonly id: string;
|
|
1154
1399
|
readonly type: AuthProviderEntry.Type;
|
|
@@ -33,6 +33,30 @@ export namespace TeamSubscription {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
export interface TeamSubscription2 {
|
|
37
|
+
id: string;
|
|
38
|
+
teamId: string;
|
|
39
|
+
planId: string;
|
|
40
|
+
startDate: string;
|
|
41
|
+
endDate?: string;
|
|
42
|
+
quantity: number;
|
|
43
|
+
/** The Chargebee subscription id */
|
|
44
|
+
paymentReference: string;
|
|
45
|
+
cancellationDate?: string;
|
|
46
|
+
excludeFromMoreResources: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export namespace TeamSubscription2 {
|
|
50
|
+
export const create = (ts2: Omit<TeamSubscription2, "id">): TeamSubscription2 => {
|
|
51
|
+
const withId = ts2 as TeamSubscription2;
|
|
52
|
+
withId.id = uuidv4();
|
|
53
|
+
return withId;
|
|
54
|
+
};
|
|
55
|
+
export const isActive = (ts2: TeamSubscription2, date: string): boolean => {
|
|
56
|
+
return ts2.startDate <= date && (ts2.endDate === undefined || date < ts2.endDate);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
36
60
|
/**
|
|
37
61
|
* A slot represents one unit of a TeamSubscription that gets assigned to one user at a time
|
|
38
62
|
*/
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { PrebuiltWorkspaceState } from "./protocol";
|
|
8
8
|
import { v4 as uuidv4 } from "uuid";
|
|
9
9
|
import { DeepPartial } from "./util/deep-partial";
|
|
10
|
+
import { WebhookEvent } from "./webhook-event";
|
|
10
11
|
|
|
11
12
|
export interface ProjectConfig {
|
|
12
13
|
".gitpod.yml": string;
|
|
@@ -14,6 +15,8 @@ export interface ProjectConfig {
|
|
|
14
15
|
|
|
15
16
|
export interface ProjectSettings {
|
|
16
17
|
useIncrementalPrebuilds?: boolean;
|
|
18
|
+
usePersistentVolumeClaim?: boolean;
|
|
19
|
+
keepOutdatedPrebuildsRunning?: boolean;
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
export interface Project {
|
|
@@ -69,6 +72,11 @@ export namespace Project {
|
|
|
69
72
|
|
|
70
73
|
export type PartialProject = DeepPartial<Project> & Pick<Project, "id">;
|
|
71
74
|
|
|
75
|
+
export interface ProjectUsage {
|
|
76
|
+
lastWebhookReceived: string;
|
|
77
|
+
lastWorkspaceStart: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
72
80
|
export interface PrebuildWithStatus {
|
|
73
81
|
info: PrebuildInfo;
|
|
74
82
|
status: PrebuiltWorkspaceState;
|
|
@@ -145,3 +153,15 @@ export interface TeamMembershipInvite {
|
|
|
145
153
|
/** This is a flag that triggers the HARD DELETION of this entity */
|
|
146
154
|
deleted?: boolean;
|
|
147
155
|
}
|
|
156
|
+
|
|
157
|
+
export interface PrebuildEvent {
|
|
158
|
+
id: string;
|
|
159
|
+
creationTime: string;
|
|
160
|
+
status: WebhookEvent.Status | WebhookEvent.PrebuildStatus;
|
|
161
|
+
message?: string;
|
|
162
|
+
prebuildId?: string;
|
|
163
|
+
projectId?: string;
|
|
164
|
+
cloneUrl?: string;
|
|
165
|
+
branch?: string;
|
|
166
|
+
commit?: string;
|
|
167
|
+
}
|
package/src/usage.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2022 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 { WorkspaceType } from "./protocol";
|
|
8
|
+
|
|
9
|
+
export interface BillableSession {
|
|
10
|
+
// The id of the one paying the bill
|
|
11
|
+
attributionId: string;
|
|
12
|
+
|
|
13
|
+
// Relevant for workspace type. When prebuild, shows "prebuild"
|
|
14
|
+
userId?: string;
|
|
15
|
+
teamId?: string;
|
|
16
|
+
|
|
17
|
+
instanceId: string;
|
|
18
|
+
|
|
19
|
+
workspaceId: string;
|
|
20
|
+
|
|
21
|
+
workspaceType: BillableWorkspaceType;
|
|
22
|
+
|
|
23
|
+
// "standard" or "XL"
|
|
24
|
+
workspaceClass: string;
|
|
25
|
+
|
|
26
|
+
// When the workspace started
|
|
27
|
+
startTime: string;
|
|
28
|
+
|
|
29
|
+
// When the workspace ended
|
|
30
|
+
endTime: string;
|
|
31
|
+
|
|
32
|
+
// The credits used for this session
|
|
33
|
+
credits: number;
|
|
34
|
+
|
|
35
|
+
// TODO - maybe
|
|
36
|
+
projectId?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type BillableWorkspaceType = WorkspaceType;
|
|
40
|
+
|
|
41
|
+
export const billableSessionDummyData: BillableSession[] = [
|
|
42
|
+
{
|
|
43
|
+
attributionId: "some-attribution-id",
|
|
44
|
+
userId: "prebuild",
|
|
45
|
+
teamId: "prebuild",
|
|
46
|
+
instanceId: "some-instance-id",
|
|
47
|
+
workspaceId: "some-workspace-id",
|
|
48
|
+
workspaceType: "prebuild",
|
|
49
|
+
workspaceClass: "XL",
|
|
50
|
+
startTime: new Date(Date.now() + -3 * 24 * 3600 * 1000).toISOString(), // 3 days ago
|
|
51
|
+
endTime: new Date().toISOString(),
|
|
52
|
+
credits: 320,
|
|
53
|
+
projectId: "project-123",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
attributionId: "some-attribution-id2",
|
|
57
|
+
userId: "some-user",
|
|
58
|
+
teamId: "some-team",
|
|
59
|
+
instanceId: "some-instance-id2",
|
|
60
|
+
workspaceId: "some-workspace-id2",
|
|
61
|
+
workspaceType: "regular",
|
|
62
|
+
workspaceClass: "standard",
|
|
63
|
+
startTime: new Date(Date.now() + -5 * 24 * 3600 * 1000).toISOString(),
|
|
64
|
+
endTime: new Date().toISOString(),
|
|
65
|
+
credits: 130,
|
|
66
|
+
projectId: "project-123",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
attributionId: "some-attribution-id3",
|
|
70
|
+
userId: "some-other-user",
|
|
71
|
+
teamId: "some-other-team",
|
|
72
|
+
instanceId: "some-instance-id3",
|
|
73
|
+
workspaceId: "some-workspace-id3",
|
|
74
|
+
workspaceType: "regular",
|
|
75
|
+
workspaceClass: "XL",
|
|
76
|
+
startTime: new Date(Date.now() + -5 * 24 * 3600 * 1000).toISOString(),
|
|
77
|
+
endTime: new Date(Date.now() + -4 * 24 * 3600 * 1000).toISOString(),
|
|
78
|
+
credits: 150,
|
|
79
|
+
projectId: "project-134",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
attributionId: "some-attribution-id4",
|
|
83
|
+
userId: "some-other-user2",
|
|
84
|
+
teamId: "some-other-team2",
|
|
85
|
+
instanceId: "some-instance-id4",
|
|
86
|
+
workspaceId: "some-workspace-id4",
|
|
87
|
+
workspaceType: "regular",
|
|
88
|
+
workspaceClass: "standard",
|
|
89
|
+
startTime: new Date(Date.now() + -10 * 24 * 3600 * 1000).toISOString(),
|
|
90
|
+
endTime: new Date(Date.now() + -9 * 24 * 3600 * 1000).toISOString(),
|
|
91
|
+
credits: 330,
|
|
92
|
+
projectId: "project-137",
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
attributionId: "some-attribution-id5",
|
|
96
|
+
userId: "some-other-user3",
|
|
97
|
+
teamId: "some-other-team3",
|
|
98
|
+
instanceId: "some-instance-id5",
|
|
99
|
+
workspaceId: "some-workspace-id5",
|
|
100
|
+
workspaceType: "regular",
|
|
101
|
+
workspaceClass: "XL",
|
|
102
|
+
startTime: new Date(Date.now() + -2 * 24 * 3600 * 1000).toISOString(),
|
|
103
|
+
endTime: new Date().toISOString(),
|
|
104
|
+
credits: 222,
|
|
105
|
+
projectId: "project-138",
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
attributionId: "some-attribution-id6",
|
|
109
|
+
userId: "some-other-user4",
|
|
110
|
+
teamId: "some-other-team4",
|
|
111
|
+
instanceId: "some-instance-id6",
|
|
112
|
+
workspaceId: "some-workspace-id3",
|
|
113
|
+
workspaceType: "regular",
|
|
114
|
+
workspaceClass: "XL",
|
|
115
|
+
startTime: new Date(Date.now() + -7 * 24 * 3600 * 1000).toISOString(),
|
|
116
|
+
endTime: new Date(Date.now() + -6 * 24 * 3600 * 1000).toISOString(),
|
|
117
|
+
credits: 300,
|
|
118
|
+
projectId: "project-134",
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
attributionId: "some-attribution-id8",
|
|
122
|
+
userId: "some-other-user5",
|
|
123
|
+
teamId: "some-other-team5",
|
|
124
|
+
instanceId: "some-instance-id8",
|
|
125
|
+
workspaceId: "some-workspace-id3",
|
|
126
|
+
workspaceType: "regular",
|
|
127
|
+
workspaceClass: "standard",
|
|
128
|
+
startTime: new Date(Date.now() + -1 * 24 * 3600 * 1000).toISOString(),
|
|
129
|
+
endTime: new Date().toISOString(),
|
|
130
|
+
credits: 100,
|
|
131
|
+
projectId: "project-567",
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
attributionId: "some-attribution-id7",
|
|
135
|
+
userId: "prebuild",
|
|
136
|
+
teamId: "some-other-team7",
|
|
137
|
+
instanceId: "some-instance-id7",
|
|
138
|
+
workspaceId: "some-workspace-id7",
|
|
139
|
+
workspaceType: "prebuild",
|
|
140
|
+
workspaceClass: "XL",
|
|
141
|
+
startTime: new Date(Date.now() + -1 * 24 * 3600 * 1000).toISOString(),
|
|
142
|
+
endTime: new Date().toISOString(),
|
|
143
|
+
credits: 200,
|
|
144
|
+
projectId: "project-345",
|
|
145
|
+
},
|
|
146
|
+
];
|
|
@@ -0,0 +1,81 @@
|
|
|
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 * as http from "http";
|
|
8
|
+
import * as express from "express";
|
|
9
|
+
import { injectable, postConstruct } from "inversify";
|
|
10
|
+
import { log, LogrusLogLevel } from "./logging";
|
|
11
|
+
|
|
12
|
+
export interface SetLogLevelRequest {
|
|
13
|
+
level: LogrusLogLevel;
|
|
14
|
+
}
|
|
15
|
+
export namespace SetLogLevelRequest {
|
|
16
|
+
export function is(o: any): o is SetLogLevelRequest {
|
|
17
|
+
return typeof o === "object" && "level" in o;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@injectable()
|
|
22
|
+
export class DebugApp {
|
|
23
|
+
protected _app: express.Application;
|
|
24
|
+
protected httpServer: http.Server | undefined = undefined;
|
|
25
|
+
|
|
26
|
+
@postConstruct()
|
|
27
|
+
public ctor() {
|
|
28
|
+
this._app = this.create();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
create(): express.Application {
|
|
32
|
+
const app = express();
|
|
33
|
+
|
|
34
|
+
app.use(express.json());
|
|
35
|
+
app.use(express.urlencoded({ extended: true }));
|
|
36
|
+
|
|
37
|
+
app.post("/debug/logging", (req, res) => {
|
|
38
|
+
try {
|
|
39
|
+
const levelRequest = req.body;
|
|
40
|
+
if (!SetLogLevelRequest.is(levelRequest)) {
|
|
41
|
+
res.status(400).end("not a SetLogLevelRequest");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const newLogLevel = levelRequest.level;
|
|
46
|
+
log.setLogLevel(newLogLevel);
|
|
47
|
+
log.info("set log level", { newLogLevel });
|
|
48
|
+
res.status(200).end(JSON.stringify(levelRequest));
|
|
49
|
+
} catch (err) {
|
|
50
|
+
res.status(500).end(err);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return app;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public start(port: number = 6060) {
|
|
57
|
+
this.httpServer = this._app.listen(port, "localhost", () => {
|
|
58
|
+
log.info(`debug server listening on port: ${port}`);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public async stop() {
|
|
63
|
+
const server = this.httpServer;
|
|
64
|
+
if (!server) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
return new Promise<void>((resolve) =>
|
|
68
|
+
server.close((err: any) => {
|
|
69
|
+
if (err) {
|
|
70
|
+
log.warn(`error while closing http server`, { err });
|
|
71
|
+
}
|
|
72
|
+
this.httpServer = undefined;
|
|
73
|
+
resolve();
|
|
74
|
+
}),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public get app(): express.Application {
|
|
79
|
+
return this._app;
|
|
80
|
+
}
|
|
81
|
+
}
|