@gitpod/gitpod-protocol 0.1.5-sefftinge-create-feature-flag-for-4354.0 → 0.1.5-server-vscode-oauth2.11

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.
Files changed (223) hide show
  1. package/data/gitpod-schema.json +4 -22
  2. package/lib/accounting-protocol.d.ts +3 -5
  3. package/lib/accounting-protocol.d.ts.map +1 -1
  4. package/lib/accounting-protocol.js +6 -11
  5. package/lib/accounting-protocol.js.map +1 -1
  6. package/lib/admin-protocol.d.ts +9 -4
  7. package/lib/admin-protocol.d.ts.map +1 -1
  8. package/lib/admin-protocol.js +2 -13
  9. package/lib/admin-protocol.js.map +1 -1
  10. package/lib/analytics.d.ts +44 -0
  11. package/lib/analytics.d.ts.map +1 -0
  12. package/lib/{util/without.js → analytics.js} +4 -2
  13. package/lib/analytics.js.map +1 -0
  14. package/lib/context-url.d.ts +18 -0
  15. package/lib/context-url.d.ts.map +1 -0
  16. package/lib/context-url.js +49 -0
  17. package/lib/context-url.js.map +1 -0
  18. package/lib/{util/context-url.spec.d.ts → context-url.spec.d.ts} +2 -0
  19. package/lib/context-url.spec.d.ts.map +1 -0
  20. package/lib/context-url.spec.js +73 -0
  21. package/lib/context-url.spec.js.map +1 -0
  22. package/lib/email-protocol.d.ts +1 -2
  23. package/lib/email-protocol.d.ts.map +1 -1
  24. package/lib/email-protocol.js +3 -3
  25. package/lib/email-protocol.js.map +1 -1
  26. package/lib/encryption/container-module.js +4 -4
  27. package/lib/encryption/container-module.js.map +1 -1
  28. package/lib/encryption/encryption-engine.js +19 -20
  29. package/lib/encryption/encryption-engine.js.map +1 -1
  30. package/lib/encryption/encryption-engine.spec.js +29 -36
  31. package/lib/encryption/encryption-engine.spec.js.map +1 -1
  32. package/lib/encryption/encryption-service.js +29 -43
  33. package/lib/encryption/encryption-service.js.map +1 -1
  34. package/lib/encryption/key-provider.js +25 -30
  35. package/lib/encryption/key-provider.js.map +1 -1
  36. package/lib/env.d.ts +1 -2
  37. package/lib/env.d.ts.map +1 -1
  38. package/lib/env.js +20 -21
  39. package/lib/env.js.map +1 -1
  40. package/lib/gitpod-file-parser.js +25 -41
  41. package/lib/gitpod-file-parser.js.map +1 -1
  42. package/lib/gitpod-file-parser.spec.js +116 -116
  43. package/lib/gitpod-file-parser.spec.js.map +1 -1
  44. package/lib/gitpod-service.d.ts +74 -5
  45. package/lib/gitpod-service.d.ts.map +1 -1
  46. package/lib/gitpod-service.js +149 -294
  47. package/lib/gitpod-service.js.map +1 -1
  48. package/lib/headless-workspace-log.d.ts +8 -11
  49. package/lib/headless-workspace-log.d.ts.map +1 -1
  50. package/lib/headless-workspace-log.js +4 -7
  51. package/lib/headless-workspace-log.js.map +1 -1
  52. package/lib/index.d.ts +2 -0
  53. package/lib/index.d.ts.map +1 -1
  54. package/lib/index.js +2 -0
  55. package/lib/index.js.map +1 -1
  56. package/lib/messaging/browser/connection.d.ts +3 -3
  57. package/lib/messaging/browser/connection.d.ts.map +1 -1
  58. package/lib/messaging/browser/connection.js +172 -35
  59. package/lib/messaging/browser/connection.js.map +1 -1
  60. package/lib/messaging/browser/window-connection.js +34 -54
  61. package/lib/messaging/browser/window-connection.js.map +1 -1
  62. package/lib/messaging/client-call-metrics.d.ts +35 -0
  63. package/lib/messaging/client-call-metrics.d.ts.map +1 -0
  64. package/lib/messaging/client-call-metrics.js +83 -0
  65. package/lib/messaging/client-call-metrics.js.map +1 -0
  66. package/lib/messaging/connection-error-handler.js +11 -23
  67. package/lib/messaging/connection-error-handler.js.map +1 -1
  68. package/lib/messaging/error.d.ts +1 -0
  69. package/lib/messaging/error.d.ts.map +1 -1
  70. package/lib/messaging/error.js +2 -0
  71. package/lib/messaging/error.js.map +1 -1
  72. package/lib/messaging/handler.d.ts +10 -0
  73. package/lib/messaging/handler.d.ts.map +1 -1
  74. package/lib/messaging/node/connection.js +21 -21
  75. package/lib/messaging/node/connection.js.map +1 -1
  76. package/lib/messaging/proxy-factory.d.ts +2 -0
  77. package/lib/messaging/proxy-factory.d.ts.map +1 -1
  78. package/lib/messaging/proxy-factory.js +74 -159
  79. package/lib/messaging/proxy-factory.js.map +1 -1
  80. package/lib/permission.d.ts +1 -2
  81. package/lib/permission.d.ts.map +1 -1
  82. package/lib/permission.js +12 -13
  83. package/lib/permission.js.map +1 -1
  84. package/lib/plans.js +38 -57
  85. package/lib/plans.js.map +1 -1
  86. package/lib/protocol.d.ts +52 -22
  87. package/lib/protocol.d.ts.map +1 -1
  88. package/lib/protocol.js +68 -115
  89. package/lib/protocol.js.map +1 -1
  90. package/lib/team-subscription-protocol.d.ts +3 -3
  91. package/lib/team-subscription-protocol.d.ts.map +1 -1
  92. package/lib/team-subscription-protocol.js +13 -10
  93. package/lib/team-subscription-protocol.js.map +1 -1
  94. package/lib/teams-projects-protocol.d.ts +102 -0
  95. package/lib/teams-projects-protocol.d.ts.map +1 -0
  96. package/lib/teams-projects-protocol.js +23 -0
  97. package/lib/teams-projects-protocol.js.map +1 -0
  98. package/lib/util/analytics.d.ts +1 -26
  99. package/lib/util/analytics.d.ts.map +1 -1
  100. package/lib/util/analytics.js +36 -28
  101. package/lib/util/analytics.js.map +1 -1
  102. package/lib/util/async-iterator.js +55 -133
  103. package/lib/util/async-iterator.js.map +1 -1
  104. package/lib/util/cancelable.js +17 -59
  105. package/lib/util/cancelable.js.map +1 -1
  106. package/lib/util/date-time.js +8 -8
  107. package/lib/util/date-time.js.map +1 -1
  108. package/lib/util/deferred.js +10 -12
  109. package/lib/util/deferred.js.map +1 -1
  110. package/lib/util/disposable.js +26 -39
  111. package/lib/util/disposable.js.map +1 -1
  112. package/lib/util/event.js +58 -74
  113. package/lib/util/event.js.map +1 -1
  114. package/lib/util/garbage-collected-cache.js +22 -46
  115. package/lib/util/garbage-collected-cache.js.map +1 -1
  116. package/lib/util/generate-workspace-id.d.ts.map +1 -1
  117. package/lib/util/generate-workspace-id.js +12 -67
  118. package/lib/util/generate-workspace-id.js.map +1 -1
  119. package/lib/util/generate-workspace-id.spec.js +34 -79
  120. package/lib/util/generate-workspace-id.spec.js.map +1 -1
  121. package/lib/util/gitpod-cookie.d.ts +20 -0
  122. package/lib/util/gitpod-cookie.d.ts.map +1 -0
  123. package/lib/util/gitpod-cookie.js +44 -0
  124. package/lib/util/gitpod-cookie.js.map +1 -0
  125. package/lib/util/gitpod-host-url.js +93 -103
  126. package/lib/util/gitpod-host-url.js.map +1 -1
  127. package/lib/util/gitpod-host-url.spec.d.ts +5 -0
  128. package/lib/util/gitpod-host-url.spec.d.ts.map +1 -1
  129. package/lib/util/gitpod-host-url.spec.js +92 -70
  130. package/lib/util/gitpod-host-url.spec.js.map +1 -1
  131. package/lib/util/grpc.d.ts +15 -0
  132. package/lib/util/grpc.d.ts.map +1 -0
  133. package/lib/util/grpc.js +18 -0
  134. package/lib/util/grpc.js.map +1 -0
  135. package/lib/util/logging.d.ts +17 -1
  136. package/lib/util/logging.d.ts.map +1 -1
  137. package/lib/util/logging.js +107 -110
  138. package/lib/util/logging.js.map +1 -1
  139. package/lib/util/make-link.js +2 -2
  140. package/lib/util/make-link.js.map +1 -1
  141. package/lib/util/parse-workspace-id.d.ts +10 -0
  142. package/lib/util/parse-workspace-id.d.ts.map +1 -1
  143. package/lib/util/parse-workspace-id.js +31 -7
  144. package/lib/util/parse-workspace-id.js.map +1 -1
  145. package/lib/util/parse-workspace-id.spec.d.ts +4 -0
  146. package/lib/util/parse-workspace-id.spec.d.ts.map +1 -1
  147. package/lib/util/parse-workspace-id.spec.js +123 -84
  148. package/lib/util/parse-workspace-id.spec.js.map +1 -1
  149. package/lib/util/queue.js +16 -55
  150. package/lib/util/queue.js.map +1 -1
  151. package/lib/util/queue.spec.js +144 -288
  152. package/lib/util/queue.spec.js.map +1 -1
  153. package/lib/util/repeater.js +35 -88
  154. package/lib/util/repeater.js.map +1 -1
  155. package/lib/util/safe-promise.js +9 -12
  156. package/lib/util/safe-promise.js.map +1 -1
  157. package/lib/util/semaphore.js +15 -46
  158. package/lib/util/semaphore.js.map +1 -1
  159. package/lib/util/skip-if.js +6 -6
  160. package/lib/util/skip-if.js.map +1 -1
  161. package/lib/util/timeutil.js +16 -16
  162. package/lib/util/timeutil.js.map +1 -1
  163. package/lib/util/timeutil.spec.js +21 -24
  164. package/lib/util/timeutil.spec.js.map +1 -1
  165. package/lib/util/tracing.js +43 -47
  166. package/lib/util/tracing.js.map +1 -1
  167. package/lib/util/workspace-port-authentication.js +2 -2
  168. package/lib/util/workspace-port-authentication.js.map +1 -1
  169. package/lib/workspace-cluster.d.ts +12 -3
  170. package/lib/workspace-cluster.d.ts.map +1 -1
  171. package/lib/workspace-cluster.js +3 -3
  172. package/lib/workspace-cluster.js.map +1 -1
  173. package/lib/workspace-instance.d.ts +3 -0
  174. package/lib/workspace-instance.d.ts.map +1 -1
  175. package/lib/wsready.js +1 -1
  176. package/lib/wsready.js.map +1 -1
  177. package/package.json +11 -6
  178. package/pkg-yarn.lock +7 -4
  179. package/src/accounting-protocol.ts +3 -7
  180. package/src/admin-protocol.ts +10 -5
  181. package/src/analytics.ts +52 -0
  182. package/src/context-url.spec.ts +39 -0
  183. package/src/context-url.ts +51 -0
  184. package/src/email-protocol.ts +1 -2
  185. package/src/env.ts +10 -10
  186. package/src/gitpod-service.ts +90 -12
  187. package/src/headless-workspace-log.ts +7 -11
  188. package/src/index.ts +2 -0
  189. package/src/messaging/browser/connection.ts +176 -10
  190. package/src/messaging/client-call-metrics.ts +97 -0
  191. package/src/messaging/error.ts +3 -0
  192. package/src/messaging/handler.ts +12 -0
  193. package/src/messaging/node/connection.ts +2 -2
  194. package/src/messaging/proxy-factory.ts +13 -5
  195. package/src/permission.ts +0 -1
  196. package/src/protocol.ts +73 -28
  197. package/src/team-subscription-protocol.ts +5 -3
  198. package/src/teams-projects-protocol.ts +131 -0
  199. package/src/util/analytics.ts +17 -30
  200. package/src/util/generate-workspace-id.ts +1 -0
  201. package/src/util/gitpod-cookie.ts +39 -0
  202. package/src/util/gitpod-host-url.spec.ts +20 -0
  203. package/src/util/gitpod-host-url.ts +1 -1
  204. package/src/util/grpc.ts +15 -0
  205. package/src/util/logging.ts +70 -6
  206. package/src/util/parse-workspace-id.spec.ts +21 -1
  207. package/src/util/parse-workspace-id.ts +32 -6
  208. package/src/workspace-cluster.ts +9 -3
  209. package/src/workspace-instance.ts +19 -7
  210. package/src/wsready.ts +1 -1
  211. package/lib/util/context-url.d.ts +0 -13
  212. package/lib/util/context-url.d.ts.map +0 -1
  213. package/lib/util/context-url.js +0 -26
  214. package/lib/util/context-url.js.map +0 -1
  215. package/lib/util/context-url.spec.d.ts.map +0 -1
  216. package/lib/util/context-url.spec.js +0 -52
  217. package/lib/util/context-url.spec.js.map +0 -1
  218. package/lib/util/without.d.ts +0 -7
  219. package/lib/util/without.d.ts.map +0 -1
  220. package/lib/util/without.js.map +0 -1
  221. package/src/util/context-url.spec.ts +0 -25
  222. package/src/util/context-url.ts +0 -23
  223. package/src/util/without.ts +0 -8
