Skip to content

Commit

Permalink
Create updates from a Koji tag.
Browse files Browse the repository at this point in the history
This lets users specify a Koji tag instead of an explicit set of builds,
from which the latest component builds will be pulled.

Signed-off-by: Nils Philippsen <nils@redhat.com>
  • Loading branch information
nphilipp committed May 29, 2019
1 parent a62b482 commit 58e8955
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 3 deletions.
5 changes: 5 additions & 0 deletions bodhi/server/schemas.py
Expand Up @@ -170,6 +170,11 @@ class SaveUpdateSchema(CSRFProtectedSchema, colander.MappingSchema):
builds = Builds(colander.Sequence(accept_scalar=True),
preparer=[util.splitter])

from_tag = colander.SchemaNode(
colander.String(),
missing=None,
)

bugs = Bugs(colander.Sequence(accept_scalar=True), missing=None, preparer=[util.splitter])

close_bugs = colander.SchemaNode(
Expand Down
23 changes: 20 additions & 3 deletions bodhi/server/services/updates.py
Expand Up @@ -26,7 +26,7 @@
from sqlalchemy.sql import or_
from requests import RequestException, Timeout as RequestsTimeout

from bodhi.server import log, security
from bodhi.server import buildsys, log, security
from bodhi.server.exceptions import BodhiException, LockedUpdateException
from bodhi.server.models import (
Update,
Expand Down Expand Up @@ -432,6 +432,10 @@ def new_update(request):
edit an existing update, the update's alias must be specified in
the ``edited`` parameter.
If the ``from_tag`` parameter is specified and ``builds`` is missing or
empty, the list of builds will be filled with the latest builds in this
Koji tag.
Args:
request (pyramid.request): The current request.
"""
Expand All @@ -442,14 +446,25 @@ def new_update(request):
# it since the models don't care about a csrf argument.
data.pop('csrf_token')

build_nvrs = data.get('builds', [])
from_tag = data.get('from_tag')

if from_tag and not build_nvrs:
# If from_tag is set and build_nvrs (`builds` in the request) is empty,
# fill from latest builds in the submitted Koji tag. This lets users
# submit the builds when editing in order to skip this step.
koji = buildsys.get_session()

build_nvrs = [b['nvr'] for b in koji.listTagged(from_tag, latest=True)]

caveats = []
try:

releases = set()
builds = []

# Create the Package and Build entities
for nvr in data['builds']:
for nvr in build_nvrs:
name, version, release = request.buildinfo[nvr]['nvr']

package = Package.get_or_create(request.buildinfo[nvr])
Expand Down Expand Up @@ -481,7 +496,7 @@ def new_update(request):
# were tied to the previous session that has now been terminated.
builds = []
releases = set()
for nvr in data['builds']:
for nvr in build_nvrs:
# At this moment, we are sure the builds are in the database (that is what the commit
# was for actually).
build = Build.get(nvr)
Expand All @@ -494,6 +509,7 @@ def new_update(request):

data['release'] = list(releases)[0]
data['builds'] = [b.nvr for b in builds]
data['from_tag'] = from_tag
result, _caveats = Update.edit(request, data)
caveats.extend(_caveats)
else:
Expand All @@ -509,6 +525,7 @@ def new_update(request):
_data = copy.copy(data) # Copy it because .new(..) mutates it
_data['builds'] = [b for b in builds if b.release == release]
_data['release'] = release
_data['from_tag'] = from_tag

log.info('Creating new update: %r' % _data['builds'])
result, _caveats = Update.new(request, _data)
Expand Down
96 changes: 96 additions & 0 deletions bodhi/tests/server/services/test_updates.py
Expand Up @@ -277,6 +277,43 @@ def test_new_rpm_update_koji_error(self, *args):
self.assertEqual(up['errors'][0]['description'],
"Koji error getting build: bodhi-2.0.0-2.fc17")

@mock.patch.dict('bodhi.server.validators.config', {'acl_system': 'dummy'})
@mock.patch(**mock_uuid4_version1)
@mock.patch(**mock_valid_requirements)
def test_new_rpm_update_from_tag(self, *args):
"""Test creating an update using builds from a Koji tag."""
# We don't want the new update to obsolete the existing one.
self.db.delete(Update.query.one())

update = self.get_update(builds=None, from_tag='f17-updates-candidate')
with fml_testing.mock_sends(update_schemas.UpdateRequestTestingV1):
r = self.app.post_json('/updates/', update)

up = r.json_body
self.assertEqual(up['title'], 'TurboGears-1.0.2.2-3.fc17')
self.assertEqual(up['builds'][0]['nvr'], 'TurboGears-1.0.2.2-3.fc17')
self.assertEqual(up['status'], 'pending')
self.assertEqual(up['request'], 'testing')
self.assertEqual(up['user']['name'], 'guest')
self.assertEqual(up['release']['name'], 'F17')
self.assertEqual(up['type'], 'bugfix')
self.assertEqual(up['content_type'], 'rpm')
self.assertEqual(up['severity'], 'unspecified')
self.assertEqual(up['suggest'], 'unspecified')
self.assertEqual(up['close_bugs'], True)
self.assertEqual(up['notes'], 'this is a test update')
self.assertIsNotNone(up['date_submitted'])
self.assertIsNone(up['date_modified'])
self.assertIsNone(up['date_approved'])
self.assertIsNone(up['date_pushed'])
self.assertEqual(up['locked'], False)
self.assertIn(up['alias'],
(f'FEDORA-{YEAR}-033713b73b',
f'FEDORA-{YEAR + 1}-033713b73b'))
self.assertEqual(up['karma'], 0)
self.assertEqual(up['requirements'], 'rpmlint')
self.assertEqual(up['from_tag'], 'f17-updates-candidate')

@mock.patch(**mock_valid_requirements)
def test_koji_config_url(self, *args):
"""
Expand Down Expand Up @@ -2738,6 +2775,65 @@ def test_edit_update(self, *args):
self.assertEqual(self.db.query(RpmBuild).filter_by(nvr='bodhi-2.0.0-2.fc17').first(),
None)

@mock.patch(**mock_uuid4_version1)
@mock.patch(**mock_valid_requirements)
def test_edit_rpm_update_from_tag(self, *args):
"""Test editing an update using (updated) builds from a Koji tag."""
# We don't want the new update to obsolete the existing one.
self.db.delete(Update.query.one())

# We don't want an existing buildroot override to clutter the messages.
self.db.delete(BuildrootOverride.query.one())

update = self.get_update(from_tag='f17-updates-candidate')
with fml_testing.mock_sends(update_schemas.UpdateRequestTestingV1):
r = self.app.post_json('/updates/', update)

update['edited'] = r.json['alias']
update['builds'] = 'bodhi-2.0.0-3.fc17'
update['requirements'] = 'upgradepath'

with fml_testing.mock_sends(update_schemas.UpdateEditV1):
r = self.app.post_json('/updates/', update)

up = r.json_body
self.assertEqual(up['title'], 'bodhi-2.0.0-3.fc17')
self.assertEqual(up['status'], 'pending')
self.assertEqual(up['request'], 'testing')
self.assertEqual(up['user']['name'], 'guest')
self.assertEqual(up['release']['name'], 'F17')
self.assertEqual(up['type'], 'bugfix')
self.assertEqual(up['severity'], 'unspecified')
self.assertEqual(up['suggest'], 'unspecified')
self.assertEqual(up['close_bugs'], True)
self.assertEqual(up['notes'], 'this is a test update')
self.assertIsNotNone(up['date_submitted'])
self.assertIsNotNone(up['date_modified'], None)
self.assertEqual(up['date_approved'], None)
self.assertEqual(up['date_pushed'], None)
self.assertEqual(up['locked'], False)
self.assertEqual(up['alias'], 'FEDORA-%s-033713b73b' % YEAR)
self.assertEqual(up['karma'], 0)
self.assertEqual(up['requirements'], 'upgradepath')
comment = textwrap.dedent("""
guest edited this update.
New build(s):
- bodhi-2.0.0-3.fc17
Removed build(s):
- bodhi-2.0-1.fc17
Karma has been reset.
""").strip()
self.assertMultiLineEqual(up['comments'][-1]['text'], comment)
self.assertEqual(len(up['builds']), 1)
self.assertEqual(up['builds'][0]['nvr'], 'bodhi-2.0.0-3.fc17')
self.assertEqual(self.db.query(RpmBuild).filter_by(nvr='bodhi-2.0.0-2.fc17').first(),
None)

@mock.patch(**mock_valid_requirements)
def test_edit_testing_update_with_new_builds(self, *args):
nvr = 'bodhi-2.0.0-2.fc17'
Expand Down

0 comments on commit 58e8955

Please sign in to comment.