Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/gitpod-protocol/src/teams-projects-protocol.ts
2498 views
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 { PrebuiltWorkspaceState, Workspace, WorkspaceClasses } from "./protocol";
8
import { v4 as uuidv4 } from "uuid";
9
import { DeepPartial } from "./util/deep-partial";
10
import { WorkspaceInstance } from "./workspace-instance";
11
12
export interface ProjectConfig {
13
".gitpod.yml": string;
14
}
15
16
export interface ProjectSettings {
17
/**
18
* Controls settings of prebuilds for this project.
19
*/
20
prebuilds?: PrebuildSettings;
21
22
// preferred workspace classes
23
workspaceClasses?: WorkspaceClasses;
24
25
/**
26
* Controls workspace class restriction for this project, the list is a NOT ALLOW LIST. Empty array to allow all kind of workspace classes
27
*/
28
restrictedWorkspaceClasses?: string[];
29
30
restrictedEditorNames?: string[];
31
32
/**
33
* Enable automatic authentication for docker daemon with all credentials specified in GITPOD_IMAGE_AUTH
34
*/
35
enableDockerdAuthentication?: boolean;
36
}
37
export namespace PrebuildSettings {
38
export type BranchStrategy = "default-branch" | "all-branches" | "matched-branches";
39
export type TriggerStrategy = "activity-based" | "webhook-based";
40
export interface CloneSettings {
41
fullClone?: boolean;
42
}
43
}
44
45
export interface PrebuildSettings {
46
enable?: boolean;
47
48
/**
49
* Defines an interval of commits to run new prebuilds for. Defaults to 20
50
*/
51
prebuildInterval?: number;
52
53
/**
54
* Which branches to consider to run new prebuilds on. Default to "all-branches"
55
*/
56
branchStrategy?: PrebuildSettings.BranchStrategy;
57
/**
58
* If `branchStrategy` s set to "matched-branches", this should define a glob-pattern to be used
59
* to match the branch to run new prebuilds on. Defaults to "**"
60
*/
61
branchMatchingPattern?: string;
62
63
/**
64
* Preferred workspace class for prebuilds.
65
*/
66
workspaceClass?: string;
67
68
/**
69
* The activation strategy for prebuilds. Defaults to "webhook-based"
70
*/
71
triggerStrategy?: PrebuildSettings.TriggerStrategy;
72
73
cloneSettings?: PrebuildSettings.CloneSettings;
74
}
75
76
export interface Project {
77
id: string;
78
name: string;
79
cloneUrl: string;
80
teamId: string;
81
appInstallationId: string;
82
settings?: ProjectSettings;
83
creationTime: string;
84
markedDeleted?: boolean;
85
}
86
87
export namespace Project {
88
export function is(data?: any): data is Project {
89
return typeof data === "object" && ["id", "name", "cloneUrl", "teamId"].every((p) => p in data);
90
}
91
92
export const create = (project: Omit<Project, "id" | "creationTime">): Project => {
93
return {
94
...project,
95
id: uuidv4(),
96
creationTime: new Date().toISOString(),
97
};
98
};
99
100
export type PrebuildSettingsWithDefaults = Required<Pick<PrebuildSettings, "prebuildInterval">> & PrebuildSettings;
101
102
export const PREBUILD_SETTINGS_DEFAULTS: PrebuildSettingsWithDefaults = {
103
enable: false,
104
branchMatchingPattern: "**",
105
prebuildInterval: 20,
106
branchStrategy: "all-branches",
107
triggerStrategy: "activity-based",
108
};
109
110
/**
111
* Returns effective prebuild settings for the given project. The resulting settings
112
* contain default values for properties which are not set explicitly for this project.
113
*/
114
export function getPrebuildSettings(project: Project): PrebuildSettingsWithDefaults {
115
// ignoring persisted properties with `undefined` values to exclude them from the override.
116
const overrides = Object.fromEntries(
117
Object.entries(project.settings?.prebuilds ?? {}).filter(([_, value]) => value !== undefined),
118
);
119
120
return {
121
...PREBUILD_SETTINGS_DEFAULTS,
122
...overrides,
123
};
124
}
125
126
export function hasPrebuildSettings(project: Project) {
127
return !(typeof project.settings?.prebuilds === "undefined");
128
}
129
130
export interface Overview {
131
branches: BranchDetails[];
132
isConsideredInactive?: boolean;
133
}
134
135
export namespace Overview {
136
export function is(data?: any): data is Project.Overview {
137
return Array.isArray(data?.branches);
138
}
139
}
140
141
export interface BranchDetails {
142
name: string;
143
url: string;
144
isDefault: boolean;
145
146
// Latest commit
147
changeTitle: string;
148
changeDate?: string;
149
changeAuthor?: string;
150
changeAuthorAvatar?: string;
151
changePR?: string;
152
changeUrl?: string;
153
changeHash: string;
154
}
155
156
export type Visibility = "public" | "org-public" | "private";
157
}
158
159
export type PartialProject = DeepPartial<Project> & Pick<Project, "id">;
160
161
export interface ProjectUsage {
162
lastWebhookReceived: string;
163
lastWorkspaceStart: string;
164
}
165
166
export interface PrebuildWithStatus {
167
info: PrebuildInfo;
168
status: PrebuiltWorkspaceState;
169
workspace: Workspace;
170
instance?: WorkspaceInstance;
171
error?: string;
172
}
173
174
export interface PrebuildInfo {
175
id: string;
176
buildWorkspaceId: string;
177
basedOnPrebuildId?: string;
178
179
teamId?: string;
180
userId?: string;
181
182
projectId: string;
183
projectName: string;
184
185
cloneUrl: string;
186
branch: string;
187
188
startedAt: string;
189
startedBy: string;
190
startedByAvatar?: string;
191
192
changeTitle: string;
193
changeDate: string;
194
changeAuthor: string;
195
changeAuthorAvatar?: string;
196
changePR?: string;
197
changeUrl?: string;
198
changeHash: string;
199
}
200
export namespace PrebuildInfo {
201
export function is(data?: any): data is PrebuildInfo {
202
return typeof data === "object" && ["id", "buildWorkspaceId", "projectId", "branch"].every((p) => p in data);
203
}
204
}
205
206
export interface StartPrebuildResult {
207
prebuildId: string;
208
wsid: string;
209
done: boolean;
210
}
211
212
// alias for backwards compatibility
213
export type Team = Organization;
214
export interface Organization {
215
id: string;
216
name: string;
217
slug?: string;
218
creationTime: string;
219
markedDeleted?: boolean;
220
maintenanceMode?: boolean;
221
maintenanceNotification?: MaintenanceNotification;
222
}
223
export interface MaintenanceNotification {
224
enabled: boolean;
225
message?: string;
226
}
227
228
export interface OrganizationSettings {
229
workspaceSharingDisabled?: boolean;
230
// undefined or empty string to reset to default
231
defaultWorkspaceImage?: string;
232
233
// empty array to allow all kind of workspace classes
234
allowedWorkspaceClasses?: string[];
235
236
pinnedEditorVersions?: { [key: string]: string };
237
238
restrictedEditorNames?: string[];
239
240
// what role new members will get, default is "member"
241
defaultRole?: OrgMemberRole;
242
243
// the default organization-wide timeout settings for workspaces
244
timeoutSettings?: TimeoutSettings;
245
246
roleRestrictions?: RoleRestrictions;
247
248
// max number of parallel running workspaces per user
249
maxParallelRunningWorkspaces?: number;
250
251
// onboarding settings for the organization
252
onboardingSettings?: OnboardingSettings;
253
254
// whether to add a special annotation to commits that are created through Gitpod
255
annotateGitCommits?: boolean;
256
}
257
258
export type TimeoutSettings = {
259
// default per-org workspace timeout
260
inactivity?: string;
261
262
// If this field is true, workspaces neither a) pick up user-defined workspace timeouts, nor b) members can set custom timeouts during workspace runtime.
263
denyUserTimeouts?: boolean;
264
};
265
266
export const VALID_ORG_MEMBER_ROLES = ["owner", "member", "collaborator"] as const;
267
268
export type TeamMemberRole = OrgMemberRole;
269
export type OrgMemberRole = typeof VALID_ORG_MEMBER_ROLES[number];
270
271
export type OrgMemberPermission = "start_arbitrary_repositories";
272
export type RoleRestrictions = Partial<Record<OrgMemberRole, OrgMemberPermission[]>>;
273
274
export namespace TeamMemberRole {
275
export function isValid(role: unknown): role is TeamMemberRole {
276
return VALID_ORG_MEMBER_ROLES.includes(role as TeamMemberRole);
277
}
278
}
279
280
export interface OnboardingSettings {
281
/**
282
* the link to an internal onboarding page for the organization, possibly featuring a custom onboarding guide and other resources
283
*/
284
internalLink?: string;
285
286
/**
287
* the repository IDs of the repositories that are recommended for members to start with
288
*/
289
recommendedRepositories?: string[];
290
291
/**
292
* the welcome message for new members of the organization
293
*/
294
welcomeMessage?: WelcomeMessage;
295
}
296
297
export interface WelcomeMessage {
298
enabled?: boolean;
299
featuredMemberId?: string;
300
featuredMemberResolvedAvatarUrl?: string;
301
message?: string;
302
}
303
304
export type TeamMemberInfo = OrgMemberInfo;
305
export interface OrgMemberInfo {
306
userId: string;
307
fullName?: string;
308
primaryEmail?: string;
309
avatarUrl?: string;
310
role: TeamMemberRole;
311
memberSince: string;
312
ownedByOrganization: boolean;
313
}
314
315
export interface TeamMembershipInvite {
316
id: string;
317
teamId: string;
318
role: TeamMemberRole;
319
creationTime: string;
320
invalidationTime: string;
321
invitedEmail?: string;
322
323
/** This is a flag that triggers the HARD DELETION of this entity */
324
deleted?: boolean;
325
}
326
327