@@ -0,0 +1,131 @@
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 } from "./protocol";
8
+ import uuidv4 = require("uuid/v4");
9
+
10
+ export interface ProjectConfig {
11
+ '.gitpod.yml': string;
12
+ }
13
+
14
+ export interface Project {
15
+ id: string;
16
+ name: string;
17
+ cloneUrl: string;
18
+ teamId?: string;
19
+ userId?: string;
20
+ appInstallationId: string;
21
+ config?: ProjectConfig;
22
+ creationTime: string;
23
+ /** This is a flag that triggers the HARD DELETION of this entity */
24
+ deleted?: boolean;
25
+ markedDeleted?: boolean;
26
+ }
27
+
28
+ export namespace Project {
29
+ export const create = (project: Omit<Project, 'id' | 'creationTime'>): Project => {
30
+ return {
31
+ ...project,
32
+ id: uuidv4(),
33
+ creationTime: new Date().toISOString()
34
+ };
35
+ }
36
+
37
+ export interface Overview {
38
+ branches: BranchDetails[]
39
+ }
40
+
41
+ export interface BranchDetails {
42
+ name: string;
43
+ url: string;
44
+ isDefault: boolean;
45
+
46
+ // Latest commit
47
+ changeTitle: string;
48
+ changeDate?: string;
49
+ changeAuthor?: string;
50
+ changeAuthorAvatar?: string;
51
+ changePR?: string;
52
+ changeUrl?: string;
53
+ changeHash: string;
54
+ }
55
+ }
56
+
57
+ export interface PrebuildWithStatus {
58
+ info: PrebuildInfo;
59
+ status: PrebuiltWorkspaceState;
60
+ error?: string;
61
+ }
62
+
63
+ export interface PrebuildInfo {
64
+ id: string;
65
+ buildWorkspaceId: string;
66
+
67
+ teamId?: string;
68
+ userId?: string;
69
+
70
+ projectId: string;
71
+ projectName: string;
72
+
73
+ cloneUrl: string;
74
+ branch: string;
75
+
76
+ startedAt: string;
77
+ startedBy: string;
78
+ startedByAvatar?: string;
79
+
80
+ changeTitle: string;
81
+ changeDate: string;
82
+ changeAuthor: string;
83
+ changeAuthorAvatar?: string;
84
+ changePR?: string;
85
+ changeUrl?: string;
86
+ changeHash: string;
87
+ }
88
+ export namespace PrebuildInfo {
89
+ export function is(data?: any): data is PrebuildInfo {
90
+ return typeof data === "object" && ["id", "buildWorkspaceId", "projectId", "branch"].every(p => p in data);
91
+ }
92
+ }
93
+
94
+ export interface StartPrebuildResult {
95
+ prebuildId: string;
96
+ wsid: string;
97
+ done: boolean;
98
+ }
99
+
100
+ export interface Team {
101
+ id: string;
102
+ name: string;
103
+ slug: string;
104
+ creationTime: string;
105
+ markedDeleted?: boolean;
106
+ /** This is a flag that triggers the HARD DELETION of this entity */
107
+ deleted?: boolean;
108
+ }
109
+
110
+ export type TeamMemberRole = "owner" | "member";
111
+
112
+ export interface TeamMemberInfo {
113
+ userId: string;
114
+ fullName?: string;
115
+ primaryEmail?: string;
116
+ avatarUrl?: string;
117
+ role: TeamMemberRole;
118
+ memberSince: string;
119
+ }
120
+
121
+ export interface TeamMembershipInvite {
122
+ id: string;
123
+ teamId: string;
124
+ role: TeamMemberRole;
125
+ creationTime: string;
126
+ invalidationTime: string;
127
+ invitedEmail?: string;
128
+
129
+ /** This is a flag that triggers the HARD DELETION of this entity */
130
+ deleted?: boolean;
131
+ }
@@ -5,30 +5,9 @@
5
5
  */
