Skip to content

Commit 2085beb

Browse files
committed
[wip]
1 parent e54329b commit 2085beb

File tree

2 files changed

+129
-59
lines changed

2 files changed

+129
-59
lines changed

.github/workflows/compare-builds.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,11 @@ jobs:
116116
echo "combined<<EOF"
117117
cat "${result_files[@]}"
118118
echo "EOF"
119-
echo "has_results=true"
120119
} >> "$GITHUB_OUTPUT"
121-
else
122-
echo "has_results=false" >> "$GITHUB_OUTPUT"
123120
fi
124121
125122
- name: Add Comment to PR
126-
if: steps.combine.outputs.has_results == 'true'
123+
if: steps.combine.outputs.combined
127124
uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b # v3.0.1
128125
with:
129126
comment-tag: compared

scripts/compare-builds/web.mjs

Lines changed: 128 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { stat, readdir } from 'node:fs/promises';
22
import path from 'node:path';
33
import { fileURLToPath } from 'node:url';
44

5-
const BASE = fileURLToPath(import.meta.resolve(`../../out/base`));
6-
const HEAD = fileURLToPath(import.meta.resolve(`../../out/head`));
5+
const BASE = fileURLToPath(import.meta.resolve('../../out'));
6+
const HEAD = fileURLToPath(import.meta.resolve('../../out'));
7+
const UNITS = ['B', 'KB', 'MB', 'GB'];
78

89
/**
910
* Formats bytes into human-readable format
@@ -14,25 +15,21 @@ const formatBytes = bytes => {
1415
if (!bytes) {
1516
return '0 B';
1617
}
17-
18-
const units = ['B', 'KB', 'MB', 'GB'];
1918
const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(1024));
20-
21-
return `${(bytes / 1024 ** i).toFixed(2)} ${units[i]}`;
19+
return `${(bytes / Math.pow(1024, i)).toFixed(2)} ${UNITS[i]}`;
2220
};
2321

2422
/**
2523
* Formats the difference between base and head sizes
2624
* @param {number} base - Base file size in bytes
2725
* @param {number} head - Head file size in bytes
28-
* @returns {string} Formatted diff string (e.g., "+1.50 KB (+10.00%)")
26+
* @returns {string} Formatted diff string (e.g., "+1.50 KB (+10. 00%)")
2927
*/
3028
const formatDiff = (base, head) => {
3129
const diff = head - base;
32-
const pct = base ? `${((diff / base) * 100).toFixed(2)}%` : 'N/A';
3330
const sign = diff > 0 ? '+' : '';
34-
35-
return `${sign}${formatBytes(diff)} (${sign}${pct})`;
31+
const percent = base ? `${sign}${((diff / base) * 100).toFixed(2)}%` : 'N/A';
32+
return `${sign}${formatBytes(diff)} (${percent})`;
3633
};
3734

