[IMP] mergebot, forwardbot: various UI bits

- code in the various menus added over time through the UI (queues,
  configuration, ...)
- update / improve PR layout a tick
- fix "outstanding forward ports" count on the dashboard
- improve hover title / help on dashboard
  - add date of last modification (usually date of success / failure)
  - make casing more coherent (everything lowercase)
  - add explicit note that UTC date on staged at label is staged at datetime
  - rediscover yet again that the staging information is when hovering
    on the staging *except the staged at label*
- improve `PullRequest.unstage` to always insert the PR at the start of the
  reason when cancelling the staging, for clarity / traceability

Closes #560, closes #609
This commit is contained in:
Xavier Morel 2022-06-07 15:49:52 +02:00
parent 56898df93f
commit 2204c0410a
11 changed files with 241 additions and 72 deletions

View File

@ -8,6 +8,7 @@
'data/security.xml',
'data/crons.xml',
'data/views.xml',
'data/queues.xml',
],
'license': 'LGPL-3',
}

View File

@ -0,0 +1,51 @@
<odoo>
<record id="action_forward_port" model="ir.actions.act_window">
<field name="name">Forward port batches</field>
<field name="res_model">forwardport.batches</field>
<field name="context">{'active_test': False}</field>
</record>
<record id="tree_forward_port" model="ir.ui.view">
<field name="name">Forward port batches</field>
<field name="model">forwardport.batches</field>
<field name="arch" type="xml">
<tree>
<field name="source"/>
<field name="batch_id"/>
</tree>
</field>
</record>
<record id="form_forward_port" model="ir.ui.view">
<field name="name">Forward port batch</field>
<field name="model">forwardport.batches</field>
<field name="arch" type="xml">
<form>
<group>
<group><field name="source"/></group>
<group><field name="batch_id"/></group>
</group>
</form>
</field>
</record>
<record id="action_followup_updates" model="ir.actions.act_window">
<field name="name">Followup Updates</field>
<field name="res_model">forwardport.updates</field>
</record>
<record id="tree_followup_updates" model="ir.ui.view">
<field name="name">Followup Updates</field>
<field name="model">forwardport.updates</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="original_root"/>
<field name="new_root"/>
</tree>
</field>
</record>
<menuitem name="Forward Port Batches" id="menu_forward_port"
parent="runbot_merge.menu_queues"
action="action_forward_port"/>
<menuitem name="Followup Updates" id="menu_followup"
parent="runbot_merge.menu_queues"
action="action_followup_updates"/>
</odoo>

View File

@ -12,6 +12,7 @@
<t t-set="outstanding" t-value="env['runbot_merge.pull_requests'].search_count([
('source_id', '!=', False),
('state', 'not in', ['merged', 'closed']),
('source_id.merge_date', '&lt;', datetime.datetime.now() - relativedelta(days=3)),
])"/>
<div t-if="outstanding != 0" class="alert col-md-12 alert-warning mb-0">
<a href="/forwardport/outstanding">
@ -175,6 +176,9 @@
<field name="inherit_id" ref="runbot_merge.runbot_merge_form_prs"/>
<field name="model">runbot_merge.pull_requests</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='state']" position="after">
<field name="merge_date" attrs="{'invisible': [('state', '!=', 'merged')]}"/>
</xpath>
<xpath expr="//sheet/group[2]" position="after">
<separator string="Forward Port" attrs="{'invisible': [('source_id', '=', False)]}"/>
<group attrs="{'invisible': [('source_id', '!=', False)]}">

View File

@ -10,6 +10,8 @@
'views/res_partner.xml',
'views/runbot_merge_project.xml',
'views/mergebot.xml',
'views/queues.xml',
'views/configuration.xml',
'views/templates.xml',
'models/project_freeze/views.xml',
],

View File

@ -0,0 +1,6 @@
IMP: various UI items
- more clearly differentiate between "pending" and "unknown" statuses on stagings
- fix "outstanding forward ports" count
- add date of staging last modification (= success / failure instant)
- correctly retrieve and include fast-forward and unstaging reasons

View File

