mapbox-gl
Version:
A WebGL interactive maps library
141 lines (124 loc) • 5.23 kB
JavaScript
import { Octokit } from "@octokit/rest";
import prettyBytes from 'pretty-bytes';
import fs from 'fs';
import {execSync} from 'child_process';
import zlib from 'zlib';
process.on('unhandledRejection', error => {
// don't log `error` directly, because errors from child_process.execSync
// contain an (undocumented) `envPairs` with environment variable values
console.log(error.message || 'Error');
process.exit(1)
});
const FILES = [
['JS', "dist/mapbox-gl.js"],
['CSS', "dist/mapbox-gl.css"]
];
const PK = process.env['MBX_CI_DOMAIN'];
if (!PK) {
console.log('Fork PR; not computing size.');
process.exit(0);
}
const owner = 'mapbox';
const repo = 'mapbox-gl-js';
(async () => {
// Initialize github client
const github = new Octokit({
auth: execSync('~/mbx-ci github notifier token').toString().trim()
});
//get current sizes
const currentSizes = FILES.map(([label, filePath]) => [label, getSize(filePath)]);
console.log(currentSizes);
async function getMergeBase() {
const head = process.env['CIRCLE_SHA1'];
const pr = process.env['CIRCLE_PULL_REQUEST'];
if (pr) {
const number = +pr.match(/\/(\d+)\/?$/)[1];
return github.pulls.get({
owner,
repo,
pull_number: number
}).then(({data}) => {
const base = data.base.ref;
return execSync(`git merge-base origin/${base} ${head}`).toString().trim();
});
} else {
// Walk backward through the history (maximum of 10 commits) until
// finding a commit on either master or release-*; assume that's the
// base branch.
for (const sha of execSync(`git rev-list --max-count=10 ${head}`).toString().trim().split('\n')) {
const base = execSync(`git branch -r --contains ${sha} origin/main origin/release-*`).toString().split('\n')[0].trim();
if (base) {
return Promise.resolve(execSync(`git merge-base ${base} ${head}`).toString().trim());
}
}
}
return Promise.resolve(null);
}
async function getPriorSize(mergeBase, name) {
if (!mergeBase) {
console.log('No merge base available.');
return Promise.resolve(null);
}
return github.checks.listForRef({
owner,
repo,
ref: mergeBase
}).then(({data}) => {
const run = data.check_runs.find(run => run.name === name);
if (run) {
const match = run.output.summary.match(/`[^`]+` is (\d+) bytes \([^\)]+\) uncompressed, (\d+) bytes \([^\)]+\) gzipped\./);
if (match) {
const prior = { size: +match[1], gzipSize: +match[2] };
console.log(`Prior size was ${prettyBytes(prior.size)}, gzipped ${prior.gzipSize}.`);
return prior;
}
}
console.log('No matching check found.');
return Promise.resolve(null);
});
}
const mergeBase = await getMergeBase();
// Generate a github check for each filetype
for(let check_idx=0; check_idx<FILES.length; check_idx++){
const [label, file] = FILES[check_idx];
const name = `Size - ${label}`;
const size = currentSizes[check_idx][1];
const priorSize = await getPriorSize(mergeBase, name);
console.log('priorSize: ', label, priorSize);
const title = `${formatSize(size.size, priorSize ? priorSize.size : null)}, gzipped ${formatSize(size.gzipSize, priorSize ? priorSize.gzipSize : null)}`;
const megabit = Math.pow(2, 12);
const downloadTime3G = (size.gzipSize / (3 * megabit)).toFixed(0);
const downloadTime4G = (size.gzipSize / (10 * megabit)).toFixed(0);
const summary = `\`${file}\` is ${size.size} bytes (${prettyBytes(size.size)}) uncompressed, ${size.gzipSize} bytes (${prettyBytes(size.gzipSize)}) gzipped.
That's **${downloadTime3G} seconds** over slow 3G (3 Mbps), **${downloadTime4G} seconds** over fast 4G (10 Mbps).`;
console.log('Posting check to GitHub');
console.log(`Title: ${title}`);
console.log(`Summary: ${summary}`);
await github.checks.create({
owner,
repo,
name,
head_branch: process.env['CIRCLE_BRANCH'],
head_sha: process.env['CIRCLE_SHA1'],
status: 'completed',
conclusion: 'success',
completed_at: new Date().toISOString(),
output: { title, summary }
});
}
})();
function getSize(filePath) {
const {size} = fs.statSync(filePath);
const gzipSize = zlib.gzipSync(fs.readFileSync(filePath)).length;
return {size, gzipSize};
}
function formatSize(size, priorSize) {
if (priorSize) {
const change = size - priorSize;
const percent = (change / priorSize) * 100;
return `${change >= 0 ? '+' : ''}${prettyBytes(change)} ${percent.toFixed(3)}% (${prettyBytes(size)})`;
} else {
return prettyBytes(size);
}
}