Skip to content

Instantly share code, notes, and snippets.

@malliapi
Created October 15, 2020 16:28
Show Gist options
  • Save malliapi/49633556f19677bcd67c99355880db43 to your computer and use it in GitHub Desktop.
Save malliapi/49633556f19677bcd67c99355880db43 to your computer and use it in GitHub Desktop.
RollBar Sourcemaps Upload
/**
* @module build/scripts/rollbar-sourcemap-upload
*
* Extracts currently built sourcemaps and uploads them to rollbar.
*/
const request = require('request');
const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const logger = require('../lib/logger');
const config = require('../../config/config.server');
const { getBundles } = require('../../config/config.assets');
// eslint-disable-next-line import/no-unresolved
const webpackAssets = require('../../dist/assets.json');
// SOURCE_VERSION is the SHA of the current git commit
// exposed under a Heroku build environment variable
// see https://devcenter.heroku.com/articles/buildpack-api#bin-compile-summary
// CIRCLE_SHA1 is the same for CircleCI environments
const version = process.env.SOURCE_VERSION || process.env.CIRCLE_SHA1;
if (require.main === module && !version) {
logger.error('SOURCE_VERSION or CIRCLE_SHA1 must be provided for Rollbar sourcemaps to be matched to error traces');
process.exit(1);
}
/**
* Helps resolve the local file path.
*
* @param {string} publicPath - public path of a file to search eg. `/assets/js/app.js`
* @returns {string} Absolute path to file on local filesystem
*/
function getLocalFilePath(publicPath) {
return path.resolve(path.join(__dirname, `../../dist/public${publicPath}`));
}
/**
* Uploads a single source map to Rollbar.
*
* @param {string} filePath - public path of a file to search eg. `/assets/js/app.js`
* @returns {Promise} Promised request
*/
function uploadSingleSourceMap(filePath) {
const rollbarUrl = 'https://api.rollbar.com/api/1/sourcemap';
const accessToken = config.rollbarServerAccessToken;
const minifiedUrl = config.app + filePath;
const fileName = filePath.split('/').pop();
return new Promise((resolve, reject) => {
request.post(
{
url: rollbarUrl,
headers: {
'content-type': 'multipart/form-data',
},
multipart: [
{
'Content-Disposition': 'form-data; name="access_token"',
body: accessToken,
},
{
'Content-Disposition': 'form-data; name="version"',
body: version,
},
{
'Content-Disposition': 'form-data; name="minified_url"',
body: minifiedUrl,
},
{
'Content-Disposition': `form-data; name="source_map" filename="${fileName}"`,
body: fs.readFileSync(getLocalFilePath(`${filePath}.map`)),
},
],
},
(err, response, body) => {
if (err) {
reject(err);
}
if (response.statusCode !== 200) {
reject(new Error(`Expected 200 got ${response.statusCode}`));
} else {
resolve(body);
}
}
);
});
}
/**
* Executes requests to Rollbar.
*
* @param {object} [assets=webpackAssets] - Assets to upload. webpack.assets by default.
* @returns {Promise} Promise chain of all simultaneous uploads
*/
function uploadSourceMapsToRollbar(assets = webpackAssets) {
const { assetsByChunkName } = assets;
const fileUploads = Object.keys(assetsByChunkName).map((bundleName) => {
const filePath = getBundles(bundleName, assets).js[0];
return uploadSingleSourceMap(filePath);
});
return Promise.resolve()
.then(() => logger.info(`Uploading sourcemaps to Rollbar for ${chalk.bold(config.env)} target environment`))
.then(() => Promise.all(fileUploads))
.then((response) => {
logger.success('Sourcemap upload successful');
return response;
})
.catch((err) => {
logger.error(`Upload failed ${err.stack}`);
throw err;
});
}
// Called directly (npm run upload-sourcemaps), start uploading
if (require.main === module) {
uploadSourceMapsToRollbar().catch(() => process.exit(1));
}
module.exports = {
uploadSourceMapsToRollbar,
uploadSingleSourceMap,
getLocalFilePath,
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment