2022-06-03 17:08:49 +07:00
|
|
|
import requests
|
|
|
|
|
2022-11-04 21:22:36 +07:00
|
|
|
from utils import Commit, to_pr, seen
|
[FIX] runbot_merge: ensure PR description is correct on merge
Because sometimes github updates are missed (usually because github
never triggers it), it's possible for the mergebot's view of a PR
description to be incorrect. In that case, the PR may get merged with
the wrong merge message entirely, through no fault of the user.
Since we already fetch the PR info when staging it, there's very
little overhead to checking that the PR message we store is correct
then, and update it if it's not. This means the forward-port's
description should also be correct.
While at it, clean the forward port PR's creation a bit:
- there should always be a message since the title is required on
PRs (only the body can be missing), therefore no need to check that
- as we're adding a bunch of pseudo-headers, there always is a body,
no need for the condition
- inline the `pr_data` and `URL`: they were extracted for the support
of draft PRs, since that's been removed it's now unnecessary
Fixes #530
2021-09-24 13:03:24 +07:00
|
|
|
|
|
|
|
|
2020-03-16 20:16:01 +07:00
|
|
|
def test_partner_merge(env):
|
|
|
|
p_src = env['res.partner'].create({
|
|
|
|
'name': "xxx",
|
|
|
|
'github_login': 'xxx'
|
|
|
|
})
|
|
|
|
# proper login with useful info
|
|
|
|
p_dest = env['res.partner'].create({
|
|
|
|
'name': 'Partner P. Partnersson',
|
|
|
|
'github_login': ''
|
|
|
|
})
|
|
|
|
|
|
|
|
env['base.partner.merge.automatic.wizard'].create({
|
|
|
|
'state': 'selection',
|
|
|
|
'partner_ids': (p_src + p_dest).ids,
|
|
|
|
'dst_partner_id': p_dest.id,
|
2021-10-06 18:03:03 +07:00
|
|
|
}).action_merge()
|
2020-03-16 20:16:01 +07:00
|
|
|
assert not p_src.exists()
|
|
|
|
assert p_dest.name == 'Partner P. Partnersson'
|
|
|
|
assert p_dest.github_login == 'xxx'
|
2021-03-01 20:42:20 +07:00
|
|
|
|
|
|
|
def test_name_search(env):
|
|
|
|
""" PRs should be findable by:
|
|
|
|
|
|
|
|
* number
|
|
|
|
* display_name (`repository#number`)
|
|
|
|
* label
|
|
|
|
|
|
|
|
This way we can find parents or sources by these informations.
|
|
|
|
"""
|
|
|
|
p = env['runbot_merge.project'].create({
|
|
|
|
'name': 'proj',
|
|
|
|
'github_token': 'no',
|
|
|
|
})
|
|
|
|
b = env['runbot_merge.branch'].create({
|
|
|
|
'name': 'target',
|
|
|
|
'project_id': p.id
|
|
|
|
})
|
|
|
|
r = env['runbot_merge.repository'].create({
|
|
|
|
'name': 'repo',
|
|
|
|
'project_id': p.id,
|
|
|
|
})
|
|
|
|
|
|
|
|
baseline = {'target': b.id, 'repository': r.id}
|
|
|
|
PRs = env['runbot_merge.pull_requests']
|
|
|
|
prs = PRs.create({**baseline, 'number': 1964, 'label': 'victor:thump', 'head': 'a', 'message': 'x'})\
|
|
|
|
| PRs.create({**baseline, 'number': 1959, 'label': 'marcus:frankenstein', 'head': 'b', 'message': 'y'})\
|
|
|
|
| PRs.create({**baseline, 'number': 1969, 'label': 'victor:patch-1', 'head': 'c', 'message': 'z'})
|
|
|
|
pr0, pr1, pr2 = prs.name_get()
|
|
|
|
|
|
|
|
assert PRs.name_search('1964') == [pr0]
|
|
|
|
assert PRs.name_search('1969') == [pr2]
|
|
|
|
|
|
|
|
assert PRs.name_search('frank') == [pr1]
|
|
|
|
assert PRs.name_search('victor') == [pr2, pr0]
|
|
|
|
|
|
|
|
assert PRs.name_search('thump') == [pr0]
|
|
|
|
|
|
|
|
assert PRs.name_search('repo') == [pr2, pr0, pr1]
|
|
|
|
assert PRs.name_search('repo#1959') == [pr1]
|
[FIX] runbot_merge: ensure PR description is correct on merge
Because sometimes github updates are missed (usually because github
never triggers it), it's possible for the mergebot's view of a PR
description to be incorrect. In that case, the PR may get merged with
the wrong merge message entirely, through no fault of the user.
Since we already fetch the PR info when staging it, there's very
little overhead to checking that the PR message we store is correct
then, and update it if it's not. This means the forward-port's
description should also be correct.
While at it, clean the forward port PR's creation a bit:
- there should always be a message since the title is required on
PRs (only the body can be missing), therefore no need to check that
- as we're adding a bunch of pseudo-headers, there always is a body,
no need for the condition
- inline the `pr_data` and `URL`: they were extracted for the support
of draft PRs, since that's been removed it's now unnecessary
Fixes #530
2021-09-24 13:03:24 +07:00
|
|
|
|
2022-06-03 17:08:49 +07:00
|
|
|
def test_unreviewer(env, project, port):
|
|
|
|
repo = env['runbot_merge.repository'].create({
|
|
|
|
'project_id': project.id,
|
|
|
|
'name': 'a_test_repo',
|
|
|
|
'status_ids': [(0, 0, {'context': 'status'})]
|
|
|
|
})
|
|
|
|
p = env['res.partner'].create({
|
|
|
|
'name': 'George Pearce',
|
|
|
|
'github_login': 'emubitch',
|
|
|
|
'review_rights': [(0, 0, {'repository_id': repo.id, 'review': True})]
|
|
|
|
})
|
|
|
|
|
|
|
|
r = requests.post(f'http://localhost:{port}/runbot_merge/get_reviewers', json={
|
|
|
|
'jsonrpc': '2.0',
|
|
|
|
'id': None,
|
|
|
|
'method': 'call',
|
|
|
|
'params': {},
|
|
|
|
})
|
|
|
|
r.raise_for_status()
|
|
|
|
assert 'error' not in r.json()
|
|
|
|
assert r.json()['result'] == ['emubitch']
|
|
|
|
|
|
|
|
r = requests.post(f'http://localhost:{port}/runbot_merge/remove_reviewers', json={
|
|
|
|
'jsonrpc': '2.0',
|
|
|
|
'id': None,
|
|
|
|
'method': 'call',
|
|
|
|
'params': {'github_logins': ['emubitch']},
|
|
|
|
})
|
|
|
|
r.raise_for_status()
|
|
|
|
assert 'error' not in r.json()
|
|
|
|
|
|
|
|
assert p.review_rights == env['res.partner.review']
|
2022-11-04 21:22:36 +07:00
|
|
|
|
|
|
|
def test_staging_post_update(env, project, make_repo, setreviewers, users, config):
|
|
|
|
"""Because statuses come from commits, it's possible to update the commits
|
|
|
|
of a staging after that staging has completed (one way or the other), either
|
|
|
|
by sending statuses directly (e.g. rebuilding, for non-deterministic errors)
|
|
|
|
or just using the staging's head commit in a branch.
|
|
|
|
|
|
|
|
This makes post-mortem analysis quite confusing, so stagings should
|
|
|
|
"lock in" their statuses once they complete.
|
|
|
|
"""
|
|
|
|
repo = make_repo('repo')
|
|
|
|
project.write({'repo_ids': [(0, 0, {
|
|
|
|
'name': repo.name,
|
|
|
|
'group_id': False,
|
|
|
|
'required_statuses': 'legal/cla,ci/runbot'
|
|
|
|
})]})
|
|
|
|
setreviewers(*project.repo_ids)
|
|
|
|
|
|
|
|
with repo:
|
|
|
|
[m] = repo.make_commits(None, Commit('initial', tree={'m': 'm'}), ref='heads/master')
|
|
|
|
|
|
|
|
repo.make_commits(m, Commit('thing', tree={'m': 'c'}), ref='heads/other')
|
|
|
|
pr = repo.make_pr(target='master', head='other')
|
|
|
|
repo.post_status(pr.head, 'success', 'ci/runbot')
|
|
|
|
repo.post_status(pr.head, 'success', 'legal/cla')
|
|
|
|
pr.post_comment('hansen r+ rebase-merge', config['role_reviewer']['token'])
|
|
|
|
env.run_crons()
|
|
|
|
pr_id = to_pr(env, pr)
|
|
|
|
staging_id = pr_id.staging_id
|
|
|
|
assert staging_id
|
|
|
|
|
|
|
|
staging_head = repo.commit('staging.master')
|
|
|
|
with repo:
|
|
|
|
repo.post_status(staging_head, 'failure', 'ci/runbot')
|
|
|
|
env.run_crons()
|
|
|
|
assert pr_id.state == 'error'
|
|
|
|
assert staging_id.state == 'failure'
|
|
|
|
assert staging_id.statuses == [
|
|
|
|
[repo.name, 'ci/runbot', 'failure', ''],
|
|
|
|
]
|
|
|
|
|
|
|
|
with repo:
|
|
|
|
repo.post_status(staging_head, 'success', 'ci/runbot')
|
|
|
|
env.run_crons()
|
|
|
|
assert staging_id.state == 'failure'
|
|
|
|
assert staging_id.statuses == [
|
|
|
|
[repo.name, 'ci/runbot', 'failure', ''],
|
|
|
|
]
|