6
6
 
7
7
  import Analytics = require("analytics-node");
8
+ import { IAnalyticsWriter, IdentifyMessage, TrackMessage, PageMessage } from "../analytics";
8
9
  import { log } from './logging';
9
10
 
10
- export const IAnalyticsWriter = Symbol("IAnalyticsWriter");
11
-
12
- type Identity =
13
- | { userId: string | number }
14
- | { userId?: string | number; anonymousId: string | number };
15
-
16
- interface Message {
17
- messageId?: string;
18
- }
19
-
20
- export type IdentifyMessage = Message & Identity & {
21
- traits?: any;
22
- timestamp?: Date;
23
- context?: any;
24
- };
25
-
26
- export type TrackMessage = Message & Identity & {
27
- event: string;
28
- properties?: any;
29
- timestamp?: Date;
30
- context?: any;
31
- };
32
11
 
33
12
  export function newAnalyticsWriterFromEnv(): IAnalyticsWriter {
34
13
  switch (process.env.GITPOD_ANALYTICS_WRITER) {
@@ -41,14 +20,6 @@ export function newAnalyticsWriterFromEnv(): IAnalyticsWriter {
41
20
  }
42
21
  }
43
22
 
44
- export interface IAnalyticsWriter {
45
-
46
- identify(msg: IdentifyMessage): void;
47
-
48
- track(msg: TrackMessage): void;
49
-
50
- }
51
-
52
23
  class SegmentAnalyticsWriter implements IAnalyticsWriter {
53
24
 
54
25
  protected readonly analytics: Analytics;
@@ -81,6 +52,18 @@ class SegmentAnalyticsWriter implements IAnalyticsWriter {
81
52
  }
82
53
  }
83
54
 
55
+ page(msg: PageMessage) {
56
+ try{
57
+ this.analytics.page(msg, (err: Error) => {
58
+ if (err) {
59
+ log.warn("analytics.page failed", err);
60
+ }
61
+ });
62
+ } catch (err) {
63
+ log.warn("analytics.page failed", err);
64
+ }
65
+ }
66
+
84
67
  }