3835
/**
@@ -41,66 +38,142 @@ const formatDiff = (base, head) => {
4138
* @returns {Promise<Map<string, number>>} Map of filename to size
4239
*/
4340
const getDirectoryStats = async dir => {
44-
const entries = await readdir(dir);
45-
const stats = await Promise.all(
46-
entries.map(async file => [file, (await stat(path.join(dir, file))).size])
41+
const files = await readdir(dir);
42+
const entries = await Promise.all(
43+
files.map(async file => [file, (await stat(path.join(dir, file))).size])
4744
);
48-
49-
return new Map(stats);
45+
return new Map(entries);
5046
};
5147

48+
/**
49+
* Gets the extension of a file
50+
* @param {string} file - Filename
51+
* @returns {string} File extension (without dot)
52+
*/
53+
const getExtension = file => file.split('.').pop();
54+
5255
/**
5356
* Gets the base name of a file (without extension)
5457
* @param {string} file - Filename
55-
* @returns {string} Base name
58+
* @returns {string} Base filename
5659
*/
57-
const getBaseName = file => file.replace(/\.[^. ]+$/, '');
60+
const getBaseName = file => file.slice(0, file.lastIndexOf('.') || file.length);
5861

59-
const [baseStats, headStats] = await Promise.all(
60-
[BASE, HEAD].map(getDirectoryStats)
61-
);
62+
/**
63+
* Generates a table row for a file
64+
* @param {string} file - Filename
65+
* @param {number} [baseSize] - Base size in bytes
66+
* @param {number} [headSize] - Head size in bytes
67+
* @returns {string} Markdown table row
68+
*/
69+
const generateRow = (file, baseSize, headSize) => {
70+
const baseCol = baseSize != null ? formatBytes(baseSize) : '-';
71+
const headCol = headSize != null ? formatBytes(headSize) : '-';
72+
73+
let diffCol = 'Added';
74+
if (baseSize != null && headSize != null) {
75+
diffCol = formatDiff(baseSize, headSize);
76+
} else if (baseSize != null) {
77+
diffCol = 'Removed';
78+
}
6279

63-
const allFiles = new Set([...baseStats.keys(), ...headStats.keys()]);
80+
return `| \`${file}\` | ${baseCol} | ${headCol} | ${diffCol} |`;
81+
};
6482

65-
// Count occurrences of each base name to identify paired files
66-
const baseNameCounts = new Map();
67-
for (const file of allFiles) {
68-
const name = getBaseName(file);
69-
baseNameCounts.set(name, (baseNameCounts.get(name) || 0) + 1);
70-
}
83+
/**
84+
* Generates a markdown table
85+
* @param {string[]} files - List of files
86+
* @param {Map<string, number>} baseStats - Base stats map
87+
* @param {Map<string, number>} headStats - Head stats map
88+
* @returns {string} Markdown table
89+
*/
90+
const generateTable = (files, baseStats, headStats) => {
91+
const header = '| File | Base | Head | Diff |\n|------|------|------|------|';
92+
const rows = files.map(f =>
93+
generateRow(f, baseStats.get(f), headStats.get(f))
94+
);
95+
return `${header}\n${rows.join('\n')}`;
96+
};
7197

72-
// Find and sort changed files: non-paired first (alphabetically), then paired (alphabetically)
73-
const changedFiles = [...allFiles]
74-
// .filter(file => baseStats.get(file) !== headStats.get(file))
75-
.sort((a, b) => {
76-
const aPaired = baseNameCounts.get(getBaseName(a)) > 1;
77-
const bPaired = baseNameCounts.get(getBaseName(b)) > 1;
78-
return aPaired === bPaired ? a.localeCompare(b) : aPaired - bPaired;
79-
});
80-
81-
if (changedFiles.length) {
82-
const rows = changedFiles.map(file => {
83-
const baseSize = baseStats.get(file);
84-
const headSize = headStats.get(file);
85-
86-
if (!baseSize) {
87-
return `| \`${file}\` | - | ${formatBytes(headSize)} | Added |`;
98+
/**
99+
* Wraps content in a details/summary element
100+
* @param {string} summary - Summary text
101+
* @param {string} content - Content to wrap
102+
* @returns {string} Markdown details element
103+
*/
104+
const details = (summary, content) =>
105+
`<details>\n<summary>${summary}</summary>\n\n${content}\n\n</details>`;
106+
107+
async function main() {
108+
const [baseStats, headStats] = await Promise.all(
109+
[BASE, HEAD].map(getDirectoryStats)
110+
);
111+
112+
const allFiles = Array.from(
113+
new Set([...baseStats.keys(), ...headStats.keys()])
114+
);
115+
116+
if (!allFiles.length) {
117+
return;
118+
}
119+
120+
// Separate HTML/JS pairs from other files
121+
const pairs = [];
122+
const other = [];
123+
const processed = new Set();
124+
125+
for (const file of allFiles) {
126+
if (processed.has(file)) {
127+
continue;
88128
}
89129

90-
if (!headSize) {
91-
return `| \`${file}\` | ${formatBytes(baseSize)} | - | Removed |`;
130+
const basename = getBaseName(file);
131+
const hasHtml = allFiles.some(
132+
f => getBaseName(f) === basename && getExtension(f) === 'html'
133+
);
134+
const hasJs = allFiles.some(
135+
f => getBaseName(f) === basename && getExtension(f) === 'js'
136+
);
137+
138+
if (hasHtml && hasJs) {
139+
allFiles
140+
.filter(f => getBaseName(f) === basename)
141+
.forEach(f => {
142+
pairs.push(f);
143+
processed.add(f);
144+
});
145+
} else {
146+
other.push(file);
147+
processed.add(file);
92148
}
149+
}
93150

94-
return `| \`${file}\` | ${formatBytes(baseSize)} | ${formatBytes(headSize)} | ${formatDiff(baseSize, headSize)} |`;
95-
});
151+
pairs.sort();
152+
other.sort();
96153

97-
console.log(
98-
`
99-
## Web Generator
154+
// Generate report sections
155+
const sections = [];
100156

101-
| File | Base | Head | Diff |
102-
|------|------|------|------|
103-
${rows.join('\n')}
104-
`.trim()
105-
);
157+
if (pairs.length) {
158+
sections.push(
159+
details(
160+
`HTML/JS Pairs (${pairs.length})`,
161+
generateTable(pairs, baseStats, headStats)
162+
)
163+
);
164+
}
165+
166+
if (other.length) {
167+
sections.push(
168+
details(
169+
`Other Files (${other.length})`,
170+
generateTable(other, baseStats, headStats)
171+
)
172+
);
173+
}
174+
175+
console.log('## Web Generator');
176+
console.log(sections.join('\n\n'));
106177
}
178+
179+
main();

0 commit comments

Comments
 (0)