Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/build/lib/screenshotBlocksCi.ts
13379 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
// Compares blocks-ci fixture screenshots from a rendered manifest against the committed markdown.
7
// Usage: node build/lib/screenshotBlocksCi.ts <manifest-path> <markdown-path> <service-url> [--json]
8
//
9
// Exit codes:
10
// 0 — all screenshots match (or no blocks-ci fixtures)
11
// 1 — mismatches found
12
//
13
// Without --json: prints the full updated markdown to stdout.
14
// With --json: prints a JSON object with { startLine, endLine, replacement } for a GitHub suggestion.
15
16
import * as fs from 'fs';
17
18
const HEADER = '<!-- auto-generated by CI — do not edit manually -->';
19
20
interface ManifestFixture {
21
readonly fixtureId: string;
22
readonly imageHash: string;
23
readonly labels?: readonly string[];
24
}
25
26
interface Manifest {
27
readonly fixtures: readonly ManifestFixture[];
28
}
29
30
function generateMarkdown(fixtures: readonly ManifestFixture[], serviceUrl: string): string {
31
const lines: string[] = [HEADER, ''];
32
const seen = new Set<string>();
33
const sorted = [...fixtures].sort((a, b) => a.fixtureId.localeCompare(b.fixtureId));
34
for (const f of sorted) {
35
if (f.labels?.includes('blocks-ci') && !seen.has(f.fixtureId)) {
36
seen.add(f.fixtureId);
37
lines.push(`#### ${f.fixtureId}`);
38
lines.push(`![screenshot](${serviceUrl}/images/${f.imageHash})`);
39
lines.push('');
40
}
41
}
42
return lines.join('\n');
43
}
44
45
function computeDiff(committedLines: string[], updatedLines: string[]): { startLine: number; endLine: number; replacement: string } {
46
let firstDiff = 0;
47
while (firstDiff < committedLines.length && firstDiff < updatedLines.length && committedLines[firstDiff] === updatedLines[firstDiff]) {
48
firstDiff++;
49
}
50
51
let committedEnd = committedLines.length - 1;
52
let updatedEnd = updatedLines.length - 1;
53
while (committedEnd > firstDiff && updatedEnd > firstDiff && committedLines[committedEnd] === updatedLines[updatedEnd]) {
54
committedEnd--;
55
updatedEnd--;
56
}
57
58
return {
59
startLine: firstDiff + 1, // 1-indexed
60
endLine: committedEnd + 1, // 1-indexed
61
replacement: updatedLines.slice(firstDiff, updatedEnd + 1).join('\n'),
62
};
63
}
64
65
function main(): void {
66
const args = process.argv.slice(2);
67
const jsonMode = args.includes('--json');
68
const positional = args.filter(a => a !== '--json');
69
const [manifestPath, markdownPath, serviceUrl] = positional;
70
71
if (!manifestPath || !markdownPath || !serviceUrl) {
72
console.error('Usage: node build/lib/screenshotBlocksCi.ts <manifest-path> <markdown-path> <service-url> [--json]');
73
process.exit(1);
74
}
75
76
const manifest: Manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
77
const actual = generateMarkdown(manifest.fixtures, serviceUrl);
78
79
let committed = '';
80
if (fs.existsSync(markdownPath)) {
81
committed = fs.readFileSync(markdownPath, 'utf8');
82
}
83
84
if (actual === committed) {
85
process.exit(0);
86
}
87
88
console.error('blocks-ci screenshots have changed.');
89
90
if (jsonMode) {
91
const diff = computeDiff(committed.split('\n'), actual.split('\n'));
92
process.stdout.write(JSON.stringify(diff) + '\n');
93
} else {
94
process.stdout.write(actual);
95
}
96
process.exit(1);
97
}
98
99
main();
100
101