def test_copr_build_end( copr_build_end, pc_build_pr, copr_build_pr, pc_comment_pr_succ, pr_comment_called, ): flexmock(GithubProject).should_receive("is_private").and_return(False) flexmock(GithubProject).should_receive("get_pr").and_return( flexmock(source_project=flexmock()) ) pc_build_pr.jobs[0].notifications.pull_request.successful_build = pc_comment_pr_succ flexmock(AbstractCoprBuildEvent).should_receive("get_package_config").and_return( pc_build_pr ) flexmock(CoprBuildEndHandler).should_receive( "was_last_packit_comment_with_congratulation" ).and_return(False) if pr_comment_called: flexmock(GithubProject).should_receive("pr_comment") else: flexmock(GithubProject).should_receive("pr_comment").never() flexmock(CoprBuildModel).should_receive("get_by_build_id").and_return(copr_build_pr) copr_build_pr.should_receive("set_status").with_args("success") copr_build_pr.should_receive("set_end_time").once() url = get_copr_build_info_url_from_flask(1) flexmock(requests).should_receive("get").and_return(requests.Response()) flexmock(requests.Response).should_receive("raise_for_status").and_return(None) # check if packit-service set correct PR status flexmock(StatusReporter).should_receive("report").with_args( state=CommitStatus.success, description="RPMs were built successfully.", url=url, check_names=CoprBuildJobHelper.get_build_check(copr_build_end["chroot"]), ).once() # no test job defined => testing farm should be skipped flexmock(TestingFarmJobHelper).should_receive("run_testing_farm").times(0) flexmock(Signature).should_receive("apply_async").once() processing_results = SteveJobs().process_message(copr_build_end) event_dict, job, job_config, package_config = get_parameters_from_results( processing_results ) run_copr_build_end_handler( package_config=package_config, event=event_dict, job_config=job_config, )
def test_copr_build_just_tests_defined(copr_build_start, pc_tests, copr_build_pr): flexmock(GithubProject).should_receive("is_private").and_return(False) flexmock(GithubProject).should_receive("get_pr").and_return( flexmock(source_project=flexmock()) ) flexmock(AbstractCoprBuildEvent).should_receive("get_package_config").and_return( pc_tests ) flexmock(TestingFarmJobHelper).should_receive("get_build_check").and_return( EXPECTED_BUILD_CHECK_NAME ) flexmock(TestingFarmJobHelper).should_receive("get_test_check").and_return( EXPECTED_TESTING_FARM_CHECK_NAME ) flexmock(CoprBuildModel).should_receive("get_by_build_id").and_return(copr_build_pr) url = get_copr_build_info_url_from_flask(1) flexmock(requests).should_receive("get").and_return(requests.Response()) flexmock(requests.Response).should_receive("raise_for_status").and_return(None) copr_build_pr.should_receive("set_start_time").once() copr_build_pr.should_receive("set_status").with_args("pending") copr_build_pr.should_receive("set_build_logs_url") # check if packit-service sets the correct PR status flexmock(StatusReporter).should_receive("report").with_args( state=CommitStatus.pending, description="RPM build is in progress...", url=url, check_names=EXPECTED_BUILD_CHECK_NAME, ).never() flexmock(StatusReporter).should_receive("report").with_args( state=CommitStatus.pending, description="RPM build is in progress...", url=url, check_names=TestingFarmJobHelper.get_test_check(copr_build_start["chroot"]), ).once() flexmock(Signature).should_receive("apply_async").once() processing_results = SteveJobs().process_message(copr_build_start) event_dict, job, job_config, package_config = get_parameters_from_results( processing_results ) run_copr_build_start_handler( package_config=package_config, event=event_dict, job_config=job_config, )
def test_get_logs(client): chroot = "foo-1-x86_64" state = "success" build_id = 2 project = GitProjectModel() project.namespace = "john-foo" project.repo_name = "bar" pr = PullRequestModel() pr.pr_id = 234 pr.project = project srpm = SRPMBuildModel() srpm.url = "https://some.random.copr.subdomain.org/my_srpm.srpm" c = CoprBuildModel() c.target = chroot c.build_id = str(build_id) c.srpm_build_id = 11 c.status = state c.srpm_build = srpm c.web_url = ( "https://copr.fedorainfracloud.org/coprs/john-foo-bar/john-foo-bar/build/2/" ) c.build_logs_url = "https://localhost:5000/build/2/foo-1-x86_64/logs" c.owner = "packit" c.project_name = "example_project" flexmock(CoprBuildModel).should_receive("get_by_id").and_return(c) flexmock(CoprBuildModel).should_receive("get_project").and_return(project) flexmock(CoprBuildModel).should_receive("job_trigger").and_return( flexmock(get_trigger_object=lambda: pr)) url = "/copr-build/1" logs_url = get_copr_build_info_url_from_flask(1) assert logs_url.endswith(url) resp = client.get(url).data.decode() assert f"srpm-build/{c.srpm_build_id}/logs" in resp assert c.web_url in resp assert c.build_logs_url in resp assert c.target in resp assert "Status: success" in resp assert "You can install" in resp assert "Download SRPM" in resp assert srpm.url in resp
def test_copr_build_not_comment_on_success(copr_build_end, pc_build_pr, copr_build_pr): flexmock(GithubProject).should_receive("is_private").and_return(False) flexmock(GithubProject).should_receive("get_pr").and_return( flexmock(source_project=flexmock()) ) flexmock(AbstractCoprBuildEvent).should_receive("get_package_config").and_return( pc_build_pr ) flexmock(CoprBuildJobHelper).should_receive("get_build_check").and_return( EXPECTED_BUILD_CHECK_NAME ) flexmock(CoprBuildEndHandler).should_receive( "was_last_packit_comment_with_congratulation" ).and_return(True) flexmock(GithubProject).should_receive("pr_comment").never() flexmock(CoprBuildModel).should_receive("get_by_build_id").and_return(copr_build_pr) copr_build_pr.should_receive("set_status").with_args("success") copr_build_pr.should_receive("set_end_time").once() url = get_copr_build_info_url_from_flask(1) flexmock(requests).should_receive("get").and_return(requests.Response()) flexmock(requests.Response).should_receive("raise_for_status").and_return(None) # check if packit-service set correct PR status flexmock(StatusReporter).should_receive("report").with_args( state=CommitStatus.success, description="RPMs were built successfully.", url=url, check_names=CoprBuildJobHelper.get_build_check(copr_build_end["chroot"]), ).once() # skip testing farm flexmock(CoprBuildJobHelper).should_receive("job_tests").and_return(None) flexmock(Signature).should_receive("apply_async").once() processing_results = SteveJobs().process_message(copr_build_end) event_dict, job, job_config, package_config = get_parameters_from_results( processing_results ) run_copr_build_end_handler( package_config=package_config, event=event_dict, job_config=job_config, )
def run(self): build_job_helper = CoprBuildJobHelper( service_config=self.service_config, package_config=self.package_config, project=self.project, metadata=self.data, db_trigger=self.db_trigger, job_config=self.job_config, ) if self.copr_event.chroot == "srpm-builds": # we don't want to set the check status for this msg = "SRPM build in copr has started." logger.debug(msg) return TaskResults(success=True, details={"msg": msg}) if not self.build: msg = f"Copr build {self.copr_event.build_id} not in CoprBuildDB." logger.warning(msg) return TaskResults(success=False, details={"msg": msg}) start_time = ( datetime.utcfromtimestamp(self.copr_event.timestamp) if self.copr_event.timestamp else None ) self.build.set_start_time(start_time) url = get_copr_build_info_url_from_flask(self.build.id) self.build.set_status("pending") copr_build_logs = self.copr_event.get_copr_build_logs_url() self.build.set_build_logs_url(copr_build_logs) build_job_helper.report_status_to_all_for_chroot( description="RPM build is in progress...", state=CommitStatus.pending, url=url, chroot=self.copr_event.chroot, ) msg = f"Build on {self.copr_event.chroot} in copr has started..." return TaskResults(success=True, details={"msg": msg})
def test_get_logs(client): chroot = "foo-1-x86_64" state = "pending" build_id = 2 project = GitProjectModel() project.namespace = "john-foo" project.repo_name = "bar" pr = PullRequestModel() pr.pr_id = 234 pr.project = project c = CoprBuildModel() c.target = chroot c.build_id = str(build_id) c.srpm_build_id = 11 c.status = state c.web_url = ( "https://copr.fedorainfracloud.org/coprs/john-foo-bar/john-foo-bar/build/2/" ) c.build_logs_url = "https://localhost:5000/build/2/foo-1-x86_64/logs" flexmock(CoprBuildModel).should_receive("get_by_id").and_return(c) flexmock(CoprBuildModel).should_receive("get_project").and_return(project) flexmock(CoprBuildModel).should_receive("job_trigger").and_return( flexmock(get_trigger_object=lambda: pr)) url = "/copr-build/1" logs_url = get_copr_build_info_url_from_flask(1) assert logs_url.endswith(url) resp = client.get(url).data.decode() assert f"srpm-build/{c.srpm_build_id}/logs" in resp assert c.web_url in resp assert c.build_logs_url in resp assert c.target in resp
def run(self): build_job_helper = CoprBuildJobHelper( service_config=self.service_config, package_config=self.package_config, project=self.project, metadata=self.data, db_trigger=self.db_trigger, job_config=self.job_config, ) if self.copr_event.chroot == "srpm-builds": # we don't want to set check for this msg = "SRPM build in copr has finished." logger.debug(msg) return TaskResults(success=True, details={"msg": msg}) if not self.build: # TODO: how could this happen? msg = f"Copr build {self.copr_event.build_id} not in CoprBuildDB." logger.warning(msg) return TaskResults(success=False, details={"msg": msg}) if self.build.status in [ PG_COPR_BUILD_STATUS_FAILURE, PG_COPR_BUILD_STATUS_SUCCESS, ]: msg = (f"Copr build {self.copr_event.build_id} is already" f" processed (status={self.copr_event.build.status}).") logger.info(msg) return TaskResults(success=True, details={"msg": msg}) end_time = (datetime.utcfromtimestamp(self.copr_event.timestamp) if self.copr_event.timestamp else None) self.build.set_end_time(end_time) url = get_copr_build_info_url_from_flask(self.build.id) # https://pagure.io/copr/copr/blob/master/f/common/copr_common/enums.py#_42 if self.copr_event.status != COPR_API_SUCC_STATE: failed_msg = "RPMs failed to be built." build_job_helper.report_status_to_all_for_chroot( state=CommitStatus.failure, description=failed_msg, url=url, chroot=self.copr_event.chroot, ) self.build.set_status(PG_COPR_BUILD_STATUS_FAILURE) return TaskResults(success=False, details={"msg": failed_msg}) if (build_job_helper.job_build and build_job_helper.job_build.trigger == JobConfigTriggerType.pull_request and self.copr_event.pr_id and isinstance(self.project, (GithubProject, GitlabProject)) and not self.was_last_packit_comment_with_congratulation() and self.job_config.notifications.pull_request.successful_build): msg = ( f"Congratulations! One of the builds has completed. :champagne:\n\n" ":warning: Please note that our current plans include removal of these " "comments in the near future (at least 2 weeks after including this " "disclaimer), if you have serious concerns regarding their removal " "or would like to continue receiving them please reach out to us. " ":warning:\n\n" "You can install the built RPMs by following these steps:\n\n" "* `sudo yum install -y dnf-plugins-core` on RHEL 8\n" "* `sudo dnf install -y dnf-plugins-core` on Fedora\n" f"* `dnf copr enable {self.copr_event.owner}/{self.copr_event.project_name}`\n" "* And now you can install the packages.\n" "\nPlease note that the RPMs should be used only in a testing environment." ) self.project.pr_comment(pr_id=self.copr_event.pr_id, body=msg) build_job_helper.report_status_to_build_for_chroot( state=CommitStatus.success, description="RPMs were built successfully.", url=url, chroot=self.copr_event.chroot, ) build_job_helper.report_status_to_test_for_chroot( state=CommitStatus.pending, description="RPMs were built successfully.", url=url, chroot=self.copr_event.chroot, ) self.build.set_status(PG_COPR_BUILD_STATUS_SUCCESS) if (build_job_helper.job_tests and self.copr_event.chroot in build_job_helper.tests_targets): signature( TaskName.testing_farm.value, kwargs={ "package_config": dump_package_config(self.package_config), "job_config": dump_job_config(build_job_helper.job_tests), "event": self.data.get_dict(), "chroot": self.copr_event.chroot, "build_id": self.build.id, }, ).apply_async() else: logger.debug("Testing farm not in the job config.") return TaskResults(success=True, details={})
def test_copr_build_end_failed_testing_farm_no_json(copr_build_end, copr_build_pr): flexmock(GithubProject).should_receive("is_private").and_return(False) config = PackageConfig(jobs=[ JobConfig( type=JobType.copr_build, trigger=JobConfigTriggerType.pull_request, metadata=JobMetadataConfig( targets=["fedora-rawhide"], owner="some-owner", project="some-project", ), ), JobConfig( type=JobType.tests, trigger=JobConfigTriggerType.pull_request, metadata=JobMetadataConfig(targets=["fedora-rawhide"]), ), ]) flexmock(CoprBuildEvent).should_receive("get_package_config").and_return( config) flexmock(PackageConfigGetter).should_receive( "get_package_config_from_repo").and_return(config) flexmock(CoprBuildEndHandler).should_receive( "was_last_packit_comment_with_congratulation").and_return(False) flexmock(GithubProject).should_receive("pr_comment") flexmock(LocalProject).should_receive("refresh_the_arguments").and_return( None) flexmock(CoprBuildModel).should_receive("get_by_build_id").and_return( copr_build_pr) copr_build_pr.should_receive("set_status").with_args("success") copr_build_pr.should_receive("set_end_time").once() url = get_copr_build_info_url_from_flask(1) flexmock(requests).should_receive("get").and_return(requests.Response()) flexmock( requests.Response).should_receive("raise_for_status").and_return(None) # check if packit-service set correct PR status flexmock(StatusReporter).should_receive("report").with_args( state=CommitStatus.success, description="RPMs were built successfully.", url=url, check_names=EXPECTED_BUILD_CHECK_NAME, ).once() flexmock(StatusReporter).should_receive("report").with_args( state=CommitStatus.pending, description="RPMs were built successfully.", url=url, check_names=EXPECTED_TESTING_FARM_CHECK_NAME, ).once() flexmock(TestingFarmJobHelper).should_receive( "send_testing_farm_request").and_return( RequestResponse( status_code=400, ok=False, content=b"some text error", reason="some text error", json=None, )) flexmock(CoprBuildModel).should_receive("set_status").with_args("failure") flexmock(StatusReporter).should_receive("report").with_args( state=CommitStatus.pending, description="Build succeeded. Submitting the tests ...", check_names=EXPECTED_TESTING_FARM_CHECK_NAME, url="", ).once() flexmock(StatusReporter).should_receive("report").with_args( state=CommitStatus.failure, description="Failed to submit tests: some text error", check_names=EXPECTED_TESTING_FARM_CHECK_NAME, url="", ).once() tft_test_run_model = flexmock() tft_test_run_model.should_receive("set_status").with_args( TestingFarmResult.error).and_return().once() pipeline_id = "5e8079d8-f181-41cf-af96-28e99774eb68" flexmock(uuid).should_receive("uuid4").and_return(uuid.UUID(pipeline_id)) flexmock(TFTTestRunModel).should_receive("create").with_args( pipeline_id=pipeline_id, commit_sha="0011223344", status=TestingFarmResult.new, target="fedora-rawhide-x86_64", trigger_model=copr_build_pr.job_trigger.get_trigger_object(), web_url=None, ).and_return(tft_test_run_model) flexmock(Signature).should_receive("apply_async").twice() processing_results = SteveJobs().process_message(copr_build_end) event_dict, package_config, job = get_parameters_from_results( processing_results) run_copr_build_end_handler( package_config=package_config, event=event_dict, job_config=job, ) flexmock(GithubTestingFarmHandler).should_receive("db_trigger").and_return( copr_build_pr.job_trigger.get_trigger_object()) run_testing_farm_handler( package_config=package_config, event=event_dict, job_config=job, chroot="fedora-rawhide-x86_64", build_id=flexmock(), )
def test_copr_build_end_testing_farm(copr_build_end, copr_build_pr): flexmock(GithubProject).should_receive("is_private").and_return(False) config = PackageConfig(jobs=[ JobConfig( type=JobType.copr_build, trigger=JobConfigTriggerType.pull_request, metadata=JobMetadataConfig( targets=["fedora-rawhide"], owner="some-owner", project="some-project", ), ), JobConfig( type=JobType.tests, trigger=JobConfigTriggerType.pull_request, metadata=JobMetadataConfig(targets=["fedora-rawhide"]), ), ]) flexmock(CoprBuildEvent).should_receive("get_package_config").and_return( config) flexmock(PackageConfigGetter).should_receive( "get_package_config_from_repo").and_return(config) flexmock(CoprBuildEndHandler).should_receive( "was_last_packit_comment_with_congratulation").and_return(False) flexmock(GithubProject).should_receive("pr_comment") flexmock(LocalProject).should_receive("refresh_the_arguments").and_return( None) flexmock(CoprBuildModel).should_receive("get_by_build_id").and_return( copr_build_pr) copr_build_pr.should_receive("set_status").with_args("success") copr_build_pr.should_receive("set_end_time").once() flexmock(requests).should_receive("get").and_return(requests.Response()) flexmock( requests.Response).should_receive("raise_for_status").and_return(None) # check if packit-service set correct PR status url = get_copr_build_info_url_from_flask(1) flexmock(StatusReporter).should_receive("report").with_args( state=CommitStatus.success, description="RPMs were built successfully.", url=url, check_names=EXPECTED_BUILD_CHECK_NAME, ).once() flexmock(StatusReporter).should_receive("report").with_args( state=CommitStatus.pending, description="RPMs were built successfully.", url=url, check_names=EXPECTED_TESTING_FARM_CHECK_NAME, ).once() pipeline_id = "5e8079d8-f181-41cf-af96-28e99774eb68" flexmock(uuid).should_receive("uuid4").and_return(uuid.UUID(pipeline_id)) payload: dict = { "pipeline": { "id": pipeline_id }, "api": { "token": "" }, "response-url": "https://stg.packit.dev/api/testing-farm/results", "artifact": { "repo-name": "bar", "repo-namespace": "foo", "copr-repo-name": "some-owner/some-project", "copr-chroot": "fedora-rawhide-x86_64", "commit-sha": "0011223344", "git-url": "https://github.com/foo/bar.git", "git-ref": "0011223344", }, } tft_test_run_model = flexmock() tft_test_run_model.should_receive("set_status").with_args( TestingFarmResult.running).and_return().once() flexmock(TFTTestRunModel).should_receive("create").with_args( pipeline_id=pipeline_id, commit_sha="0011223344", status=TestingFarmResult.new, target="fedora-rawhide-x86_64", trigger_model=copr_build_pr.job_trigger.get_trigger_object(), web_url=None, ).and_return(tft_test_run_model) flexmock(TestingFarmJobHelper).should_receive( "send_testing_farm_request").with_args( TESTING_FARM_TRIGGER_URL, "POST", {}, json.dumps(payload)).and_return( RequestResponse( status_code=200, ok=True, content=b'{"url": "some-url"}', json={"url": "some-url"}, )) flexmock(StatusReporter).should_receive("report").with_args( state=CommitStatus.pending, description="Build succeeded. Submitting the tests ...", check_names=EXPECTED_TESTING_FARM_CHECK_NAME, url="", ).once() flexmock(StatusReporter).should_receive("report").with_args( state=CommitStatus.pending, description="Tests are running ...", url="some-url", check_names=EXPECTED_TESTING_FARM_CHECK_NAME, ).once() flexmock(Signature).should_receive("apply_async").twice() processing_results = SteveJobs().process_message(copr_build_end) event_dict, package_config, job = get_parameters_from_results( processing_results) run_copr_build_end_handler( package_config=package_config, event=event_dict, job_config=job, ) flexmock(GithubTestingFarmHandler).should_receive("db_trigger").and_return( copr_build_pr.job_trigger.get_trigger_object()) run_testing_farm_handler( package_config=package_config, event=event_dict, job_config=job, chroot="fedora-rawhide-x86_64", build_id=flexmock(), )
def run_copr_build(self) -> TaskResults: if not (self.job_build or self.job_tests): msg = "No copr_build or tests job defined." # we can't report it to end-user at this stage return TaskResults(success=False, details={"msg": msg}) self.report_status_to_all( description="Building SRPM ...", state=CommitStatus.pending, # pagure requires "valid url" url="", ) self.create_srpm_if_needed() if not self.srpm_model.success: msg = "SRPM build failed, check the logs for details." self.report_status_to_all( state=CommitStatus.failure, description=msg, url=get_srpm_log_url_from_flask(self.srpm_model.id), ) return TaskResults(success=False, details={"msg": msg}) try: build_id, web_url = self.run_build() except Exception as ex: sentry_integration.send_to_sentry(ex) # TODO: Where can we show more info about failure? # TODO: Retry self.report_status_to_all( state=CommitStatus.error, description=f"Submit of the build failed: {ex}", ) return TaskResults( success=False, details={ "msg": "Submit of the Copr build failed.", "error": str(ex) }, ) for chroot in self.build_targets: copr_build = CoprBuildModel.get_or_create( build_id=str(build_id), commit_sha=self.metadata.commit_sha, project_name=self.job_project, owner=self.job_owner, web_url=web_url, target=chroot, status="pending", srpm_build=self.srpm_model, trigger_model=self.db_trigger, ) url = get_copr_build_info_url_from_flask(id_=copr_build.id) self.report_status_to_all_for_chroot( state=CommitStatus.pending, description="Starting RPM build...", url=url, chroot=chroot, ) # release the hounds! celery_app.send_task( "task.babysit_copr_build", args=(build_id, ), countdown=120, # do the first check in 120s ) return TaskResults(success=True, details={})
def run_copr_build(self) -> TaskResults: if not (self.job_build or self.job_tests): msg = "No copr_build or tests job defined." # we can't report it to end-user at this stage return TaskResults(success=False, details={"msg": msg}) self.report_status_to_all( description="Building SRPM ...", state=CommitStatus.pending, # pagure requires "valid url" url="", ) self.create_srpm_if_needed() if not self.srpm_model.success: msg = "SRPM build failed, check the logs for details." self.report_status_to_all( state=CommitStatus.failure, description=msg, url=get_srpm_log_url_from_flask(self.srpm_model.id), ) return TaskResults(success=False, details={"msg": msg}) try: build_id, web_url = self.run_build() Pushgateway().push_copr_build_created() except Exception as ex: sentry_integration.send_to_sentry(ex) # TODO: Where can we show more info about failure? # TODO: Retry self.report_status_to_all( state=CommitStatus.error, description=f"Submit of the build failed: {ex}", ) return TaskResults( success=False, details={"msg": "Submit of the Copr build failed.", "error": str(ex)}, ) unprocessed_chroots = [] for chroot in self.build_targets: if chroot not in self.available_chroots: self.report_status_to_all_for_chroot( state=CommitStatus.error, description=f"Not supported target: {chroot}", url=get_srpm_log_url_from_flask(self.srpm_model.id), chroot=chroot, ) unprocessed_chroots.append(chroot) continue copr_build = CoprBuildModel.get_or_create( build_id=str(build_id), commit_sha=self.metadata.commit_sha, project_name=self.job_project, owner=self.job_owner, web_url=web_url, target=chroot, status="pending", srpm_build=self.srpm_model, trigger_model=self.db_trigger, ) url = get_copr_build_info_url_from_flask(id_=copr_build.id) self.report_status_to_all_for_chroot( state=CommitStatus.pending, description="Starting RPM build...", url=url, chroot=chroot, ) if unprocessed_chroots: unprocessed = "\n".join(sorted(unprocessed_chroots)) available = "\n".join(sorted(self.available_chroots)) self.project.pr_comment( pr_id=self.metadata.pr_id, body="There are build targets that are not supported by COPR.\n" "<details>\n<summary>Unprocessed build targets</summary>\n\n" f"```\n{unprocessed}\n```\n</details>\n" "<details>\n<summary>Available build targets</summary>\n\n" f"```\n{available}\n```\n</details>", ) # release the hounds! celery_app.send_task( "task.babysit_copr_build", args=(build_id,), countdown=120, # do the first check in 120s ) return TaskResults(success=True, details={})