From 2d73e083f47c98cea58043ce926cb0075d12520a Mon Sep 17 00:00:00 2001
From: sarah256 <srieger@bu.edu>
Date: Feb 24 2020 16:03:49 +0000
Subject: Populate builds list with reused builds


---

diff --git a/freshmaker/logger.py b/freshmaker/logger.py
index 570d7ab..3b5d113 100644
--- a/freshmaker/logger.py
+++ b/freshmaker/logger.py
@@ -88,7 +88,7 @@ def init_logging(conf):
 
         log = logging.getLogger()
         log.propagate = False
-        log.addHandler(journal.JournalHandler())
+        log.addHandler(journal.JournaldLogHandler())
     else:
         logging.basicConfig(filename=conf.log_file, level=conf.log_level,
                             format=log_format)
diff --git a/freshmaker/migrations/alembic.ini b/freshmaker/migrations/alembic.ini
index f8ed480..d676023 100644
--- a/freshmaker/migrations/alembic.ini
+++ b/freshmaker/migrations/alembic.ini
@@ -1,6 +1,7 @@
 # A generic, single database configuration.
 
 [alembic]
+script_location = migrations
 # template used to generate migration files
 # file_template = %%(rev)s_%%(slug)s
 
diff --git a/freshmaker/migrations/versions/9df9f02e6903_.py b/freshmaker/migrations/versions/9df9f02e6903_.py
new file mode 100644
index 0000000..709b56d
--- /dev/null
+++ b/freshmaker/migrations/versions/9df9f02e6903_.py
@@ -0,0 +1,26 @@
+"""Add where reused builds are reused from
+
+Revision ID: 9df9f02e6903
+Revises: 2358b6f55f24
+Create Date: 2020-02-03 13:48:45.665684
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '9df9f02e6903'
+down_revision = '2358b6f55f24'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.add_column('artifact_builds', sa.Column('reused_from', sa.Integer(), nullable=True))
+    # ### end Alembic commands ###
+
+
+def downgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.drop_column('artifact_builds', 'reused_from')
+    # ### end Alembic commands ###
diff --git a/freshmaker/models.py b/freshmaker/models.py
index e143b73..3a4adf6 100644
--- a/freshmaker/models.py
+++ b/freshmaker/models.py
@@ -532,11 +532,15 @@ class ArtifactBuild(FreshmakerBase):
 
     composes = db.relationship('ArtifactBuildCompose', back_populates='build')
 
+    # If a build has been reused, this will be the ID of the event that it came
+    # from. If the build has not been reused, this will be None
+    reused_from = db.Column(db.Integer, nullable=True)
+
     @classmethod
     def create(cls, session, event, name, type,
                build_id=None, dep_on=None, state=None,
                original_nvr=None, rebuilt_nvr=None,
-               rebuild_reason=0):
+               rebuild_reason=0, reused_from=None):
 
         now = datetime.utcnow()
         build = cls(
@@ -549,7 +553,8 @@ class ArtifactBuild(FreshmakerBase):
             build_id=build_id,
             time_submitted=now,
             dep_on=dep_on,
-            rebuild_reason=rebuild_reason
+            rebuild_reason=rebuild_reason,
+            reused_from=reused_from,
         )
         session.add(build)
         return build
@@ -671,7 +676,8 @@ class ArtifactBuild(FreshmakerBase):
             "url": build_url,
             "build_args": build_args,
             "odcs_composes": [rel.compose.odcs_compose_id for rel in self.composes],
-            "rebuild_reason": RebuildReason(self.rebuild_reason or 0).name.lower()
+            "rebuild_reason": RebuildReason(self.rebuild_reason or 0).name.lower(),
+            "reused_from": self.reused_from,
         }
 
     def get_root_dep_on(self):
diff --git a/freshmaker/views.py b/freshmaker/views.py
index 7dafffc..ee4c821 100644
--- a/freshmaker/views.py
+++ b/freshmaker/views.py
@@ -519,7 +519,32 @@ class BuildAPI(MethodView):
         # event based on the data. Currently it generates just
         # ManualRebuildWithAdvisoryEvent.
         parser = FreshmakerManualRebuildParser()
-        db_event = _create_rebuild_event_from_request(db.session, parser, request)
+        event = parser.parse_post_data(data)
+
+        # Store the event into database, so it gets the ID which we can return
+        # to client sending this POST request. The client can then use the ID
+        # to check for the event status.
+        db_event = models.Event.get_or_create_from_event(db.session, event)
+        if db_event:
+            db_event.requester = g.user.username
+            db_event.requested_rebuilds = " ".join(event.container_images)
+
+        # We need to check for successful builds, because if they are successful
+        # then they can be reused.
+        if dependent_event and dependent_event.builds:
+            for build in dependent_event.builds:
+                if build.state == 1:
+                    build.reused_from = dependent_event.id
+                    db_event.builds.append(build)
+
+        if event.requester_metadata_json:
+            db_event.requester_metadata = json.dumps(event.requester_metadata_json)
+        if dependent_event:
+            dependency = db_event.add_event_dependency(db.session, dependent_event)
+            if not dependency:
+                log.warn('Dependency between {} and {} could not be added!'.format(
+                    event.freshmaker_event_id, dependent_event.id))
+        db.session.commit()
 
         # Forward the POST data (including the msg_id of the database event we
         # added to DB) to backend using UMB messaging. Backend will then
diff --git a/tests/test_views.py b/tests/test_views.py
index 9b59d8a..2fdea61 100644
--- a/tests/test_views.py
+++ b/tests/test_views.py
@@ -785,6 +785,40 @@ class TestManualTriggerRebuild(ViewBaseTest):
            'from_advisory_id')
     @patch('freshmaker.parsers.internal.manual_rebuild.time.time')
     @patch('freshmaker.models.Event.add_event_dependency')
+    def test_dependent_manual_rebuild_on_existing_event_with_builds(self, add_dependency, time,
+                                                                    from_advisory_id, publish):
+        event = models.Event.create(db.session,
+                                    "2017-00000000-0000-0000-0000-000000000003",
+                                    "105", events.TestingEvent)
+        build = models.ArtifactBuild.create(db.session, name='test-build', state=1, event=event, type=1)
+        event.builds.append(build)
+        db.session.commit()
+        time.return_value = 123
+        from_advisory_id.return_value = ErrataAdvisory(
+            105, 'name', 'RHEL_PREP', ['rpm'])
+
+        payload = {
+            'errata_id': 105,
+            'container_images': ['foo-1-2'],
+            'freshmaker_event_id': 1,
+        }
+        with self.test_request_context(user='root'):
+            resp = self.client.post('/api/1/builds/', json=payload, content_type='application/json')
+        data = resp.json
+        # Other fields are predictible.
+        self.assertEqual(data['requested_rebuilds'], ["foo-1-2"])
+        assert add_dependency.call_count == 1
+        assert "105" == add_dependency.call_args[0][1].search_key
+        publish.assert_called_once_with(
+            'manual.rebuild',
+            {'msg_id': 'manual_rebuild_123', u'errata_id': 105,
+             'container_images': ["foo-1-2"], 'freshmaker_event_id': 1})
+
+    @patch('freshmaker.messaging.publish')
+    @patch('freshmaker.parsers.internal.manual_rebuild.ErrataAdvisory.'
+           'from_advisory_id')
+    @patch('freshmaker.parsers.internal.manual_rebuild.time.time')
+    @patch('freshmaker.models.Event.add_event_dependency')
     def test_dependent_manual_rebuild_on_existing_event_no_errata_id(
         self, add_dependency, time, from_advisory_id, publish,
     ):

