Repository: fedora-infra/bodhi

Issue:
Build uncorrectly untag when update edited
Following the report of https://pagure.io/fedora-infrastructure/issue/8818#comment-640432

It seems that bodhi is not managing correctly the tags when an update is edited. The Update https://bodhi.fedoraproject.org/updates/FEDORA-2020-369ab3db3d add the following build added `gala-3.3.0-1.fc32` and a buildroot override was created for it but it seems that the build was untagged for it

we can see the tag history of the build using the following command `koji list-tag-history --all --package gala | grep 3.3.0-1.fc32`


Discussion:
I tried to get a chronological order of things (time showed here is UTC+2):
`koji list-tag-history --all --package gala | grep 3.3.0-1.fc32`

**gala-3.3.0-1.fc32 has been built**
`Fri Apr  3 23:04:04 2020: gala-3.3.0-1.fc32 tagged into f32-updates-candidate by decathorpe`

**a buildroot override for gala-3.3.0-1.fc32 is created in Bodhi**
`Fri Apr  3 23:13:44 2020: gala-3.3.0-1.fc32 tagged into f32-override by bodhi`

**gala-3.3.0-1.fc32 is pushed as a replacement in the existing update**
```
Sat Apr  4 00:53:18 2020: gala-3.3.0-1.fc32 untagged from f32-updates-candidate by bodhi
Sat Apr  4 00:53:18 2020: gala-3.3.0-1.fc32 untagged from f32-override by bodhi
Sat Apr  4 00:53:22 2020: gala-3.3.0-1.fc32 tagged into f32-updates-candidate by bodhi
Sat Apr  4 00:53:23 2020: gala-3.3.0-1.fc32 tagged into f32-signing-pending by bodhi
Sat Apr  4 00:53:26 2020: gala-3.3.0-1.fc32 tagged into f32-updates-candidate by bodhi
Sat Apr  4 00:53:26 2020: gala-3.3.0-1.fc32 untagged from f32-updates-candidate by bodhi
Sat Apr  4 00:53:45 2020: gala-3.3.0-1.fc32 tagged into f32-updates-testing-pending by autopen
Sat Apr  4 00:53:45 2020: gala-3.3.0-1.fc32 untagged from f32-signing-pending by autopen
```
In the end, everything is ok: gala-3.3.0-1.fc32 is tagged into f32-updates-testing-pending.
We probably want to check why we're tagging and untagging it into f32-updates-candidate twice...

**the update is pushed to testing**
```
Sat Apr  4 06:21:37 2020: gala-3.3.0-1.fc32 untagged from f32-updates-candidate by bodhi
Sat Apr  4 06:21:37 2020: gala-3.3.0-1.fc32 tagged into f32-updates-testing by bodhi
Sat Apr  4 06:22:56 2020: gala-3.3.0-1.fc32 untagged from f32-updates-testing-pending by bodhi
```
Now we have gala-3.3.0-1.fc32 tagged f32-updates-testing

**elementary-greeter-5.0.3-1.fc32 is pushed as a replacement in the existing update**
```
Mon Apr  6 00:50:14 2020: gala-3.3.0-1.fc32 untagged from f32-updates-testing by bodhi
Mon Apr  6 00:50:15 2020: gala-3.3.0-1.fc32 tagged into f32-updates-candidate by bodhi
Mon Apr  6 01:10:42 2020: gala-3.3.0-1.fc32 untagged from f32-updates-candidate by bodhi
Mon Apr  6 01:10:44 2020: gala-3.3.0-1.fc32 tagged into f32-updates-candidate by bodhi
Mon Apr  6 01:10:46 2020: gala-3.3.0-1.fc32 tagged into f32-signing-pending by bodhi
Mon Apr  6 01:10:47 2020: gala-3.3.0-1.fc32 tagged into f32-updates-candidate by bodhi
Mon Apr  6 01:10:47 2020: gala-3.3.0-1.fc32 untagged from f32-updates-candidate by bodhi
Mon Apr  6 01:10:50 2020: gala-3.3.0-1.fc32 tagged into f32-updates-testing-pending by autopen
Mon Apr  6 01:10:50 2020: gala-3.3.0-1.fc32 untagged from f32-signing-pending by autopen
```
All the builds in the update have f32-updates-testing tag removed and are re-tagged into f32-updates-testing-pending

**the update is pushed again to testing**
```
Mon Apr  6 03:06:12 2020: gala-3.3.0-1.fc32 untagged from f32-updates-candidate by bodhi
Mon Apr  6 03:06:12 2020: gala-3.3.0-1.fc32 tagged into f32-updates-testing by bodhi
Mon Apr  6 03:06:23 2020: gala-3.3.0-1.fc32 untagged from f32-updates-testing-pending by bodhi
```
We have gala-3.3.0-1.fc32 tagged f32-updates-testing again

**the buildroot override is activated again** 
`Mon Apr  6 12:03:35 2020: gala-3.3.0-1.fc32 tagged into f32-override by bodhi`

