Repository: fedora-infra/bodhi

Issue:
Gracefully handle attempts to edit updates that don't exist.
I hit this traceback in staging with the `tools/test-python-fedora-api.py` script. It occurs when we try to edit an update that doesn't exist.

```
Traceback (most recent call last):
  File "/home/lmacken/.virtualenvs/bodhi-python2.7/lib/python2.7/site-packages/pyramid-1.6b2-py2.7.egg/pyramid/tweens.py", line
 20, in excview_tween
    response = handler(request)
  File "/home/lmacken/.virtualenvs/bodhi-python2.7/lib/python2.7/site-packages/pyramid-1.6b2-py2.7.egg/pyramid/router.py", line
 145, in handle_request
    view_name
  File "/home/lmacken/.virtualenvs/bodhi-python2.7/lib/python2.7/site-packages/pyramid-1.6b2-py2.7.egg/pyramid/view.py", line 5
41, in _call_view
    response = view_callable(context, request)
  File "/home/lmacken/.virtualenvs/bodhi-python2.7/lib/python2.7/site-packages/pyramid-1.6b2-py2.7.egg/pyramid/config/views.py"
, line 600, in __call__
    return view(context, request)
  File "/home/lmacken/.virtualenvs/bodhi-python2.7/lib/python2.7/site-packages/pyramid-1.6b2-py2.7.egg/pyramid/config/views.py"
, line 326, in attr_view
    return view(context, request)
  File "/home/lmacken/.virtualenvs/bodhi-python2.7/lib/python2.7/site-packages/pyramid-1.6b2-py2.7.egg/pyramid/config/views.py"
, line 302, in predicate_wrapper
    return view(context, request)
  File "/home/lmacken/.virtualenvs/bodhi-python2.7/lib/python2.7/site-packages/pyramid-1.6b2-py2.7.egg/pyramid/config/views.py"
, line 242, in _secured_view
    return view(context, request)
  File "/home/lmacken/.virtualenvs/bodhi-python2.7/lib/python2.7/site-packages/pyramid-1.6b2-py2.7.egg/pyramid/config/views.py"
, line 351, in rendered_view
    result = view(context, request)
  File "/home/lmacken/.virtualenvs/bodhi-python2.7/lib/python2.7/site-packages/pyramid-1.6b2-py2.7.egg/pyramid/config/views.py"
, line 505, in _requestonly_view
    response = view(request)
  File "/home/lmacken/.virtualenvs/bodhi-python2.7/lib/python2.7/site-packages/cornice-1.1.0-py2.7.egg/cornice/service.py", lin
e 564, in wrapper
    validator(request)
  File "/home/lmacken/code/github.com/bodhi/bodhi/validators.py", line 116, in validate_build_tags
    .filter_by(title=edited)\
AttributeError: 'NoneType' object has no attribute 'release'
```



Discussion:

Resolving patch:
diff --git a/bodhi/validators.py b/bodhi/validators.py
--- a/bodhi/validators.py
+++ b/bodhi/validators.py
@@ -112,10 +112,15 @@ def validate_build_tags(request):
     release = None
     if edited:
         valid_tags = tag_types['candidate'] + tag_types['testing']
-        release = request.db.query(Update)\
+        update = request.db.query(Update)\
                          .filter_by(title=edited)\
-                         .first()\
-                         .release
+                         .first()
+        if not update:
+            # No need to tack on any more errors here, since they should have
+            # already been added by `validate_builds`
+            return
+
+        release = update.release
         if not release:
             # If the edited update has no release, something went wrong a while
             # ago.  We're already in a corrupt state.  We can't perform the


Test patch:
diff --git a/bodhi/tests/functional/test_updates.py b/bodhi/tests/functional/test_updates.py
--- a/bodhi/tests/functional/test_updates.py
+++ b/bodhi/tests/functional/test_updates.py
@@ -2196,6 +2196,18 @@ def test_edit_update_bugs(self, publish, *args):
         self.assertEquals(up['status'], u'pending')
         self.assertEquals(up['request'], u'testing')
 
+    @mock.patch(**mock_valid_requirements)
+    @mock.patch('bodhi.notifications.publish')
+    def test_edit_missing_update(self, publish, *args):
+        """ Attempt to edit an update that doesn't exist """
+        build = 'bodhi-2.0.0-2.fc17'
+        edited = 'bodhi-1.0-1.fc17'
+        args = self.get_update(build)
+        args['edited'] = edited
+        r = self.app.post_json('/updates/', args, status=400).json_body
+        self.assertEquals(r['status'], 'error')
+        self.assertEquals(r['errors'][0]['description'], 'Cannot find update to edit: %s' % edited)
+
     @mock.patch(**mock_valid_requirements)
     @mock.patch('bodhi.notifications.publish')
     def test_edit_update_and_disable_features(self, publish, *args):