[FIX] runbot: redirect to the relevant build on actions

Currently killing, waking or rebuilding a build then redirects to the
repository root which is worse than useless: you've lost the build you
come from, and for rebuilds it's no help getting to the new build.

Since it's very easy to go from a build to its repository, redirect to
the "most useful" build instead:

* if rebuilding the current build (from its page), open the page of
  the new build which was just created
* otherwise reload the current page whatever it is
This commit is contained in:
Xavier Morel 2019-11-29 16:03:28 +01:00 committed by Christophe Monniez
parent 4ae6907e3a
commit 5d1772a9a5
3 changed files with 64 additions and 65 deletions

View File

@ -3,8 +3,12 @@ import operator
import werkzeug import werkzeug
from collections import OrderedDict from collections import OrderedDict
import werkzeug.utils
import werkzeug.urls
from odoo.addons.http_routing.models.ir_http import slug from odoo.addons.http_routing.models.ir_http import slug
from odoo.addons.website.controllers.main import QueryURL from odoo.addons.website.controllers.main import QueryURL
from odoo.http import Controller, request, route from odoo.http import Controller, request, route
from ..common import uniq_list, flatten, fqdn from ..common import uniq_list, flatten, fqdn
from odoo.osv import expression from odoo.osv import expression
@ -117,26 +121,23 @@ class Runbot(Controller):
context.update({'message': request.env['ir.config_parameter'].sudo().get_param('runbot.runbot_message')}) context.update({'message': request.env['ir.config_parameter'].sudo().get_param('runbot.runbot_message')})
return request.render('runbot.repo', context) return request.render('runbot.repo', context)
@route(['/runbot/build/<int:build_id>/kill'], type='http', auth="user", methods=['POST'], csrf=False)
def build_ask_kill(self, build_id, search=None, **post):
build = request.env['runbot.build'].sudo().browse(build_id)
build._ask_kill()
return werkzeug.utils.redirect('/runbot/repo/%s' % build.repo_id.id + ('?search=%s' % search if search else ''))
@route(['/runbot/build/<int:build_id>/wakeup'], type='http', auth="user", methods=['POST'], csrf=False)
def build_wake_up(self, build_id, search=None, **post):
build = request.env['runbot.build'].sudo().browse(build_id)
build._wake_up()
return werkzeug.utils.redirect('/runbot/repo/%s' % build.repo_id.id + ('?search=%s' % search if search else ''))
@route([ @route([
'/runbot/build/<int:build_id>/force', '/runbot/build/<int:build_id>/<operation>',
'/runbot/build/<int:build_id>/force/<int:exact>', '/runbot/build/<int:build_id>/<operation>/<int:exact>',
], type='http', auth="public", methods=['POST'], csrf=False) ], type='http', auth="public", methods=['POST'], csrf=False)
def build_force(self, build_id, exact=0, search=None, **post): def build_force(self, build_id, operation, exact=0, search=None, **post):
build = request.env['runbot.build'].sudo().browse(build_id) build = request.env['runbot.build'].sudo().browse(build_id)
build._force(exact=bool(exact)) if operation == 'force':
return werkzeug.utils.redirect('/runbot/repo/%s' % build.repo_id.id + ('?search=%s' % search if search else '')) build = build._force(exact=bool(exact))
elif operation == 'kill':
build._ask_kill()
elif operation == 'wakeup':
build._wake_up()
qs = ''
if search:
qs = '?' + werkzeug.urls.url_encode({'search': search})
return werkzeug.utils.redirect(build.build_url + qs)
@route(['/runbot/build/<int:build_id>'], type='http', auth="public", website=True) @route(['/runbot/build/<int:build_id>'], type='http', auth="public", website=True)
def build(self, build_id, search=None, **post): def build(self, build_id, search=None, **post):

View File

@ -1,45 +1,43 @@
(function($) { (function($) {
"use strict"; "use strict";
$(function() { var OPMAP = {
$('a.runbot-rebuild').click(function() { 'rebuild': {operation: 'force', then: 'redirect'},
var $f = $('<form method="POST">'), 'rebuild-exact': {operation: 'force/1', then: 'redirect'},
url = _.str.sprintf('/runbot/build/%s/force', $(this).data('runbot-build')) + window.location.search; 'kill': {operation: 'kill', then: 'reload'},
$f.attr('action', url); 'wakeup': {operation: 'wakeup', then: 'reload'}
$f.appendTo($('body')); };
$f.submit();
return false; $(function () {
}); $(document).on('click', '[data-runbot]', function (e) {
}); e.preventDefault();
$(function() {
$('a.runbot-rebuild-exact').click(function() { var data = $(this).data();
var $f = $('<form method="POST">'), var segment = OPMAP[data.runbot];
url = _.str.sprintf('/runbot/build/%s/force/1', $(this).data('runbot-build')) + window.location.search; if (!segment) { return; }
$f.attr('action', url);
$f.appendTo($('body')); // window.location.pathname but compatibility is iffy
$f.submit(); var currentPath = window.location.href.replace(window.location.protocol + '//' + window.location.host, '').split('?')[0];
return false; var buildPath = _.str.sprintf('/runbot/build/%s', data.runbotBuild);
}); // no responseURL on $.ajax so use native object
}); var xhr = new XMLHttpRequest();
$(function() { xhr.addEventListener('load', function () {
$('a.runbot-kill').click(function() { switch (segment.then) {
var $f = $('<form method="POST">'), case 'redirect':
url = _.str.sprintf('/runbot/build/%s/kill', $(this).data('runbot-build')) + window.location.search; if (currentPath === buildPath && xhr.responseURL) {
$f.attr('action', url); window.location.href = xhr.responseURL;
$f.appendTo($('body')); break;
$f.submit(); }
return false; // fallthrough to reload if no responseURL or we're
}); // not on the build's page
}); case 'reload':
$(function() { window.location.reload();
$('a.runbot-wakeup').click(function() { break;
var $f = $('<form method="POST">'), }
url = _.str.sprintf('/runbot/build/%s/wakeup', $(this).data('runbot-build')) + window.location.search; });
$f.attr('action', url); xhr.open('POST', _.str.sprintf('%s/%s', buildPath, segment.operation));
$f.appendTo($('body')); xhr.send();
$f.submit(); });
return false;
});
}); });
//$(function() { //$(function() {
// new Clipboard('.clipbtn'); // new Clipboard('.clipbtn');

View File

@ -45,13 +45,13 @@
<div t-attf-class="pull-right"> <div t-attf-class="pull-right">
<div t-attf-class="btn-group {{klass}}"> <div t-attf-class="btn-group {{klass}}">
<a t-if="bu.real_build.local_state=='running'" t-attf-href="http://{{bu['domain']}}/?db={{bu.real_build.dest}}-all" class="btn btn-primary" title="Sign in on this build" aria-label="Sign in on this build"><i class="fa fa-sign-in"/></a> <a t-if="bu.real_build.local_state=='running'" t-attf-href="http://{{bu['domain']}}/?db={{bu.real_build.dest}}-all" class="btn btn-primary" title="Sign in on this build" aria-label="Sign in on this build"><i class="fa fa-sign-in"/></a>
<a t-if="bu.real_build.local_state=='done' and bu.real_build.requested_action != 'wake_up'" href="#" t-att-data-runbot-build="bu.real_build.id" class="btn btn-default runbot-wakeup" title="Wake up this build" aria-label="Wake up this build"><i class="fa fa-coffee"/></a> <a t-if="bu.real_build.local_state=='done' and bu.real_build.requested_action != 'wake_up'" href="#" data-runbot="wakeup" t-att-data-runbot-build="bu.real_build.id" class="btn btn-default" title="Wake up this build" aria-label="Wake up this build"><i class="fa fa-coffee"/></a>
<a t-attf-href="/runbot/build/{{bu['id']}}" class="btn btn-default" title="Build details" aria-label="Build details"><i class="fa fa-file-text-o"/></a> <a t-attf-href="/runbot/build/{{bu['id']}}" class="btn btn-default" title="Build details" aria-label="Build details"><i class="fa fa-file-text-o"/></a>
<a t-if="show_commit_button" t-attf-href="https://#{repo.base}/commit/#{bu['name']}" class="btn btn-default" title="Open commit on GitHub" aria-label="Open commit on GitHub"><i class="fa fa-github"/></a> <a t-if="show_commit_button" t-attf-href="https://#{repo.base}/commit/#{bu['name']}" class="btn btn-default" title="Open commit on GitHub" aria-label="Open commit on GitHub"><i class="fa fa-github"/></a>
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown" title="Build options" aria-label="Build options" aria-expanded="false"><i class="fa fa-cog"/><span class="caret"></span></button> <button class="btn btn-default dropdown-toggle" data-toggle="dropdown" title="Build options" aria-label="Build options" aria-expanded="false"><i class="fa fa-cog"/><span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu"> <ul class="dropdown-menu dropdown-menu-right" role="menu">
<li t-if="bu.global_result=='skipped'" groups="runbot.group_runbot_admin"> <li t-if="bu.global_result=='skipped'" groups="runbot.group_runbot_admin">
<a href="#" class="runbot-rebuild" t-att-data-runbot-build="bu['id']">Force Build <i class="fa fa-level-up"></i></a> <a href="#" data-runbot="rebuild" t-att-data-runbot-build="bu['id']">Force Build <i class="fa fa-level-up"></i></a>
</li> </li>
<t t-if="bu.local_state=='running'"> <t t-if="bu.local_state=='running'">
<li><a t-attf-href="http://{{bu['domain']}}/?db={{bu['real_build'].dest}}-all">Connect all <i class="fa fa-sign-in"></i></a></li> <li><a t-attf-href="http://{{bu['domain']}}/?db={{bu['real_build'].dest}}-all">Connect all <i class="fa fa-sign-in"></i></a></li>
@ -60,23 +60,23 @@
</t> </t>
<li t-if="bu.global_state in ['done','running'] or requested_action == 'deathrow'" groups="base.group_user"> <li t-if="bu.global_state in ['done','running'] or requested_action == 'deathrow'" groups="base.group_user">
<t t-if="show_rebuild_button"> <t t-if="show_rebuild_button">
<a href="#" class="runbot-rebuild" t-att-data-runbot-build="bu['id']" <a href="#" data-runbot="rebuild" t-att-data-runbot-build="bu['id']"
title="Create a new build keeping build commit head, but will recompute all other info (config, dependencies, extra_params)"> title="Create a new build keeping build commit head, but will recompute all other info (config, dependencies, extra_params)">
Rebuild <i class="fa fa-refresh"/> Rebuild <i class="fa fa-refresh"/>
</a> </a>
</t> </t>
<a href="#" class="runbot-rebuild-exact" t-att-data-runbot-build="bu['id']" <a href="#" data-runbot="rebuild-exact" t-att-data-runbot-build="bu['id']"
title="Create a new build keeping all build info (config, dependencies, extra_params)"> title="Create a new build keeping all build info (config, dependencies, extra_params)">
Exact Rebuild <i class="fa fa-refresh"/> Exact Rebuild <i class="fa fa-refresh"/>
</a> </a>
</li> </li>
<li t-if="bu.global_state != 'done'" groups="base.group_user"> <li t-if="bu.global_state != 'done'" groups="base.group_user">
<a t-if="bu.real_build.requested_action != 'deathrow'" href="#" class="runbot-kill" t-att-data-runbot-build="bu['id']">Kill <i class="fa fa-crosshairs"/></a> <a t-if="bu.real_build.requested_action != 'deathrow'" href="#" data-runbot="kill" t-att-data-runbot-build="bu['id']">Kill <i class="fa fa-crosshairs"/></a>
<span t-else="" class="runbot-kill" > Killing <i class="fa fa-spinner fa-spin"/> <i class="fa fa-crosshairs"/></span> <span t-else="" data-runbot="kill" > Killing <i class="fa fa-spinner fa-spin"/> <i class="fa fa-crosshairs"/></span>
</li> </li>
<li t-if="bu.global_state == 'done'" groups="base.group_user"> <li t-if="bu.global_state == 'done'" groups="base.group_user">
<a t-if="bu.real_build.requested_action != 'wake_up'" href="#" class="runbot-wakeup" t-att-data-runbot-build="bu['id']">Wake up <i class="fa fa-coffee"/></a> <a t-if="bu.real_build.requested_action != 'wake_up'" href="#" data-runbot="wakeup" t-att-data-runbot-build="bu['id']">Wake up <i class="fa fa-coffee"/></a>
<span t-else="" class="runbot-wakeup" > Waking up <i class="fa fa-spinner fa-spin"/> <i class="fa fa-crosshairs"/></span> <span t-else="" data-runbot="wakeup" > Waking up <i class="fa fa-spinner fa-spin"/> <i class="fa fa-crosshairs"/></span>
</li> </li>
<li t-if="bu.global_state not in ('testing', 'waiting', 'pending')" class="divider"></li> <li t-if="bu.global_state not in ('testing', 'waiting', 'pending')" class="divider"></li>
@ -123,7 +123,7 @@
</div> </div>
</form> </form>
<form class="form-inline" t-attf-action="/runbot/build/#{build['id']}/force" method='POST' t-if="request.params.get('ask_rebuild')" groups="runbot.group_user"> <form class="form-inline" t-attf-action="/runbot/build/#{build['id']}/force" method='POST' t-if="request.params.get('ask_rebuild')" groups="runbot.group_user">
<a href='#' class="btn btn-danger runbot-rebuild" t-attf-data-runbot-build="#{build['id']}" > <i class='fa fa-refresh'/> Force Rebuild</a> <a href='#' class="btn btn-danger" data-runbot="rebuild" t-attf-data-runbot-build="#{build['id']}" > <i class='fa fa-refresh'/> Force Rebuild</a>
</form> </form>
</t> </t>
<div class="row" > <div class="row" >