promoteBuild: split main function to _promote_build

This commit is contained in:
Yuming Zhu 2023-10-17 20:44:01 +08:00 committed by Yu Ming Zhu
parent 70518c01a1
commit c045bc7100
2 changed files with 98 additions and 90 deletions

View file

@ -13679,94 +13679,7 @@ class RootExports(object):
:rtype: dict
"""
context.session.assertLogin()
user = self.getLoggedInUser()
binfo = get_build(build, strict=strict)
if not binfo:
return None
if not binfo.get('draft'):
if strict:
raise koji.GenericError(f'Not a draft build: {binfo}')
else:
return None
old_release = binfo['release']
extra = binfo.get('extra') or {}
# get target release in binfo.extra
draft_info = extra.get('draft', {}).copy()
target_release = draft_info.get('target_release')
if not target_release:
if strict:
raise koji.GenericError(
f'draft.target_release not found in extra of build: {binfo}'
)
else:
return None
# task_id and volume_id are for apply_volume_policy
# drop id to get build by NVR
target_build = dslice(binfo, ['name', 'version', 'task_id', 'volume_id'])
target_build['release'] = target_release
old_build = get_build(target_build)
if old_build:
if strict:
raise koji.GenericError(f'Target build already exists: {old_build}')
else:
return None
# policy checks
policy_data = {
'build': binfo['id'],
'target_release': target_release
}
assert_policy('draft_promotion', policy_data, force=force)
# volume check, deny it if volume is changed as it's only allowed for admin
# after building, see applyVolumePolicy
new_volume = apply_volume_policy(target_build, strict=False, dry_run=True)
if new_volume is not None and new_volume['id'] != binfo['volume_id']:
# probably we can just apply the volume change here
if strict:
raise koji.GenericError(
f'Denial as volume will be changed to {new_volume["name"]}'
)
else:
return None
koji.plugin.run_callbacks(
'preBuildPromote',
draft_release=old_release,
target_release=target_release,
build=binfo,
user=user
)
# temp solution with python generated time, maybe better to be an event?
now = datetime.datetime.now()
extra['draft'] = draft_info
draft_info['promoted'] = True
draft_info['old_release'] = old_release
draft_info['promotion_time'] = encode_datetime(now)
draft_info['promotion_ts'] = now.timestamp()
draft_info['promoter'] = user['name']
extra = json.dumps(extra)
update = UpdateProcessor('build', clauses=['id=%(id)i'], values=binfo)
update.set(draft=False, release=target_release, extra=extra)
update.execute()
new_binfo = get_build(binfo['id'], strict=strict)
move_and_symlink(koji.pathinfo.build(binfo), koji.pathinfo.build(new_binfo))
ensure_volume_symlink(new_binfo)
for tag in list_tags(build=binfo['id']):
set_tag_update(tag['id'], 'DRAFT_PROMOTION')
koji.plugin.run_callbacks(
'postBuildPromote',
draft_release=old_release,
target_release=target_release,
build=new_binfo,
user=user
)
return new_binfo
return _promote_build(build, strict=strict, force=force)
def count(self, methodName, *args, **kw):
"""Execute the XML-RPC method with the given name and count the results.
@ -16056,3 +15969,99 @@ def _clean_draft_link(promoted_build):
# only unlink whe its a symlink.
if os.path.islink(draft_builddir):
os.unlink(draft_builddir)
def _promote_build(build, user=None, strict=True, force=False):
"""promote a draft build to a regular one"""
binfo = get_build(build, strict=strict)
if not binfo:
return None
if not binfo.get('draft'):
if strict:
raise koji.GenericError(f'Not a draft build: {binfo}')
else:
return None
old_release = binfo['release']
extra = binfo.get('extra') or {}
# get target release in binfo.extra
draft_info = extra.get('draft', {}).copy()
target_release = draft_info.get('target_release')
if not target_release:
if strict:
raise koji.GenericError(
f'draft.target_release not found in extra of build: {binfo}'
)
else:
return None
# task_id and volume_id are for apply_volume_policy
# drop id to get build by NVR
target_build = dslice(binfo, ['name', 'version', 'task_id', 'volume_id'])
target_build['release'] = target_release
old_build = get_build(target_build)
if old_build:
if strict:
raise koji.GenericError(f'Target build already exists: {old_build}')
else:
return None
user = get_user(user, strict=strict)
if not user and not strict:
return None
# policy checks
policy_data = {
'build': binfo['id'],
'target_release': target_release,
'user_id': user['id']
}
assert_policy('draft_promotion', policy_data, force=force)
# volume check, deny it if volume is changed as it's only allowed for admin
# after building, see applyVolumePolicy
new_volume = apply_volume_policy(target_build, strict=False, dry_run=True)
if new_volume is not None and new_volume['id'] != binfo['volume_id']:
# probably we can just apply the volume change here
if strict:
raise koji.GenericError(
f'Denial as volume will be changed to {new_volume["name"]}'
)
else:
return None
koji.plugin.run_callbacks(
'preBuildPromote',
draft_release=old_release,
target_release=target_release,
build=binfo,
user=user
)
# temp solution with python generated time, maybe better to be an event?
now = datetime.datetime.now()
extra['draft'] = draft_info
draft_info['promoted'] = True
draft_info['old_release'] = old_release
draft_info['promotion_time'] = encode_datetime(now)
draft_info['promotion_ts'] = now.timestamp()
draft_info['promoter'] = user['name']
extra = json.dumps(extra)
update = UpdateProcessor('build', clauses=['id=%(id)i'], values=binfo)
update.set(draft=False, release=target_release, extra=extra)
update.execute()
new_binfo = get_build(binfo['id'], strict=strict)
move_and_symlink(koji.pathinfo.build(binfo), koji.pathinfo.build(new_binfo))
ensure_volume_symlink(new_binfo)
for tag in list_tags(build=binfo['id']):
set_tag_update(tag['id'], 'DRAFT_PROMOTION')
koji.plugin.run_callbacks(
'postBuildPromote',
draft_release=old_release,
target_release=target_release,
build=new_binfo,
user=user
)
return new_binfo

View file

@ -25,8 +25,7 @@ class TestPromoteBuild(unittest.TestCase):
self.context = mock.patch('kojihub.kojihub.context').start()
self.context.session.assertLogin = mock.MagicMock()
self.user = {'id': 1, 'name': 'jdoe'}
self.getLoggedInUser = mock.patch.object(self.exports, 'getLoggedInUser',
return_value=self.user).start()
self.get_user = mock.patch('kojihub.kojihub.get_user', return_value=self.user).start()
self.get_build = mock.patch('kojihub.kojihub.get_build').start()
self.assert_policy = mock.patch('kojihub.kojihub.assert_policy').start()
self.apply_volume_policy = mock.patch('kojihub.kojihub.apply_volume_policy',