Skip to content

Commit

Permalink
Add CI workflow to compute diff between files dist files
Browse files Browse the repository at this point in the history
  • Loading branch information
Kocal committed Oct 13, 2024
1 parent 320e635 commit bd04a12
Show file tree
Hide file tree
Showing 2 changed files with 196 additions and 0 deletions.
118 changes: 118 additions & 0 deletions .github/generate-dist-files-size-diff.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/**
* Generate a markdown table with the difference in size of the dist files between the base and the PR.
*/

/*
Usage:
```shell
BASE_DIST_FILES='{"src/Autocomplete/assets/dist/controller.js":{"size":15382,"size_gz":3716,"size_brotli":3125},"src/Chartjs/assets/dist/controller.js":{"size":2281,"size_gz":771,"size_brotli":642},"src/Cropperjs/assets/dist/controller.js":{"size":1044,"size_gz":475,"size_brotli":371}}' \
PR_DIST_FILES='{"src/Chartjs/assets/dist/controller.js":{"size":2281,"size_gz":771,"size_brotli":642},"src/Cropperjs/assets/dist/controller.js":{"size":1044,"size_gz":475,"size_brotli":371},"src/Cropperjs/assets/dist/style.min.css":{"size":32,"size_gz":66,"size_brotli":34},"src/Dropzone/assets/dist/controller.js":{"size":3199,"size_gz":816,"size_brotli":634}}' \
node .github/generate-dist-files-size-diff.mjs
```
*/

if (!process.env.BASE_DIST_FILES) {
throw new Error('Missing or invalid "BASE_DIST_FILES" env variable.');
}

if (!process.env.PR_DIST_FILES) {
throw new Error('Missing or invalid "PR_DIST_FILES" env variable.');
}

/**
* Adapted from https://gist.github.com/zentala/1e6f72438796d74531803cc3833c039c?permalink_comment_id=4455218#gistcomment-4455218
* @param {number} bytes
* @param {number} digits
* @returns {string}
*/
function formatBytes(bytes, digits = 2) {
if (bytes === 0) {
return '0 B';
}
const sizes = [`B`, 'kB', 'MB'];
const i = Math.floor(Math.log(bytes) / Math.log(1024));

return parseFloat((bytes / Math.pow(1024, i)).toFixed(digits)) + ' ' + sizes[i];
}

/**
* @param {number} from
* @param {number} to
* @returns {number}
*/
function computeDiffPercent(from, to) {
if (from === to) {
return 0;
}

return Number(((from - to) / to * -100).toFixed(2));
}

/**
* @param {number} percent
* @returns {string}
*/
function formatDiffPercent(percent) {
return percent > 0 ? `+${percent}% 📈` : percent < 0 ? `${percent}% 📉` : `${percent}%`;
}

export function main() {
let base = JSON.parse(process.env.BASE_DIST_FILES);
let pr = JSON.parse(process.env.PR_DIST_FILES);
let output = '<h1>📊 Dist files size difference</h1>\n\n';

const files = [...new Set([...Object.keys(pr), ...Object.keys(base)])].sort().reduce((acc, file) => {
const added = !base[file] && pr[file];
const removed = base[file] && !pr[file];
const diff_percent_size = removed ? -100 : (added ? 100 : (computeDiffPercent(base[file].size, pr[file].size)));
const diff_percent_size_gz = removed ? -100 : (added ? 100 : (computeDiffPercent(base[file].size_gz, pr[file].size_gz)));
const diff_percent_size_brotli = removed ? -100 : (added ? 100 : (computeDiffPercent(base[file].size_brotli, pr[file].size_brotli)));

if (diff_percent_size !== 0 && diff_percent_size_gz !== 0 && diff_percent_size_brotli !== 0) {
acc.set(file, {
state: added ? 'added' : (removed ? 'removed' : 'changed'),
diff_percent_size,
diff_percent_size_gz,
diff_percent_size_brotli
});
}

return acc;
}, new Map);

if (files.size === 0) {
output += 'ℹ️ No difference in dist files.\n';
return output;
}

output += 'Thanks for the PR! Here is the difference in size of the dist files between the base and the PR.\n';
output += 'Please review the changes and make sure they are expected.\n\n';
output += `<table>
<thead><tr><th>File</th><th>Diff (B)</th><th>Diff (%)</th></tr></thead>
<tbody>`;
for (const [file, details] of files.entries()) {
output += `<tr>
<td><code>${file}</code> ${details.state === 'added' ? '(new)' : (details.state === 'removed' ? '(deleted)' : '')}</td>
<td>
Size: <code>${formatBytes(base[file]?.size || 0)}</code> → <code>${formatBytes(pr[file]?.size || 0)}</code><br>
Gzip: <code>${formatBytes(base[file]?.size_gz || 0)}</code> → <code>${formatBytes(pr[file]?.size_gz || 0)}</code><br>
Brotli: <code>${formatBytes(base[file]?.size_brotli || 0)}</code> → <code>${formatBytes(pr[file]?.size_brotli || 0)}</code>
</td>
<td align="right">
Size: <b>${formatDiffPercent(details.diff_percent_size)}</b><br>
Gzip: <b>${formatDiffPercent(details.diff_percent_size_gz)}</b><br>
Brotli: <b>${formatDiffPercent(details.diff_percent_size_brotli)}</b>
</td>
</tr>
`;
}
output += `</tbody>
</table>
`;

return output;
}

