Repository: packit/packit-service
Issue: packit_api.up.local_project.git_repo is None in AbstractSyncReleaseHandler

Sentry Issue: [PCKT-002-PACKIT-SERVICE-549](https://sentry.io/organizations/red-hat-it/issues/3893427876/?referrer=github_integration)

```
AttributeError: 'NoneType' object has no attribute 'is_dirty'
  File "packit_service/worker/handlers/distgit.py", line 179, in sync_branch
    downstream_pr = self.packit_api.sync_release(
  File "packit/api.py", line 766, in sync_release
    if not force and self.up.is_dirty() and not use_local_content:
  File "packit/base_git.py", line 444, in is_dirty
    return self.local_project.git_repo.is_dirty()

AttributeError: 'NoneType' object has no attribute 'head'
  File "packit_service/worker/handlers/distgit.py", line 280, in run
    downstream_pr = self.sync_branch(
  File "packit_service/worker/handlers/distgit.py", line 212, in sync_branch
    self.packit_api.up.local_project.git_repo.head.reset(
```

creator: @lachmanfrantisek
notes:
* Looks like the `git_repo` is not filled during the API initialisation.
* ~~Problem should be caused by this (very nicely done!) refactor: https://github.com/packit/packit-service/commit/bf1b977f37b6f21bb083983db42884034dbf9dd1~~ (too old)  (Also, a few GitLab-related fixes has been included to the last release.)
* This problem cause `propose-downstream` to fail. (e.g. [here](https://github.com/rhinstaller/anaconda/runs/10840558704))

Changed files:
packit_service/worker/handlers/abstract.py, packit_service/worker/handlers/koji.py, packit_service/worker/handlers/distgit.py, tests/integration/test_handler.py, packit_service/worker/handlers/vm_image.py, packit_service/worker/handlers/testing_farm.py, packit_service/worker/handlers/forges.py, packit_service/worker/handlers/copr.py, tests/unit/test_distgit.py

diff --git a/packit_service/worker/handlers/abstract.py b/packit_service/worker/handlers/abstract.py
index b44e2e4c..ce9590bb 100644
--- a/packit_service/worker/handlers/abstract.py
+++ b/packit_service/worker/handlers/abstract.py
@@ -33,7 +33,7 @@ from packit_service.worker.checker.abstract import Checker
 
 from packit_service.worker.mixin import (
     Config,
-    PackitAPIWithDownstreamMixin,
+    PackitAPIProtocol,
 )
 
 logger = logging.getLogger(__name__)
@@ -219,7 +219,7 @@ class TaskName(str, enum.Enum):
     pull_from_upstream = "pull_from_upstream"
 
 
-class Handler(PackitAPIWithDownstreamMixin, Config):
+class Handler(PackitAPIProtocol, Config):
     def run(self) -> TaskResults:
         raise NotImplementedError("This should have been implemented.")
 
diff --git a/packit_service/worker/handlers/copr.py b/packit_service/worker/handlers/copr.py
index 869ef973..d836f346 100644
--- a/packit_service/worker/handlers/copr.py
+++ b/packit_service/worker/handlers/copr.py
@@ -59,6 +59,7 @@ from packit_service.worker.handlers.abstract import (
     run_for_check_rerun,
     RetriableJobHandler,
 )
+from packit_service.worker.mixin import PackitAPIWithDownstreamMixin
 from packit_service.worker.handlers.mixin import (
     GetCoprBuildEventMixin,
     GetCoprBuildJobHelperForIdMixin,
@@ -85,7 +86,9 @@ logger = logging.getLogger(__name__)
 @reacts_to(CheckRerunPullRequestEvent)
 @reacts_to(CheckRerunCommitEvent)
 @reacts_to(CheckRerunReleaseEvent)
-class CoprBuildHandler(RetriableJobHandler, GetCoprBuildJobHelperMixin):
+class CoprBuildHandler(
+    RetriableJobHandler, PackitAPIWithDownstreamMixin, GetCoprBuildJobHelperMixin
+):
     task_name = TaskName.copr_build
 
     def __init__(
@@ -111,7 +114,10 @@ class CoprBuildHandler(RetriableJobHandler, GetCoprBuildJobHelperMixin):
 
 
 class AbstractCoprBuildReportHandler(
-    JobHandler, GetCoprBuildJobHelperForIdMixin, GetCoprBuildEventMixin
+    JobHandler,
+    PackitAPIWithDownstreamMixin,
+    GetCoprBuildJobHelperForIdMixin,
+    GetCoprBuildEventMixin,
 ):
     @staticmethod
     def get_checkers() -> Tuple[Type[Checker], ...]:
diff --git a/packit_service/worker/handlers/distgit.py b/packit_service/worker/handlers/distgit.py
index d46c6105..a8d8c120 100644
--- a/packit_service/worker/handlers/distgit.py
+++ b/packit_service/worker/handlers/distgit.py
@@ -133,8 +133,8 @@ class SyncFromDownstream(
 class AbstractSyncReleaseHandler(
     RetriableJobHandler,
     ConfigFromEventMixin,
-    PackitAPIWithUpstreamMixin,
     LocalProjectMixin,
+    PackitAPIWithUpstreamMixin,
 ):
     helper_kls: type[SyncReleaseHelper]
     sync_release_job_type: SyncReleaseJobType
diff --git a/packit_service/worker/handlers/forges.py b/packit_service/worker/handlers/forges.py
index a642892c..7e56206e 100644
--- a/packit_service/worker/handlers/forges.py
+++ b/packit_service/worker/handlers/forges.py
@@ -34,14 +34,16 @@ from packit_service.worker.handlers.abstract import (
     TaskName,
     reacts_to,
 )
-from packit_service.worker.mixin import GetIssueMixin
+from packit_service.worker.mixin import GetIssueMixin, PackitAPIWithDownstreamMixin
 from packit_service.worker.result import TaskResults
 
 logger = logging.getLogger(__name__)
 
 
 @reacts_to(event=InstallationEvent)
-class GithubAppInstallationHandler(JobHandler, ConfigFromEventMixin):
+class GithubAppInstallationHandler(
+    JobHandler, ConfigFromEventMixin, PackitAPIWithDownstreamMixin
+):
     task_name = TaskName.installation
 
     # https://developer.github.com/v3/activity/events/types/#events-api-payload-28
@@ -145,7 +147,9 @@ class GithubAppInstallationHandler(JobHandler, ConfigFromEventMixin):
 
 
 @reacts_to(event=IssueCommentEvent)
-class GithubFasVerificationHandler(JobHandler, GetIssueMixin):
+class GithubFasVerificationHandler(
+    JobHandler, PackitAPIWithDownstreamMixin, GetIssueMixin
+):
     task_name = TaskName.github_fas_verification
 
     def __init__(
diff --git a/packit_service/worker/handlers/koji.py b/packit_service/worker/handlers/koji.py
index 1db4acf8..2f9ea722 100644
--- a/packit_service/worker/handlers/koji.py
+++ b/packit_service/worker/handlers/koji.py
@@ -50,6 +50,7 @@ from packit_service.worker.handlers.abstract import (
 from packit_service.worker.reporting import BaseCommitStatus
 from packit_service.worker.result import TaskResults
 from packit_service.worker.checker.koji import PermissionOnKoji
+from packit_service.worker.mixin import PackitAPIWithDownstreamMixin
 from packit_service.worker.handlers.mixin import GetKojiBuildJobHelperMixin
 
 logger = logging.getLogger(__name__)
@@ -70,7 +71,9 @@ logger = logging.getLogger(__name__)
 @reacts_to(CheckRerunPullRequestEvent)
 @reacts_to(CheckRerunCommitEvent)
 @reacts_to(CheckRerunReleaseEvent)
-class KojiBuildHandler(JobHandler, GetKojiBuildJobHelperMixin):
+class KojiBuildHandler(
+    JobHandler, PackitAPIWithDownstreamMixin, GetKojiBuildJobHelperMixin
+):
     task_name = TaskName.upstream_koji_build
 
     def __init__(
@@ -100,7 +103,9 @@ class KojiBuildHandler(JobHandler, GetKojiBuildJobHelperMixin):
 @configured_as(job_type=JobType.production_build)
 @configured_as(job_type=JobType.upstream_koji_build)
 @reacts_to(event=KojiTaskEvent)
-class KojiTaskReportHandler(JobHandler, ConfigFromEventMixin):
+class KojiTaskReportHandler(
+    JobHandler, PackitAPIWithDownstreamMixin, ConfigFromEventMixin
+):
     task_name = TaskName.upstream_koji_build_report
 
     def __init__(
@@ -229,7 +234,9 @@ class KojiTaskReportHandler(JobHandler, ConfigFromEventMixin):
 @configured_as(job_type=JobType.koji_build)
 @configured_as(job_type=JobType.bodhi_update)
 @reacts_to(event=KojiBuildEvent)
-class KojiBuildReportHandler(JobHandler, ConfigFromEventMixin):
+class KojiBuildReportHandler(
+    JobHandler, PackitAPIWithDownstreamMixin, ConfigFromEventMixin
+):
     task_name = TaskName.downstream_koji_build_report
 
     def __init__(
diff --git a/packit_service/worker/handlers/testing_farm.py b/packit_service/worker/handlers/testing_farm.py
index e2f8c766..d1f27f02 100644
--- a/packit_service/worker/handlers/testing_farm.py
+++ b/packit_service/worker/handlers/testing_farm.py
@@ -59,6 +59,7 @@ from packit_service.worker.handlers.mixin import (
     GetCoprBuildMixin,
     GetTestingFarmJobHelperMixin,
 )
+from packit_service.worker.mixin import PackitAPIWithDownstreamMixin
 from packit_service.worker.handlers.mixin import GetGithubCommentEventMixin
 
 logger = logging.getLogger(__name__)
@@ -79,6 +80,7 @@ logger = logging.getLogger(__name__)
 @configured_as(job_type=JobType.tests)
 class TestingFarmHandler(
     RetriableJobHandler,
+    PackitAPIWithDownstreamMixin,
     GetTestingFarmJobHelperMixin,
     GetCoprBuildMixin,
     GetGithubCommentEventMixin,
@@ -261,7 +263,9 @@ class TestingFarmHandler(
 
 @configured_as(job_type=JobType.tests)
 @reacts_to(event=TestingFarmResultsEvent)
-class TestingFarmResultsHandler(JobHandler, ConfigFromEventMixin):
+class TestingFarmResultsHandler(
+    JobHandler, ConfigFromEventMixin, PackitAPIWithDownstreamMixin
+):
     __test__ = False
     task_name = TaskName.testing_farm_results
 
diff --git a/packit_service/worker/handlers/vm_image.py b/packit_service/worker/handlers/vm_image.py
index d4c4a648..4d13f2d7 100644
--- a/packit_service/worker/handlers/vm_image.py
+++ b/packit_service/worker/handlers/vm_image.py
@@ -33,6 +33,7 @@ from packit_service.worker.checker.vm_image import (
 from packit_service.worker.mixin import (
     ConfigFromEventMixin,
     GetVMImageBuilderMixin,
+    PackitAPIWithDownstreamMixin,
 )
 from packit_service.models import (
     VMImageBuildTargetModel,
@@ -51,6 +52,7 @@ logger = logging.getLogger(__name__)
 class VMImageBuildHandler(
     RetriableJobHandler,
     ConfigFromEventMixin,
+    PackitAPIWithDownstreamMixin,
     GetVMImageBuilderMixin,
     GetVMImageBuildReporterFromJobHelperMixin,
 ):
@@ -119,6 +121,7 @@ class VMImageBuildHandler(
 class VMImageBuildResultHandler(
     JobHandler,
     ConfigFromEventMixin,
+    PackitAPIWithDownstreamMixin,
     GetVMImageBuilderMixin,
     GetVMImageBuildReporterFromJobHelperMixin,
 ):
diff --git a/tests/integration/test_handler.py b/tests/integration/test_handler.py
index 17a7a8bd..372f4744 100644
--- a/tests/integration/test_handler.py
+++ b/tests/integration/test_handler.py
@@ -22,7 +22,10 @@ from packit_service.models import (
     JobTriggerModel,
     JobTriggerModelType,
 )
-from packit_service.worker.mixin import ConfigFromEventMixin
+from packit_service.worker.mixin import (
+    ConfigFromEventMixin,
+    PackitAPIWithDownstreamMixin,
+)
 from packit_service.worker.handlers import (
     JobHandler,
     CoprBuildHandler,
@@ -40,7 +43,9 @@ def trick_p_s_with_k8s():
 
 
 def test_handler_cleanup(tmp_path, trick_p_s_with_k8s):
-    class TestJobHandler(JobHandler, ConfigFromEventMixin):
+    class TestJobHandler(
+        JobHandler, ConfigFromEventMixin, PackitAPIWithDownstreamMixin
+    ):
         pass
 
     tmp_path.joinpath("a").mkdir()
diff --git a/tests/unit/test_distgit.py b/tests/unit/test_distgit.py
index 6f210d77..d30f5e91 100644
--- a/tests/unit/test_distgit.py
+++ b/tests/unit/test_distgit.py
@@ -10,6 +10,7 @@ from packit.api import PackitAPI
 from packit_service.worker.handlers.distgit import (
     ProposeDownstreamHandler,
     DownstreamKojiBuildHandler,
+    AbstractSyncReleaseHandler,
 )
 from packit_service.worker.events.event import EventData
 from packit_service.config import PackageConfigGetter
@@ -95,3 +96,21 @@ def test_retrigger_downstream_koji_build_pre_check(user_groups, data, check_pass
         None, flexmock(issue_repository=flexmock()), data_dict
     )
     assert result == check_passed
+
+
+def test_downstream_handler_init_order():
+    class Test(AbstractSyncReleaseHandler):
+        pass
+
+    handler = Test(None, None, {"event_type": "unknown"}, None)
+    assert handler.local_project
+
+
+def test_upstream_local_project_is_used():
+    class Test(AbstractSyncReleaseHandler):
+        pass
+
+    handler = Test(None, None, {"event_type": "unknown"}, None)
+    assert handler.packit_api
+    assert not handler.packit_api.downstream_local_project
+    assert handler.packit_api.upstream_local_project