mirror of
https://github.com/odoo/runbot.git
synced 2025-03-27 13:25:47 +07:00
[IMP] *: allow disabling staging on branch, remove fp target flag
- currently disabling staging only works globally, allow disabling on a single branch - use a toggle - remove a pair of tests which work specifically with `fp_target`, can't work with `active` (probably) - cleanup search of possible and active stagings, add relevant indexes and use direct search of relevant branches instead of looking up from the project - also use toggle button for `active` on branches - shitty workaround for upgrading DB: apparently mail really wants to have a `user_id` to do some weird thing, so need to re-add it after resetting everything Fixes #727
This commit is contained in:
parent
4a4252b4b9
commit
2009177ada
@ -152,12 +152,6 @@
|
|||||||
help="Repository where forward port branches will be created"
|
help="Repository where forward port branches will be created"
|
||||||
/>
|
/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
<xpath expr="//field[@name='branch_ids']/tree" position="inside">
|
|
||||||
<field name="fp_target" string="FP to"
|
|
||||||
help="This branch will be forward-ported to (from lower ones)"
|
|
||||||
/>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
@ -210,17 +210,6 @@ class Repository(models.Model):
|
|||||||
_inherit = 'runbot_merge.repository'
|
_inherit = 'runbot_merge.repository'
|
||||||
fp_remote_target = fields.Char(help="where FP branches get pushed")
|
fp_remote_target = fields.Char(help="where FP branches get pushed")
|
||||||
|
|
||||||
class Branch(models.Model):
|
|
||||||
_inherit = 'runbot_merge.branch'
|
|
||||||
|
|
||||||
fp_target = fields.Boolean(default=True)
|
|
||||||
fp_enabled = fields.Boolean(compute='_compute_fp_enabled')
|
|
||||||
|
|
||||||
@api.depends('active', 'fp_target')
|
|
||||||
def _compute_fp_enabled(self):
|
|
||||||
for b in self:
|
|
||||||
b.fp_enabled = b.active and b.fp_target
|
|
||||||
|
|
||||||
class PullRequests(models.Model):
|
class PullRequests(models.Model):
|
||||||
_inherit = 'runbot_merge.pull_requests'
|
_inherit = 'runbot_merge.pull_requests'
|
||||||
|
|
||||||
@ -438,7 +427,7 @@ class PullRequests(models.Model):
|
|||||||
ping = False
|
ping = False
|
||||||
msg = "Forward-port disabled."
|
msg = "Forward-port disabled."
|
||||||
self.limit_id = limit_id
|
self.limit_id = limit_id
|
||||||
elif not limit_id.fp_enabled:
|
elif not limit_id.active:
|
||||||
msg = "branch %r is disabled, it can't be used as a forward port target." % limit_id.name
|
msg = "branch %r is disabled, it can't be used as a forward port target." % limit_id.name
|
||||||
else:
|
else:
|
||||||
ping = False
|
ping = False
|
||||||
@ -550,7 +539,7 @@ class PullRequests(models.Model):
|
|||||||
return next((
|
return next((
|
||||||
branch
|
branch
|
||||||
for branch in branches[from_+1:to_+1]
|
for branch in branches[from_+1:to_+1]
|
||||||
if branch.fp_enabled
|
if branch.active
|
||||||
), None)
|
), None)
|
||||||
|
|
||||||
def _commits_lazy(self):
|
def _commits_lazy(self):
|
||||||
|
@ -16,7 +16,7 @@ def test_conflict(env, config, make_repo, users):
|
|||||||
project = env['runbot_merge.project'].search([])
|
project = env['runbot_merge.project'].search([])
|
||||||
project.write({
|
project.write({
|
||||||
'branch_ids': [
|
'branch_ids': [
|
||||||
(0, 0, {'name': 'd', 'sequence': 40, 'fp_target': True})
|
(0, 0, {'name': 'd', 'sequence': 40})
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -50,31 +50,6 @@ def test_configure(env, config, make_repo):
|
|||||||
assert prs[2].number == originals[2]
|
assert prs[2].number == originals[2]
|
||||||
|
|
||||||
|
|
||||||
def test_self_disabled(env, config, make_repo):
|
|
||||||
""" Allow setting target as limit even if it's disabled
|
|
||||||
"""
|
|
||||||
prod, other = make_basic(env, config, make_repo)
|
|
||||||
bot_name = env['runbot_merge.project'].search([]).fp_github_name
|
|
||||||
branch_a = env['runbot_merge.branch'].search([('name', '=', 'a')])
|
|
||||||
branch_a.fp_target = False
|
|
||||||
with prod:
|
|
||||||
[c] = prod.make_commits('a', Commit('c', tree={'0': '0'}), ref='heads/mybranch')
|
|
||||||
pr = prod.make_pr(target='a', head='mybranch')
|
|
||||||
prod.post_status(c, 'success', 'legal/cla')
|
|
||||||
prod.post_status(c, 'success', 'ci/runbot')
|
|
||||||
pr.post_comment('hansen r+\n%s up to a' % bot_name, config['role_reviewer']['token'])
|
|
||||||
env.run_crons()
|
|
||||||
pr_id = env['runbot_merge.pull_requests'].search([('number', '=', pr.number)])
|
|
||||||
assert pr_id.limit_id == branch_a
|
|
||||||
|
|
||||||
with prod:
|
|
||||||
prod.post_status('staging.a', 'success', 'legal/cla')
|
|
||||||
prod.post_status('staging.a', 'success', 'ci/runbot')
|
|
||||||
|
|
||||||
assert env['runbot_merge.pull_requests'].search([]) == pr_id,\
|
|
||||||
"should not have created a forward port"
|
|
||||||
|
|
||||||
|
|
||||||
def test_ignore(env, config, make_repo):
|
def test_ignore(env, config, make_repo):
|
||||||
""" Provide an "ignore" command which is equivalent to setting the limit
|
""" Provide an "ignore" command which is equivalent to setting the limit
|
||||||
to target
|
to target
|
||||||
@ -100,17 +75,12 @@ def test_ignore(env, config, make_repo):
|
|||||||
"should not have created a forward port"
|
"should not have created a forward port"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('enabled', ['active', 'fp_target'])
|
def test_disable(env, config, make_repo, users):
|
||||||
def test_disable(env, config, make_repo, users, enabled):
|
|
||||||
""" Checks behaviour if the limit target is disabled:
|
""" Checks behaviour if the limit target is disabled:
|
||||||
|
|
||||||
* disable target while FP is ongoing -> skip over (and stop there so no FP)
|
* disable target while FP is ongoing -> skip over (and stop there so no FP)
|
||||||
* forward-port over a disabled branch
|
* forward-port over a disabled branch
|
||||||
* request a disabled target as limit
|
* request a disabled target as limit
|
||||||
|
|
||||||
Disabling (with respect to forward ports) can be performed by marking the
|
|
||||||
branch as !active (which also affects mergebot operations), or as
|
|
||||||
!fp_target (won't be forward-ported to).
|
|
||||||
"""
|
"""
|
||||||
prod, other = make_basic(env, config, make_repo)
|
prod, other = make_basic(env, config, make_repo)
|
||||||
project = env['runbot_merge.project'].search([])
|
project = env['runbot_merge.project'].search([])
|
||||||
@ -133,7 +103,7 @@ def test_disable(env, config, make_repo, users, enabled):
|
|||||||
prod.post_status('staging.a', 'success', 'legal/cla')
|
prod.post_status('staging.a', 'success', 'legal/cla')
|
||||||
prod.post_status('staging.a', 'success', 'ci/runbot')
|
prod.post_status('staging.a', 'success', 'ci/runbot')
|
||||||
# disable branch b
|
# disable branch b
|
||||||
env['runbot_merge.branch'].search([('name', '=', 'b')]).write({enabled: False})
|
env['runbot_merge.branch'].search([('name', '=', 'b')]).active = False
|
||||||
env.run_crons()
|
env.run_crons()
|
||||||
|
|
||||||
# should have created a single PR (to branch c, for pr 1)
|
# should have created a single PR (to branch c, for pr 1)
|
||||||
@ -168,49 +138,6 @@ def test_disable(env, config, make_repo, users, enabled):
|
|||||||
seen(env, pr, users),
|
seen(env, pr, users),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_default_disabled(env, config, make_repo, users):
|
|
||||||
""" If the default limit is disabled, it should still be the default
|
|
||||||
limit but the ping message should be set on the actual last FP (to the
|
|
||||||
last non-deactivated target)
|
|
||||||
"""
|
|
||||||
prod, other = make_basic(env, config, make_repo)
|
|
||||||
branch_c = env['runbot_merge.branch'].search([('name', '=', 'c')])
|
|
||||||
branch_c.fp_target = False
|
|
||||||
|
|
||||||
with prod:
|
|
||||||
[c] = prod.make_commits('a', Commit('c', tree={'0': '0'}), ref='heads/branch0')
|
|
||||||
pr = prod.make_pr(target='a', head='branch0')
|
|
||||||
prod.post_status(c, 'success', 'legal/cla')
|
|
||||||
prod.post_status(c, 'success', 'ci/runbot')
|
|
||||||
pr.post_comment('hansen r+', config['role_reviewer']['token'])
|
|
||||||
env.run_crons()
|
|
||||||
|
|
||||||
assert env['runbot_merge.pull_requests'].search([]).limit_id == branch_c
|
|
||||||
|
|
||||||
with prod:
|
|
||||||
prod.post_status('staging.a', 'success', 'legal/cla')
|
|
||||||
prod.post_status('staging.a', 'success', 'ci/runbot')
|
|
||||||
env.run_crons()
|
|
||||||
|
|
||||||
p1, p2 = env['runbot_merge.pull_requests'].search([], order='number')
|
|
||||||
assert p1.number == pr.number
|
|
||||||
pr2 = prod.get_pr(p2.number)
|
|
||||||
|
|
||||||
cs = pr2.comments
|
|
||||||
assert len(cs) == 2
|
|
||||||
assert pr2.comments == [
|
|
||||||
seen(env, pr2, users),
|
|
||||||
(users['user'], """\
|
|
||||||
@%(user)s @%(reviewer)s this PR targets b and is the last of the forward-port chain.
|
|
||||||
|
|
||||||
To merge the full chain, say
|
|
||||||
> @%(user)s r+
|
|
||||||
|
|
||||||
More info at https://github.com/odoo/odoo/wiki/Mergebot#forward-port
|
|
||||||
""" % users)
|
|
||||||
]
|
|
||||||
|
|
||||||
def test_limit_after_merge(env, config, make_repo, users):
|
def test_limit_after_merge(env, config, make_repo, users):
|
||||||
""" If attempting to set a limit (<up to>) on a PR which is merged
|
""" If attempting to set a limit (<up to>) on a PR which is merged
|
||||||
(already forward-ported or not), or is a forward-port PR, fwbot should
|
(already forward-ported or not), or is a forward-port PR, fwbot should
|
||||||
|
@ -151,9 +151,7 @@ def test_update_merged(env, make_repo, config, users):
|
|||||||
with prod:
|
with prod:
|
||||||
prod.make_ref('heads/d', prod.commit('c').id)
|
prod.make_ref('heads/d', prod.commit('c').id)
|
||||||
env['runbot_merge.project'].search([]).write({
|
env['runbot_merge.project'].search([]).write({
|
||||||
'branch_ids': [(0, 0, {
|
'branch_ids': [(0, 0, {'name': 'd', 'sequence': 40})]
|
||||||
'name': 'd', 'sequence': 40, 'fp_target': True,
|
|
||||||
})]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
with prod:
|
with prod:
|
||||||
@ -251,10 +249,10 @@ def test_duplicate_fw(env, make_repo, setreviewers, config, users):
|
|||||||
'github_prefix': 'hansen',
|
'github_prefix': 'hansen',
|
||||||
'fp_github_token': config['github']['token'],
|
'fp_github_token': config['github']['token'],
|
||||||
'branch_ids': [
|
'branch_ids': [
|
||||||
(0, 0, {'name': 'master', 'sequence': 0, 'fp_target': True}),
|
(0, 0, {'name': 'master', 'sequence': 0}),
|
||||||
(0, 0, {'name': 'v3', 'sequence': 1, 'fp_target': True}),
|
(0, 0, {'name': 'v3', 'sequence': 1}),
|
||||||
(0, 0, {'name': 'v2', 'sequence': 2, 'fp_target': True}),
|
(0, 0, {'name': 'v2', 'sequence': 2}),
|
||||||
(0, 0, {'name': 'v1', 'sequence': 3, 'fp_target': True}),
|
(0, 0, {'name': 'v1', 'sequence': 3}),
|
||||||
],
|
],
|
||||||
'repo_ids': [
|
'repo_ids': [
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
|
@ -26,9 +26,9 @@ def make_basic(env, config, make_repo, *, fp_token, fp_remote):
|
|||||||
'github_prefix': 'hansen',
|
'github_prefix': 'hansen',
|
||||||
'fp_github_token': fp_token and config['github']['token'],
|
'fp_github_token': fp_token and config['github']['token'],
|
||||||
'branch_ids': [
|
'branch_ids': [
|
||||||
(0, 0, {'name': 'a', 'sequence': 2, 'fp_target': True}),
|
(0, 0, {'name': 'a', 'sequence': 2}),
|
||||||
(0, 0, {'name': 'b', 'sequence': 1, 'fp_target': True}),
|
(0, 0, {'name': 'b', 'sequence': 1}),
|
||||||
(0, 0, {'name': 'c', 'sequence': 0, 'fp_target': True}),
|
(0, 0, {'name': 'c', 'sequence': 0}),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -263,9 +263,9 @@ class TestNotAllBranches:
|
|||||||
'github_prefix': 'hansen',
|
'github_prefix': 'hansen',
|
||||||
'fp_github_token': config['github']['token'],
|
'fp_github_token': config['github']['token'],
|
||||||
'branch_ids': [
|
'branch_ids': [
|
||||||
(0, 0, {'name': 'a', 'sequence': 2, 'fp_target': True}),
|
(0, 0, {'name': 'a', 'sequence': 2}),
|
||||||
(0, 0, {'name': 'b', 'sequence': 1, 'fp_target': True}),
|
(0, 0, {'name': 'b', 'sequence': 1}),
|
||||||
(0, 0, {'name': 'c', 'sequence': 0, 'fp_target': True}),
|
(0, 0, {'name': 'c', 'sequence': 0}),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
repo_a = env['runbot_merge.repository'].create({
|
repo_a = env['runbot_merge.repository'].create({
|
||||||
@ -514,7 +514,7 @@ def test_new_intermediate_branch(env, config, make_repo):
|
|||||||
env.run_crons()
|
env.run_crons()
|
||||||
project.write({
|
project.write({
|
||||||
'branch_ids': [
|
'branch_ids': [
|
||||||
(0, False, {'name': 'new', 'sequence': 1, 'fp_target': True}),
|
(0, False, {'name': 'new', 'sequence': 1}),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
env.run_crons()
|
env.run_crons()
|
||||||
@ -748,7 +748,7 @@ def test_retarget_after_freeze(env, config, make_repo, users):
|
|||||||
project.write({
|
project.write({
|
||||||
'branch_ids': [
|
'branch_ids': [
|
||||||
(1, branch_c.id, {'sequence': 1}),
|
(1, branch_c.id, {'sequence': 1}),
|
||||||
(0, 0, {'name': 'bprime', 'sequence': 2, 'fp_target': True}),
|
(0, 0, {'name': 'bprime', 'sequence': 2}),
|
||||||
(1, branch_b.id, {'sequence': 3}),
|
(1, branch_b.id, {'sequence': 3}),
|
||||||
(1, branch_a.id, {'sequence': 4}),
|
(1, branch_a.id, {'sequence': 4}),
|
||||||
]
|
]
|
||||||
|
@ -74,9 +74,9 @@ def make_basic(env, config, make_repo, *, reponame='proj', project_name='myproje
|
|||||||
'github_prefix': 'hansen',
|
'github_prefix': 'hansen',
|
||||||
'fp_github_token': config['github']['token'],
|
'fp_github_token': config['github']['token'],
|
||||||
'branch_ids': [
|
'branch_ids': [
|
||||||
(0, 0, {'name': 'a', 'sequence': 100, 'fp_target': True}),
|
(0, 0, {'name': 'a', 'sequence': 100}),
|
||||||
(0, 0, {'name': 'b', 'sequence': 80, 'fp_target': True}),
|
(0, 0, {'name': 'b', 'sequence': 80}),
|
||||||
(0, 0, {'name': 'c', 'sequence': 60, 'fp_target': True}),
|
(0, 0, {'name': 'c', 'sequence': 60}),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -46,10 +46,11 @@ class Project(models.Model):
|
|||||||
freeze_reminder = fields.Text()
|
freeze_reminder = fields.Text()
|
||||||
|
|
||||||
def _check_stagings(self, commit=False):
|
def _check_stagings(self, commit=False):
|
||||||
for branch in self.search([]).mapped('branch_ids').filtered('active'):
|
# check branches with an active staging
|
||||||
|
for branch in self.env['runbot_merge.branch']\
|
||||||
|
.with_context(active_test=False)\
|
||||||
|
.search([('active_staging_id', '!=', False)]):
|
||||||
staging = branch.active_staging_id
|
staging = branch.active_staging_id
|
||||||
if not staging:
|
|
||||||
continue
|
|
||||||
try:
|
try:
|
||||||
with self.env.cr.savepoint():
|
with self.env.cr.savepoint():
|
||||||
staging.check_status()
|
staging.check_status()
|
||||||
@ -61,16 +62,20 @@ class Project(models.Model):
|
|||||||
self.env.cr.commit()
|
self.env.cr.commit()
|
||||||
|
|
||||||
def _create_stagings(self, commit=False):
|
def _create_stagings(self, commit=False):
|
||||||
for branch in self.search([]).mapped('branch_ids').filtered('active'):
|
# look up branches which can be staged on and have no active staging
|
||||||
if not branch.active_staging_id:
|
for branch in self.env['runbot_merge.branch'].search([
|
||||||
try:
|
('active_staging_id', '=', False),
|
||||||
with self.env.cr.savepoint():
|
('active', '=', True),
|
||||||
branch.try_staging()
|
('staging_enabled', '=', True),
|
||||||
except Exception:
|
]):
|
||||||
_logger.exception("Failed to create staging for branch %r", branch.name)
|
try:
|
||||||
else:
|
with self.env.cr.savepoint():
|
||||||
if commit:
|
branch.try_staging()
|
||||||
self.env.cr.commit()
|
except Exception:
|
||||||
|
_logger.exception("Failed to create staging for branch %r", branch.name)
|
||||||
|
else:
|
||||||
|
if commit:
|
||||||
|
self.env.cr.commit()
|
||||||
|
|
||||||
def _find_commands(self, comment):
|
def _find_commands(self, comment):
|
||||||
return re.findall(
|
return re.findall(
|
||||||
|
@ -67,7 +67,7 @@ class Repository(models.Model):
|
|||||||
|
|
||||||
sequence = fields.Integer(default=50, group_operator=None)
|
sequence = fields.Integer(default=50, group_operator=None)
|
||||||
name = fields.Char(required=True)
|
name = fields.Char(required=True)
|
||||||
project_id = fields.Many2one('runbot_merge.project', required=True)
|
project_id = fields.Many2one('runbot_merge.project', required=True, index=True)
|
||||||
status_ids = fields.One2many('runbot_merge.repository.status', 'repo_id', string="Required Statuses")
|
status_ids = fields.One2many('runbot_merge.repository.status', 'repo_id', string="Required Statuses")
|
||||||
|
|
||||||
group_id = fields.Many2one('res.groups', default=lambda self: self.env.ref('base.group_user'))
|
group_id = fields.Many2one('res.groups', default=lambda self: self.env.ref('base.group_user'))
|
||||||
@ -235,10 +235,10 @@ class Branch(models.Model):
|
|||||||
_order = 'sequence, name'
|
_order = 'sequence, name'
|
||||||
|
|
||||||
name = fields.Char(required=True)
|
name = fields.Char(required=True)
|
||||||
project_id = fields.Many2one('runbot_merge.project', required=True)
|
project_id = fields.Many2one('runbot_merge.project', required=True, index=True)
|
||||||
|
|
||||||
active_staging_id = fields.Many2one(
|
active_staging_id = fields.Many2one(
|
||||||
'runbot_merge.stagings', compute='_compute_active_staging', store=True,
|
'runbot_merge.stagings', compute='_compute_active_staging', store=True, index=True,
|
||||||
help="Currently running staging for the branch."
|
help="Currently running staging for the branch."
|
||||||
)
|
)
|
||||||
staging_ids = fields.One2many('runbot_merge.stagings', 'target')
|
staging_ids = fields.One2many('runbot_merge.stagings', 'target')
|
||||||
@ -252,6 +252,8 @@ class Branch(models.Model):
|
|||||||
active = fields.Boolean(default=True)
|
active = fields.Boolean(default=True)
|
||||||
sequence = fields.Integer(group_operator=None)
|
sequence = fields.Integer(group_operator=None)
|
||||||
|
|
||||||
|
staging_enabled = fields.Boolean(default=True)
|
||||||
|
|
||||||
def _auto_init(self):
|
def _auto_init(self):
|
||||||
res = super(Branch, self)._auto_init()
|
res = super(Branch, self)._auto_init()
|
||||||
tools.create_unique_index(
|
tools.create_unique_index(
|
||||||
|
41
runbot_merge/tests/test_staging.py
Normal file
41
runbot_merge/tests/test_staging.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from utils import Commit, to_pr
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def repo(env, project, make_repo, users, setreviewers):
|
||||||
|
r = make_repo('repo')
|
||||||
|
project.write({'repo_ids': [(0, 0, {
|
||||||
|
'name': r.name,
|
||||||
|
'group_id': False,
|
||||||
|
'required_statuses': 'ci'
|
||||||
|
})]})
|
||||||
|
setreviewers(*project.repo_ids)
|
||||||
|
return r
|
||||||
|
|
||||||
|
def test_staging_disabled_branch(env, project, repo, config):
|
||||||
|
"""Check that it's possible to disable staging on a specific branch
|
||||||
|
"""
|
||||||
|
project.branch_ids = [(0, 0, {
|
||||||
|
'name': 'other',
|
||||||
|
'staging_enabled': False,
|
||||||
|
})]
|
||||||
|
with repo:
|
||||||
|
[master_commit] = repo.make_commits(None, Commit("master", tree={'a': '1'}), ref="heads/master")
|
||||||
|
[c1] = repo.make_commits(master_commit, Commit("thing", tree={'a': '2'}), ref='heads/master-thing')
|
||||||
|
master_pr = repo.make_pr(title="whatever", target="master", head="master-thing")
|
||||||
|
master_pr.post_comment("hansen r+", config['role_reviewer']['token'])
|
||||||
|
repo.post_status(c1, 'success', 'ci')
|
||||||
|
|
||||||
|
[other_commit] = repo.make_commits(None, Commit("other", tree={'b': '1'}), ref='heads/other')
|
||||||
|
[c2] = repo.make_commits(other_commit, Commit("thing", tree={'b': '2'}), ref='heads/other-thing')
|
||||||
|
other_pr = repo.make_pr(title="whatever", target="other", head="other-thing")
|
||||||
|
other_pr.post_comment("hansen r+", config['role_reviewer']['token'])
|
||||||
|
repo.post_status(c2, 'success', 'ci')
|
||||||
|
env.run_crons()
|
||||||
|
|
||||||
|
assert to_pr(env, master_pr).staging_id, \
|
||||||
|
"master is allowed to stage, should be staged"
|
||||||
|
assert not to_pr(env, other_pr).staging_id, \
|
||||||
|
"other is *not* allowed to stage, should not be staged"
|
@ -25,6 +25,7 @@
|
|||||||
<field name="display_name" string="Name"/>
|
<field name="display_name" string="Name"/>
|
||||||
<field name="github_login"/>
|
<field name="github_login"/>
|
||||||
<field name="review_rights" widget="many2many_tags"/>
|
<field name="review_rights" widget="many2many_tags"/>
|
||||||
|
<field name="user_id" invisible="1"/>
|
||||||
</tree>
|
</tree>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
|
@ -56,7 +56,8 @@
|
|||||||
<tree editable="bottom" decoration-muted="not active">
|
<tree editable="bottom" decoration-muted="not active">
|
||||||
<field name="sequence" widget="handle" />
|
<field name="sequence" widget="handle" />
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="active"/>
|
<field name="active" widget="boolean_toggle"/>
|
||||||
|
<field name="staging_enabled" widget="boolean_toggle"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</sheet>
|
</sheet>
|
||||||
|
Loading…
Reference in New Issue
Block a user