Commit 0a60f51d authored by Robert Knight's avatar Robert Knight

Merge pull request #3055 from hypothesis/travis-sentry-sourcemaps

Travis Sentry sourcemaps
parents d0fe4c66 c3a6bf6f
......@@ -254,13 +254,18 @@ gulp.task('test-watch-extension', function (callback) {
}, callback).start();
});
gulp.task('upload-sourcemaps', function () {
gulp.task('upload-sourcemaps',
['build-app-js',
'build-extension-js'], function () {
var uploadToSentry = require('./scripts/gulp/upload-to-sentry');
gulp.src(['build/scripts/*.js', 'build/scripts/*.map'])
.pipe(uploadToSentry({
apiKey: getEnv('SENTRY_API_KEY'),
release: getEnv('SENTRY_RELEASE_VERSION'),
organization: getEnv('SENTRY_ORGANIZATION'),
project: getEnv('SENTRY_PROJECT'),
}));
var opts = {
key: getEnv('SENTRY_API_KEY'),
organization: getEnv('SENTRY_ORGANIZATION'),
};
var projects = getEnv('SENTRY_PROJECTS').split(',');
var release = getEnv('SENTRY_RELEASE_VERSION');
return gulp.src(['build/scripts/*.js', 'build/scripts/*.map'])
.pipe(uploadToSentry(opts, projects, release));
});
'use strict';
var fs = require('fs');
var gulpUtil = require('gulp-util');
var path = require('path');
var gulpUtil = require('gulp-util');
var request = require('request');
var through = require('through2');
var SENTRY_API_ROOT = 'https://app.getsentry.com/api/0';
/**
* interface SentryOptions {
* /// The Sentry API key
* apiKey: string;
* /// The release string for the release to create
* release: string;
* /// The organization slug to use when constructing the API URL
* key: string;
* /// The Sentry organisation to upload the release to
* organization: string;
* /// The project name slug to use when constructing the API URL
* project: string;
* }
*/
/** Wrapper around request() that returns a Promise. */
function httpRequest(opts) {
return new Promise(function (resolve, reject) {
......@@ -27,7 +26,7 @@ function httpRequest(opts) {
reject(err);
} else {
resolve({
status: response.statusCode,
response: response,
body: body,
});
}
......@@ -35,6 +34,55 @@ function httpRequest(opts) {
});
}
/** Create a release in Sentry. Returns a Promise. */
function createRelease(opts, project, release) {
return httpRequest({
uri: `${SENTRY_API_ROOT}/projects/${opts.organization}/${project}/releases/`,
method: 'POST',
auth: {
user: opts.key,
password: '',
},
body: {
version: release,
},
json: true,
}).then(function (result) {
var success = (result.response.statusCode === 201);
var alreadyCreated = (result.response.statusCode === 400 &&
result.body.detail.match(/already exists/));
if (success || alreadyCreated) {
return;
}
throw new Error(`unable to create release '${release}' in project '${project}'`);
});
}
/** Upload a named file to a release in Sentry. Returns a Promise. */
function uploadReleaseFile(opts, project, release, file) {
return httpRequest({
uri: `${SENTRY_API_ROOT}/projects/${opts.organization}/${project}/releases/${release}/files/`,
method: 'POST',
auth: {
user: opts.key,
password: '',
},
formData: {
file: fs.createReadStream(file.path),
name: path.basename(file.path),
}
}).then(function (result) {
if (result.response.statusCode === 201) {
return;
}
throw new Error(`Uploading file failed: ${result.response.statusCode}: ${result.body}`);
});
}
/**
* Upload a stream of Vinyl files as a Sentry release.
*
......@@ -43,73 +91,35 @@ function httpRequest(opts) {
* files as artefacts for the release.
*
* @param {SentryOptions} opts
* @param {Array[String]} projects - A list of projects to which to upload
* files.
* @param {String} release - The name of the release.
* @return {NodeJS.ReadWriteStream} - A stream into which Vinyl files from
* gulp.src() etc. can be piped.
*/
module.exports = function uploadToSentry(opts) {
// A map of already-created release versions.
// Once the release has been successfully created, this is used
// to avoid creating it again.
var createdReleases = {};
module.exports = function uploadToSentry(opts, projects, release) {
// Create releases in every project
var releases = projects.map(function (project) {
gulpUtil.log(`Creating release '${release}' in project '${project}'`);
return createRelease(opts, project, release);
});
return through.obj(function (file, enc, callback) {
enc = enc;
gulpUtil.log(`Uploading ${file.path} to Sentry`);
var sentryURL =
`https://app.getsentry.com/api/0/projects/${opts.organization}/${opts.project}/releases`;
var releaseCreated;
if (createdReleases[opts.release]) {
releaseCreated = Promise.resolve();
} else {
releaseCreated = httpRequest({
uri: `${sentryURL}/`,
method: 'POST',
auth: {
user: opts.apiKey,
password: '',
},
body: {
version: opts.release,
},
json: true,
}).then(function (result) {
if (result.status === 201 ||
(result.status === 400 &&
result.body.detail.match(/already exists/))) {
createdReleases[opts.release] = true;
return;
}
});
}
releaseCreated.then(function () {
return httpRequest({
uri: `${sentryURL}/${opts.release}/files/`,
method: 'POST',
auth: {
user: opts.apiKey,
password: '',
},
formData: {
file: fs.createReadStream(file.path),
name: path.basename(file.path),
},
Promise.all(releases)
.then(function () {
gulpUtil.log(`Uploading ${path.basename(file.path)}`);
var uploads = projects.map(function (project) {
return uploadReleaseFile(opts, project, release, file);
});
}).then(function (result) {
if (result.status === 201) {
callback();
return;
}
var message =
`Uploading file failed: ${result.status}: ${result.body}`;
throw new Error(message);
}).catch(function (err) {
return Promise.all(uploads);
})
.then(function () {
callback();
})
.catch(function (err) {
gulpUtil.log('Sentry upload failed: ', err);
throw err;
callback(err);
});
});
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment