Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3433)

Unified Diff: appengine/chromium_rietveld/static/script.js

Issue 1058893004: Rietveld schedules builds on buildbucket (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: appengine/chromium_rietveld/static/script.js
diff --git a/appengine/chromium_rietveld/static/script.js b/appengine/chromium_rietveld/static/script.js
index eb4805fec1c2c9843aace1217a72e1fe96d25f00..0a7da1edd3b26ea4ee580762fdc3b0a05dad7a99 100644
--- a/appengine/chromium_rietveld/static/script.js
+++ b/appengine/chromium_rietveld/static/script.js
@@ -12,6 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// Global Rietveld namespace.
+var rietveld = {
+ preferredDomainName: document.location.hostname,
+ buildbucketHostname: "cr-buildbucket-test.appspot.com",
jrobbins 2015/04/16 18:09:27 It looks like you hardcoded a test value here.
nodir 2015/04/16 18:15:11 it is overwritten in base.html
+ // Current rietveld user.
+ user: null,
+ gapi: {
+ // Client ID to use.
+ clientId: null,
+ }
+};
+
// Generic helpers
/**
@@ -120,7 +132,7 @@ function M_editPatchsetTitle(issue, patchset, xsrf_token,
var new_patchset_title = prompt(
'Please enter the new title of Patch Set ' + patch_count,
original_patchset_title);
- if (new_patchset_title == null) {
+ if (new_patchset_title == null) {
return false;
} else if (new_patchset_title == original_patchset_title) {
// Do not make an HTTP req if the new specified title is exactly the same.
@@ -627,7 +639,7 @@ function M_editFlags(issue) {
}
/**
- * Edit the list of pending try jobs for the given patchset.
+ * Edit the list of pending try jobs for the given patchset.
* @param {String} patchset The patchset key.
*/
function M_editPendingTryJobs(patchset) {
@@ -656,38 +668,60 @@ function M_editPendingTryJobs(patchset) {
// Move popup as need to be on screen.
var popupRect = popupElement.getBoundingClientRect();
if (popupRect.bottom > window.innerHeight)
- popupElement.style.top = (anchorRect.bottom - (popupRect.bottom - window.innerHeight) - scrollbarWidth) + 'px';
+ popupElement.style.top = (anchorRect.bottom - (popupRect.bottom - window.innerHeight) - scrollbarWidth) + 'px';
if (popupRect.right > window.innerWidth)
- popupElement.style.left = (anchorRect.left - (popupRect.right - window.innerWidth) - scrollbarWidth) + 'px';
+ popupElement.style.left = (anchorRect.left - (popupRect.right - window.innerWidth) - scrollbarWidth) + 'px';
}
/**
* Updates the pending builders for the patchset.
* @param {String} issue The issue key.
* @param {String} patchset The patchset key.
- * @param {String} xsrf_token Security token.
+ * @param {String} project Issue project.
*/
-function M_updatePendingTrybots(issue, patchset, xsrf_token) {
+function M_updatePendingTrybots(issue, patchset, project) {
// Find which builder are checked.
- var builders = [];
+ var builds = [];
var popup = jQuery('#trybot-popup');
jQuery('input:checkbox', popup).each(function(i) {
var self = jQuery(this);
- if (self.attr('checked'))
- builders.push(self.attr('name'));
+ if (!self.attr('checked')) {
+ return;
+ }
+ var name = self.attr('name');
+ var nameParts = name.split(":", 2);
+ builds.push({
+ name: name,
+ master: nameParts[0],
+ builder: nameParts[1]
+ });
});
-
- // Build POST data for request.
- var data = [];
- data.push('xsrf_token=' + xsrf_token);
- data.push('last_patchset=' + patchset);
- data.push('builders=' + builders.join(','));
-
- M_sendEditFlagsRequest(issue, data.join("&"), function(xhr) {
- if (xhr.status == 200)
- window.location.reload();
+
+ var buildPromises = [];
+ var alerted403 = false;
+
+ for (var i = 0; i < builds.length; i++) {
+ var build = builds[i];
+ var buildPromise = M_scheduleBuild(
esprehn 2015/04/14 01:00:11 Is this making one http call per builder?
+ build.master, build.builder, issue, patchset, project);
+ buildPromise.then(null, function (reason) {
+ console.log('Failed to schedule build ' + build.name + ":", reason);
+ if (reason.status == 403 && !alerted403) {
+ alerted403 = true;
+ alert(
+ "Permission denied. User " + rietveld.user.email + " does not " +
+ "have access to build bucket for master " + build.master
+ );
+ }
+ return Promise.reject(reason);
+ });
+ buildPromises.push(buildPromise);
+ }
+ // Reload after all builds are scheduled.
+ Promise.all(buildPromises).then(function () {
+ window.location.reload();
});
-
+
// Hide the popup.
jQuery('#trybot-popup').css('display', 'none');
return true;
@@ -701,7 +735,7 @@ function M_closePendingTrybots() {
}
/**
- * Show or hide older try bot results.
+ * Show or hide older try bot results.
* @param {String} id The id of the div elements that holds all the try job
* a elements.
* @param makeVisible If true, makes older try bots visible.
@@ -3664,3 +3698,99 @@ M_draftMessage.prototype.discard = function(cb) {
M_draftMessage.prototype.get_dialog_ = function() {
return document.getElementById(this.id_dlg_container);
}
+
+/**
+ * Schedules a build on buildbucket.
esprehn 2015/04/14 01:00:11 This makes N http requests now when scheduling a b
+ * @param {String} masterName Master name where the build will be scheduled,
+ * without "master." prefix.
+ * @param {String} builderName Builder name where the build will be scheduled.
+ * @return A scheduled build as a promise.
+ */
+function M_scheduleBuild(masterName, builderName, issue, patchset, project) {
+ console.log("Scheduling a build: ", masterName, builderName);
+ return M_ensureBuildBucketLoaded().then(function () {
+ // Buildset tag: see https://cr-buildbucket.appspot.com/#docs/conventions
+ var buildset = (
+ "patch/rietveld/" + rietveld.preferredDomainName +
+ "/" + issue + "/" + patchset
+ );
+ var callPut = gapi.client.buildbucket.put({
nodir 2015/04/13 16:56:48 This call has to be compatible with existing recip
+ bucket: "master." + masterName,
+ tags: [
+ "builder:" + builderName,
+ "buildset:" + buildset,
+ "master:" + masterName,
+ "user_agent:rietveld",
+ ],
+ parameters_json: JSON.stringify({
+ builder_name: builderName,
+ changes: [{
+ author: {email: rietveld.user.email }
+ }],
+ properties: {
+ clobber: false,
+ issue: issue,
+ master: masterName,
+ patch_project: project,
+ patch_storage: "rietveld",
+ patchset: patchset,
+ revision: "HEAD",
+ rietveld: "https://" + rietveld.preferredDomainName
+ }
+ })
+ });
+
+ return callPut.then(function (resp) {
+ var build = resp.result.build;
+ console.log("Scheduled build", build.id);
+ return build;
+ });
+ });
+}
+
+/**
+ * Loads buildbucket api.
+ * @return A promise with no value.
+ */
+function M_ensureBuildBucketLoaded() {
+ // remove this
+ return M_ensureGapiAuthorized().then(function () {
+ var root = "https://" + rietveld.buildbucketHostname + "/_ah/api";
+ return gapi.client.load("buildbucket", "v1", null, root);
+ });
+}
+
+/**
+ * Acquires an access token to talk to Google APIs.
+ * @return A promise with no value.
+ */
+function M_ensureGapiAuthorized() {
+ // API authentication and Rietveld authentication are orthogonal
+ // but we try to merge them so users don't notice the difference.
+ // Rietveld authentication is considered primary:
+ // * API authentication does not happen until Rietveld user is not logged in.
+ // * When authenticating to Google APIs, we enforce API user to match
+ // Rietveld user by email.
+ if (!rietveld.user) {
+ throw "This function may not be called if Rietveld user is not logged in";
+ }
+ if (!rietveld.gapi.clientId) {
+ var msg = "ClientID is not configured for this Rietveld instance";
+ alert(msg);
+ throw msg;
+ }
+
+ var authOptions = {
+ client_id: rietveld.gapi.clientId,
+ scope: "email",
+ immediate: true,
+ // Enfoce API user to match Rietveld user.
+ login_hint: rietveld.user.email
+ };
+ return gapi.auth.authorize(authOptions).then(null, function () {
+ console.log("non-immediate gapi.auth.authorize failed");
+ // If immediate (windowless) authorization fails, try non-immediate one.
+ authOptions.immediate = false;
+ return gapi.auth.authorize(authOptions);
+ });
+}

Powered by Google App Engine
This is Rietveld 408576698