85
68
 
86
69
  class LogAnalyticsWriter implements IAnalyticsWriter {
@@ -91,10 +74,14 @@ class LogAnalyticsWriter implements IAnalyticsWriter {
91
74
  track(msg: TrackMessage): void {
92
75
  log.debug("analytics track", msg);
93
76
  }
77
+ page(msg: PageMessage): void {
78
+ log.debug("analytics page", msg);
79
+ }
94
80
 
95
81
  }
96
82
 
97
83
  class NoAnalyticsWriter implements IAnalyticsWriter {
98
84
  identify(msg: IdentifyMessage): void {}
99
85
  track(msg: TrackMessage): void {}
86
+ page(msg: PageMessage): void {}
100
87
  }
@@ -173,6 +173,7 @@ export const colors = [
173
173
  'deer',
174
174
  'dingo',
175
175
  'dinosaur',
176
+ 'dodo',
176
177
  'dog',
177
178
  'dolphin',
178
179
  'donkey',
@@ -0,0 +1,39 @@
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
+ import * as cookie from 'cookie';
7
+
8
+
9
+ /**
10
+ * This cookie indicates whether the connected client is a Gitpod user (= "has logged in within the last year") or not.
11
+ * This is used by "gitpod.io" and "www.gitpod.io" to display different content/buttons.
12
+ */
13
+ export const NAME = "gitpod-user";
14
+ export const VALUE = "true";
15
+
16
+ /**
17
+ * @param domain The domain the Gitpod installation is installed onto
18
+ * @returns
19
+ */
20
+ export function options(domain: string): cookie.CookieSerializeOptions {
21
+ // Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
22
+ return {
23
+ path: "/", // make sure we send the cookie to all sub-pages
24
+ httpOnly: false,
25
+ secure: false,
26
+ maxAge: 60 * 60 * 24 * 365, // 1 year
27
+ sameSite: "lax", // default: true. "Lax" needed to ensure we see cookies from users that neavigate to gitpod.io from external sites
28
+ domain: `.${domain}`, // explicilty include subdomains to not only cover "gitpod.io", but also "www.gitpod.io" or workspaces
29
+ };
30
+ };
31
+
32
+ export function generateCookie(domain: string): string {
33
+ return cookie.serialize(NAME, VALUE, options(domain));
34
+ };
35
+
36
+ export function isPresent(cookies: string): boolean {
37
+ // needs to match the old (gitpod-user=loggedIn) and new (gitpod-user=true) values to ensure a smooth transition during rollout.
38
+ return !!cookies.match(`${NAME}=`);
39
+ };
@@ -25,5 +25,25 @@ export class GitpodHostUrlTest {
25
25
  @test public async testWithoutWorkspacePrefix() {
26
26
  expect(GitpodHostUrl.fromWorkspaceUrl("https://3000-moccasin-ferret-155799b3.ws-eu02.gitpod-staging.com/").withoutWorkspacePrefix().toString()).to.equal("https://gitpod-staging.com/");
27
27
  }
28
+
29
+ @test public async testWithoutWorkspacePrefix2() {
30
+ expect(GitpodHostUrl.fromWorkspaceUrl("https://gitpod-staging.com/").withoutWorkspacePrefix().toString()).to.equal("https://gitpod-staging.com/");
31
+ }
32
+
33
+ @test public async testWithoutWorkspacePrefix3() {
34
+ expect(GitpodHostUrl.fromWorkspaceUrl("https://gray-rook-5523v5d8.ws-dev.my-branch-1234.staging.gitpod-dev.com/").withoutWorkspacePrefix().toString()).to.equal("https://my-branch-1234.staging.gitpod-dev.com/");
35
+ }
36
+
37
+ @test public async testWithoutWorkspacePrefix4() {
38
+ expect(GitpodHostUrl.fromWorkspaceUrl("https://my-branch-1234.staging.gitpod-dev.com/").withoutWorkspacePrefix().toString()).to.equal("https://my-branch-1234.staging.gitpod-dev.com/");
39
+ }
40
+
41
+ @test public async testWithoutWorkspacePrefix5() {
42
+ expect(GitpodHostUrl.fromWorkspaceUrl("https://abc-nice-brunch-4224.staging.gitpod-dev.com/").withoutWorkspacePrefix().toString()).to.equal("https://abc-nice-brunch-4224.staging.gitpod-dev.com/");
43
+ }
44
+
45
+ @test public async testWithoutWorkspacePrefix6() {
46
+ expect(GitpodHostUrl.fromWorkspaceUrl("https://gray-rook-5523v5d8.ws-dev.abc-nice-brunch-4224.staging.gitpod-dev.com/").withoutWorkspacePrefix().toString()).to.equal("https://abc-nice-brunch-4224.staging.gitpod-dev.com/");
47
+ }
28
48
  }
29
49
  module.exports = new GitpodHostUrlTest()
@@ -18,7 +18,7 @@ const basewoWkspaceIDRegex = "(([a-f][0-9a-f]{7}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f
18
18
  const workspaceIDRegex = RegExp(`^${basewoWkspaceIDRegex}$`);
19
19
 
20
20
  // this pattern matches URL prefixes of workspaces
21
- const workspaceUrlPrefixRegex = RegExp(`^([0-9]{4,6}-)?${basewoWkspaceIDRegex}\.`);
21
+ const workspaceUrlPrefixRegex = RegExp(`^([0-9]{4,6}-)?${basewoWkspaceIDRegex}\\.`);
22
22
 
23
23
  export class GitpodHostUrl {
24
24
  readonly url: URL;
@@ -0,0 +1,15 @@
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
+ export const defaultGRPCOptions = {
8
+ "grpc.keepalive_timeout_ms": 10000,
9
+ "grpc.keepalive_time_ms": 60000,
10
+ "grpc.http2.min_time_between_pings_ms": 10000,
11
+ "grpc.keepalive_permit_without_calls": 1,
12
+ "grpc-node.max_session_memory": 50,
13
+ "grpc.max_reconnect_backoff_ms": 5000,
14
+ "grpc.max_receive_message_length": 1024 * 1024 * 16,
15
+ };
@@ -97,10 +97,14 @@ export namespace log {
97
97
  /**
98
98
  * Do not use in frontend.
99
99
  */
100
- export function enableJSONLogging(componentArg: string, versionArg: string | undefined): void {
100
+ export function enableJSONLogging(componentArg: string, versionArg: string | undefined, logLevel?: LogrusLogLevel): void {
101
101
  component = componentArg;
102
102
  version = versionArg;
103
103
 
104
+ setLogLevel(logLevel);
105
+ }
106
+
107
+ export function setLogLevel(logLevel: LogrusLogLevel | undefined) {
104
108
  jsonLogging = true;
105
109
 
106
110
  console.error = function (...args: any[]): void {
@@ -115,8 +119,20 @@ export namespace log {
115
119
  console.debug = function (...args: any[]): void {
116
120
  debugLog(true, args);
117
121
  }
122
+
118
123
  console.log = console.info;
119
124
  // FIXME wrap also other console methods (e.g. trace())
125
+
126
+ // set/unset log functions based on loglevel so we only have to evaluate once, not every call
127
+ const noop = () => {};
128
+ const setLog = (logFunc: DoLogFunction, funcLevel: LogrusLogLevel): DoLogFunction => {
129
+ return LogrusLogLevel.isGreatherOrEqual(funcLevel, logLevel) ? logFunc : noop;
130
+ };
131
+
132
+ errorLog = setLog(doErrorLog, "error");
133
+ warnLog = setLog(doWarnLog, "warning");
134
+ infoLog = setLog(doInfoLog, "info");
135
+ debugLog = setLog(doDebugLog, "debug");
120
136
  }
121
137
 
122
138
  export function resetToDefaultLogging(): void {
@@ -128,24 +144,73 @@ export namespace log {
128
144
  console.info = infoConsoleLog;
129
145
  console.debug = debugConsoleLog;
130
146
  }
147
+
148
+ export function setVersion(versionArg: string) {
149
+ version = versionArg;
150
+ }
131
151
  }
132
152
 
133
- function errorLog(calledViaConsole: boolean, args: any[]): void {
153
+ type DoLogFunction = (calledViaConsole: boolean, args: any[]) => void;
154
+
155
+ let errorLog = doErrorLog;
156
+ function doErrorLog(calledViaConsole: boolean, args: any[]): void {
134
157
  doLog(calledViaConsole, errorConsoleLog, 'ERROR', args);
135
158
  }
136
159
 
137
- function warnLog(calledViaConsole: boolean, args: any[]): void {
160
+ let warnLog = doWarnLog;
161
+ function doWarnLog(calledViaConsole: boolean, args: any[]): void {
138
162
  doLog(calledViaConsole, warnConsoleLog, 'WARNING', args);
139
163
  }
140
164
 
141
- function infoLog(calledViaConsole: boolean, args: any[]): void {
165
+ let infoLog = doInfoLog;
166
+ function doInfoLog(calledViaConsole: boolean, args: any[]): void {
142
167
  doLog(calledViaConsole, infoConsoleLog, 'INFO', args);
143
168
  }
144
169
 
145
- function debugLog(calledViaConsole: boolean, args: any[]): void {
170
+ let debugLog = doDebugLog;
171
+ function doDebugLog(calledViaConsole: boolean, args: any[]): void {
146
172
  doLog(calledViaConsole, debugConsoleLog, 'DEBUG', args);
147
173
  }
148
174
 
175
+ // Ref: https://github.com/sirupsen/logrus#level-logging
176
+ export type LogrusLogLevel = keyof (typeof LogrusLogLevels);
177
+ export const LogrusLogLevels = {
178
+ trace: true,
179
+ debug: true,
180
+ info: true,
181
+ warning: true,
182
+ error: true,
183
+ fatal: true,
184
+ panic: true,
185
+ }
186
+ export namespace LogrusLogLevel {
187
+ export function isGreatherOrEqual(lvl: LogrusLogLevel | undefined, ref: LogrusLogLevel | undefined): boolean {
188
+ if (lvl === undefined) {
189
+ return false;
190
+ }
191
+ if (ref === undefined) {
192
+ return true;
193
+ }
194
+ return getLevelArity(lvl) >= getLevelArity(ref);
195
+ }
196
+ function getLevelArity(lvl: LogrusLogLevel): number {
197
+ return Object.keys(LogrusLogLevels)
198
+ .findIndex((l) => l === lvl);
199
+ }
200
+ export function getFromEnv(): LogrusLogLevel | undefined {
201
+ const lvlStr = process.env.LOG_LEVEL;
202
+ if (!lvlStr) {
203
+ return undefined;
204
+ }
205
+ const lvl = lvlStr as LogrusLogLevel;
206
+ const exists = LogrusLogLevels[lvl]
207
+ if (!exists) {
208
+ return undefined;
209
+ }
210
+ return lvl;
211
+ }
212
+ }
213
+
149
214
  // Source: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity
150
215
  type GoogleLogSeverity = 'EMERGENCY' | 'ALERT' | 'CRITICAL' | 'ERROR' | 'WARNING' | 'INFO' | 'DEBUG';
151
216
  namespace GoogleLogSeverity {
@@ -243,7 +308,6 @@ function makeLogItem(severity: GoogleLogSeverity, context: LogContext | undefine
243
308
  severity,
244
309
  time: new Date().toISOString(),
245
310
  environment: process.env.KUBE_STAGE,
246
- region: process.env.GITPOD_REGION,
247
311
  context,
248
312
  message,
249
313
  error,
@@ -6,7 +6,7 @@
6
6
 
7
7
  import * as chai from 'chai';
8
8
  import { suite, test } from 'mocha-typescript';
9
- import { parseWorkspaceIdFromHostname } from './parse-workspace-id';
9
+ import { matchesInstanceIdOrLegacyWorkspaceIdExactly, matchesNewWorkspaceIdExactly, parseWorkspaceIdFromHostname } from './parse-workspace-id';
10
10
  const expect = chai.expect;
11
11
 
12
12
  @suite
@@ -52,5 +52,25 @@ export class ParseWorkspaceIdTest {
52
52
  const actual = parseWorkspaceIdFromHostname("webview-3000-ca81a50f-09d7-465c-acd9-264a747d5351.ws-eu01.some.subdomain.somehost.com");
53
53
  expect(actual).to.equal("ca81a50f-09d7-465c-acd9-264a747d5351");
54
54
  }
55
+
56
+ // match - instance ID
57
+ @test public matchesInstanceIdOrLegacyWorkspaceIdExactly_positive() {
58
+ const actual = matchesInstanceIdOrLegacyWorkspaceIdExactly("b7e0eaf8-ec73-44ec-81ea-04859263b656");
59
+ expect(actual).to.be.true;
60
+ }
61
+ @test public matchesInstanceIdOrLegacyWorkspaceIdExactly_negative() {
62
+ const actual = matchesInstanceIdOrLegacyWorkspaceIdExactly("b7e0eaf8-ec73-44ec-81a-04859263b656");
63
+ expect(actual).to.be.false;
64
+ }
65
+
66
+ // match - new workspace ID
67
+ @test public matchesWorkspaceIdExactly_new_positive() {
68
+ const actual = matchesNewWorkspaceIdExactly("moccasin-ferret-155799b3");
69
+ expect(actual).to.be.true;
70
+ }
71
+ @test public matchesWorkspaceIdExactly_new_negative() {
72
+ const actual = matchesNewWorkspaceIdExactly("moccasin-ferret-15599b3");
73
+ expect(actual).to.be.false;
74
+ }
55
75
  }
56
76
  module.exports = new ParseWorkspaceIdTest()
@@ -4,6 +4,14 @@
4
4
  * See License-AGPL.txt in the project root for license information.
5
5
  */
6
6
 
7
+ const REGEX_WORKSPACE_ID = /[0-9a-z]{2,16}-[0-9a-z]{2,16}-[0-9a-z]{8}/;
8
+ const REGEX_WORKSPACE_ID_EXACT = new RegExp(`^${REGEX_WORKSPACE_ID.source}$`);
9
+ // We need to parse the workspace id precisely here to get the case '<some-str>-<port>-<wsid>.ws.' right
10
+ const REGEX_WORKSPACE_ID_FROM_HOSTNAME = new RegExp(`(${REGEX_WORKSPACE_ID.source})\.ws`);
11
+
12
+ const REGEX_WORKSPACE_ID_LEGACY = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/;
13
+ const REGEX_WORKSPACE_ID_LEGACY_EXACT = new RegExp(`^${REGEX_WORKSPACE_ID_LEGACY.source}$`);
14
+ const REGEX_WORKSPACE_ID_LEGACY_FROM_HOSTNAME = new RegExp(`(${REGEX_WORKSPACE_ID_LEGACY.source})\.ws`);
7
15
 
8
16
  /**
9
17
  * Hostname may be of the form:
@@ -13,17 +21,35 @@
13
21
  * @param hostname The hostname the request is headed to
14
22
  */
15
23
  export const parseWorkspaceIdFromHostname = function(hostname: string) {
16
- // We need to parse the workspace id precisely here to get the case '<some-str>-<port>-<wsid>.ws.' right
17
- const wsIdExpression = /([0-9a-z]{2,16}-[0-9a-z]{2,16}-[0-9a-z]{8})\.ws/g;
18
- const match = wsIdExpression.exec(hostname);
24
+ const match = REGEX_WORKSPACE_ID_FROM_HOSTNAME.exec(hostname);
19
25
  if (match && match.length >= 2) {
20
26
  return match[1];
21
27
  } else {
22
- const legacyUrlFormat = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.ws/g;
23
- const legacyMatch = legacyUrlFormat.exec(hostname);
28
+ const legacyMatch = REGEX_WORKSPACE_ID_LEGACY_FROM_HOSTNAME.exec(hostname);
24
29
  if (legacyMatch && legacyMatch.length >= 2) {
25
30
  return legacyMatch[1];
26
31
  }
27
32
  return undefined;
28
33
  }
29
- }
34
+ };
35
+
36
+ /** Equalls UUIDv4 (and REGEX_WORKSPACE_ID_LEGACY!) */
37
+ const REGEX_INSTANCE_ID = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/;
38
+ const REGEX_INSTANCE_ID_EXACT = new RegExp(`^${REGEX_INSTANCE_ID.source}$`);
39
+
40
+ /**
41
+ * @param maybeId
42
+ * @returns
43
+ */
44
+ export const matchesInstanceIdOrLegacyWorkspaceIdExactly = function(maybeId: string): boolean {
45
+ return REGEX_INSTANCE_ID_EXACT.test(maybeId)
46
+ || REGEX_WORKSPACE_ID_LEGACY_EXACT.test(maybeId);
47
+ };
48
+
49
+ /**
50
+ * @param maybeWorkspaceId
51
+ * @returns
52
+ */
53
+ export const matchesNewWorkspaceIdExactly = function(maybeWorkspaceId: string): boolean {
54
+ return REGEX_WORKSPACE_ID_EXACT.test(maybeWorkspaceId);
55
+ };
@@ -7,7 +7,6 @@
7
7
  import * as fs from 'fs';
8
8
  import { filePathTelepresenceAware } from './env';
9
9
  import { DeepPartial } from "./util/deep-partial";
10
- import { Without } from './util/without';
11
10
  import { PermissionName } from './permission';
12
11
 
13
12
  export interface WorkspaceCluster {
@@ -36,6 +35,9 @@ export interface WorkspaceCluster {
36
35
 
37
36
  // An optional set of constraints that limit who can start workspaces on the cluster
38
37
  admissionConstraints?: AdmissionConstraint[];
38
+
39
+ // An optional set of admission preferences that guide cluster selection
40
+ admissionPreferences?: AdmissionPreference[];
39
41
  }
40
42
 
41
43
  export type WorkspaceClusterState = "available" | "cordoned" | "draining";
@@ -50,12 +52,16 @@ export interface TLSConfig {
50
52
  export namespace TLSConfig {
51
53
  export const loadFromBase64File = (path: string): string => fs.readFileSync(filePathTelepresenceAware(path)).toString("base64");
52
54
  }
53
- export type WorkspaceClusterWoTLS = Without<WorkspaceCluster, "tls">;
55
+ export type WorkspaceClusterWoTLS = Omit<WorkspaceCluster, "tls">;
54
56
  export type WorkspaceManagerConnectionInfo = Pick<WorkspaceCluster, "name" | "url" | "tls">;
55
57
 
56
- export type AdmissionConstraint = AdmissionConstraintFeaturePreview | AdmissionConstraintHasRole;
58
+ export type AdmissionConstraint = AdmissionConstraintFeaturePreview | AdmissionConstraintHasRole | AdmissionConstraintHasUserLevel;
57
59
  export type AdmissionConstraintFeaturePreview = { type: "has-feature-preview" };
58
60
  export type AdmissionConstraintHasRole = { type: "has-permission", permission: PermissionName };
61
+ export type AdmissionConstraintHasUserLevel = { type: "has-user-level", level: string };
62
+
63
+ export type AdmissionPreference = AdmissionPreferenceUserLevel;
64
+ export type AdmissionPreferenceUserLevel = { type: 'user-level', level: string };
59
65
 
60
66
 
61
67
  export const WorkspaceClusterDB = Symbol("WorkspaceClusterDB");
@@ -23,16 +23,22 @@ export interface WorkspaceInstance {
23
23
  // The time an instance has switched phase to 'Running'
24
24
  startedTime?: string;
25
25
 
26
+ // The time an instance has switched phase to 'Stopping' */
27
+ stoppingTime?: string;
28
+
26
29
  // The time an instance has switched phase to 'Stopped' */
27
30
  stoppedTime?: string;
28
31
 
29
32
  // ideUrl is the URL at which the workspace is available on the internet
33
+ // Note: this is nitially empty, filled during starting process!
30
34
  ideUrl: string;
31
35
 
32
36
  // region is the name of the workspace cluster this instance runs in
37
+ // Note: this is nitially empty, filled during starting process!
33
38
  region: string;
34
39
 
35
40
  // workspaceImage is the name of the Docker image this instance runs
41
+ // Note: this is nitially empty, filled during starting process!
36
42
  workspaceImage: string;
37
43
 
38
44
  // status is the latest status of the instance that we're aware of
@@ -83,7 +89,7 @@ export interface WorkspaceInstanceStatus {
83
89
  // WorkspaceInstancePhase describes a high-level state of a workspace instance
84
90
  export type WorkspaceInstancePhase =
85
91
  // unknown indicates an issue within the system in that it cannot determine the actual phase of
86
- // a workspace. This phase is usually accompanied by an error.
92
+ // a workspace. This phase is usually accompanied by an error.
87
93
  "unknown" |
88
94
 
89
95
  // Preparing means that we haven't actually started the workspace instance just yet, but rather
@@ -91,21 +97,21 @@ export type WorkspaceInstancePhase =
91
97
  "preparing" |
92
98
 
93
99
  // Pending means the workspace does not yet consume resources in the cluster, but rather is looking for
94
- // some space within the cluster. If for example the cluster needs to scale up to accomodate the
95
- // workspace, the workspace will be in Pending state until that happened.
100
+ // some space within the cluster. If for example the cluster needs to scale up to accomodate the
101
+ // workspace, the workspace will be in Pending state until that happened.
96
102
  "pending" |
97
103
 
98
104
  // Creating means the workspace is currently being created. Thati includes downloading the images required
99
- // to run the workspace over the network. The time spent in this phase varies widely and depends on the current
100
- // network speed, image size and cache states.
105
+ // to run the workspace over the network. The time spent in this phase varies widely and depends on the current
106
+ // network speed, image size and cache states.
101
107
  "creating" |
102
108
 
103
109
  // Initializing is the phase in which the workspace is executing the appropriate workspace initializer (e.g. Git
104
- // clone or backup download). After this phase one can expect the workspace to either be Running or Failed.
110
+ // clone or backup download). After this phase one can expect the workspace to either be Running or Failed.
105
111
  "initializing" |
106
112
 
107
113
  // Running means the workspace is able to actively perform work, either by serving a user through Theia,
108
- // or as a headless workspace.
114
+ // or as a headless workspace.
109
115
  "running" |
110
116
 
111
117
  // Interrupted is an exceptional state where the container should be running but is temporarily unavailable.
@@ -139,6 +145,12 @@ export interface WorkspaceInstanceConditions {
139
145
 
140
146
  // ISO8601 timestamp when the first user activity was registered in the frontend. Only set if the workspace is running.
141
147
  firstUserActivity?: string;
148
+
149
+ // headless_task_failed indicates that a headless workspace task failed
150
+ headlessTaskFailed?: string;
151
+
152
+ // stopped_by_request is true if the workspace was stopped using a StopWorkspace call
153
+ stoppedByRequest?: boolean;
142
154
  }
143
155
 
144
156
  // AdmissionLevel describes who can access a workspace instance and its ports.
package/src/wsready.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * See License-AGPL.txt in the project root for license information.
5
5
  */
6
6
 
7
- // generated using github.com/32leaves/bel on 2021-04-20 10:08:58.0197329 +0000 UTC m=+0.008313436
7
+ // generated using github.com/32leaves/bel on 2021-08-03 10:42:32.582603295 +0000 UTC m=+0.005734479
8
8
  // DO NOT MODIFY
9
9
 
10
10
  export enum WorkspaceInitSource {
@@ -1,13 +0,0 @@
1
- /**
2
- * Copyright (c) 2020 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
- * The field "contextUrl" might contain prefixes like:
8
- * - envvar1=value1/...
9
- * - prebuild/...
10
- * This is the analogon to the (Prefix)ContextParser structure in "server".
11
- */
12
- export declare function contextUrlToUrl(contextUrl: string | undefined): URL | undefined;
13
- //# sourceMappingURL=context-url.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context-url.d.ts","sourceRoot":"","sources":["../../src/util/context-url.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,GAAG,GAAG,SAAS,CAU/E"}