Skip to content

Commit cec8894

Browse files
committed
Add in product changelog
1 parent 99a52e9 commit cec8894

File tree

7 files changed

+337
-2
lines changed

7 files changed

+337
-2
lines changed

extensions/gitpod-remote/package.nls.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
"openTwitter": "Gitpod: Follow us on Twitter",
1111
"reportIssue": "Gitpod: Report Issue",
1212
"stopWorkspace": "Gitpod: Stop Workspace",
13+
"showReleaseNote": "Gitpod: Show Release Note",
14+
"cleanReleaseNoteCache": "Gitpod: Debug Clean Release Note Cache",
1315
"upgradeSubscription": "Gitpod: Upgrade Subscription",
1416
"extendTimeout": "Gitpod: Extend Workspace Timeout",
1517
"takeSnapshot": "Gitpod: Share Workspace Snapshot",

extensions/gitpod-shared/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"prepare": "node scripts/inflate.js"
1313
},
1414
"devDependencies": {
15+
"@types/js-yaml": "^4.0.5",
1516
"@types/node": "16.x",
1617
"@types/uuid": "^8.3.1",
1718
"@types/ws": "^7.2.6"
@@ -20,8 +21,9 @@
2021
"@gitpod/gitpod-protocol": "main",
2122
"@gitpod/supervisor-api-grpc": "main",
2223
"bufferutil": "^4.0.1",
23-
"utf-8-validate": "^5.0.2",
24+
"js-yaml": "^4.1.0",
2425
"reconnecting-websocket": "^4.4.0",
26+
"utf-8-validate": "^5.0.2",
2527
"uuid": "^8.3.1",
2628
"vscode-nls": "^5.0.0",
2729
"ws": "^7.4.6",

extensions/gitpod-shared/src/extension.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import * as vscode from 'vscode';
66
import { registerActiveLanguageAnalytics, registerUsageAnalytics } from './analytics';
77
import { createGitpodExtensionContext, GitpodExtensionContext, registerDefaultLayout, registerNotifications, registerWorkspaceCommands, registerWorkspaceSharing, registerWorkspaceTimeout } from './features';
8+
import { registerReleaseNotesView } from './releaseNote';
89

910
export { GitpodExtensionContext, registerTasks, SupervisorConnection, registerIpcHookCli } from './features';
1011
export * from './gitpod-plugin-model';
@@ -32,6 +33,7 @@ export async function setupGitpodContext(context: vscode.ExtensionContext): Prom
3233
registerWorkspaceTimeout(gitpodContext);
3334
registerNotifications(gitpodContext);
3435
registerDefaultLayout(gitpodContext);
36+
registerReleaseNotesView(gitpodContext);
3537
return gitpodContext;
3638
}
3739

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Gitpod. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import fetch from 'node-fetch';
7+
import * as vscode from 'vscode';
8+
import { load } from 'js-yaml';
9+
10+
const LAST_READ_RELEASE_NOTES_ID = 'gitpod.lastReadReleaseNotesId';
11+
12+
export function registerReleaseNotesView(context: vscode.ExtensionContext) {
13+
14+
async function shouldShowReleaseNotes(lastReadId: string | undefined) {
15+
const releaseId = await getLastPublish();
16+
console.log(`gitpod release notes lastReadId: ${lastReadId}, latestReleaseId: ${releaseId}`);
17+
return releaseId !== lastReadId;
18+
}
19+
20+
context.subscriptions.push(
21+
vscode.commands.registerCommand('gitpod.showReleaseNotes', () => {
22+
ReleaseNotesPanel.createOrShow(context);
23+
})
24+
);
25+
26+
// sync between machines
27+
context.globalState.setKeysForSync([LAST_READ_RELEASE_NOTES_ID]);
28+
29+
const lastReadId = context.globalState.get<string>(LAST_READ_RELEASE_NOTES_ID);
30+
shouldShowReleaseNotes(lastReadId).then(shouldShow => {
31+
if (shouldShow) {
32+
ReleaseNotesPanel.createOrShow(context);
33+
}
34+
});
35+
}
36+
37+
async function getLastPublish() {
38+
const resp = await fetch(`${websiteHost}/changelog/latest`);
39+
if (!resp.ok) {
40+
throw new Error(`Getting latest releaseId failed: ${resp.statusText}`);
41+
}
42+
const { releaseId } = JSON.parse(await resp.text());
43+
return releaseId as string;
44+
}
45+
46+
const websiteHost = 'https://www.gitpod.io';
47+
48+
class ReleaseNotesPanel {
49+
public static currentPanel: ReleaseNotesPanel | undefined;
50+
public static readonly viewType = 'gitpodReleaseNotes';
51+
private readonly panel: vscode.WebviewPanel;
52+
private lastReadId: string | undefined;
53+
private _disposables: vscode.Disposable[] = [];
54+
55+
private async loadChangelog(releaseId: string) {
56+
const resp = await fetch(`${websiteHost}/changelog/raw-markdown?releaseId=${releaseId}`);
57+
if (!resp.ok) {
58+
throw new Error(`Getting raw markdown content failed: ${resp.statusText}`);
59+
}
60+
const md = await resp.text();
61+
62+
const parseInfo = (md: string) => {
63+
if (!md.startsWith('---')) {
64+
return;
65+
}
66+
const lines = md.split('\n');
67+
const end = lines.indexOf('---', 1);
68+
const content = lines.slice(1, end).join('\n');
69+
return load(content) as { title: string; date: string; image: string; alt: string; excerpt: string };
70+
};
71+
const info = parseInfo(md);
72+
73+
const content = md
74+
.replace(/---.*?---/gms, '')
75+
.replace(/<script>.*?<\/script>/gms, '')
76+
.replace(/<Badge.*?text="(.*?)".*?\/>/gim, '`$1`')
77+
.replace(/<Contributors usernames="(.*?)" \/>/gim, (_, p1) => {
78+
const users = p1
79+
.split(',')
80+
.map((e: string) => `[${e}](https://github.com/${e})`);
81+
return `Contributors: ${users.join(', ')}`;
82+
})
83+
.replace(/<p>(.*?)<\/p>/gm, '$1')
84+
.replace(/^[\n]+/m, '');
85+
if (!info) {
86+
return content;
87+
}
88+
89+
return [
90+
`# ${info.title}`,
91+
`> Published at ${releaseId}, see also https://gitpod.io/changelog`,
92+
`![${info.alt ?? 'image'}](https://www.gitpod.io/images/changelog/${info.image})`,
93+
content,
94+
].join('\n\n');
95+
}
96+
97+
public async updateHtml(releaseId?: string) {
98+
if (!releaseId) {
99+
releaseId = await getLastPublish();
100+
}
101+
const mdContent = await this.loadChangelog(releaseId);
102+
const html = await vscode.commands.executeCommand('markdown.api.render', mdContent) as string;
103+
this.panel.webview.html = `<!DOCTYPE html>
104+
<html lang="en">
105+
<head>
106+
<meta charset="UTF-8">
107+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
108+
<title>Gitpod Release Notes</title>
109+
<style>
110+
${DEFAULT_MARKDOWN_STYLES}
111+
</style>
112+
</head>
113+
<body>
114+
${html}
115+
</body>
116+
</html>`;
117+
if (!this.lastReadId || releaseId > this.lastReadId) {
118+
await this.context.globalState.update(LAST_READ_RELEASE_NOTES_ID, releaseId);
119+
this.lastReadId = releaseId;
120+
}
121+
}
122+
123+
public static createOrShow(context: vscode.ExtensionContext) {
124+
const column = vscode.window.activeTextEditor
125+
? vscode.window.activeTextEditor.viewColumn
126+
: undefined;
127+
128+
if (ReleaseNotesPanel.currentPanel) {
129+
ReleaseNotesPanel.currentPanel.panel.reveal(column);
130+
return;
131+
}
132+
133+
const panel = vscode.window.createWebviewPanel(
134+
ReleaseNotesPanel.viewType,
135+
'Gitpod Release Notes',
136+
column || vscode.ViewColumn.One,
137+
{ enableScripts: true },
138+
);
139+
140+
ReleaseNotesPanel.currentPanel = new ReleaseNotesPanel(context, panel);
141+
}
142+
143+
public static revive(context: vscode.ExtensionContext, panel: vscode.WebviewPanel) {
144+
ReleaseNotesPanel.currentPanel = new ReleaseNotesPanel(context, panel);
145+
}
146+
147+
private constructor(
148+
private readonly context: vscode.ExtensionContext,
149+
panel: vscode.WebviewPanel
150+
) {
151+
this.lastReadId = this.context.globalState.get<string>(LAST_READ_RELEASE_NOTES_ID);
152+
this.panel = panel;
153+
154+
this.updateHtml();
155+
156+
this.panel.onDidDispose(() => this.dispose(), null, this._disposables);
157+
this.panel.onDidChangeViewState(
158+
() => {
159+
if (this.panel.visible) {
160+
this.updateHtml();
161+
}
162+
},
163+
null,
164+
this._disposables
165+
);
166+
}
167+
168+
public dispose() {
169+
ReleaseNotesPanel.currentPanel = undefined;
170+
this.panel.dispose();
171+
while (this._disposables.length) {
172+
const x = this._disposables.pop();
173+
if (x) {
174+
x.dispose();
175+
}
176+
}
177+
}
178+
}
179+
180+
// Align with https://github.com/gitpod-io/openvscode-server/blob/494f7eba3615344ee634e6bec0b20a1903e5881d/src/vs/workbench/contrib/markdown/browser/markdownDocumentRenderer.ts#L14
181+
export const DEFAULT_MARKDOWN_STYLES = `
182+
body {
183+
padding: 10px 20px;
184+
line-height: 22px;
185+
max-width: 882px;
186+
margin: 0 auto;
187+
}
188+
189+
body *:last-child {
190+
margin-bottom: 0;
191+
}
192+
193+
img {
194+
max-width: 100%;
195+
max-height: 100%;
196+
}
197+
198+
a {
199+
text-decoration: none;
200+
}
201+
202+
a:hover {
203+
text-decoration: underline;
204+
}
205+
206+
a:focus,
207+
input:focus,
208+
select:focus,
209+
textarea:focus {
210+
outline: 1px solid -webkit-focus-ring-color;
211+
outline-offset: -1px;
212+
}
213+
214+
hr {
215+
border: 0;
216+
height: 2px;
217+
border-bottom: 2px solid;
218+
}
219+
220+
h1 {
221+
padding-bottom: 0.3em;
222+
line-height: 1.2;
223+
border-bottom-width: 1px;
224+
border-bottom-style: solid;
225+
}
226+
227+
h1, h2, h3 {
228+
font-weight: normal;
229+
}
230+
231+
table {
232+
border-collapse: collapse;
233+
}
234+
235+
table > thead > tr > th {
236+
text-align: left;
237+
border-bottom: 1px solid;
238+
}
239+
240+
table > thead > tr > th,
241+
table > thead > tr > td,
242+
table > tbody > tr > th,
243+
table > tbody > tr > td {
244+
padding: 5px 10px;
245+
}
246+
247+
table > tbody > tr + tr > td {
248+
border-top-width: 1px;
249+
border-top-style: solid;
250+
}
251+
252+
blockquote {
253+
margin: 0 7px 0 5px;
254+
padding: 0 16px 0 10px;
255+
border-left-width: 5px;
256+
border-left-style: solid;
257+
}
258+
259+
code {
260+
font-family: "SF Mono", Monaco, Menlo, Consolas, "Ubuntu Mono", "Liberation Mono", "DejaVu Sans Mono", "Courier New", monospace;
261+
}
262+
263+
pre code {
264+
font-family: var(--vscode-editor-font-family);
265+
font-weight: var(--vscode-editor-font-weight);
266+
font-size: var(--vscode-editor-font-size);
267+
line-height: 1.5;
268+
}
269+
270+
code > div {
271+
padding: 16px;
272+
border-radius: 3px;
273+
overflow: auto;
274+
}
275+
276+
.monaco-tokenized-source {
277+
white-space: pre;
278+
}
279+
280+
/** Theming */
281+
282+
.vscode-light code > div {
283+
background-color: rgba(220, 220, 220, 0.4);
284+
}
285+
286+
.vscode-dark code > div {
287+
background-color: rgba(10, 10, 10, 0.4);
288+
}
289+
290+
.vscode-high-contrast code > div {
291+
background-color: var(--vscode-textCodeBlock-background);
292+
}
293+
294+
.vscode-high-contrast h1 {
295+
border-color: rgb(0, 0, 0);
296+
}
297+
298+
.vscode-light table > thead > tr > th {
299+
border-color: rgba(0, 0, 0, 0.69);
300+
}
301+
302+
.vscode-dark table > thead > tr > th {
303+
border-color: rgba(255, 255, 255, 0.69);
304+
}
305+
306+
.vscode-light h1,
307+
.vscode-light hr,
308+
.vscode-light table > tbody > tr + tr > td {
309+
border-color: rgba(0, 0, 0, 0.18);
310+
}
311+
312+
.vscode-dark h1,
313+
.vscode-dark hr,
314+
.vscode-dark table > tbody > tr + tr > td {
315+
border-color: rgba(255, 255, 255, 0.18);
316+
}
317+
318+
`;

extensions/gitpod-web/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141
"title": "%stopWorkspace%",
4242
"enablement": "gitpod.inWorkspace == true && gitpod.workspaceOwned == true"
4343
},
44+
{
45+
"command": "gitpod.showReleaseNotes",
46+
"title": "%showReleaseNotes%",
47+
"enablement": "gitpod.inWorkspace == true && gitpod.workspaceOwned == true"
48+
},
4449
{
4550
"command": "gitpod.open.settings",
4651
"title": "%openSettings%",

extensions/gitpod-web/package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"openTwitter": "Gitpod: Follow us on Twitter",
2121
"reportIssue": "Gitpod: Report Issue",
2222
"stopWorkspace": "Gitpod: Stop Workspace",
23+
"showReleaseNotes": "Gitpod: Show Release Notes",
2324
"upgradeSubscription": "Gitpod: Upgrade Subscription",
2425
"extendTimeout": "Gitpod: Extend Workspace Timeout",
2526
"takeSnapshot": "Gitpod: Share Workspace Snapshot",

0 commit comments

Comments
 (0)