**elementary-greeter-5.0.3-1.fc32 is pushed as a replacement in the existing update**
```
Mon Apr  6 14:24:40 2020: gala-3.3.0-1.fc32 untagged from f32-updates-testing by bodhi
Mon Apr  6 14:24:41 2020: gala-3.3.0-1.fc32 untagged from f32-override by bodhi
Mon Apr  6 14:24:43 2020: gala-3.3.0-1.fc32 tagged into f32-updates-candidate by bodhi
Mon Apr  6 17:48:55 2020: gala-3.3.0-1.fc32 untagged from f32-updates-candidate by bodhi
Mon Apr  6 17:48:57 2020: gala-3.3.0-1.fc32 tagged into f32-updates-candidate by bodhi
Mon Apr  6 17:48:58 2020: gala-3.3.0-1.fc32 tagged into f32-signing-pending by bodhi
Mon Apr  6 17:49:00 2020: gala-3.3.0-1.fc32 tagged into f32-updates-candidate by bodhi
Mon Apr  6 17:49:00 2020: gala-3.3.0-1.fc32 untagged from f32-updates-candidate by bodhi
Mon Apr  6 17:49:03 2020: gala-3.3.0-1.fc32 tagged into f32-updates-testing-pending by autopen
Mon Apr  6 17:49:03 2020: gala-3.3.0-1.fc32 untagged from f32-signing-pending by autopen
```
gala-3.3.0-1.fc32 is untagged from f32-override but I suppose the BR override in Bodhi isn't expired, since it's still active now.

**the update is pushed again to testing**
```
Tue Apr  7 02:14:34 2020: gala-3.3.0-1.fc32 untagged from f32-updates-candidate by bodhi
Tue Apr  7 02:14:34 2020: gala-3.3.0-1.fc32 tagged into f32-updates-testing by bodhi [still active]
Tue Apr  7 02:15:08 2020: gala-3.3.0-1.fc32 untagged from f32-updates-testing-pending by bodhi
```

Apart from all those `updates-candidate` tagging and untagging, the only issue I see is that Bodhi isn't expiring the buildroot override while it correctly untag the build.
See #699 #798 #867 #1947 #3978 

...should we fix this? :-p

Resolving patch:
diff --git a/bodhi/server/models.py b/bodhi/server/models.py
--- a/bodhi/server/models.py
+++ b/bodhi/server/models.py
@@ -3363,7 +3363,7 @@ def unpush(self, db):
             raise BodhiException("Can't unpush a %s update"
                                  % self.status.description)
 
-        self.untag(db)
+        self.untag(db, preserve_override=True)
 
         for build in self.builds:
             koji.tagBuild(self.release.candidate_tag, build.nvr, force=True)
@@ -3402,12 +3402,13 @@ def revoke(self):
 
         self.request = None
 
-    def untag(self, db):
+    def untag(self, db, preserve_override: bool = False):
         """
         Untag all of the :class:`Builds <Build>` in this update.
 
         Args:
             db (sqlalchemy.orm.session.Session): A database session.
+            preserve_override: whether to preserve the override tag or not
         """
         log.info("Untagging %s", self.alias)
         koji = buildsys.get_session()
@@ -3416,7 +3417,10 @@ def untag(self, db):
             for tag in build.get_tags():
                 # Only remove tags that we know about
                 if tag in tag_rels:
-                    koji.untagBuild(tag, build.nvr, force=True)
+                    if preserve_override and tag == self.release.override_tag:
+                        log.info("Skipping override tag")
+                    else:
+                        koji.untagBuild(tag, build.nvr, force=True)
                 else:
                     log.info("Skipping tag that we don't know about: %s" % tag)
         self.pushed = False


Test patch:
diff --git a/bodhi/tests/server/test_models.py b/bodhi/tests/server/test_models.py
--- a/bodhi/tests/server/test_models.py
+++ b/bodhi/tests/server/test_models.py
@@ -2946,6 +2946,23 @@ def test_unpush_pending_stable(self):
             ('dist-f11-updates-testing-pending', 'TurboGears-1.0.8-3.fc11'),
             ('dist-f11-updates-pending', 'TurboGears-1.0.8-3.fc11')]
 
+    @mock.patch('bodhi.server.models.log.info')
+    def test_unpush_update(self, info):
+        """Unpushing an update shouldn't clear the override tag from builds."""
+        self.obj.status = UpdateStatus.testing
+        assert len(self.obj.builds) == 1
+        b = self.obj.builds[0]
+        release = self.obj.release
+        koji = buildsys.get_session()
+        koji.__tagged__[b.nvr] = [release.testing_tag,
+                                  release.pending_signing_tag,
+                                  release.pending_testing_tag,
+                                  release.override_tag,
+                                  # Add an unknown tag that we shouldn't touch
+                                  release.dist_tag + '-compose']
+        self.obj.unpush(self.db)
+        info.assert_any_call("Skipping override tag")
+
     @mock.patch('bodhi.server.models.log.debug')
     def test_unpush_stable(self, debug):
         """unpush() should raise a BodhiException on a stable update."""