@ -171,11 +171,7 @@ def handle_pr(env, event):
return "It's my understanding that closed/merged PRs don't get sync'd"
if pr_obj.state == 'ready':
pr_obj.unstage(
"PR %s updated by %s",
pr_obj.display_name,
event['sender']['login']
)
pr_obj.unstage("updated by %s", event['sender']['login'])
_logger.info(
"PR %s updated to %s by %s, resetting to 'open' and squash=%s",

View File

@ -846,7 +846,7 @@ class PullRequests(models.Model):
'pull_request': self.number,
'message': "PR priority reset to 1, as pull requests with priority 0 ignore review state.",
})
self.unstage("unreview (r-) by %s", author.github_login)
self.unstage("unreviewed (r-) by %s", author.github_login)
ok = True
else:
msg = "r- makes no sense in the current PR state."
@ -1349,7 +1349,7 @@ class PullRequests(models.Model):
# else remove this batch from the split
b.split_id = False
self.staging_id.cancel(reason, *args)
self.staging_id.cancel('%s ' + reason, self.display_name, *args)
def _try_closing(self, by):
# ignore if the PR is already being updated in a separate transaction
@ -1369,11 +1369,7 @@ class PullRequests(models.Model):
''', [self.id])
self.env.cr.commit()
self.modified(['state'])
self.unstage(
"PR %s closed by %s",
self.display_name,
by
)
self.unstage("closed by %s", by)
return True
# state changes on reviews

View File

@ -0,0 +1,43 @@
<odoo>
<record id="action_overrides" model="ir.actions.act_window">
<field name="name">CI / statuses overrides</field>
<field name="res_model">res.partner.override</field>
</record>
<record id="tree_overrides" model="ir.ui.view">
<field name="name">Overrides List</field>
<field name="model">res.partner.override</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="context"/>
<field name="repository_id"/>
<field name="partner_ids" widget="many2many_tags"/>
</tree>
</field>
</record>
<record id="action_review" model="ir.actions.act_window">
<field name="name">Review Rights</field>
<field name="res_model">res.partner.review</field>
<field name="context">{'search_default_group_by_repository': True}</field>
</record>
<record id="tree_review" model="ir.ui.view">
<field name="name">Review Rights</field>
<field name="model">res.partner.review</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="repository_id"/>
<field name="partner_id"/>
<field name="review"/>
<field name="self_review"/>
</tree>
</field>
</record>
<menuitem name="Configuration" id="menu_configuration" parent="runbot_merge_menu"/>
<menuitem name="CI Overrides" id="menu_configuration_overrides"
parent="menu_configuration"
action="action_overrides"/>
<menuitem name="Review Rights" id="menu_configuration_review"
parent="menu_configuration"
action="action_review"/>
</odoo>

View File

@ -97,10 +97,10 @@
<field name="target"/>
<field name="state"/>
<field name="author"/>
<field name="priority"/>
</group>
<group>
<field name="label"/>
<field name="priority"/>
<field name="squash"/>
</group>
</group>
@ -108,6 +108,8 @@
<group colspan="4">
<field name="head"/>
<field name="statuses"/>
</group>
<group colspan="4">
<field name="overrides"/>
</group>
</group>
@ -205,66 +207,33 @@
</field>
</record>
<record id="runbot_merge_action_fetches" model="ir.actions.act_window">
<field name="name">PRs to fetch</field>
<field name="res_model">runbot_merge.fetch_job</field>
<field name="view_mode">tree</field>
<field name="context">{'default_active': True}</field>
<record id="runbot_merge_action_commits" model="ir.actions.act_window">
<field name="name">Commit Statuses</field>
<field name="res_model">runbot_merge.commit</field>
<field name="view_mode">tree,form</field>
</record>
<record id="runbot_merge_search_fetches" model="ir.ui.view">
<field name="name">Fetches Search</field>
<field name="model">runbot_merge.fetch_job</field>
<field name="arch" type="xml">
<search>
<filter string="Active" name="active"
domain="[('active', '=', True)]"/>
<field name="repository"/>
<field name="number"/>
</search>
</field>
</record>
<record id="runbot_merge_tree_fetches" model="ir.ui.view">
<field name="name">Fetches Tree</field>
<field name="model">runbot_merge.fetch_job</field>
<record id="runbot_merge_commits_tree" model="ir.ui.view">
<field name="name">commits list</field>
<field name="model">runbot_merge.commit</field>
<field name="arch" type="xml">
<tree>
<field name="repository"/>
<field name="number"/>
</tree>
</field>
</record>
<record id="runbot_merge_action_overrides" model="ir.actions.act_window">
<field name="name">CI / statuses overrides</field>
<field name="res_model">res.partner.override</field>
</record>
<record id="runot_merge_tree_overrides" model="ir.ui.view">
<field name="name">Overrides List</field>
<field name="model">res.partner.override</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="context"/>
<field name="repository_id"/>
<field name="partner_ids" widget="many2many_tags"/>
<field name="sha"/>
<field name="statuses"/>
</tree>
</field>
</record>
<menuitem name="Mergebot" id="runbot_merge_menu"/>
<menuitem name="Projects" id="runbot_merge_menu_project"
parent="runbot_merge_menu"
action="runbot_merge_action_projects"/>
<menuitem name="Pull Requests" id="runbot_merge_menu_prs"
parent="runbot_merge_menu"
action="runbot_merge_action_prs"/>
<menuitem name="Stagings" id="runbot_merge_menu_stagings"
parent="runbot_merge_menu"
action="runbot_merge_action_stagings"/>
<menuitem name="Fetches" id="runbot_merge_menu_fetches"
parent="runbot_merge_menu"
action="runbot_merge_action_fetches"/>
<menuitem name="Configuration" id="runbot_merge_menu_configuration" parent="runbot_merge_menu"/>
<menuitem name="CI Overrides" id="runbot_merge_menu_configuration_overrides"
parent="runbot_merge_menu"
action="runbot_merge_action_overrides"/>
<menuitem name="Projects" id="runbot_merge_menu_project"
parent="runbot_merge_menu"
action="runbot_merge_action_projects"/>
<menuitem name="Pull Requests" id="runbot_merge_menu_prs"
parent="runbot_merge_menu"
action="runbot_merge_action_prs"/>
<menuitem name="Stagings" id="runbot_merge_menu_stagings"
parent="runbot_merge_menu"
action="runbot_merge_action_stagings"/>
<menuitem name="Commits" id="runbot_merge_menu_commits"
parent="runbot_merge_menu"
action="runbot_merge_action_commits"/>
</odoo>

View File

@ -0,0 +1,97 @@
<odoo>
<!--
Queues mergebot menu: contains various list views inspecting the cron tasks
(mostly)
-->
<record id="action_splits" model="ir.actions.act_window">
<field name="name">Splits</field>
<field name="res_model">runbot_merge.split</field>
</record>
<record id="tree_splits" model="ir.ui.view">
<field name="name">Splits</field>
<field name="model">runbot_merge.split</field>
<field name="arch" type="xml">
<tree>
<field name="id"/>
<field name="target"/>
</tree>
</field>
</record>
<record id="action_feedback" model="ir.actions.act_window">
<field name="name">Feedback</field>
<field name="res_model">runbot_merge.pull_requests.feedback</field>
</record>
<record id="tree_feedback" model="ir.ui.view">
<field name="name">Feedback</field>
<field name="model">runbot_merge.pull_requests.feedback</field>
<field name="arch" type="xml">
<tree>
<field name="repository"/>
<field name="pull_request"/>
<field name="message"/>
<field name="close"/>
</tree>
</field>
</record>
<record id="action_tagging" model="ir.actions.act_window">
<field name="name">Tagging</field>
<field name="res_model">runbot_merge.pull_requests.tagging</field>
</record>
<record id="tree_tagging" model="ir.ui.view">
<field name="name">Tagging</field>
<field name="model">runbot_merge.pull_requests.tagging</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="repository"/>
<field name="pull_request"/>
<field name="tags_add"/>
<field name="tags_remove"/>
</tree>
</field>
</record>
<record id="action_fetches" model="ir.actions.act_window">
<field name="name">PRs to fetch</field>
<field name="res_model">runbot_merge.fetch_job</field>
<field name="view_mode">tree</field>
<field name="context">{'default_active': True}</field>
</record>
<record id="search_fetches" model="ir.ui.view">
<field name="name">Fetches Search</field>
<field name="model">runbot_merge.fetch_job</field>
<field name="arch" type="xml">
<search>
<filter string="Active" name="active"
domain="[('active', '=', True)]"/>
<field name="repository"/>
<field name="number"/>
</search>
</field>
</record>
<record id="tree_fetches" model="ir.ui.view">
<field name="name">Fetches Tree</field>
<field name="model">runbot_merge.fetch_job</field>
<field name="arch" type="xml">
<tree>
<field name="repository"/>
<field name="number"/>
</tree>
</field>
</record>
<menuitem name="Queues" id="menu_queues" parent="runbot_merge_menu"/>
<menuitem name="Splits" id="menu_queues_splits"
parent="menu_queues"
action="action_splits"/>
<menuitem name="Feedback" id="menu_queues_feedback"
parent="menu_queues"
action="action_feedback"/>
<menuitem name="Tagging" id="menu_queues_tagging"
parent="menu_queues"
action="action_tagging"/>
<menuitem name="Fetches" id="menu_fetches"
parent="menu_queues"
action="action_fetches"/>
</odoo>

View File

@ -135,11 +135,15 @@
<t t-if="staging_index >= 4">visible-lg-block</t>
</t>
<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 t-if="staging.state not in ('canceled', 'ff_failed')"><t t-esc="staging.reason"/></t>
<t t-if="staging.state == 'ff_failed'">fast forward failed</t>
<t t-if="staging.state == 'pending'">last status</t>
<t t-if="staging.state not in ('pending', 'ff_failed')"><t t-esc="staging.reason"/></t>
</t>
<li t-attf-class="staging {{stateclass.strip()}} {{decorationclass.strip()}}" t-att-title="title.strip() or None">
<!-- separate concatenation to avoid having line-break in title as some browsers trigger it -->
<!-- write-date may have microsecond precision, strip that information -->
<!-- use write-date under assumption that a staging is last modified when it ends -->
<t t-set="title"><t t-esc="title.strip()"/> at <t t-esc="staging.write_date.replace(microsecond=0)"/>Z</t>
<li t-attf-class="staging {{stateclass.strip()}} {{decorationclass.strip()}}" 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"/>
@ -152,7 +156,7 @@
<t t-if="staging.heads">
<div class="dropdown">
<button class="btn btn-link dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"
t-attf-title="{{staging.staged_at}}Z">
t-attf-title="Staged at {{staging.staged_at}}Z">
Staged <span t-field="staging.staged_at" t-options="{'widget': 'relative'}"/>
<span class="caret"></span>
</button>