Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2008 Google Inc. | 1 // Copyright 2008 Google Inc. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. | 13 // limitations under the License. |
| 14 | 14 |
| 15 // Global Rietveld namespace. | |
| 16 var rietveld = { | |
| 17 preferredDomainName: document.location.hostname, | |
| 18 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
| |
| 19 // Current rietveld user. | |
| 20 user: null, | |
| 21 gapi: { | |
| 22 // Client ID to use. | |
| 23 clientId: null, | |
| 24 } | |
| 25 }; | |
| 26 | |
| 15 // Generic helpers | 27 // Generic helpers |
| 16 | 28 |
| 17 /** | 29 /** |
| 18 * Create a new XMLHttpRequest in a cross-browser-compatible way. | 30 * Create a new XMLHttpRequest in a cross-browser-compatible way. |
| 19 * @return XMLHttpRequest object | 31 * @return XMLHttpRequest object |
| 20 */ | 32 */ |
| 21 function M_getXMLHttpRequest() { | 33 function M_getXMLHttpRequest() { |
| 22 try { | 34 try { |
| 23 return new XMLHttpRequest(); | 35 return new XMLHttpRequest(); |
| 24 } catch (e) { } | 36 } catch (e) { } |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 113 } | 125 } |
| 114 return y; | 126 return y; |
| 115 } | 127 } |
| 116 | 128 |
| 117 function M_editPatchsetTitle(issue, patchset, xsrf_token, | 129 function M_editPatchsetTitle(issue, patchset, xsrf_token, |
| 118 original_patchset_title, patch_count) { | 130 original_patchset_title, patch_count) { |
| 119 | 131 |
| 120 var new_patchset_title = prompt( | 132 var new_patchset_title = prompt( |
| 121 'Please enter the new title of Patch Set ' + patch_count, | 133 'Please enter the new title of Patch Set ' + patch_count, |
| 122 original_patchset_title); | 134 original_patchset_title); |
| 123 if (new_patchset_title == null) { | 135 if (new_patchset_title == null) { |
| 124 return false; | 136 return false; |
| 125 } else if (new_patchset_title == original_patchset_title) { | 137 } else if (new_patchset_title == original_patchset_title) { |
| 126 // Do not make an HTTP req if the new specified title is exactly the same. | 138 // Do not make an HTTP req if the new specified title is exactly the same. |
| 127 return false; | 139 return false; |
| 128 } | 140 } |
| 129 | 141 |
| 130 //Build POST data for request. | 142 //Build POST data for request. |
| 131 var data = []; | 143 var data = []; |
| 132 data.push('xsrf_token=' + xsrf_token); | 144 data.push('xsrf_token=' + xsrf_token); |
| 133 data.push('patchset_title=' + new_patchset_title); | 145 data.push('patchset_title=' + new_patchset_title); |
| (...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 620 } | 632 } |
| 621 | 633 |
| 622 M_sendEditFlagsRequest(issue, req.join("&"), function(xhr) { | 634 M_sendEditFlagsRequest(issue, req.join("&"), function(xhr) { |
| 623 if (xhr.status == 200) | 635 if (xhr.status == 200) |
| 624 window.location.reload(); | 636 window.location.reload(); |
| 625 }); | 637 }); |
| 626 return true; | 638 return true; |
| 627 } | 639 } |
| 628 | 640 |
| 629 /** | 641 /** |
| 630 * Edit the list of pending try jobs for the given patchset. | 642 * Edit the list of pending try jobs for the given patchset. |
| 631 * @param {String} patchset The patchset key. | 643 * @param {String} patchset The patchset key. |
| 632 */ | 644 */ |
| 633 function M_editPendingTryJobs(patchset) { | 645 function M_editPendingTryJobs(patchset) { |
| 634 var checkboxContainer = document.getElementById('trybot-popup-checkboxes'); | 646 var checkboxContainer = document.getElementById('trybot-popup-checkboxes'); |
| 635 if (! checkboxContainer) { | 647 if (! checkboxContainer) { |
| 636 checkboxContainer = document.getElementById( | 648 checkboxContainer = document.getElementById( |
| 637 'trybot-popup-checkboxes-with-categories') | 649 'trybot-popup-checkboxes-with-categories') |
| 638 } | 650 } |
| 639 var checkboxElements = checkboxContainer.getElementsByTagName('input'); | 651 var checkboxElements = checkboxContainer.getElementsByTagName('input'); |
| 640 for (var checkbox, i = 0; checkbox = checkboxElements[i]; i++) { | 652 for (var checkbox, i = 0; checkbox = checkboxElements[i]; i++) { |
| 641 checkbox.checked = false; | 653 checkbox.checked = false; |
| 642 checkbox.disabled = false; | 654 checkbox.disabled = false; |
| 643 } | 655 } |
| 644 | 656 |
| 645 // Position popup below anchor. | 657 // Position popup below anchor. |
| 646 var anchor = document.getElementById('tryjobchange-' + patchset); | 658 var anchor = document.getElementById('tryjobchange-' + patchset); |
| 647 var anchorRect = anchor.getBoundingClientRect(); | 659 var anchorRect = anchor.getBoundingClientRect(); |
| 648 var popupElement = document.getElementById('trybot-popup'); | 660 var popupElement = document.getElementById('trybot-popup'); |
| 649 popupElement.style.left = anchorRect.left + 'px'; | 661 popupElement.style.left = anchorRect.left + 'px'; |
| 650 popupElement.style.top = anchorRect.bottom + 'px'; | 662 popupElement.style.top = anchorRect.bottom + 'px'; |
| 651 popupElement.style.display = ''; | 663 popupElement.style.display = ''; |
| 652 | 664 |
| 653 // Extra padding to allow for scrollbars. | 665 // Extra padding to allow for scrollbars. |
| 654 var scrollbarWidth = 20; | 666 var scrollbarWidth = 20; |
| 655 | 667 |
| 656 // Move popup as need to be on screen. | 668 // Move popup as need to be on screen. |
| 657 var popupRect = popupElement.getBoundingClientRect(); | 669 var popupRect = popupElement.getBoundingClientRect(); |
| 658 if (popupRect.bottom > window.innerHeight) | 670 if (popupRect.bottom > window.innerHeight) |
| 659 popupElement.style.top = (anchorRect.bottom - (popupRect.bottom - window.inn erHeight) - scrollbarWidth) + 'px'; | 671 popupElement.style.top = (anchorRect.bottom - (popupRect.bottom - window.inn erHeight) - scrollbarWidth) + 'px'; |
| 660 if (popupRect.right > window.innerWidth) | 672 if (popupRect.right > window.innerWidth) |
| 661 popupElement.style.left = (anchorRect.left - (popupRect.right - window.inner Width) - scrollbarWidth) + 'px'; | 673 popupElement.style.left = (anchorRect.left - (popupRect.right - window.inner Width) - scrollbarWidth) + 'px'; |
| 662 } | 674 } |
| 663 | 675 |
| 664 /** | 676 /** |
| 665 * Updates the pending builders for the patchset. | 677 * Updates the pending builders for the patchset. |
| 666 * @param {String} issue The issue key. | 678 * @param {String} issue The issue key. |
| 667 * @param {String} patchset The patchset key. | 679 * @param {String} patchset The patchset key. |
| 668 * @param {String} xsrf_token Security token. | 680 * @param {String} project Issue project. |
| 669 */ | 681 */ |
| 670 function M_updatePendingTrybots(issue, patchset, xsrf_token) { | 682 function M_updatePendingTrybots(issue, patchset, project) { |
| 671 // Find which builder are checked. | 683 // Find which builder are checked. |
| 672 var builders = []; | 684 var builds = []; |
| 673 var popup = jQuery('#trybot-popup'); | 685 var popup = jQuery('#trybot-popup'); |
| 674 jQuery('input:checkbox', popup).each(function(i) { | 686 jQuery('input:checkbox', popup).each(function(i) { |
| 675 var self = jQuery(this); | 687 var self = jQuery(this); |
| 676 if (self.attr('checked')) | 688 if (!self.attr('checked')) { |
| 677 builders.push(self.attr('name')); | 689 return; |
| 690 } | |
| 691 var name = self.attr('name'); | |
| 692 var nameParts = name.split(":", 2); | |
| 693 builds.push({ | |
| 694 name: name, | |
| 695 master: nameParts[0], | |
| 696 builder: nameParts[1] | |
| 697 }); | |
| 678 }); | 698 }); |
| 679 | 699 |
| 680 // Build POST data for request. | 700 var buildPromises = []; |
| 681 var data = []; | 701 var alerted403 = false; |
| 682 data.push('xsrf_token=' + xsrf_token); | 702 |
| 683 data.push('last_patchset=' + patchset); | 703 for (var i = 0; i < builds.length; i++) { |
| 684 data.push('builders=' + builders.join(',')); | 704 var build = builds[i]; |
| 685 | 705 var buildPromise = M_scheduleBuild( |
|
esprehn
2015/04/14 01:00:11
Is this making one http call per builder?
| |
| 686 M_sendEditFlagsRequest(issue, data.join("&"), function(xhr) { | 706 build.master, build.builder, issue, patchset, project); |
| 687 if (xhr.status == 200) | 707 buildPromise.then(null, function (reason) { |
| 688 window.location.reload(); | 708 console.log('Failed to schedule build ' + build.name + ":", reason); |
| 709 if (reason.status == 403 && !alerted403) { | |
| 710 alerted403 = true; | |
| 711 alert( | |
| 712 "Permission denied. User " + rietveld.user.email + " does not " + | |
| 713 "have access to build bucket for master " + build.master | |
| 714 ); | |
| 715 } | |
| 716 return Promise.reject(reason); | |
| 717 }); | |
| 718 buildPromises.push(buildPromise); | |
| 719 } | |
| 720 // Reload after all builds are scheduled. | |
| 721 Promise.all(buildPromises).then(function () { | |
| 722 window.location.reload(); | |
| 689 }); | 723 }); |
| 690 | 724 |
| 691 // Hide the popup. | 725 // Hide the popup. |
| 692 jQuery('#trybot-popup').css('display', 'none'); | 726 jQuery('#trybot-popup').css('display', 'none'); |
| 693 return true; | 727 return true; |
| 694 } | 728 } |
| 695 | 729 |
| 696 /** | 730 /** |
| 697 * Hide the pending builders popup. | 731 * Hide the pending builders popup. |
| 698 */ | 732 */ |
| 699 function M_closePendingTrybots() { | 733 function M_closePendingTrybots() { |
| 700 jQuery('#trybot-popup').css('display', 'none'); | 734 jQuery('#trybot-popup').css('display', 'none'); |
| 701 } | 735 } |
| 702 | 736 |
| 703 /** | 737 /** |
| 704 * Show or hide older try bot results. | 738 * Show or hide older try bot results. |
| 705 * @param {String} id The id of the div elements that holds all the try job | 739 * @param {String} id The id of the div elements that holds all the try job |
| 706 * a elements. | 740 * a elements. |
| 707 * @param makeVisible If true, makes older try bots visible. | 741 * @param makeVisible If true, makes older try bots visible. |
| 708 */ | 742 */ |
| 709 function M_showTryJobResult(id, makeVisible) { | 743 function M_showTryJobResult(id, makeVisible) { |
| 710 // This set keeps track of the first occurance of each try job result for | 744 // This set keeps track of the first occurance of each try job result for |
| 711 // a given builder. The try job results are ordered reverse chronologically, | 745 // a given builder. The try job results are ordered reverse chronologically, |
| 712 // so we visit them from newest to oldest. | 746 // so we visit them from newest to oldest. |
| 713 var firstBuilderSet = {}; | 747 var firstBuilderSet = {}; |
| 714 var oldBuildersExist = false; | 748 var oldBuildersExist = false; |
| (...skipping 2942 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3657 httpreq.open("DELETE", base_url + this.issue_id + "/draft_message", true); | 3691 httpreq.open("DELETE", base_url + this.issue_id + "/draft_message", true); |
| 3658 httpreq.send(""); | 3692 httpreq.send(""); |
| 3659 } | 3693 } |
| 3660 | 3694 |
| 3661 /** | 3695 /** |
| 3662 * Helper function that returns the dialog's HTML container. | 3696 * Helper function that returns the dialog's HTML container. |
| 3663 */ | 3697 */ |
| 3664 M_draftMessage.prototype.get_dialog_ = function() { | 3698 M_draftMessage.prototype.get_dialog_ = function() { |
| 3665 return document.getElementById(this.id_dlg_container); | 3699 return document.getElementById(this.id_dlg_container); |
| 3666 } | 3700 } |
| 3701 | |
| 3702 /** | |
| 3703 * Schedules a build on buildbucket. | |
|
esprehn
2015/04/14 01:00:11
This makes N http requests now when scheduling a b
| |
| 3704 * @param {String} masterName Master name where the build will be scheduled, | |
| 3705 * without "master." prefix. | |
| 3706 * @param {String} builderName Builder name where the build will be scheduled. | |
| 3707 * @return A scheduled build as a promise. | |
| 3708 */ | |
| 3709 function M_scheduleBuild(masterName, builderName, issue, patchset, project) { | |
| 3710 console.log("Scheduling a build: ", masterName, builderName); | |
| 3711 return M_ensureBuildBucketLoaded().then(function () { | |
| 3712 // Buildset tag: see https://cr-buildbucket.appspot.com/#docs/conventions | |
| 3713 var buildset = ( | |
| 3714 "patch/rietveld/" + rietveld.preferredDomainName + | |
| 3715 "/" + issue + "/" + patchset | |
| 3716 ); | |
| 3717 var callPut = gapi.client.buildbucket.put({ | |
|
nodir
2015/04/13 16:56:48
This call has to be compatible with existing recip
| |
| 3718 bucket: "master." + masterName, | |
| 3719 tags: [ | |
| 3720 "builder:" + builderName, | |
| 3721 "buildset:" + buildset, | |
| 3722 "master:" + masterName, | |
| 3723 "user_agent:rietveld", | |
| 3724 ], | |
| 3725 parameters_json: JSON.stringify({ | |
| 3726 builder_name: builderName, | |
| 3727 changes: [{ | |
| 3728 author: {email: rietveld.user.email } | |
| 3729 }], | |
| 3730 properties: { | |
| 3731 clobber: false, | |
| 3732 issue: issue, | |
| 3733 master: masterName, | |
| 3734 patch_project: project, | |
| 3735 patch_storage: "rietveld", | |
| 3736 patchset: patchset, | |
| 3737 revision: "HEAD", | |
| 3738 rietveld: "https://" + rietveld.preferredDomainName | |
| 3739 } | |
| 3740 }) | |
| 3741 }); | |
| 3742 | |
| 3743 return callPut.then(function (resp) { | |
| 3744 var build = resp.result.build; | |
| 3745 console.log("Scheduled build", build.id); | |
| 3746 return build; | |
| 3747 }); | |
| 3748 }); | |
| 3749 } | |
| 3750 | |
| 3751 /** | |
| 3752 * Loads buildbucket api. | |
| 3753 * @return A promise with no value. | |
| 3754 */ | |
| 3755 function M_ensureBuildBucketLoaded() { | |
| 3756 // remove this | |
| 3757 return M_ensureGapiAuthorized().then(function () { | |
| 3758 var root = "https://" + rietveld.buildbucketHostname + "/_ah/api"; | |
| 3759 return gapi.client.load("buildbucket", "v1", null, root); | |
| 3760 }); | |
| 3761 } | |
| 3762 | |
| 3763 /** | |
| 3764 * Acquires an access token to talk to Google APIs. | |
| 3765 * @return A promise with no value. | |
| 3766 */ | |
| 3767 function M_ensureGapiAuthorized() { | |
| 3768 // API authentication and Rietveld authentication are orthogonal | |
| 3769 // but we try to merge them so users don't notice the difference. | |
| 3770 // Rietveld authentication is considered primary: | |
| 3771 // * API authentication does not happen until Rietveld user is not logged in. | |
| 3772 // * When authenticating to Google APIs, we enforce API user to match | |
| 3773 // Rietveld user by email. | |
| 3774 if (!rietveld.user) { | |
| 3775 throw "This function may not be called if Rietveld user is not logged in"; | |
| 3776 } | |
| 3777 if (!rietveld.gapi.clientId) { | |
| 3778 var msg = "ClientID is not configured for this Rietveld instance"; | |
| 3779 alert(msg); | |
| 3780 throw msg; | |
| 3781 } | |
| 3782 | |
| 3783 var authOptions = { | |
| 3784 client_id: rietveld.gapi.clientId, | |
| 3785 scope: "email", | |
| 3786 immediate: true, | |
| 3787 // Enfoce API user to match Rietveld user. | |
| 3788 login_hint: rietveld.user.email | |
| 3789 }; | |
| 3790 return gapi.auth.authorize(authOptions).then(null, function () { | |
| 3791 console.log("non-immediate gapi.auth.authorize failed"); | |
| 3792 // If immediate (windowless) authorization fails, try non-immediate one. | |
| 3793 authOptions.immediate = false; | |
| 3794 return gapi.auth.authorize(authOptions); | |
| 3795 }); | |
| 3796 } | |
| OLD | NEW |