const { markdown } = require('danger'); const fs = require('fs').promises; const gzipSize = require('gzip-size'); const git = require('simple-git').gitP(__dirname); /** * Returns the contents of a text file in the base of the PR. * * The base is usually PrismJS/prism/master. * * @param {string} path * @returns {Promise} */ function readBaseFile(path) { return fs.readFile(path, 'utf-8'); } /** * Returns the contents of a text file in the pull request branch. * * @param {string} path * @returns {Promise} */ function readPRFile(path) { return git.show([`pr:${path}`]); } /** * Returns the relative paths of all files changed in the PR. * * @returns {Promise} */ const getChangedFiles = async () => { // Determine the merge base between master and the PR branch. // If files changed in master since PR was branched they would show in the diff otherwise. // https://stackoverflow.com/questions/25071579/list-all-files-changed-in-a-pull-request-in-git-github const mergeBase = (await git.raw(['merge-base', 'pr', 'HEAD'])).trim(); const result = await git.diff(['--name-only', '--no-renames', 'pr', mergeBase]); return (result || '').trim().split(/\r?\n/g); }; const getChangedMinifiedFiles = async () => { const changed = await getChangedFiles(); return changed.filter(file => file.endsWith('.min.js')); }; // https://stackoverflow.com/questions/15900485/correct-way-to-convert-size-in-bytes-to-kb-mb-gb-in-javascript const formatBytes = (bytes, decimals = 2) => { if (bytes === 0) { return '0 Bytes'; } const k = 1000; const dm = decimals < 0 ? 0 : decimals; const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; }; const maybePlus = (from, to) => from < to ? '+' : ''; const absDiff = (from, to) => { if (from === to) { return formatBytes(0); } return `${maybePlus(from, to)}${formatBytes(to - from)}`; }; const percDiff = (from, to) => { if (from === to) { return '0%'; } return `${maybePlus(from, to)}${(100 * (to - from) / (from || to)).toFixed(1)}%`; }; const getSummary = (rows, totalMasterFileSize, totalFileSize) => { const numFiles = rows.length; const maybeS = rows.length > 0 ? 's' : ''; const byteDiff = absDiff(totalMasterFileSize, totalFileSize); const percentDiff = percDiff(totalMasterFileSize, totalFileSize); return `A total of ${numFiles} file${maybeS} have changed, with a combined diff of ${byteDiff} (${percentDiff}).`; }; const run = async () => { const minified = await getChangedMinifiedFiles(); if (minified.length === 0) { markdown(`## No JS Changes`); return; } const rows = []; let totalFileSize = 0; let totalMasterFileSize = 0; for (const file of minified) { const [fileContents, fileMasterContents] = await Promise.all([ readPRFile(file).catch(() => ''), readBaseFile(file).catch(() => ''), ]); const [fileSize, fileMasterSize] = await Promise.all([ gzipSize(fileContents), gzipSize(fileMasterContents), ]); totalFileSize += fileSize; totalMasterFileSize += fileMasterSize; rows.push([ file, formatBytes(fileMasterSize), formatBytes(fileSize), absDiff(fileMasterSize, fileSize), percDiff(fileMasterSize, fileSize), ]); } markdown(`## JS File Size Changes (gzipped) ${getSummary(rows, totalMasterFileSize, totalFileSize)}
| file | master | pull | size diff | % diff | | --- | --- | --- | --- | --- | ${rows.map(row => `| ${row.join(' | ')} |`).join('\n')}
`); }; run().catch(err => { console.error(err); process.exit(1); });