mirror of
https://github.com/odoo/runbot.git
synced 2025-03-16 16:05:42 +07:00
439 lines
24 KiB
XML
439 lines
24 KiB
XML
<odoo>
|
|
<function model="website.page" name="write">
|
|
<value eval="ref('website.homepage_page')"/>
|
|
<value eval="{'active': False}"/>
|
|
</function>
|
|
|
|
<template id="assets_frontend" inherit_id="web.assets_frontend">
|
|
<xpath expr="link[last()]" position="after">
|
|
<link rel="stylesheet" type="text/scss" href="/runbot_merge/static/scss/runbot_merge.scss"/>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template id="dashboard" name="mergebot dashboard">
|
|
<t t-call="website.layout">
|
|
<div id="wrap"><div class="container-fluid">
|
|
<div id="alerts" class="row text-center">
|
|
<div class="alert alert-light col-md-12 h6 mb-0">
|
|
<a href="/runbot_merge/changelog">Changelog</a>
|
|
</div>
|
|
<t t-set="stagingcron" t-value="env(user=1).ref('runbot_merge.staging_cron')"/>
|
|
<div t-if="not stagingcron.active" class="alert alert-warning col-12 mb-0" role="alert">
|
|
Staging is disabled, "ready" pull requests will not be staged.
|
|
</div>
|
|
<t t-set="mergecron" t-value="env(user=1).ref('runbot_merge.merge_cron')"/>
|
|
<div t-if="not mergecron.active" class="alert alert-warning col-12 mb-0" role="alert">
|
|
Merging is disabled, stagings will not be disabled.
|
|
</div>
|
|
</div>
|
|
<section t-foreach="projects.with_context(active_test=False)" t-as="project" class="row">
|
|
<h1 class="col-md-12"><t t-esc="project.name"/></h1>
|
|
<div class="col-md-12">
|
|
key:
|
|
<ul class="list-inline">
|
|
<li class="bg-success">success (hopefully merged)</li>
|
|
<li class="bg-info">ongoing</li>
|
|
<li class="bg-danger">failure</li>
|
|
<li class="bg-gray-lighter">cancelled</li>
|
|
</ul>
|
|
</div>
|
|
<section t-foreach="project.branch_ids" t-as="branch" t-if="branch.active" class="col-md-12">
|
|
<h2>
|
|
<a t-attf-href="/runbot_merge/{{branch.id}}">
|
|
<t t-esc="branch.name"/>
|
|
</a>
|
|
</h2>
|
|
<t t-call="runbot_merge.stagings"/>
|
|
<t t-set="splits" t-value="branch.split_ids"/>
|
|
<t t-set="ready_unstaged" t-value="
|
|
project.env['runbot_merge.pull_requests'].search([
|
|
('target', '=', branch.id),
|
|
('state', '=', 'ready'),
|
|
('staging_id', '=', False),
|
|
]) - splits.mapped('batch_ids.prs')
|
|
"/>
|
|
<t t-set="ready" t-value="ready_unstaged.filtered(lambda p: not p.blocked)"/>
|
|
<t t-set="blocked" t-value="ready_unstaged.filtered(lambda p: p.blocked)"/>
|
|
<div t-if="splits" class="splits bg-warning pr-awaiting">
|
|
<h5>
|
|
Splits
|
|
<small class="text-muted">will be staged next</small>
|
|
</h5>
|
|
<ul>
|
|
<li t-foreach="splits" t-as="split">
|
|
<ul class="pr-listing list-inline list-unstyled mb0">
|
|
<li t-foreach="split.mapped('batch_ids.prs')" t-as="pr">
|
|
<a t-attf-href="https://github.com/{{ pr.repository.name }}/pull/{{ pr.number }}"
|
|
t-att-title="pr.message.split('\n')[0]">
|
|
<t t-esc="pr.repository.name"/>#<t t-esc="pr.number"/>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div t-if="ready" class="pr-listing pr-awaiting bg-warning">
|
|
<h5>Awaiting</h5>
|
|
<ul class="list-inline">
|
|
<li t-foreach="ready" t-as="pr">
|
|
<a t-attf-href="https://github.com/{{ pr.repository.name }}/pull/{{ pr.number }}"
|
|
t-att-title="pr.message.split('\n')[0]">
|
|
<t t-esc="pr.repository.name"/>#<t t-esc="pr.number"/>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div t-if="blocked" class="pr-listing pr-blocked bg-info">
|
|
<h5>Blocked</h5>
|
|
<ul class="list-inline">
|
|
<li t-foreach="blocked" t-as="pr">
|
|
<a t-attf-href="https://github.com/{{ pr.repository.name }}/pull/{{ pr.number }}"
|
|
t-att-title="pr.blocked">
|
|
<t t-esc="pr.repository.name"/>#<t t-esc="pr.number"/>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<t t-set="failed" t-value="
|
|
project.env['runbot_merge.pull_requests'].search([
|
|
('target', '=', branch.id),
|
|
('state', '=', 'error'),
|
|
('staging_id', '=', False),
|
|
])
|
|
"/>
|
|
<div t-if="failed" class="pr-listing pr-failed bg-danger">
|
|
<h5>Failed</h5>
|
|
<ul class="list-inline">
|
|
<li t-foreach="failed" t-as="pr">
|
|
<a t-attf-href="https://github.com/{{ pr.repository.name }}/pull/{{ pr.number }}"
|
|
t-att-title="pr.message.split('\n')[0]">
|
|
<t t-esc="pr.repository.name"/>#<t t-esc="pr.number"/>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</section>
|
|
</section>
|
|
</div></div>
|
|
</t>
|
|
</template>
|
|
<template id="stagings" name="mergebot branch stagings">
|
|
<t t-set="repo_statuses" t-value="branch.project_id.repo_ids.having_branch(branch).status_ids"/>
|
|
<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.active and (not staging.state or staging.state == 'pending')"/>
|
|
<t t-set="stateclass">
|
|
<t t-if="success">bg-success <t t-if="staging.active">bg-unmerged</t></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 >= 2">hidden-xs</t>
|
|
<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>
|
|
<li t-attf-class="staging {{stateclass.strip()}} {{decorationclass.strip()}}" t-att-title="title.strip() or None">
|
|
<ul class="list-unstyled">
|
|
<li t-foreach="staging.batch_ids" t-as="batch" class="batch">
|
|
<t t-esc="batch.prs[:1].label"/>
|
|
<t t-foreach="batch.prs" t-as="pr">
|
|
<a t-attf-href="https://github.com/{{ pr.repository.name }}/pull/{{ pr.number }}"
|
|
t-att-title="pr.message.split('\n')[0]"><t t-esc="pr.repository.name"/>#<t t-esc="pr.number"/></a>
|
|
</t>
|
|
</li>
|
|
</ul>
|
|
<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">
|
|
Staged <span t-field="staging.staged_at" t-options="{'widget': 'relative'}"/>
|
|
<span class="caret"></span>
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li groups="runbot_merge.group_admin">
|
|
<a t-attf-href="/web#id={{staging.id}}&view_type=form&model=runbot_merge.stagings" target="new">
|
|
Open Staging
|
|
</a>
|
|
</li>
|
|
|
|
<t t-set="statuses" t-value="{(r, c): (s, t) for r, c, s, t in staging.statuses}"/>
|
|
<t t-foreach="repo_statuses._for_staging(staging)" t-as="req">
|
|
<t t-set="st" t-value="statuses.get((req.repo_id.name, req.context)) or ('pending', None)"/>
|
|
<li t-att-class="
|
|
'bg-success' if st[0] == 'success'
|
|
else 'bg-danger' if st[0] in ('error', 'failure')
|
|
else 'bg-info'"
|
|
>
|
|
<a t-att-href="st[1]" target="new">
|
|
<t t-esc="req.repo_id.name"/>: <t t-esc="req.context"/>
|
|
</a>
|
|
</li>
|
|
</t>
|
|
</ul>
|
|
</div>
|
|
</t>
|
|
</li>
|
|
</t>
|
|
</ul>
|
|
</template>
|
|
<template id="branch_stagings" name="mergebot stagings page">
|
|
<t t-set="repo_statuses" t-value="branch.project_id.repo_ids.having_branch(branch).status_ids"/>
|
|
<t t-call="website.layout">
|
|
<div id="wrap"><div class="container-fluid">
|
|
<section class="row">
|
|
<h1 class="col-md-12"><t t-esc="branch.project_id.name"/>: <t t-esc="branch.name"/></h1>
|
|
</section>
|
|
<table>
|
|
<t t-foreach="stagings" 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.active and (not staging.state or staging.state == 'pending')"/>
|
|
<t t-set="stateclass">
|
|
<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="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>
|
|
<tr t-att-class="stateclass"
|
|
style="border-bottom: 1px solid gainsboro; vertical-align: top">
|
|
<th t-att-title="title.strip() or None">
|
|
<t t-if="not staging.heads">
|
|
<span t-field="staging.staged_at"
|
|
t-options="{'format': 'yyyy-MM-dd\'T\'HH:mm:ssZ'}"/>
|
|
</t>
|
|
<div class="dropdown" t-if="staging.heads">
|
|
<button class="btn btn-link dropdown-toggle"
|
|
type="button"
|
|
data-toggle="dropdown"
|
|
aria-haspopup="true"
|
|
aria-expanded="true">
|
|
<span t-field="staging.staged_at"
|
|
t-options="{'format': 'yyyy-MM-dd\'T\'HH:mm:ssZ'}"/>
|
|
<span class="caret"></span>
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li groups="runbot_merge.group_admin">
|
|
<a t-attf-href="/web#id={{staging.id}}&view_type=form&model=runbot_merge.stagings"
|
|
target="new">
|
|
Open Staging
|
|
</a>
|
|
</li>
|
|
<t t-set="statuses" t-value="{(r, c): (s, t) for r, c, s, t in staging.statuses}"/>
|
|
<t t-foreach="repo_statuses._for_staging(staging)" t-as="req">
|
|
<t t-set="st" t-value="statuses.get((req.repo_id.name, req.context)) or ('pending', None)"/>
|
|
<li t-att-class="
|
|
'bg-success' if st[0] == 'success'
|
|
else 'bg-danger' if st[0] in ('error', 'failure')
|
|
else 'bg-info'"
|
|
>
|
|
<a t-att-href="st[1]"
|
|
target="new">
|
|
<t t-esc="req.repo_id.name"/>:
|
|
<t t-esc="req.context"/>
|
|
</a>
|
|
</li>
|
|
</t>
|
|
</ul>
|
|
</div>
|
|
</th>
|
|
<td>
|
|
<ul class="list-inline list-unstyled mb0">
|
|
<t t-foreach="staging.batch_ids"
|
|
t-as="batch">
|
|
<t t-set="first_pr"
|
|
t-value="batch.prs[-1]"/>
|
|
<li class="dropdown">
|
|
<button class="btn btn-link dropdown-toggle"
|
|
type="button"
|
|
data-toggle="dropdown"
|
|
aria-haspopup="true"
|
|
aria-expanded="true"
|
|
t-att-title="first_pr.message.split('\n')[0]"
|
|
>
|
|
<t t-esc="first_pr.label"/>
|
|
<span class="caret"></span>
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li t-foreach="batch.prs"
|
|
t-as="pr">
|
|
<a t-attf-href="https://github.com/{{ pr.repository.name }}/pull/{{ pr.number }}"
|
|
t-att-title="pr.message.split('\n')[0]"
|
|
target="new">
|
|
<t t-esc="pr.repository.name"/>
|
|
#
|
|
<t t-esc="pr.number"/>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</t>
|
|
</ul>
|
|
</td>
|
|
</tr>
|
|
</t>
|
|
</table>
|
|
<t t-if="next">
|
|
<a t-attf-href="/runbot_merge/{{branch.id}}?until={{next}}">
|
|
Next >
|
|
</a>
|
|
</t>
|
|
</div></div>
|
|
</t>
|
|
</template>
|
|
<template id="changelog" name="mergebot changelog">
|
|
<t t-call="website.layout">
|
|
<div id="wrap"><div class="container-fluid">
|
|
<h1>Changelog</h1>
|
|
<section t-foreach="entries" t-as="entry">
|
|
<h3 t-if="not entry_first" t-esc="entry"/>
|
|
<ul>
|
|
<li t-foreach="sorted(entry_value)" t-as="item">
|
|
<t t-out="item"/>
|
|
</li>
|
|
</ul>
|
|
</section>
|
|
</div></div>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="view_pull_request_info_merged">
|
|
<div class="alert alert-success">
|
|
Merged
|
|
<t t-if="merged_head">
|
|
at <a t-attf-href="https://github.com/{{pr.repository.name}}/commit/{{merged_head}}"><t t-esc="merged_head"/></a>
|
|
</t>
|
|
|
|
<t t-set="linked_prs" t-value="pr._linked_prs"/>
|
|
<div t-if="linked_prs">
|
|
Linked pull requests
|
|
<ul>
|
|
<li t-foreach="linked_prs" t-as="linked">
|
|
<a t-att-href="linked.url" t-field="linked.display_name"/>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template id="view_pull_request_info_closed">
|
|
<div class="alert alert-light">
|
|
Closed
|
|
</div>
|
|
</template>
|
|
<template id="view_pull_request_info_error">
|
|
<div class="alert alert-danger">
|
|
Error:
|
|
<span t-esc="pr.with_context(active_test=False).batch_ids[-1:].staging_id.reason">
|
|
Unable to stage PR
|
|
</span>
|
|
</div>
|
|
</template>
|
|
<template id="view_pull_request_info_staging">
|
|
<div class="alert alert-primary">
|
|
Staged <span t-field="pr.staging_id.staged_at" t-options="{'widget': 'relative'}"/>.
|
|
|
|
<t t-set="linked_prs" t-value="pr._linked_prs"/>
|
|
<div t-if="linked_prs">
|
|
Linked pull requests
|
|
<ul>
|
|
<li t-foreach="linked_prs" t-as="linked">
|
|
<a t-att-href="linked.url" t-field="linked.display_name"/>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template id="view_pull_request_info_open">
|
|
<!-- nb: replicates `blocked`, maybe that should be split into various criteria? -->
|
|
<div class="alert alert-info">
|
|
<p t-if="pr.blocked" class="alert-danger">Blocked</p>
|
|
<p t-else="" class="alert-success">Ready (waiting for staging)</p>
|
|
<ul class="todo">
|
|
<li t-att-class="'ok' if pr.squash or pr.merge_method else 'fail'">
|
|
Merge method
|
|
</li>
|
|
<li t-att-class="'ok' if pr._approved else 'fail'">
|
|
Review
|
|
</li>
|
|
<li t-att-class="'ok' if pr.state not in ('opened', 'approved') else ''">
|
|
CI
|
|
<ul class="todo">
|
|
<t t-foreach="pr.repository.status_ids._for_pr(pr)" t-as="ci">
|
|
<t t-set="st" t-value="statuses.get(ci.context.strip())"/>
|
|
<t t-set="result">
|
|
<t t-if="not st or st['state'] == 'pending'"></t>
|
|
<t t-elif="st['state'] in ('error', 'failure')">fail</t>
|
|
<t t-else="">ok</t>
|
|
</t>
|
|
<li t-att-class="result">
|
|
<a t-att-href="st.get('target_url') if st else None"><t t-esc="ci.context.strip()"/></a><t t-if="st and st.get('description')">: <t t-esc="st['description']"/></t>
|
|
</li>
|
|
</t>
|
|
</ul>
|
|
</li>
|
|
<t t-set="linked_prs" t-value="pr._linked_prs"/>
|
|
<li t-if="linked_prs" t-att-class="'ok' if all(l._ready for l in linked_prs) else 'fail'">
|
|
Linked pull requests
|
|
<ul class="todo">
|
|
<t t-foreach="linked_prs" t-as="linked">
|
|
<li t-att-class="'ok' if linked._ready else 'fail'">
|
|
<a t-att-href="linked.url" t-field="linked.display_name"/>
|
|
</li>
|
|
</t>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="view_pull_request">
|
|
<t t-call="website.layout">
|
|
<div id="wrap"><div class="container-fluid">
|
|
<h1>
|
|
<a t-att-href="pr.github_url" t-field="pr.display_name">
|
|
</a>
|
|
<a t-attf-href="/web#view_type=form&model=runbot_merge.pull_requests&id={{pr.id}}"
|
|
class="btn btn-sm btn-secondary align-top float-right"
|
|
groups="base.group_user">View in backend</a>
|
|
</h1>
|
|
<h6>Created by <span t-field="pr.author.display_name"/></h6>
|
|
<t t-set="tmpl">
|
|
<t t-if="pr.state in ('merged', 'closed', 'error')"><t t-esc="pr.state"/></t>
|
|
<t t-elif="pr.staging_id">staging</t>
|
|
<t t-else="">open</t>
|
|
</t>
|
|
<t t-call="runbot_merge.view_pull_request_info_{{tmpl.strip()}}"/>
|
|
<dl class="runbot-merge-fields">
|
|
<dt>label</dt>
|
|
<dd><span t-field="pr.label"/></dd>
|
|
<dt>head</dt>
|
|
<dd><a t-attf-href="{{pr.github_url}}/commits/{{pr.head}}"><span t-field="pr.head"/></a></dd>
|
|
</dl>
|
|
<p t-field="pr.message"/>
|
|
</div></div>
|
|
</t>
|
|
</template>
|
|
</odoo>
|