Better reporting of staging state

* [ADD] runbot_merge: more informative states to stagings on error

Currently, when a staging fails for other reasons than a CI failure:

* the staging having been cancelled is known implicitly, because the
  staging will be deactivated but will never get a status beyond
  pending (because it's not found when looking for it since it's not
  `active`)
* the fast-forward having failed is completely silent (logging aside),
  it looks for all the world like the staging succeeded

Timeout fails the PR already, but split-on-timeout was not so fix that
one bit.

* [FIX] odoo/odoo#cb2862ad2a60ff4ce66c14e7af2548fdf6fc5961

Closes #41
This commit is contained in:
xmo-odoo 2018-10-01 10:21:32 +02:00 committed by Christophe Monniez
parent 5ebb53cdc7
commit d042bc541f
3 changed files with 39 additions and 10 deletions

View File

@ -93,7 +93,7 @@ class Project(models.Model):
staging_heads.get(repo_name + '^') or head
)
updated.append(repo_name)
except exceptions.FastForwardError:
except exceptions.FastForwardError as e:
logger.warning(
"Could not fast-forward successful staging on %s:%s, reverting updated repos %s and re-staging",
repo_name, staging.target.name,
@ -102,6 +102,10 @@ class Project(models.Model):
)
for name in reversed(updated):
gh[name].set_ref(staging.target.name, old_heads[name])
staging.write({
'state': 'ff_failed',
'reason': str(e.__cause__ or e.__context__ or '')
})
else:
prs = staging.mapped('batch_ids.prs')
logger.info(
@ -794,11 +798,13 @@ class Stagings(models.Model):
('success', 'Success'),
('failure', 'Failure'),
('pending', 'Pending'),
('cancelled', "Cancelled"),
('ff_failed', "Fast forward failed")
])
active = fields.Boolean(default=True)
staged_at = fields.Datetime(default=fields.Datetime.now)
restaged = fields.Integer(default=0)
reason = fields.Text("Reason for final state (if any)")
# seems simpler than adding yet another indirection through a model
heads = fields.Char(required=True, help="JSON-encoded map of heads, one per repo in the project")
@ -806,6 +812,9 @@ class Stagings(models.Model):
def _validate(self):
Commits = self.env['runbot_merge.commit']
for s in self:
if s.state in ('cancelled', 'ff_failed'):
continue
heads = [
head for repo, head in json.loads(s.heads).items()
if not repo.endswith('^')
@ -840,7 +849,11 @@ class Stagings(models.Model):
_logger.info("Cancelling staging %s: " + reason, self, *args)
self.batch_ids.write({'active': False})
self.active = False
self.write({
'active': False,
'state': 'cancelled',
'reason': reason,
})
def fail(self, message, prs=None):
_logger.error("Staging %s failed: %s", self, message)
@ -851,7 +864,11 @@ class Stagings(models.Model):
pr.number, "Staging failed: %s" % message)
self.batch_ids.write({'active': False})
self.active = False
self.write({
'active': False,
'state': 'failure',
'reason': message,
})
def try_splitting(self):
batches = len(self.batch_ids)
@ -870,7 +887,11 @@ class Stagings(models.Model):
_logger.info("Split %s to %s (%s) and %s (%s)",
self, h, sh, t, st)
self.batch_ids.write({'active': False})
self.active = False
self.write({
'active': False,
'state': 'failure',
'reason': self.reason if self.state == 'failure' else 'timed out'
})
return True
# single batch => the staging is an unredeemable failure

View File

@ -17,6 +17,7 @@ def registry(request):
odoo.tools.config.parse_config(['--addons-path', addons, '-d', db, '--db-filter', db])
try:
odoo.service.db._create_empty_database(db)
odoo.service.db._initialize_db(None, db, False, False, 'admin')
except odoo.service.db.DatabaseExists:
pass

View File

@ -52,16 +52,23 @@
<template id="stagings" name="mergebot branch stagings">
<ul class="list-unstyled stagings">
<t t-foreach="branch.staging_ids.sorted(lambda s: s.staged_at, reverse=True)[:6]" t-as="staging">
<t t-set="success" t-value="staging.state == 'success'"/>
<t t-set="failure" t-value="staging.state == 'failure'"/>
<t t-set="pending" t-value="staging.state == 'pending' and staging.active"/>
<t t-set="stateclass">
<t t-if="staging.state == 'success'">bg-success</t>
<t t-if="staging.state == 'failure'">bg-danger</t>
<t t-if="staging.state == 'pending' and staging.active">bg-info</t>
<t t-if="staging.state == 'pending' and not staging.active">bg-gray-lighter</t>
<t t-if="success">bg-success</t>
<t t-if="failure">bg-danger</t>
<t t-if="pending">bg-info</t>
<t t-if="not (success or failure or pending)">bg-gray-lighter</t>
</t>
<t t-set="decorationclass">
<t t-if="staging_index >= 4">visible-lg-block</t>
</t>
<li t-attf-class="{{stateclass}} {{decorationclass}}">
<t t-set="title">
<t t-if="staging.state == 'canceled'">Cancelled: <t t-esc="staging.reason"/></t>
<t t-if="staging.state == 'ff_failed'">Fast Forward Failed</t>
</t>
<li t-attf-class="{{stateclass}} {{decorationclass}}" t-att-title="title">
<ul class="list-unstyled">
<li t-foreach="staging.batch_ids" t-as="batch" class="batch">
<t t-esc="batch.prs[:1].label"/>