if (!process.env.CI) {
console.log(main());
}
78 changes: 78 additions & 0 deletions .github/workflows/dist-files-size-diff.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Dist Files Size Diff

on:
pull_request:
paths:
- 'src/*/**'
- '!src/*/doc/**'
- '.github/**'

jobs:
dist-files-size-diff:
runs-on: ubuntu-latest
permissions:
pull-requests: write # for marocchino/sticky-pull-request-comment@v2
steps:
- name: Configure git
run: |
git config --global user.email ""
git config --global user.name "github-action[bot]"
- uses: marocchino/sticky-pull-request-comment@v2
with:
message: |
⏳ The dist files size difference is being calculated...
- uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}

- name: Get dist files size (from base branch)
id: base-dist-files
run: |
set -e
FILES=$(find src -mindepth 2 -path '*/assets/dist/*' \( -name "*.js" -o -name "*.css" \) -not \( -path '*/tests/*' -o -path '*/public/*' -o -path '*/vendor/*' \) | sort | while read -r file; do
echo "{\"$file\": {\"size\": $(wc -c < "$file"), \"size_gz\": $(gzip -c "$file" | wc -c), \"size_brotli\": $(brotli -c "$file" | wc -c)}}"
done | jq -s 'add' -c)
echo "files=$FILES" >> $GITHUB_OUTPUT
- uses: actions/checkout@v4

- name: Get dist files size (from pull request)
id: pr-dist-files
run: |
set -e
FILES=$(find src -mindepth 2 -path '*/assets/dist/*' \( -name "*.js" -o -name "*.css" \) -not \( -path '*/tests/*' -o -path '*/public/*' -o -path '*/vendor/*' \) | sort | while read -r file; do
echo "{\"$file\": {\"size\": $(wc -c < "$file"), \"size_gz\": $(gzip -c "$file" | wc -c), \"size_brotli\": $(brotli -c "$file" | wc -c)}}"
done | jq -s 'add' -c)
echo "files=$FILES" >> $GITHUB_OUTPUT
- name: Generate the diff
id: diff
uses: actions/github-script@v7
env:
BASE_DIST_FILES: ${{ steps.base-dist-files.outputs.files }}
PR_DIST_FILES: ${{ steps.pr-dist-files.outputs.files }}
with:
result-encoding: string
script: |
const { main } = await import('${{ github.workspace }}/.github/generate-dist-files-size-diff.mjs')
return await main()
- name: Comment on the pull request (if any failure)
if: ${{ failure() }}
uses: marocchino/sticky-pull-request-comment@v2
with:
message: |
❌ The dist files size difference could not be calculated. Please check the logs for more details.
- name: Comment on the pull request (if success)
if: ${{ always() && steps.diff.conclusion == 'success' }}
uses: marocchino/sticky-pull-request-comment@v2
with:
message: ${{ steps.diff.outputs.result }}

0 comments on commit bd04a12

Please sign in to comment.