[IMP] *: cleanup status contexts in tests

For historical reasons pretty much all tests used to use the contexts
legal/cla and ci/runbot. While there are a few tests where we need the
interactions of multiple contexts and that makes sense, on the vast
majority of tests that's just extra traffic and noise in the
test (from needing to send multiple statuses unnecessarily).

In fact on the average PR where everything passes by default we could
even remove the required statuses entirely...
This commit is contained in:
Xavier Morel 2025-02-06 14:33:40 +01:00
parent 6d5c539c77
commit e3b4d2bb40
13 changed files with 296 additions and 546 deletions

View File

@ -122,10 +122,6 @@ def pytest_configure(config: pytest.Config) -> None:
"markers", "markers",
"expect_log_errors(reason): allow and require tracebacks in the log", "expect_log_errors(reason): allow and require tracebacks in the log",
) )
config.addinivalue_line(
"markers",
"defaultstatuses: use the statuses `default` rather than `ci/runbot,legal/cla`",
)
def pytest_unconfigure(config): def pytest_unconfigure(config):
if not is_manager(config): if not is_manager(config):

View File

@ -1,6 +1,4 @@
import re from utils import Commit, make_basic, to_pr, seen
from utils import Commit, make_basic, to_pr, seen, matches
def test_single_updated(env, config, make_repo): def test_single_updated(env, config, make_repo):
@ -9,28 +7,24 @@ def test_single_updated(env, config, make_repo):
See test_update_pr for a simpler (single-PR) version See test_update_pr for a simpler (single-PR) version
""" """
r1, _ = make_basic(env, config, make_repo, reponame='repo-1') r1, _ = make_basic(env, config, make_repo, reponame='repo-1', statuses='default')
r2, _ = make_basic(env, config, make_repo, reponame='repo-2') r2, _ = make_basic(env, config, make_repo, reponame='repo-2', statuses='default')
with r1: with r1:
r1.make_commits('a', Commit('1', tree={'1': '0'}), ref='heads/aref') r1.make_commits('a', Commit('1', tree={'1': '0'}), ref='heads/aref')
pr1 = r1.make_pr(target='a', head='aref') pr1 = r1.make_pr(target='a', head='aref')
r1.post_status('aref', 'success', 'legal/cla') r1.post_status('aref', 'success')
r1.post_status('aref', 'success', 'ci/runbot')
pr1.post_comment('hansen r+', config['role_reviewer']['token']) pr1.post_comment('hansen r+', config['role_reviewer']['token'])
with r2: with r2:
r2.make_commits('a', Commit('2', tree={'2': '0'}), ref='heads/aref') r2.make_commits('a', Commit('2', tree={'2': '0'}), ref='heads/aref')
pr2 = r2.make_pr(target='a', head='aref') pr2 = r2.make_pr(target='a', head='aref')
r2.post_status('aref', 'success', 'legal/cla') r2.post_status('aref', 'success')
r2.post_status('aref', 'success', 'ci/runbot')
pr2.post_comment('hansen r+', config['role_reviewer']['token']) pr2.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with r1, r2: with r1, r2:
r1.post_status('staging.a', 'success', 'legal/cla') r1.post_status('staging.a', 'success')
r1.post_status('staging.a', 'success', 'ci/runbot') r2.post_status('staging.a', 'success')
r2.post_status('staging.a', 'success', 'legal/cla')
r2.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
pr1_id, pr11_id, pr2_id, pr21_id = pr_ids = env['runbot_merge.pull_requests'].search([]).sorted('display_name') pr1_id, pr11_id, pr2_id, pr21_id = pr_ids = env['runbot_merge.pull_requests'].search([]).sorted('display_name')
@ -60,11 +54,9 @@ def test_single_updated(env, config, make_repo):
assert not pr21_id.parent_id assert not pr21_id.parent_id
with r1, r2: with r1, r2:
r1.post_status(pr11_id.head, 'success', 'legal/cla') r1.post_status(pr11_id.head, 'success')
r1.post_status(pr11_id.head, 'success', 'ci/runbot')
r1.get_pr(pr11_id.number).post_comment('hansen r+', config['role_reviewer']['token']) r1.get_pr(pr11_id.number).post_comment('hansen r+', config['role_reviewer']['token'])
r2.post_status(pr21_id.head, 'success', 'legal/cla') r2.post_status(pr21_id.head, 'success')
r2.post_status(pr21_id.head, 'success', 'ci/runbot')
r2.get_pr(pr21_id.number).post_comment('hansen r+', config['role_reviewer']['token']) r2.get_pr(pr21_id.number).post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
@ -74,10 +66,8 @@ def test_single_updated(env, config, make_repo):
"(%s)" % prs_again.mapped('display_name') "(%s)" % prs_again.mapped('display_name')
with r1, r2: with r1, r2:
r1.post_status('staging.b', 'success', 'legal/cla') r1.post_status('staging.b', 'success')
r1.post_status('staging.b', 'success', 'ci/runbot') r2.post_status('staging.b', 'success')
r2.post_status('staging.b', 'success', 'legal/cla')
r2.post_status('staging.b', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
new_prs = env['runbot_merge.pull_requests'].search([]).sorted('display_name') - pr_ids new_prs = env['runbot_merge.pull_requests'].search([]).sorted('display_name') - pr_ids
@ -94,9 +84,8 @@ def test_closing_during_fp(env, config, make_repo, users):
""" Closing a PR after it's been ported once should not port it further, but """ Closing a PR after it's been ported once should not port it further, but
the rest of the batch should carry on the rest of the batch should carry on
""" """
r1, _ = make_basic(env, config, make_repo) r1, _ = make_basic(env, config, make_repo, statuses='default')
r2, _ = make_basic(env, config, make_repo) r2, _ = make_basic(env, config, make_repo, statuses='default')
env['runbot_merge.repository'].search([]).required_statuses = 'default'
with r1, r2: with r1, r2:
r1.make_commits('a', Commit('1', tree={'1': '0'}), ref='heads/aref') r1.make_commits('a', Commit('1', tree={'1': '0'}), ref='heads/aref')

View File

@ -3,8 +3,6 @@ import re
import time import time
from operator import itemgetter from operator import itemgetter
import pytest
from utils import make_basic, Commit, validate_all, matches, seen, REF_PATTERN, to_pr from utils import make_basic, Commit, validate_all, matches, seen, REF_PATTERN, to_pr
@ -12,7 +10,7 @@ def test_conflict(env, config, make_repo, users):
""" Create a PR to A which will (eventually) conflict with C when """ Create a PR to A which will (eventually) conflict with C when
forward-ported. forward-ported.
""" """
prod, other = make_basic(env, config, make_repo) prod, _other = make_basic(env, config, make_repo, statuses='default')
# create a d branch # create a d branch
with prod: with prod:
prod.make_commits('c', Commit('1111', tree={'i': 'a'}), ref='heads/d') prod.make_commits('c', Commit('1111', tree={'i': 'a'}), ref='heads/d')
@ -30,14 +28,12 @@ def test_conflict(env, config, make_repo, users):
ref='heads/conflicting' ref='heads/conflicting'
) )
pr = prod.make_pr(target='a', head='conflicting') pr = prod.make_pr(target='a', head='conflicting')
prod.post_status(p_0, 'success', 'legal/cla') prod.post_status(p_0, 'success')
prod.post_status(p_0, 'success', 'ci/runbot')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
pra_id, prb_id = env['runbot_merge.pull_requests'].search([], order='number') pra_id, prb_id = env['runbot_merge.pull_requests'].search([], order='number')
# mark pr b as OK so it gets ported to c # mark pr b as OK so it gets ported to c
@ -144,15 +140,13 @@ More info at https://github.com/odoo/odoo/wiki/Mergebot#forward-port
# check that merging the fixed PR fixes the flow and restarts a forward # check that merging the fixed PR fixes the flow and restarts a forward
# port process # port process
with prod: with prod:
prod.post_status(prc.head, 'success', 'legal/cla') prod.post_status(prc.head, 'success')
prod.post_status(prc.head, 'success', 'ci/runbot')
prc.post_comment('hansen r+', config['role_reviewer']['token']) prc.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
assert prc_id.staging_id assert prc_id.staging_id
with prod: with prod:
prod.post_status('staging.c', 'success', 'legal/cla') prod.post_status('staging.c', 'success')
prod.post_status('staging.c', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
*_, prd_id = env['runbot_merge.pull_requests'].search([], order='number') *_, prd_id = env['runbot_merge.pull_requests'].search([], order='number')
@ -264,7 +258,7 @@ def test_massive_conflict(env, config, make_repo):
def test_conflict_deleted(env, config, make_repo): def test_conflict_deleted(env, config, make_repo):
prod, other = make_basic(env, config, make_repo, statuses="default") prod, _other = make_basic(env, config, make_repo, statuses="default")
# remove f from b # remove f from b
with prod: with prod:
prod.make_commits( prod.make_commits(
@ -431,7 +425,7 @@ def test_multiple_commits_same_authorship(env, config, make_repo):
""" """
author = {'name': 'George Pearce', 'email': 'gp@example.org'} author = {'name': 'George Pearce', 'email': 'gp@example.org'}
committer = {'name': 'G. P. W. Meredith', 'email': 'gpwm@example.org'} committer = {'name': 'G. P. W. Meredith', 'email': 'gpwm@example.org'}
prod, _ = make_basic(env, config, make_repo) prod, _ = make_basic(env, config, make_repo, statuses='default')
with prod: with prod:
# conflict: create `g` in `a`, using two commits # conflict: create `g` in `a`, using two commits
prod.make_commits( prod.make_commits(
@ -445,8 +439,7 @@ def test_multiple_commits_same_authorship(env, config, make_repo):
ref='heads/conflicting' ref='heads/conflicting'
) )
pr = prod.make_pr(target='a', head='conflicting') pr = prod.make_pr(target='a', head='conflicting')
prod.post_status('conflicting', 'success', 'legal/cla') prod.post_status('conflicting', 'success')
prod.post_status('conflicting', 'success', 'ci/runbot')
pr.post_comment('hansen r+ rebase-ff', config['role_reviewer']['token']) pr.post_comment('hansen r+ rebase-ff', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
@ -455,8 +448,7 @@ def test_multiple_commits_same_authorship(env, config, make_repo):
assert pr_id.staging_id assert pr_id.staging_id
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
for _ in range(20): for _ in range(20):
@ -480,7 +472,7 @@ def test_multiple_commits_different_authorship(env, config, make_repo, users, ro
""" """
author = {'name': 'George Pearce', 'email': 'gp@example.org'} author = {'name': 'George Pearce', 'email': 'gp@example.org'}
committer = {'name': 'G. P. W. Meredith', 'email': 'gpwm@example.org'} committer = {'name': 'G. P. W. Meredith', 'email': 'gpwm@example.org'}
prod, _ = make_basic(env, config, make_repo) prod, _ = make_basic(env, config, make_repo, statuses='default')
with prod: with prod:
# conflict: create `g` in `a`, using two commits # conflict: create `g` in `a`, using two commits
# just swap author and committer in the commits # just swap author and committer in the commits
@ -495,8 +487,7 @@ def test_multiple_commits_different_authorship(env, config, make_repo, users, ro
ref='heads/conflicting' ref='heads/conflicting'
) )
pr = prod.make_pr(target='a', head='conflicting') pr = prod.make_pr(target='a', head='conflicting')
prod.post_status('conflicting', 'success', 'legal/cla') prod.post_status('conflicting', 'success')
prod.post_status('conflicting', 'success', 'ci/runbot')
pr.post_comment('hansen r+ rebase-ff', config['role_reviewer']['token']) pr.post_comment('hansen r+ rebase-ff', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
@ -505,8 +496,7 @@ def test_multiple_commits_different_authorship(env, config, make_repo, users, ro
assert pr_id.staging_id assert pr_id.staging_id
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
for _ in range(20): for _ in range(20):
@ -543,8 +533,7 @@ b
pr2 = prod.get_pr(pr2_id.number) pr2 = prod.get_pr(pr2_id.number)
with prod: with prod:
prod.post_status(pr2_id.head, 'success', 'legal/cla') prod.post_status(pr2_id.head, 'success')
prod.post_status(pr2_id.head, 'success', 'ci/runbot')
pr2.post_comment('hansen r+', config['role_reviewer']['token']) pr2.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()

View File

@ -10,7 +10,7 @@ from utils import seen, Commit, make_basic, to_pr
pytest.param('b', 'a', 0, id='earlier'), pytest.param('b', 'a', 0, id='earlier'),
]) ])
def test_configure_fp_limit(env, config, make_repo, source, limit, count, page): def test_configure_fp_limit(env, config, make_repo, source, limit, count, page):
prod, other = make_basic(env, config, make_repo, statuses="default") prod, _other = make_basic(env, config, make_repo, statuses="default")
with prod: with prod:
[c] = prod.make_commits( [c] = prod.make_commits(
source, Commit('c', tree={'f': 'g'}), source, Commit('c', tree={'f': 'g'}),
@ -170,25 +170,21 @@ def test_disable(env, config, make_repo, users):
* forward-port over a disabled branch * forward-port over a disabled branch
* request a disabled target as limit * request a disabled target as limit
""" """
prod, other = make_basic(env, config, make_repo) prod, _other = make_basic(env, config, make_repo, statuses='default')
project = env['runbot_merge.project'].search([])
with prod: with prod:
[c] = prod.make_commits('a', Commit('c 0', tree={'0': '0'}), ref='heads/branch0') [c] = prod.make_commits('a', Commit('c 0', tree={'0': '0'}), ref='heads/branch0')
pr = prod.make_pr(target='a', head='branch0') pr = prod.make_pr(target='a', head='branch0')
prod.post_status(c, 'success', 'legal/cla') prod.post_status(c, 'success')
prod.post_status(c, 'success', 'ci/runbot')
pr.post_comment('hansen r+ up to b', config['role_reviewer']['token']) pr.post_comment('hansen r+ up to b', config['role_reviewer']['token'])
[c] = prod.make_commits('a', Commit('c 1', tree={'1': '1'}), ref='heads/branch1') [c] = prod.make_commits('a', Commit('c 1', tree={'1': '1'}), ref='heads/branch1')
pr = prod.make_pr(target='a', head='branch1') pr = prod.make_pr(target='a', head='branch1')
prod.post_status(c, 'success', 'legal/cla') prod.post_status(c, 'success')
prod.post_status(c, 'success', 'ci/runbot')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
# disable branch b # disable branch b
env['runbot_merge.branch'].search([('name', '=', 'b')]).active = False env['runbot_merge.branch'].search([('name', '=', 'b')]).active = False
env.run_crons() env.run_crons()
@ -201,8 +197,7 @@ def test_disable(env, config, make_repo, users):
with prod: with prod:
[c] = prod.make_commits('a', Commit('c 2', tree={'2': '2'}), ref='heads/branch2') [c] = prod.make_commits('a', Commit('c 2', tree={'2': '2'}), ref='heads/branch2')
pr = prod.make_pr(target='a', head='branch2') pr = prod.make_pr(target='a', head='branch2')
prod.post_status(c, 'success', 'legal/cla') prod.post_status(c, 'success')
prod.post_status(c, 'success', 'ci/runbot')
pr.post_comment('hansen r+ up to', config['role_reviewer']['token']) pr.post_comment('hansen r+ up to', config['role_reviewer']['token'])
pr.post_comment('hansen up to b', config['role_reviewer']['token']) pr.post_comment('hansen up to b', config['role_reviewer']['token'])
pr.post_comment('hansen up to foo', config['role_reviewer']['token']) pr.post_comment('hansen up to foo', config['role_reviewer']['token'])
@ -255,21 +250,18 @@ Note: this help text is dynamic and will change with the state of the PR.
def test_limit_after_merge(env, config, make_repo, users): def test_limit_after_merge(env, config, make_repo, users):
prod, other = make_basic(env, config, make_repo) prod, other = make_basic(env, config, make_repo, statuses='default')
reviewer = config['role_reviewer']['token'] reviewer = config['role_reviewer']['token']
branch_b = env['runbot_merge.branch'].search([('name', '=', 'b')]) branch_b = env['runbot_merge.branch'].search([('name', '=', 'b')])
branch_c = env['runbot_merge.branch'].search([('name', '=', 'c')])
with prod: with prod:
[c] = prod.make_commits('a', Commit('c', tree={'0': '0'}), ref='heads/abranch') [c] = prod.make_commits('a', Commit('c', tree={'0': '0'}), ref='heads/abranch')
pr1 = prod.make_pr(target='a', head='abranch') pr1 = prod.make_pr(target='a', head='abranch')
prod.post_status(c, 'success', 'legal/cla') prod.post_status(c, 'success')
prod.post_status(c, 'success', 'ci/runbot')
pr1.post_comment('hansen r+', reviewer) pr1.post_comment('hansen r+', reviewer)
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
p1, p2 = env['runbot_merge.pull_requests'].search([], order='number') p1, p2 = env['runbot_merge.pull_requests'].search([], order='number')
@ -321,13 +313,11 @@ More info at https://github.com/odoo/odoo/wiki/Mergebot#forward-port
(users['user'], "Forward-porting to 'c'."), (users['user'], "Forward-porting to 'c'."),
] ]
with prod: with prod:
prod.post_status(p2.head, 'success', 'legal/cla') prod.post_status(p2.head, 'success')
prod.post_status(p2.head, 'success', 'ci/runbot')
pr2.post_comment('hansen r+', reviewer) pr2.post_comment('hansen r+', reviewer)
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.b', 'success', 'legal/cla') prod.post_status('staging.b', 'success')
prod.post_status('staging.b', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
_, _, p3 = env['runbot_merge.pull_requests'].search([], order='number') _, _, p3 = env['runbot_merge.pull_requests'].search([], order='number')
@ -371,7 +361,7 @@ def test_post_merge(
limit: int, limit: int,
): ):
PRs = env['runbot_merge.pull_requests'] PRs = env['runbot_merge.pull_requests']
project, prod, _ = post_merge _project, prod, _ = post_merge
reviewer = config['role_reviewer']['token'] reviewer = config['role_reviewer']['token']
# fetch source PR # fetch source PR
@ -435,7 +425,7 @@ def test_resume_fw(env, post_merge, users, config, branches, mode):
""" """
PRs = env['runbot_merge.pull_requests'] PRs = env['runbot_merge.pull_requests']
project, prod, _ = post_merge _project, prod, _ = post_merge
reviewer = config['role_reviewer']['token'] reviewer = config['role_reviewer']['token']
# fetch source PR # fetch source PR
@ -467,7 +457,6 @@ def test_resume_fw(env, post_merge, users, config, branches, mode):
env.run_crons() env.run_crons()
with prod: with prod:
for target in numbers: for target in numbers:
pr = PRs.search([('target.name', '=', str(target))])
prod.post_status(f'staging.{target}', 'success') prod.post_status(f'staging.{target}', 'success')
env.run_crons() env.run_crons()
for number in numbers: for number in numbers:

View File

@ -11,9 +11,8 @@ def statuses(pr):
def test_override_inherited(env, config, make_repo, users): def test_override_inherited(env, config, make_repo, users):
""" A forwardport should inherit its parents' overrides, until it's edited. """ A forwardport should inherit its parents' overrides, until it's edited.
""" """
repo, other = make_basic(env, config, make_repo) repo, _other = make_basic(env, config, make_repo, statuses='default')
project = env['runbot_merge.project'].search([]) project = env['runbot_merge.project'].search([])
project.repo_ids.status_ids = [(5, 0, 0), (0, 0, {'context': 'default'})]
env['res.partner'].search([('github_login', '=', users['reviewer'])])\ env['res.partner'].search([('github_login', '=', users['reviewer'])])\
.write({'override_rights': [(0, 0, { .write({'override_rights': [(0, 0, {
'repository_id': project.repo_ids.id, 'repository_id': project.repo_ids.id,
@ -73,7 +72,7 @@ def test_override_inherited(env, config, make_repo, users):
def test_override_combination(env, config, make_repo, users): def test_override_combination(env, config, make_repo, users):
""" A forwardport should inherit its parents' overrides, until it's edited. """ A forwardport should inherit its parents' overrides, until it's edited.
""" """
repo, other = make_basic(env, config, make_repo) repo, _other = make_basic(env, config, make_repo, statuses='ci/runbot,legal/cla')
project = env['runbot_merge.project'].search([]) project = env['runbot_merge.project'].search([])
env['res.partner'].search([('github_login', '=', users['reviewer'])]) \ env['res.partner'].search([('github_login', '=', users['reviewer'])]) \
.write({'override_rights': [ .write({'override_rights': [

View File

@ -31,7 +31,7 @@ def test_straightforward_flow(env, config, make_repo, users):
('github_login', '=', users['reviewer']) ('github_login', '=', users['reviewer'])
]).name ]).name
prod, other = make_basic(env, config, make_repo) prod, other = make_basic(env, config, make_repo, statuses='default')
other_user = config['role_other'] other_user = config['role_other']
other_user_repo = prod.fork(token=other_user['token']) other_user_repo = prod.fork(token=other_user['token'])
@ -50,8 +50,7 @@ def test_straightforward_flow(env, config, make_repo, users):
head=other_user['user'] + ':hugechange', head=other_user['user'] + ':hugechange',
token=other_user['token'] token=other_user['token']
) )
prod.post_status(p_1, 'success', 'legal/cla') prod.post_status(p_1, 'success')
prod.post_status(p_1, 'success', 'ci/runbot')
# use rebase-ff (instead of rebase-merge) so we don't have to dig in # use rebase-ff (instead of rebase-merge) so we don't have to dig in
# parents of the merge commit to find the cherrypicks # parents of the merge commit to find the cherrypicks
pr.post_comment('hansen r+ rebase-ff', config['role_reviewer']['token']) pr.post_comment('hansen r+ rebase-ff', config['role_reviewer']['token'])
@ -61,8 +60,7 @@ def test_straightforward_flow(env, config, make_repo, users):
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
# should merge the staging then create the FP PR # should merge the staging then create the FP PR
env.run_crons() env.run_crons()
@ -116,8 +114,7 @@ def test_straightforward_flow(env, config, make_repo, users):
'x': '1' 'x': '1'
} }
with prod: with prod:
prod.post_status(pr1.head, 'success', 'ci/runbot') prod.post_status(pr1.head, 'success')
prod.post_status(pr1.head, 'success', 'legal/cla')
env.run_crons() env.run_crons()
pr0_, pr1_, pr2 = env['runbot_merge.pull_requests'].search([], order='number') pr0_, pr1_, pr2 = env['runbot_merge.pull_requests'].search([], order='number')
@ -176,8 +173,7 @@ More info at https://github.com/odoo/odoo/wiki/Mergebot#forward-port
)) ))
] ]
with prod: with prod:
prod.post_status(pr2.head, 'success', 'ci/runbot') prod.post_status(pr2.head, 'success')
prod.post_status(pr2.head, 'success', 'legal/cla')
pr2_remote.post_comment('hansen r+', config['role_reviewer']['token']) pr2_remote.post_comment('hansen r+', config['role_reviewer']['token'])
@ -189,10 +185,8 @@ More info at https://github.com/odoo/odoo/wiki/Mergebot#forward-port
assert pr1.staging_id != pr2.staging_id assert pr1.staging_id != pr2.staging_id
# validate # validate
with prod: with prod:
prod.post_status('staging.b', 'success', 'ci/runbot') prod.post_status('staging.b', 'success')
prod.post_status('staging.b', 'success', 'legal/cla') prod.post_status('staging.c', 'success')
prod.post_status('staging.c', 'success', 'ci/runbot')
prod.post_status('staging.c', 'success', 'legal/cla')
# and trigger merge # and trigger merge
env.run_crons() env.run_crons()
@ -249,7 +243,7 @@ def test_empty(env, config, make_repo, users):
""" Cherrypick of an already cherrypicked (or separately implemented) """ Cherrypick of an already cherrypicked (or separately implemented)
commit -> conflicting pr. commit -> conflicting pr.
""" """
prod, other = make_basic(env, config, make_repo, statuses="default") prod, _other = make_basic(env, config, make_repo, statuses="default")
# merge change to b # merge change to b
with prod: with prod:
[p_0] = prod.make_commits( [p_0] = prod.make_commits(
@ -405,7 +399,7 @@ More info at https://github.com/odoo/odoo/wiki/Mergebot#forward-port
def test_partially_empty(env, config, make_repo): def test_partially_empty(env, config, make_repo):
""" Check what happens when only some commits of the PR are now empty """ Check what happens when only some commits of the PR are now empty
""" """
prod, other = make_basic(env, config, make_repo) prod, _other = make_basic(env, config, make_repo, statuses='default')
# merge change to b # merge change to b
with prod: with prod:
[p_0] = prod.make_commits( [p_0] = prod.make_commits(
@ -413,13 +407,11 @@ def test_partially_empty(env, config, make_repo):
ref='heads/early' ref='heads/early'
) )
pr0 = prod.make_pr(target='b', head='early') pr0 = prod.make_pr(target='b', head='early')
prod.post_status(p_0, 'success', 'legal/cla') prod.post_status(p_0, 'success')
prod.post_status(p_0, 'success', 'ci/runbot')
pr0.post_comment('hansen r+', config['role_reviewer']['token']) pr0.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.b', 'success', 'legal/cla') prod.post_status('staging.b', 'success')
prod.post_status('staging.b', 'success', 'ci/runbot')
# merge same change to a afterwards # merge same change to a afterwards
with prod: with prod:
@ -431,13 +423,11 @@ def test_partially_empty(env, config, make_repo):
ref='heads/late' ref='heads/late'
) )
pr1 = prod.make_pr(target='a', head='late') pr1 = prod.make_pr(target='a', head='late')
prod.post_status(p_1, 'success', 'legal/cla') prod.post_status(p_1, 'success')
prod.post_status(p_1, 'success', 'ci/runbot')
pr1.post_comment('hansen r+ rebase-merge', config['role_reviewer']['token']) pr1.post_comment('hansen r+ rebase-merge', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
assert prod.read_tree(prod.commit('a')) == { assert prod.read_tree(prod.commit('a')) == {
@ -490,7 +480,7 @@ def test_access_rights(env, config, make_repo, users, author, reviewer, delegate
"""Validates the review rights *for the forward-port sequence*, the original """Validates the review rights *for the forward-port sequence*, the original
PR is always reviewed by `user`. PR is always reviewed by `user`.
""" """
prod, other = make_basic(env, config, make_repo) prod, _other = make_basic(env, config, make_repo, statuses='default')
project = env['runbot_merge.project'].search([]) project = env['runbot_merge.project'].search([])
# create a partner for `user` # create a partner for `user`
@ -521,29 +511,25 @@ def test_access_rights(env, config, make_repo, users, author, reviewer, delegate
head=users[author] + ':accessrights', head=users[author] + ':accessrights',
token=author_token, token=author_token,
) )
prod.post_status(c, 'success', 'legal/cla') prod.post_status(c, 'success')
prod.post_status(c, 'success', 'ci/runbot')
pr.post_comment('hansen r+', token=config['github']['token']) pr.post_comment('hansen r+', token=config['github']['token'])
if delegate: if delegate:
pr.post_comment('hansen delegate=%s' % users[delegate], token=config['github']['token']) pr.post_comment('hansen delegate=%s' % users[delegate], token=config['github']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
pr0, pr1 = env['runbot_merge.pull_requests'].search([], order='number') pr0, pr1 = env['runbot_merge.pull_requests'].search([], order='number')
assert pr0.state == 'merged' assert pr0.state == 'merged'
with prod: with prod:
prod.post_status(pr1.head, 'success', 'ci/runbot') prod.post_status(pr1.head, 'success')
prod.post_status(pr1.head, 'success', 'legal/cla')
env.run_crons() env.run_crons()
_, _, pr2 = env['runbot_merge.pull_requests'].search([], order='number') _, _, pr2 = env['runbot_merge.pull_requests'].search([], order='number')
with prod: with prod:
prod.post_status(pr2.head, 'success', 'ci/runbot') prod.post_status(pr2.head, 'success')
prod.post_status(pr2.head, 'success', 'legal/cla')
prod.get_pr(pr2.number).post_comment( prod.get_pr(pr2.number).post_comment(
'hansen r+', 'hansen r+',
token=config['role_' + reviewer]['token'] token=config['role_' + reviewer]['token']
@ -645,7 +631,7 @@ def test_delegate_fw(env, config, make_repo, users):
"""If a user is delegated *on a forward port* they should be able to approve """If a user is delegated *on a forward port* they should be able to approve
*the followup*. *the followup*.
""" """
prod, _ = make_basic(env, config, make_repo) prod, _ = make_basic(env, config, make_repo, statuses='default')
# create a partner for `other` so we can put an email on it # create a partner for `other` so we can put an email on it
env['res.partner'].create({ env['res.partner'].create({
'name': users['other'], 'name': users['other'],
@ -661,14 +647,12 @@ def test_delegate_fw(env, config, make_repo, users):
head=users['self_reviewer'] + ':accessrights', head=users['self_reviewer'] + ':accessrights',
token=author_token, token=author_token,
) )
prod.post_status(c, 'success', 'legal/cla') prod.post_status(c, 'success')
prod.post_status(c, 'success', 'ci/runbot')
pr.post_comment('hansen r+', token=config['role_reviewer']['token']) pr.post_comment('hansen r+', token=config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
# ensure pr1 has to be approved to be forward-ported # ensure pr1 has to be approved to be forward-ported
@ -679,29 +663,26 @@ def test_delegate_fw(env, config, make_repo, users):
'detach_reason': "Detached for testing.", 'detach_reason': "Detached for testing.",
}) })
with prod: with prod:
prod.post_status(pr1_id.head, 'success', 'legal/cla') prod.post_status(pr1_id.head, 'success')
prod.post_status(pr1_id.head, 'success', 'ci/runbot')
env.run_crons() env.run_crons()
pr1 = prod.get_pr(pr1_id.number) pr1 = prod.get_pr(pr1_id.number)
# delegate review to "other" consider PR fixed, and have "other" approve it # delegate review to "other" consider PR fixed, and have "other" approve it
with prod: with prod:
pr1.post_comment('hansen delegate=' + users['other'], pr1.post_comment('hansen delegate=' + users['other'],
token=config['role_reviewer']['token']) token=config['role_reviewer']['token'])
prod.post_status(pr1_id.head, 'success', 'ci/runbot') prod.post_status(pr1_id.head, 'success')
pr1.post_comment('hansen r+', token=config['role_other']['token']) pr1.post_comment('hansen r+', token=config['role_other']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.b', 'success', 'legal/cla') prod.post_status('staging.b', 'success')
prod.post_status('staging.b', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
_, _, pr2_id = env['runbot_merge.pull_requests'].search([], order='number') _, _, pr2_id = env['runbot_merge.pull_requests'].search([], order='number')
pr2 = prod.get_pr(pr2_id.number) pr2 = prod.get_pr(pr2_id.number)
# make "other" also approve this one # make "other" also approve this one
with prod: with prod:
prod.post_status(pr2_id.head, 'success', 'ci/runbot') prod.post_status(pr2_id.head, 'success')
prod.post_status(pr2_id.head, 'success', 'legal/cla')
pr2.post_comment('hansen r+', token=config['role_other']['token']) pr2.post_comment('hansen r+', token=config['role_other']['token'])
env.run_crons() env.run_crons()
@ -723,26 +704,22 @@ def test_redundant_approval(env, config, make_repo, users):
"""If a forward port sequence has been partially approved, fw-bot r+ should """If a forward port sequence has been partially approved, fw-bot r+ should
not perform redundant approval as that triggers warning messages. not perform redundant approval as that triggers warning messages.
""" """
prod, _ = make_basic(env, config, make_repo) prod, _ = make_basic(env, config, make_repo, statuses='default')
[project] = env['runbot_merge.project'].search([])
with prod: with prod:
prod.make_commits( prod.make_commits(
'a', Commit('p', tree={'x': '0'}), 'a', Commit('p', tree={'x': '0'}),
ref='heads/early' ref='heads/early'
) )
pr0 = prod.make_pr(target='a', head='early') pr0 = prod.make_pr(target='a', head='early')
prod.post_status('heads/early', 'success', 'legal/cla') prod.post_status('heads/early', 'success')
prod.post_status('heads/early', 'success', 'ci/runbot')
pr0.post_comment('hansen r+', config['role_reviewer']['token']) pr0.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
pr0_id, pr1_id = env['runbot_merge.pull_requests'].search([], order='number asc') pr0_id, pr1_id = env['runbot_merge.pull_requests'].search([], order='number asc')
with prod: with prod:
prod.post_status(pr1_id.head, 'success', 'legal/cla') prod.post_status(pr1_id.head, 'success')
prod.post_status(pr1_id.head, 'success', 'ci/runbot')
env.run_crons() env.run_crons()
_, _, pr2_id = env['runbot_merge.pull_requests'].search([], order='number asc') _, _, pr2_id = env['runbot_merge.pull_requests'].search([], order='number asc')
@ -770,8 +747,8 @@ def test_batched(env, config, make_repo, users):
""" Tests for projects with multiple repos & sync'd branches. Batches """ Tests for projects with multiple repos & sync'd branches. Batches
should be FP'd to batches should be FP'd to batches
""" """
main1, _ = make_basic(env, config, make_repo, reponame='main1') main1, _ = make_basic(env, config, make_repo, reponame='main1', statuses='default')
main2, _ = make_basic(env, config, make_repo, reponame='main2') main2, _ = make_basic(env, config, make_repo, reponame='main2', statuses='default')
main1.unsubscribe(config['role_reviewer']['token']) main1.unsubscribe(config['role_reviewer']['token'])
main2.unsubscribe(config['role_reviewer']['token']) main2.unsubscribe(config['role_reviewer']['token'])
@ -862,7 +839,6 @@ More info at https://github.com/odoo/odoo/wiki/Mergebot#forward-port
assert pr1c.label == pr2c.label, "batched source should yield batched FP" assert pr1c.label == pr2c.label, "batched source should yield batched FP"
assert pr1b.label != pr1c.label assert pr1b.label != pr1c.label
project = env['runbot_merge.project'].search([])
# ok main1 PRs # ok main1 PRs
with main1: with main1:
validate_all([main1], [pr1c.head]) validate_all([main1], [pr1c.head])
@ -894,7 +870,7 @@ class TestClosing:
def test_closing_before_fp(self, env, config, make_repo, users): def test_closing_before_fp(self, env, config, make_repo, users):
""" Closing a PR should preclude its forward port """ Closing a PR should preclude its forward port
""" """
prod, other = make_basic(env, config, make_repo) prod, _other = make_basic(env, config, make_repo, statuses='default')
with prod: with prod:
[p_1] = prod.make_commits( [p_1] = prod.make_commits(
'a', 'a',
@ -902,14 +878,12 @@ class TestClosing:
ref='heads/hugechange' ref='heads/hugechange'
) )
pr = prod.make_pr(target='a', head='hugechange') pr = prod.make_pr(target='a', head='hugechange')
prod.post_status(p_1, 'success', 'legal/cla') prod.post_status(p_1, 'success')
prod.post_status(p_1, 'success', 'ci/runbot')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
# should merge the staging then create the FP PR # should merge the staging then create the FP PR
env.run_crons() env.run_crons()
@ -921,8 +895,7 @@ class TestClosing:
assert pr1_id.state == 'closed' assert pr1_id.state == 'closed'
assert not pr1_id.parent_id, "closed PR should should be detached from its parent" assert not pr1_id.parent_id, "closed PR should should be detached from its parent"
with prod: with prod:
prod.post_status(pr1_id.head, 'success', 'legal/cla') prod.post_status(pr1_id.head, 'success')
prod.post_status(pr1_id.head, 'success', 'ci/runbot')
env.run_crons() env.run_crons()
env.run_crons('forwardport.reminder') env.run_crons('forwardport.reminder')
@ -941,8 +914,7 @@ More info at https://github.com/odoo/odoo/wiki/Mergebot#forward-port
""" Closing a PR which has been forward-ported should not touch the """ Closing a PR which has been forward-ported should not touch the
followups followups
""" """
prod, other = make_basic(env, config, make_repo) prod, _other = make_basic(env, config, make_repo, statuses='default')
project = env['runbot_merge.project'].search([])
with prod: with prod:
[p_1] = prod.make_commits( [p_1] = prod.make_commits(
'a', 'a',
@ -950,22 +922,19 @@ More info at https://github.com/odoo/odoo/wiki/Mergebot#forward-port
ref='heads/hugechange' ref='heads/hugechange'
) )
pr = prod.make_pr(target='a', head='hugechange') pr = prod.make_pr(target='a', head='hugechange')
prod.post_status(p_1, 'success', 'legal/cla') prod.post_status(p_1, 'success')
prod.post_status(p_1, 'success', 'ci/runbot')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
# should merge the staging then create the FP PR # should merge the staging then create the FP PR
env.run_crons() env.run_crons()
pr0_id, pr1_id = env['runbot_merge.pull_requests'].search([], order='number') pr0_id, pr1_id = env['runbot_merge.pull_requests'].search([], order='number')
with prod: with prod:
prod.post_status(pr1_id.head, 'success', 'legal/cla') prod.post_status(pr1_id.head, 'success')
prod.post_status(pr1_id.head, 'success', 'ci/runbot')
# should create the second staging # should create the second staging
env.run_crons() env.run_crons()
@ -995,8 +964,7 @@ More info at https://github.com/odoo/odoo/wiki/Mergebot#forward-port
be nodified if already merged, also there should not be recursive be nodified if already merged, also there should not be recursive
notifications (odoo/odoo#145969, odoo/odoo#145984) notifications (odoo/odoo#145969, odoo/odoo#145984)
""" """
repo, _ = make_basic(env, config, make_repo) repo, _ = make_basic(env, config, make_repo, statuses='default')
env['runbot_merge.repository'].search([]).required_statuses = 'default'
# prep: merge PR, create two forward ports # prep: merge PR, create two forward ports
with repo: with repo:
[c1] = repo.make_commits('a', Commit('first', tree={'m': 'c1'})) [c1] = repo.make_commits('a', Commit('first', tree={'m': 'c1'}))
@ -1072,21 +1040,19 @@ class TestBranchDeletion:
""" Regular PRs should get their branch deleted as long as they're """ Regular PRs should get their branch deleted as long as they're
created in the fp repository created in the fp repository
""" """
prod, other = make_basic(env, config, make_repo) prod, other = make_basic(env, config, make_repo, statuses='default')
with prod, other: with prod, other:
[c] = other.make_commits(prod.commit('a').id, Commit('c', tree={'0': '0'}), ref='heads/abranch') [c] = other.make_commits(prod.commit('a').id, Commit('c', tree={'0': '0'}), ref='heads/abranch')
pr = prod.make_pr( pr = prod.make_pr(
target='a', head='%s:abranch' % other.owner, target='a', head='%s:abranch' % other.owner,
title="a pr", title="a pr",
) )
prod.post_status(c, 'success', 'legal/cla') prod.post_status(c, 'success')
prod.post_status(c, 'success', 'ci/runbot')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
pr_id = to_pr(env, pr) pr_id = to_pr(env, pr)
@ -1103,13 +1069,12 @@ class TestBranchDeletion:
""" The branches of PRs which are still open or have been closed (rather """ The branches of PRs which are still open or have been closed (rather
than merged) should not get deleted than merged) should not get deleted
""" """
prod, other = make_basic(env, config, make_repo) prod, other = make_basic(env, config, make_repo, statuses='default')
with prod, other: with prod, other:
a_ref = prod.commit('a').id a_ref = prod.commit('a').id
[c] = other.make_commits(a_ref, Commit('c1', tree={'1': '0'}), ref='heads/abranch') [c] = other.make_commits(a_ref, Commit('c1', tree={'1': '0'}), ref='heads/abranch')
pr1 = prod.make_pr(target='a', head='%s:abranch' % other.owner, title='a') pr1 = prod.make_pr(target='a', head='%s:abranch' % other.owner, title='a')
prod.post_status(c, 'success', 'legal/cla') prod.post_status(c, 'success')
prod.post_status(c, 'success', 'ci/runbot')
pr1.post_comment('hansen r+', config['role_reviewer']['token']) pr1.post_comment('hansen r+', config['role_reviewer']['token'])
other.make_commits(a_ref, Commit('c2', tree={'2': '0'}), ref='heads/bbranch') other.make_commits(a_ref, Commit('c2', tree={'2': '0'}), ref='heads/bbranch')
@ -1118,8 +1083,7 @@ class TestBranchDeletion:
[c] = other.make_commits(a_ref, Commit('c3', tree={'3': '0'}), ref='heads/cbranch') [c] = other.make_commits(a_ref, Commit('c3', tree={'3': '0'}), ref='heads/cbranch')
pr3 = prod.make_pr(target='a', head='%s:cbranch' % other.owner, title='c') pr3 = prod.make_pr(target='a', head='%s:cbranch' % other.owner, title='c')
prod.post_status(c, 'success', 'legal/cla') prod.post_status(c, 'success')
prod.post_status(c, 'success', 'ci/runbot')
other.make_commits(a_ref, Commit('c3', tree={'4': '0'}), ref='heads/dbranch') other.make_commits(a_ref, Commit('c3', tree={'4': '0'}), ref='heads/dbranch')
pr4 = prod.make_pr(target='a', head='%s:dbranch' % other.owner, title='d') pr4 = prod.make_pr(target='a', head='%s:dbranch' % other.owner, title='d')
@ -1155,7 +1119,7 @@ def test_spengbab():
class TestRecognizeCommands: class TestRecognizeCommands:
def make_pr(self, env, config, make_repo): def make_pr(self, env, config, make_repo):
r, _ = make_basic(env, config, make_repo) r, _ = make_basic(env, config, make_repo, statuses='default')
with r: with r:
r.make_commits('c', Commit('p', tree={'x': '0'}), ref='heads/testbranch') r.make_commits('c', Commit('p', tree={'x': '0'}), ref='heads/testbranch')

View File

@ -2,8 +2,6 @@
Test cases for updating PRs during after the forward-porting process after the Test cases for updating PRs during after the forward-porting process after the
initial merge has succeeded (and forward-porting has started) initial merge has succeeded (and forward-porting has started)
""" """
import re
import pytest import pytest
from utils import seen, matches, Commit, make_basic, to_pr from utils import seen, matches, Commit, make_basic, to_pr
@ -17,7 +15,7 @@ def test_update_pr(env, config, make_repo, users, merge_parent) -> None:
In this case, all following forward ports should... be detached? Or maybe In this case, all following forward ports should... be detached? Or maybe
only this one and its dependent should be updated? only this one and its dependent should be updated?
""" """
prod, _ = make_basic(env, config, make_repo) prod, _ = make_basic(env, config, make_repo, statuses='ci/runbot,legal/cla')
# create a branch d from c so we can have 3 forward ports PRs, not just 2, # create a branch d from c so we can have 3 forward ports PRs, not just 2,
# for additional checks # for additional checks
env['runbot_merge.project'].search([]).write({ env['runbot_merge.project'].search([]).write({
@ -219,7 +217,7 @@ def test_update_merged(env, make_repo, config, users):
* also maybe disable or exponentially backoff the update job after some * also maybe disable or exponentially backoff the update job after some
number of attempts? number of attempts?
""" """
prod, _ = make_basic(env, config, make_repo) prod, _ = make_basic(env, config, make_repo, statuses='default')
# add a 4th branch # add a 4th branch
with prod: with prod:
prod.make_ref('heads/d', prod.commit('c').id) prod.make_ref('heads/d', prod.commit('c').id)
@ -230,33 +228,28 @@ def test_update_merged(env, make_repo, config, users):
with prod: with prod:
[c] = prod.make_commits('a', Commit('p_0', tree={'0': '0'}), ref='heads/hugechange') [c] = prod.make_commits('a', Commit('p_0', tree={'0': '0'}), ref='heads/hugechange')
pr = prod.make_pr(target='a', head='hugechange') pr = prod.make_pr(target='a', head='hugechange')
prod.post_status(c, 'success', 'legal/cla') prod.post_status(c, 'success')
prod.post_status(c, 'success', 'ci/runbot')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
_, pr1_id = env['runbot_merge.pull_requests'].search([], order='number') _, pr1_id = env['runbot_merge.pull_requests'].search([], order='number')
with prod: with prod:
prod.post_status(pr1_id.head, 'success', 'legal/cla') prod.post_status(pr1_id.head, 'success')
prod.post_status(pr1_id.head, 'success', 'ci/runbot')
env.run_crons() env.run_crons()
pr0_id, pr1_id, pr2_id = env['runbot_merge.pull_requests'].search([], order='number') pr0_id, pr1_id, pr2_id = env['runbot_merge.pull_requests'].search([], order='number')
pr2 = prod.get_pr(pr2_id.number) pr2 = prod.get_pr(pr2_id.number)
with prod: with prod:
pr2.post_comment('hansen r+', config['role_reviewer']['token']) pr2.post_comment('hansen r+', config['role_reviewer']['token'])
prod.post_status(pr2_id.head, 'success', 'legal/cla') prod.post_status(pr2_id.head, 'success')
prod.post_status(pr2_id.head, 'success', 'ci/runbot')
env.run_crons() env.run_crons()
assert pr2_id.staging_id assert pr2_id.staging_id
with prod: with prod:
prod.post_status('staging.c', 'success', 'legal/cla') prod.post_status('staging.c', 'success')
prod.post_status('staging.c', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
assert pr2_id.state == 'merged' assert pr2_id.state == 'merged'
assert pr2.state == 'closed' assert pr2.state == 'closed'
@ -371,7 +364,7 @@ def test_duplicate_fw(env, make_repo, setreviewers, config, users):
env.run_crons() env.run_crons()
parent = child parent = child
pr_ids = _, prv2_id, prv3_id, prmaster_id = PRs.search([], order='number') pr_ids = _, prv2_id, prv3_id, prmaster_id = PRs.search([], order='number')
_, prv2, prv3, prmaster = [repo.get_pr(p.number) for p in pr_ids] _, prv2, _prv3, _prmaster = [repo.get_pr(p.number) for p in pr_ids]
assert pr_ids.mapped('target.name') == ['v1', 'v2', 'v3', 'master'] assert pr_ids.mapped('target.name') == ['v1', 'v2', 'v3', 'master']
assert pr_ids.mapped('state') == ['merged', 'validated', 'validated', 'validated'] assert pr_ids.mapped('state') == ['merged', 'validated', 'validated', 'validated']
assert repo.read_tree(repo.commit(prmaster_id.head)) == {'f': 'e', 'z': 'a'} assert repo.read_tree(repo.commit(prmaster_id.head)) == {'f': 'e', 'z': 'a'}
@ -404,19 +397,17 @@ def test_subsequent_conflict(env, make_repo, config, users):
""" Test for updating an fw PR in the case where it produces a conflict in """ Test for updating an fw PR in the case where it produces a conflict in
the followup. Cf #467. the followup. Cf #467.
""" """
repo, fork = make_basic(env, config, make_repo) repo, fork = make_basic(env, config, make_repo, statuses='default')
# create a PR in branch A which adds a new file # create a PR in branch A which adds a new file
with repo: with repo:
repo.make_commits('a', Commit('newfile', tree={'x': '0'}), ref='heads/pr1') repo.make_commits('a', Commit('newfile', tree={'x': '0'}), ref='heads/pr1')
pr_1 = repo.make_pr(target='a', head='pr1') pr_1 = repo.make_pr(target='a', head='pr1')
repo.post_status('pr1', 'success', 'legal/cla') repo.post_status('pr1', 'success')
repo.post_status('pr1', 'success', 'ci/runbot')
pr_1.post_comment('hansen r+', config['role_reviewer']['token']) pr_1.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with repo: with repo:
repo.post_status('staging.a', 'success', 'legal/cla') repo.post_status('staging.a', 'success')
repo.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
pr1_id = to_pr(env, pr_1) pr1_id = to_pr(env, pr_1)
assert pr1_id.state == 'merged' assert pr1_id.state == 'merged'
@ -424,8 +415,7 @@ def test_subsequent_conflict(env, make_repo, config, users):
pr2_id = env['runbot_merge.pull_requests'].search([('source_id', '=', pr1_id.id)]) pr2_id = env['runbot_merge.pull_requests'].search([('source_id', '=', pr1_id.id)])
assert pr2_id assert pr2_id
with repo: with repo:
repo.post_status(pr2_id.head, 'success', 'legal/cla') repo.post_status(pr2_id.head, 'success')
repo.post_status(pr2_id.head, 'success', 'ci/runbot')
env.run_crons() env.run_crons()
pr3_id = env['runbot_merge.pull_requests'].search([('parent_id', '=', pr2_id.id)]) pr3_id = env['runbot_merge.pull_requests'].search([('parent_id', '=', pr2_id.id)])

View File

@ -11,21 +11,19 @@ def test_no_token(env, config, make_repo):
log log
""" """
# create project configured with remotes on the repo but no token # create project configured with remotes on the repo but no token
prod, _ = make_basic(env, config, make_repo, fp_token=False, fp_remote=True) prod, _ = make_basic(env, config, make_repo, fp_token=False, fp_remote=True, statuses='default')
with prod: with prod:
prod.make_commits( prod.make_commits(
'a', Commit('c0', tree={'a': '0'}), ref='heads/abranch' 'a', Commit('c0', tree={'a': '0'}), ref='heads/abranch'
) )
pr = prod.make_pr(target='a', head='abranch') pr = prod.make_pr(target='a', head='abranch')
prod.post_status(pr.head, 'success', 'legal/cla') prod.post_status(pr.head, 'success')
prod.post_status(pr.head, 'success', 'ci/runbot')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
# wanted to use capfd, however it's not compatible with the subprocess # wanted to use capfd, however it's not compatible with the subprocess
# being created beforehand and server() depending on capfd() would remove # being created beforehand and server() depending on capfd() would remove
@ -41,85 +39,75 @@ def test_no_token(env, config, make_repo):
"should not have created forward port" "should not have created forward port"
def test_remove_token(env, config, make_repo): def test_remove_token(env, config, make_repo):
prod, _ = make_basic(env, config, make_repo) prod, _ = make_basic(env, config, make_repo, statuses='default', fp_token=False)
env['runbot_merge.project'].search([]).fp_github_token = False
with prod: with prod:
prod.make_commits( prod.make_commits(
'a', Commit('c0', tree={'a': '0'}), ref='heads/abranch' 'a', Commit('c0', tree={'a': '0'}), ref='heads/abranch'
) )
pr = prod.make_pr(target='a', head='abranch') pr = prod.make_pr(target='a', head='abranch')
prod.post_status(pr.head, 'success', 'legal/cla') prod.post_status(pr.head, 'success')
prod.post_status(pr.head, 'success', 'ci/runbot')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
assert len(env['runbot_merge.pull_requests'].search([], order='number')) == 1,\ assert len(env['runbot_merge.pull_requests'].search([], order='number')) == 1,\
"should not have created forward port" "should not have created forward port"
def test_no_target(env, config, make_repo): def test_no_target(env, config, make_repo):
prod, _ = make_basic(env, config, make_repo, fp_remote=False) prod, _ = make_basic(env, config, make_repo, fp_remote=False, statuses='default')
with prod: with prod:
prod.make_commits( prod.make_commits(
'a', Commit('c0', tree={'a': '0'}), ref='heads/abranch' 'a', Commit('c0', tree={'a': '0'}), ref='heads/abranch'
) )
pr = prod.make_pr(target='a', head='abranch') pr = prod.make_pr(target='a', head='abranch')
prod.post_status(pr.head, 'success', 'legal/cla') prod.post_status(pr.head, 'success')
prod.post_status(pr.head, 'success', 'ci/runbot')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
assert len(env['runbot_merge.pull_requests'].search([], order='number')) == 1,\ assert len(env['runbot_merge.pull_requests'].search([], order='number')) == 1,\
"should not have created forward port" "should not have created forward port"
def test_failed_staging(env, config, make_repo): def test_failed_staging(env, config, make_repo):
prod, _ = make_basic(env, config, make_repo) prod, _ = make_basic(env, config, make_repo, statuses='default')
reviewer = config['role_reviewer']['token'] reviewer = config['role_reviewer']['token']
with prod: with prod:
prod.make_commits('a', Commit('c', tree={'a': '0'}), ref='heads/abranch') prod.make_commits('a', Commit('c', tree={'a': '0'}), ref='heads/abranch')
pr1 = prod.make_pr(target='a', head='abranch') pr1 = prod.make_pr(target='a', head='abranch')
prod.post_status(pr1.head, 'success', 'legal/cla') prod.post_status(pr1.head, 'success')
prod.post_status(pr1.head, 'success', 'ci/runbot')
pr1.post_comment('hansen r+', reviewer) pr1.post_comment('hansen r+', reviewer)
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
pr1_id, pr2_id = env['runbot_merge.pull_requests'].search([], order='number') pr1_id, pr2_id = env['runbot_merge.pull_requests'].search([], order='number')
assert pr2_id.parent_id == pr2_id.source_id == pr1_id assert pr2_id.parent_id == pr2_id.source_id == pr1_id
with prod: with prod:
prod.post_status(pr2_id.head, 'success', 'legal/cla') prod.post_status(pr2_id.head, 'success')
prod.post_status(pr2_id.head, 'success', 'ci/runbot')
env.run_crons() env.run_crons()
pr1_id, pr2_id, pr3_id = env['runbot_merge.pull_requests'].search([], order='number') _pr1_id, _pr2_id, pr3_id = env['runbot_merge.pull_requests'].search([], order='number')
pr3 = prod.get_pr(pr3_id.number) pr3 = prod.get_pr(pr3_id.number)
with prod: with prod:
prod.post_status(pr3_id.head, 'success', 'legal/cla') prod.post_status(pr3_id.head, 'success')
prod.post_status(pr3_id.head, 'success', 'ci/runbot')
pr3.post_comment('hansen r+', reviewer) pr3.post_comment('hansen r+', reviewer)
env.run_crons() env.run_crons()
prod.commit('staging.c') prod.commit('staging.c')
with prod: with prod:
prod.post_status('staging.b', 'success', 'legal/cla') prod.post_status('staging.b', 'success')
prod.post_status('staging.b', 'success', 'ci/runbot') prod.post_status('staging.c', 'failure')
prod.post_status('staging.c', 'failure', 'ci/runbot')
env.run_crons() env.run_crons()
pr3_head = env['runbot_merge.commit'].search([('sha', '=', pr3_id.head)]) pr3_head = env['runbot_merge.commit'].search([('sha', '=', pr3_id.head)])
@ -128,8 +116,7 @@ def test_failed_staging(env, config, make_repo):
# send a new status to the PR, as if somebody had rebuilt it or something # send a new status to the PR, as if somebody had rebuilt it or something
with prod: with prod:
pr3.post_comment('hansen retry', reviewer) pr3.post_comment('hansen retry', reviewer)
prod.post_status(pr3_id.head, 'success', 'foo/bar') prod.post_status(pr3_id.head, 'success')
prod.post_status(pr3_id.head, 'success', 'legal/cla')
assert pr3_head.to_check, "check that the commit was updated as to process" assert pr3_head.to_check, "check that the commit was updated as to process"
env.run_crons() env.run_crons()
assert not pr3_head.to_check, "check that the commit was processed" assert not pr3_head.to_check, "check that the commit was processed"
@ -255,13 +242,13 @@ class TestNotAllBranches:
repo_a = env['runbot_merge.repository'].create({ repo_a = env['runbot_merge.repository'].create({
'project_id': project.id, 'project_id': project.id,
'name': a.name, 'name': a.name,
'required_statuses': 'ci/runbot', 'required_statuses': 'default',
'fp_remote_target': a_dev.name, 'fp_remote_target': a_dev.name,
}) })
repo_b = env['runbot_merge.repository'].create({ repo_b = env['runbot_merge.repository'].create({
'project_id': project.id, 'project_id': project.id,
'name': b.name, 'name': b.name,
'required_statuses': 'ci/runbot', 'required_statuses': 'default',
'fp_remote_target': b_dev.name, 'fp_remote_target': b_dev.name,
'branch_filter': '[("name", "in", ["a", "c"])]', 'branch_filter': '[("name", "in", ["a", "c"])]',
}) })
@ -272,32 +259,32 @@ class TestNotAllBranches:
def test_single_first(self, env, repos, config): def test_single_first(self, env, repos, config):
""" A merge in A.a should be forward-ported to A.b and A.c """ A merge in A.a should be forward-ported to A.b and A.c
""" """
project, a, a_dev, b, _ = repos _project, a, a_dev, b, _ = repos
with a, a_dev: with a, a_dev:
[c] = a_dev.make_commits(a.commit('a').id, Commit('pr', tree={'pr': '1'}), ref='heads/change') [c] = a_dev.make_commits(a.commit('a').id, Commit('pr', tree={'pr': '1'}), ref='heads/change')
pr = a.make_pr(target='a', title="a pr", head=a_dev.owner + ':change') pr = a.make_pr(target='a', title="a pr", head=a_dev.owner + ':change')
a.post_status(c, 'success', 'ci/runbot') a.post_status(c, 'success')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
p = to_pr(env, pr) p = to_pr(env, pr)
env.run_crons() env.run_crons()
assert p.staging_id assert p.staging_id
with a, b: with a, b:
for repo in a, b: a.post_status('staging.a', 'success')
repo.post_status('staging.a', 'success', 'ci/runbot') b.post_status('staging.a', 'success')
env.run_crons() env.run_crons()
a_head = a.commit('a') a_head = a.commit('a')
assert a_head.message.startswith('pr\n\n') assert a_head.message.startswith('pr\n\n')
assert a.read_tree(a_head) == {'a': '2', 'pr': '1'} assert a.read_tree(a_head) == {'a': '2', 'pr': '1'}
pr0, pr1 = env['runbot_merge.pull_requests'].search([], order='number') _pr0, pr1 = env['runbot_merge.pull_requests'].search([], order='number')
with a: with a:
a.post_status(pr1.head, 'success', 'ci/runbot') a.post_status(pr1.head, 'success')
env.run_crons() env.run_crons()
pr0, pr1, pr2 = env['runbot_merge.pull_requests'].search([], order='number') pr0, pr1, pr2 = env['runbot_merge.pull_requests'].search([], order='number')
with a: with a:
a.post_status(pr2.head, 'success', 'ci/runbot') a.post_status(pr2.head, 'success')
a.get_pr(pr2.number).post_comment( a.get_pr(pr2.number).post_comment(
'hansen r+', 'hansen r+',
config['role_reviewer']['token']) config['role_reviewer']['token'])
@ -305,9 +292,9 @@ class TestNotAllBranches:
assert pr1.staging_id assert pr1.staging_id
assert pr2.staging_id assert pr2.staging_id
with a, b: with a, b:
a.post_status('staging.b', 'success', 'ci/runbot') a.post_status('staging.b', 'success')
a.post_status('staging.c', 'success', 'ci/runbot') a.post_status('staging.c', 'success')
b.post_status('staging.c', 'success', 'ci/runbot') b.post_status('staging.c', 'success')
env.run_crons() env.run_crons()
assert pr0.state == 'merged' assert pr0.state == 'merged'
@ -319,31 +306,31 @@ class TestNotAllBranches:
def test_single_second(self, env, repos, config): def test_single_second(self, env, repos, config):
""" A merge in B.a should "skip ahead" to B.c """ A merge in B.a should "skip ahead" to B.c
""" """
project, a, _, b, b_dev = repos _project, a, _, b, b_dev = repos
with b, b_dev: with b, b_dev:
[c] = b_dev.make_commits(b.commit('a').id, Commit('pr', tree={'pr': '1'}), ref='heads/change') [c] = b_dev.make_commits(b.commit('a').id, Commit('pr', tree={'pr': '1'}), ref='heads/change')
pr = b.make_pr(target='a', title="a pr", head=b_dev.owner + ':change') pr = b.make_pr(target='a', title="a pr", head=b_dev.owner + ':change')
b.post_status(c, 'success', 'ci/runbot') b.post_status(c, 'success')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with a, b: with a, b:
a.post_status('staging.a', 'success', 'ci/runbot') a.post_status('staging.a', 'success')
b.post_status('staging.a', 'success', 'ci/runbot') b.post_status('staging.a', 'success')
env.run_crons() env.run_crons()
assert b.read_tree(b.commit('a')) == {'a': 'z', 'pr': '1'} assert b.read_tree(b.commit('a')) == {'a': 'z', 'pr': '1'}
pr0, pr1 = env['runbot_merge.pull_requests'].search([], order='number') pr0, pr1 = env['runbot_merge.pull_requests'].search([], order='number')
with b: with b:
b.post_status(pr1.head, 'success', 'ci/runbot') b.post_status(pr1.head, 'success')
b.get_pr(pr1.number).post_comment( b.get_pr(pr1.number).post_comment(
'hansen r+', 'hansen r+',
config['role_reviewer']['token']) config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with a, b: with a, b:
a.post_status('staging.c', 'success', 'ci/runbot') a.post_status('staging.c', 'success')
b.post_status('staging.c', 'success', 'ci/runbot') b.post_status('staging.c', 'success')
env.run_crons() env.run_crons()
assert pr0.state == 'merged' assert pr0.state == 'merged'
@ -353,22 +340,22 @@ class TestNotAllBranches:
def test_both_first(self, env, repos, config, users): def test_both_first(self, env, repos, config, users):
""" A merge in A.a, B.a should... not be forward-ported at all? """ A merge in A.a, B.a should... not be forward-ported at all?
""" """
project, a, a_dev, b, b_dev = repos _project, a, a_dev, b, b_dev = repos
with a, a_dev: with a, a_dev:
[c_a] = a_dev.make_commits(a.commit('a').id, Commit('pr a', tree={'pr': 'a'}), ref='heads/change') [c_a] = a_dev.make_commits(a.commit('a').id, Commit('pr a', tree={'pr': 'a'}), ref='heads/change')
pr_a = a.make_pr(target='a', title='a pr', head=a_dev.owner + ':change') pr_a = a.make_pr(target='a', title='a pr', head=a_dev.owner + ':change')
a.post_status(c_a, 'success', 'ci/runbot') a.post_status(c_a, 'success')
pr_a.post_comment('hansen r+', config['role_reviewer']['token']) pr_a.post_comment('hansen r+', config['role_reviewer']['token'])
with b, b_dev: with b, b_dev:
[c_b] = b_dev.make_commits(b.commit('a').id, Commit('pr b', tree={'pr': 'b'}), ref='heads/change') [c_b] = b_dev.make_commits(b.commit('a').id, Commit('pr b', tree={'pr': 'b'}), ref='heads/change')
pr_b = b.make_pr(target='a', title='b pr', head=b_dev.owner + ':change') pr_b = b.make_pr(target='a', title='b pr', head=b_dev.owner + ':change')
b.post_status(c_b, 'success', 'ci/runbot') b.post_status(c_b, 'success')
pr_b.post_comment('hansen r+', config['role_reviewer']['token']) pr_b.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with a, b: with a, b:
for repo in a, b: for repo in a, b:
repo.post_status('staging.a', 'success', 'ci/runbot') repo.post_status('staging.a', 'success')
env.run_crons() env.run_crons()
pr_a_id = to_pr(env, pr_a) pr_a_id = to_pr(env, pr_a)
@ -404,11 +391,8 @@ def test_new_intermediate_branch(env, config, make_repo):
1.0, 2.0 and master, if a branch 3.0 is forked off from master and inserted 1.0, 2.0 and master, if a branch 3.0 is forked off from master and inserted
before it, we need to create a new *intermediate* forward port PR before it, we need to create a new *intermediate* forward port PR
""" """
def validate(repo, commit): prod, _ = make_basic(env, config, make_repo, statuses='default')
repo.post_status(commit, 'success', 'ci/runbot') prod2, _ = make_basic(env, config, make_repo, statuses='default')
repo.post_status(commit, 'success', 'legal/cla')
prod, _ = make_basic(env, config, make_repo)
prod2, _ = make_basic(env, config, make_repo)
project = env['runbot_merge.project'].search([]) project = env['runbot_merge.project'].search([])
assert len(project.repo_ids) == 2 assert len(project.repo_ids) == 2
@ -419,7 +403,7 @@ def test_new_intermediate_branch(env, config, make_repo):
prod.make_commits('a', Commit(i, tree={i:i}), ref='heads/branch%s' % i) prod.make_commits('a', Commit(i, tree={i:i}), ref='heads/branch%s' % i)
pr = prod.make_pr(target='a', head='branch%s' % i) pr = prod.make_pr(target='a', head='branch%s' % i)
prs.append(pr) prs.append(pr)
validate(prod, pr.head) prod.post_status(pr.head, 'success')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
# also add a PR targeting b forward-ported to c, in order to check # also add a PR targeting b forward-ported to c, in order to check
@ -429,15 +413,15 @@ def test_new_intermediate_branch(env, config, make_repo):
prod2.make_commits('b', Commit('x2', tree={'x': 'x2'}), ref='heads/branchx') prod2.make_commits('b', Commit('x2', tree={'x': 'x2'}), ref='heads/branchx')
prx = prod.make_pr(target='b', head='branchx') prx = prod.make_pr(target='b', head='branchx')
prx2 = prod2.make_pr(target='b', head='branchx') prx2 = prod2.make_pr(target='b', head='branchx')
validate(prod, prx.head) prod.post_status(prx.head, 'success')
validate(prod2, prx2.head) prod2.post_status(prx2.head, 'success')
prx.post_comment('hansen r+', config['role_reviewer']['token']) prx.post_comment('hansen r+', config['role_reviewer']['token'])
prx2.post_comment('hansen r+', config['role_reviewer']['token']) prx2.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod, prod2: with prod, prod2:
for r in [prod, prod2]: for r in [prod, prod2]:
validate(r, 'staging.a') r.post_status('staging.a', 'success')
validate(r, 'staging.b') r.post_status('staging.b', 'success')
env.run_crons() env.run_crons()
# should have merged pr1, pr2 and prx and created their forward ports, now # should have merged pr1, pr2 and prx and created their forward ports, now
@ -450,7 +434,7 @@ def test_new_intermediate_branch(env, config, make_repo):
assert pr0_fp_id assert pr0_fp_id
assert pr0_fp_id.target.name == 'b' assert pr0_fp_id.target.name == 'b'
with prod: with prod:
validate(prod, pr0_fp_id.head) prod.post_status(pr0_fp_id.head, 'success')
env.run_crons() env.run_crons()
assert pr0_fp_id.state == 'validated' assert pr0_fp_id.state == 'validated'
original0 = PRs.search([('parent_id', '=', pr0_fp_id.id)]) original0 = PRs.search([('parent_id', '=', pr0_fp_id.id)])
@ -549,7 +533,8 @@ def test_new_intermediate_branch(env, config, make_repo):
fps = PRs.search([('source_id', 'in', sources), ('target.name', '=', ['new', 'c'])]) fps = PRs.search([('source_id', 'in', sources), ('target.name', '=', ['new', 'c'])])
with prod, prod2: with prod, prod2:
for fp in fps: for fp in fps:
validate(get_repo(fp), fp.head) repo = get_repo(fp)
repo.post_status(fp.head, 'success')
env.run_crons() env.run_crons()
# now fps should be the last PR of each sequence, and thus r+-able (via # now fps should be the last PR of each sequence, and thus r+-able (via
# fwbot so preceding PR is also r+'d) # fwbot so preceding PR is also r+'d)
@ -568,8 +553,8 @@ def test_new_intermediate_branch(env, config, make_repo):
"enabled branches should have been staged" "enabled branches should have been staged"
with prod, prod2: with prod, prod2:
for target in ['new', 'c']: for target in ['new', 'c']:
validate(prod, f'staging.{target}') prod.post_status(f'staging.{target}', 'success')
validate(prod2, f'staging.{target}') prod2.post_status(f'staging.{target}', 'success')
env.run_crons() env.run_crons()
assert all(p.state == 'merged' for p in PRs.search([('target.name', '!=', 'b')])), \ assert all(p.state == 'merged' for p in PRs.search([('target.name', '!=', 'b')])), \
"All PRs except disabled branch should be merged now" "All PRs except disabled branch should be merged now"
@ -586,7 +571,7 @@ def test_new_intermediate_branch(env, config, make_repo):
}, "check that new got all the updates (should be in the same state as c really)" }, "check that new got all the updates (should be in the same state as c really)"
def test_author_can_close_via_fwbot(env, config, make_repo): def test_author_can_close_via_fwbot(env, config, make_repo):
prod, _ = make_basic(env, config, make_repo) prod, _ = make_basic(env, config, make_repo, statuses='default')
other_user = config['role_other'] other_user = config['role_other']
other_token = other_user['token'] other_token = other_user['token']
other = prod.fork(token=other_token) other = prod.fork(token=other_token)
@ -601,16 +586,14 @@ def test_author_can_close_via_fwbot(env, config, make_repo):
# should be able to close and open own PR # should be able to close and open own PR
pr.close(other_token) pr.close(other_token)
pr.open(other_token) pr.open(other_token)
prod.post_status(c, 'success', 'legal/cla') prod.post_status(c, 'success')
prod.post_status(c, 'success', 'ci/runbot')
pr.post_comment('hansen close', other_token) pr.post_comment('hansen close', other_token)
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
assert pr.state == 'open' assert pr.state == 'open'
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
pr0_id, pr1_id = env['runbot_merge.pull_requests'].search([], order='number') pr0_id, pr1_id = env['runbot_merge.pull_requests'].search([], order='number')
@ -629,21 +612,19 @@ def test_author_can_close_via_fwbot(env, config, make_repo):
assert pr1_id.state == 'closed' assert pr1_id.state == 'closed'
def test_skip_ci_all(env, config, make_repo): def test_skip_ci_all(env, config, make_repo):
prod, _ = make_basic(env, config, make_repo) prod, _ = make_basic(env, config, make_repo, statuses='default')
with prod: with prod:
prod.make_commits('a', Commit('x', tree={'x': '0'}), ref='heads/change') prod.make_commits('a', Commit('x', tree={'x': '0'}), ref='heads/change')
pr = prod.make_pr(target='a', head='change') pr = prod.make_pr(target='a', head='change')
prod.post_status(pr.head, 'success', 'legal/cla') prod.post_status(pr.head, 'success')
prod.post_status(pr.head, 'success', 'ci/runbot')
pr.post_comment('hansen fw=skipci', config['role_reviewer']['token']) pr.post_comment('hansen fw=skipci', config['role_reviewer']['token'])
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
assert to_pr(env, pr).batch_id.fw_policy == 'skipci' assert to_pr(env, pr).batch_id.fw_policy == 'skipci'
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
# run cron a few more times for the fps # run cron a few more times for the fps
@ -658,19 +639,17 @@ def test_skip_ci_all(env, config, make_repo):
assert pr2_id.source_id == pr0_id assert pr2_id.source_id == pr0_id
def test_skip_ci_next(env, config, make_repo): def test_skip_ci_next(env, config, make_repo):
prod, _ = make_basic(env, config, make_repo) prod, _ = make_basic(env, config, make_repo, statuses='default')
with prod: with prod:
prod.make_commits('a', Commit('x', tree={'x': '0'}), ref='heads/change') prod.make_commits('a', Commit('x', tree={'x': '0'}), ref='heads/change')
pr = prod.make_pr(target='a', head='change') pr = prod.make_pr(target='a', head='change')
prod.post_status(pr.head, 'success', 'legal/cla') prod.post_status(pr.head, 'success')
prod.post_status(pr.head, 'success', 'ci/runbot')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.a', 'success', 'legal/cla') prod.post_status('staging.a', 'success')
prod.post_status('staging.a', 'success', 'ci/runbot')
env.run_crons() env.run_crons()
pr0_id, pr1_id = env['runbot_merge.pull_requests'].search([], order='number') pr0_id, pr1_id = env['runbot_merge.pull_requests'].search([], order='number')
@ -696,13 +675,12 @@ def test_retarget_after_freeze(env, config, make_repo, users):
latter port. In that case the reinsertion task should just do nothing, and latter port. In that case the reinsertion task should just do nothing, and
the retargeted PR should be forward-ported normally once merged. the retargeted PR should be forward-ported normally once merged.
""" """
prod, _ = make_basic(env, config, make_repo) prod, _ = make_basic(env, config, make_repo, statuses='default')
project = env['runbot_merge.project'].search([]) project = env['runbot_merge.project'].search([])
with prod: with prod:
[c] = prod.make_commits('b', Commit('thing', tree={'x': '1'}), ref='heads/mypr') [c] = prod.make_commits('b', Commit('thing', tree={'x': '1'}), ref='heads/mypr')
pr = prod.make_pr(target='b', head='mypr') pr = prod.make_pr(target='b', head='mypr')
prod.post_status(c, 'success', 'ci/runbot') prod.post_status(c, 'success')
prod.post_status(c, 'success', 'legal/cla')
pr.post_comment('hansen r+', config['role_reviewer']['token']) pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
@ -711,8 +689,7 @@ def test_retarget_after_freeze(env, config, make_repo, users):
assert original_pr_id.staging_id assert original_pr_id.staging_id
with prod: with prod:
prod.post_status('staging.b', 'success', 'ci/runbot') prod.post_status('staging.b', 'success')
prod.post_status('staging.b', 'success', 'legal/cla')
env.run_crons() env.run_crons()
# should have created a pr targeted to C # should have created a pr targeted to C
port_id = env['runbot_merge.pull_requests'].search([('state', 'not in', ('merged', 'closed'))]) port_id = env['runbot_merge.pull_requests'].search([('state', 'not in', ('merged', 'closed'))])
@ -755,13 +732,11 @@ def test_retarget_after_freeze(env, config, make_repo, users):
# merge the retargered PR # merge the retargered PR
with prod: with prod:
prod.post_status(port_pr.head, 'success', 'ci/runbot') prod.post_status(port_pr.head, 'success')
prod.post_status(port_pr.head, 'success', 'legal/cla')
port_pr.post_comment('hansen r+', config['role_reviewer']['token']) port_pr.post_comment('hansen r+', config['role_reviewer']['token'])
env.run_crons() env.run_crons()
with prod: with prod:
prod.post_status('staging.bprime', 'success', 'ci/runbot') prod.post_status('staging.bprime', 'success')
prod.post_status('staging.bprime', 'success', 'legal/cla')
env.run_crons() env.run_crons()
# #2 batch 6 (???) # #2 batch 6 (???)
@ -773,7 +748,7 @@ def test_retarget_after_freeze(env, config, make_repo, users):
assert new_pr_id.target == branch_c assert new_pr_id.target == branch_c
def test_approve_draft(env, config, make_repo, users): def test_approve_draft(env, config, make_repo, users):
prod, _ = make_basic(env, config, make_repo) prod, _ = make_basic(env, config, make_repo, statuses='default')
with prod: with prod:
prod.make_commits('a', Commit('x', tree={'x': '0'}), ref='heads/change') prod.make_commits('a', Commit('x', tree={'x': '0'}), ref='heads/change')

View File

@ -24,7 +24,7 @@ class Commit:
self.tree = tree self.tree = tree
self.reset = reset self.reset = reset
def validate_all(repos, refs, contexts=('ci/runbot', 'legal/cla')): def validate_all(repos, refs, contexts=('default',)):
""" Post a "success" status for each context on each ref of each repo """ Post a "success" status for each context on each ref of each repo
""" """
for repo, branch, context in itertools.product(repos, refs, contexts): for repo, branch, context in itertools.product(repos, refs, contexts):
@ -76,7 +76,7 @@ def make_basic(
*, *,
project_name='myproject', project_name='myproject',
reponame='proj', reponame='proj',
statuses='legal/cla,ci/runbot', statuses,
fp_token=True, fp_token=True,
fp_remote=True, fp_remote=True,
): ):

File diff suppressed because it is too large Load Diff

View File

@ -3,8 +3,6 @@ import pytest
from utils import seen, Commit, pr_page, to_pr from utils import seen, Commit, pr_page, to_pr
pytestmark = pytest.mark.defaultstatuses
def test_existing_pr_disabled_branch(env, project, repo, config, users, page): def test_existing_pr_disabled_branch(env, project, repo, config, users, page):
""" PRs to disabled branches are ignored, but what if the PR exists *before* """ PRs to disabled branches are ignored, but what if the PR exists *before*
the branch is disabled? the branch is disabled?
@ -37,7 +35,7 @@ def test_existing_pr_disabled_branch(env, project, repo, config, users, page):
assert staging_id == pr_id.staging_id assert staging_id == pr_id.staging_id
# staging of `pr` should have generated a staging branch # staging of `pr` should have generated a staging branch
_ = repo.get_ref('heads/staging.other') _ = repo.get_ref('staging.other')
# disable branch "other" # disable branch "other"
branch_id.active = False branch_id.active = False
@ -46,7 +44,7 @@ def test_existing_pr_disabled_branch(env, project, repo, config, users, page):
# triggered cleanup should have deleted the staging for the disabled `other` # triggered cleanup should have deleted the staging for the disabled `other`
# target branch # target branch
with pytest.raises(AssertionError, match=r'Not Found'): with pytest.raises(AssertionError, match=r'Not Found'):
repo.get_ref('heads/staging.other') repo.get_ref('staging.other')
# the PR should not have been closed implicitly # the PR should not have been closed implicitly
assert pr_id.state == 'ready' assert pr_id.state == 'ready'

View File

@ -1,4 +1,3 @@
import datetime
import functools import functools
from itertools import repeat from itertools import repeat

View File

@ -1,4 +1,4 @@
from utils import Commit, to_pr, make_basic, prevent_unstaging from utils import Commit, to_pr, prevent_unstaging
def test_staging_disabled_branch(env, project, repo, config): def test_staging_disabled_branch(env, project, repo, config):