def test_get_branches(self, name, default_dg_branch, branches, mock_get_aliases): if default_dg_branch: assert get_branches( name, default_dg_branch=default_dg_branch) == branches else: assert get_branches(name) == branches
def create_update( config, dist_git_branch, koji_build, update_notes, update_type, path_or_url ): """ Create a bodhi update for the selected upstream project PATH_OR_URL argument is a local path or a URL to the upstream git repository, it defaults to the current working directory """ api = get_packit_api(config=config, local_project=path_or_url) default_dg_branch = api.dg.local_project.git_project.default_branch dist_git_branch = dist_git_branch or default_dg_branch branches_to_update = get_branches( *dist_git_branch.split(","), default_dg_branch=default_dg_branch ) click.echo( f"Creating Bodhi update for the following branches: {', '.join(branches_to_update)}" ) if branches_to_update: click.echo("Please provide Bodhi username and password when asked for.") for branch in branches_to_update: api.create_update( koji_builds=koji_build, dist_git_branch=branch, update_notes=update_notes, update_type=update_type, )
def sync_from_downstream( config, dist_git_branch, upstream_branch, no_pr, path_or_url, fork, remote_to_push, exclude, force, ): """ Copy synced files from Fedora dist-git into upstream by opening a pull request. PATH_OR_URL argument is a local path or a URL to the upstream git repository, it defaults to the current working directory """ api = get_packit_api(config=config, local_project=path_or_url) default_dg_branch = api.dg.local_project.git_project.default_branch dist_git_branch = dist_git_branch or default_dg_branch branches_to_sync = get_branches( *dist_git_branch.split(","), default_dg_branch=default_dg_branch ) click.echo(f"Syncing from the following branches: {', '.join(branches_to_sync)}") for branch in branches_to_sync: api.sync_from_downstream( dist_git_branch=branch, upstream_branch=upstream_branch, no_pr=no_pr, fork=fork, remote_name=remote_to_push, exclude_files=exclude, force=force, )
def run(self) -> HandlerResults: """ Sync the upstream release to dist-git as a pull request. """ self.local_project = LocalProject( git_project=self.project, working_dir=self.config.command_handler_work_dir) self.api = PackitAPI(self.config, self.package_config, self.local_project) errors = [] for branch in get_branches( self.job.metadata.get("dist-git-branch", "master")): try: self.api.sync_release(dist_git_branch=branch, version=self.event.tag_name) except Exception as ex: sentry_integration.send_to_sentry(ex) errors.append( f"Propose update for branch {branch} failed: {ex}") if errors: return HandlerResults( success=False, details={ "msg": "Propose update failed.", "errors": errors }, ) return HandlerResults(success=True, details={})
def dist_git_branches_to_sync(self) -> Set[str]: """ Get the dist-git branches to sync to with the aliases expansion. :return: list of dist-git branches """ configured_branches = set() configured_branches.update(self.job_config.metadata.dist_git_branches) if configured_branches: return get_branches(*configured_branches) return set()
def run(self) -> TaskResults: """ Sync the upstream release to dist-git as a pull request. """ self.local_project = LocalProject( git_project=self.project, working_dir=self.service_config.command_handler_work_dir, ) self.api = PackitAPI(self.service_config, self.job_config, self.local_project) errors = {} for branch in get_branches(*self.job_config.metadata.dist_git_branches, default="master"): try: self.api.sync_release(dist_git_branch=branch, version=self.data.tag_name) except Exception as ex: sentry_integration.send_to_sentry(ex) errors[branch] = str(ex) if errors: branch_errors = "" for branch, err in sorted( errors.items(), key=lambda branch_error: branch_error[0]): err_without_new_lines = err.replace("\n", " ") branch_errors += f"| `{branch}` | `{err_without_new_lines}` |\n" body_msg = ( f"Packit failed on creating pull-requests in dist-git:\n\n" f"| dist-git branch | error |\n" f"| --------------- | ----- |\n" f"{branch_errors}\n\n" "You can re-trigger the update by adding `/packit propose-update`" " to the issue comment.\n") self.project.create_issue( title= f"[packit] Propose update failed for release {self.data.tag_name}", body=body_msg, ) return TaskResults( success=False, details={ "msg": "Propose update failed.", "errors": errors }, ) return TaskResults(success=True, details={})
def get_dg_branches(api, dist_git_branch): cmdline_dg_branches = dist_git_branch.split(",") if dist_git_branch else [] config_dg_branches = [] if isinstance(api.package_config, PackageConfig): config_dg_branches = ( api.package_config.get_propose_downstream_dg_branches_value()) default_dg_branch = api.dg.local_project.git_project.default_branch dg_branches = (cmdline_dg_branches or config_dg_branches or default_dg_branch.split(",")) return get_branches(*dg_branches, default_dg_branch=default_dg_branch)
def dist_git_branches_to_sync(self) -> Set[str]: """ Get the dist-git branches to sync to with the aliases expansion. :return: list of dist-git branches """ configured_branches = set() for job in self.package_config.jobs: if job.type == JobType.propose_downstream: configured_branches.update(job.metadata.dist_git_branches) if configured_branches: return get_branches(*configured_branches) return set()
def build( config, dist_git_path, dist_git_branch, from_upstream, scratch, nowait, path_or_url, koji_target, ): """ Build selected upstream project in Fedora. By default, packit checks out the respective dist-git repository and performs `fedpkg build` for the selected branch. With `--from-upstream`, packit creates a SRPM out of the current checkout and sends it to koji. PATH_OR_URL argument is a local path or a URL to the upstream git repository, it defaults to the current working directory """ api = get_packit_api(config=config, dist_git_path=dist_git_path, local_project=path_or_url) branches_to_build = get_branches(*dist_git_branch.split(","), default="master") click.echo( f"Building for the following branches: {', '.join(branches_to_build)}") for branch in branches_to_build: try: out = api.build( dist_git_branch=branch, scratch=scratch, nowait=nowait, koji_target=koji_target, from_upstream=from_upstream, ) except PackitCommandFailedError as ex: logs_stdout = "\n>>> ".join(ex.stdout_output.strip().split("\n")) logs_stderr = "\n!!! ".join(ex.stderr_output.strip().split("\n")) click.echo( f"Build for branch '{branch}' failed. \n" f">>> {logs_stdout}\n" f"!!! {logs_stderr}\n", err=True, ) else: if out: print(ensure_str(out))
def dist_git_branches_to_sync(self) -> List[str]: """ Get the dist-git branches to sync to with the aliases expansion. :return: list of dist-git branches """ configured_branches = [ job.metadata.get("dist-git-branch") for job in self.package_config.jobs if job.job == JobType.propose_downstream ] if configured_branches: return list(get_branches(*configured_branches)) return []
def update( config, dist_git_path, dist_git_branch, force_new_sources, no_pr, local_content, path_or_url, upstream_ref, version, remote, # click introspects this in LocalProjectParameter force, ): """ Release current upstream release into Fedora PATH_OR_URL argument is a local path or a URL to the upstream git repository, it defaults to the current working directory VERSION argument is optional, the latest upstream version will be used by default """ api = get_packit_api(config=config, dist_git_path=dist_git_path, local_project=path_or_url) branches_to_update = get_branches(*dist_git_branch.split(","), default="master") click.echo( f"Syncing from the following branches: {', '.join(branches_to_update)}" ) for branch in branches_to_update: api.sync_release( dist_git_branch=branch, use_local_content=local_content, version=version, force_new_sources=force_new_sources, upstream_ref=upstream_ref, create_pr=not no_pr, force=force, )
def create_update(config, dist_git_branch, koji_build, update_notes, update_type, path_or_url): """ Create a bodhi update for the selected upstream project PATH_OR_URL argument is a local path or a URL to the upstream git repository, it defaults to the current working directory """ api = get_packit_api(config=config, local_project=path_or_url) branches_to_update = get_branches(*dist_git_branch.split(","), default="master") click.echo( f"Syncing from the following branches: {', '.join(branches_to_update)}" ) for branch in branches_to_update: api.create_update( koji_builds=koji_build, dist_git_branch=branch, update_notes=update_notes, update_type=update_type, )
def build(config, dist_git_path, dist_git_branch, scratch, nowait, path_or_url, koji_target): """ Build selected upstream project in Fedora. Packit goes to dist-git and performs `fedpkg build` for the selected branch. PATH_OR_URL argument is a local path or a URL to the upstream git repository, it defaults to the current working directory """ api = get_packit_api(config=config, dist_git_path=dist_git_path, local_project=path_or_url) branches_to_build = get_branches(*dist_git_branch.split(","), default="master") click.echo( f"Building for the following branches: {', '.join(branches_to_build)}") for branch in branches_to_build: try: api.build( dist_git_branch=branch, scratch=scratch, nowait=nowait, koji_target=koji_target, ) except PackitCommandFailedError as ex: logs_stdout = "\n>>> ".join( ex.stdout_output.decode().strip().split("\n")) logs_stderr = "\n!!! ".join( ex.stderr_output.decode().strip().split("\n")) click.echo( f"Build for branch '{branch}' failed. \n" f">>> {logs_stdout}\n" f"!!! {logs_stderr}\n", err=True, )
def test_get_branches_without_default(self): assert get_branches(default=None) == set()
def run(self) -> TaskResults: """ Sync the upstream release to dist-git as a pull request. """ self.local_project = LocalProject( git_project=self.project, working_dir=self.service_config.command_handler_work_dir, ) self.api = PackitAPI(self.service_config, self.job_config, self.local_project) errors = {} default_dg_branch = self.api.dg.local_project.git_project.default_branch for branch in get_branches(*self.job_config.metadata.dist_git_branches, default=default_dg_branch): try: self.api.sync_release(dist_git_branch=branch, tag=self.data.tag_name) except Exception as ex: # the archive has not been uploaded to PyPI yet if FILE_DOWNLOAD_FAILURE in str(ex): # retry for the archive to become available logger.info( f"We were not able to download the archive: {ex}") # when the task hits max_retries, it raises MaxRetriesExceededError # and the error handling code would be never executed retries = self.task.request.retries if retries < int( getenv("CELERY_RETRY_LIMIT", DEFAULT_RETRY_LIMIT)): logger.info(f"Retrying for the {retries + 1}. time...") # throw=False so that exception is not raised and task # is not retried also automatically self.task.retry(exc=ex, countdown=15 * 2**retries, throw=False) return TaskResults( success=False, details={ "msg": "Task was retried, we were not able to download the archive." }, ) sentry_integration.send_to_sentry(ex) errors[branch] = str(ex) if errors: branch_errors = "" for branch, err in sorted( errors.items(), key=lambda branch_error: branch_error[0]): err_without_new_lines = err.replace("\n", " ") branch_errors += f"| `{branch}` | `{err_without_new_lines}` |\n" msg_retrigger = MSG_RETRIGGER.format(job="update", command="propose-downstream", place="issue") body_msg = ( f"Packit failed on creating pull-requests in dist-git:\n\n" f"| dist-git branch | error |\n" f"| --------------- | ----- |\n" f"{branch_errors}\n\n" f"{msg_retrigger}\n") self.project.create_issue( title= f"[packit] Propose downstream failed for release {self.data.tag_name}", body=body_msg, ) return TaskResults( success=False, details={ "msg": "Propose downstream failed.", "errors": errors }, ) return TaskResults(success=True, details={})
def koji( config, dist_git_path, dist_git_branch, from_upstream, koji_target, scratch, nowait, release_suffix, default_release_suffix, path_or_url, ): """ Build selected upstream project in Fedora. By default, packit checks out the respective dist-git repository and performs `fedpkg build` for the selected branch. With `--from-upstream`, packit creates a SRPM out of the current checkout and sends it to koji. PATH_OR_URL argument is a local path or a URL to the upstream git repository, it defaults to the current working directory """ api = get_packit_api(config=config, dist_git_path=dist_git_path, local_project=path_or_url) release_suffix = ChangelogHelper.resolve_release_suffix( api.package_config, release_suffix, default_release_suffix) default_dg_branch = api.dg.local_project.git_project.default_branch dist_git_branch = dist_git_branch or default_dg_branch branches_to_build = get_branches(*dist_git_branch.split(","), default_dg_branch=default_dg_branch) click.echo( f"Building from the following branches: {', '.join(branches_to_build)}" ) if koji_target is None: targets_to_build = {None} else: targets_to_build = get_koji_targets(koji_target) if len(targets_to_build) > 1 and len(branches_to_build) > 1: raise PackitConfigException( "Parameters --dist-git-branch and --koji-target cannot have " "multiple values at the same time.") for target in targets_to_build: for branch in branches_to_build: try: out = api.build( dist_git_branch=branch, scratch=scratch, nowait=nowait, koji_target=target, from_upstream=from_upstream, release_suffix=release_suffix, srpm_path=config.srpm_path, ) except PackitCommandFailedError as ex: logs_stdout = "\n>>> ".join( ex.stdout_output.strip().split("\n")) logs_stderr = "\n!!! ".join( ex.stderr_output.strip().split("\n")) click.echo( f"Build for branch '{branch}' failed. \n" f">>> {logs_stdout}\n" f"!!! {logs_stderr}\n", err=True, ) else: if out: print(ensure_str(out))
def test_get_branches_from_multiple_values(self, names, versions): flexmock(packit.config.aliases).should_receive( "get_versions").and_return(versions) assert get_branches(*names) == versions
def test_get_branches(name, branches): assert get_branches(name) == branches
def fedora_branches(): return sorted(get_branches("fedora-all"))
def test_get_branches_from_multiple_values(names, versions): assert get_branches(*names) == versions
def test_get_branches(self, name, branches, mock_get_aliases): assert get_branches(name) == branches
def run(self) -> TaskResults: """ Sync the upstream release to dist-git as a pull request. """ self.local_project = LocalProject( git_project=self.project, working_dir=self.service_config.command_handler_work_dir, ) self.api = PackitAPI(self.service_config, self.job_config, self.local_project) errors = {} for branch in get_branches(*self.job_config.metadata.dist_git_branches, default="master"): try: self.api.sync_release(dist_git_branch=branch, version=self.data.tag_name) except Exception as ex: # the archive has not been uploaded to PyPI yet if FILE_DOWNLOAD_FAILURE in str(ex): # retry for the archive to become available logger.info( f"We were not able to download the archive: {ex}") # when the task hits max_retries, it raises MaxRetriesExceededError # and the error handling code would be never executed retries = self.task.request.retries if retries < RETRY_LIMIT: logger.info(f"Retrying for the {retries + 1}. time...") self.task.retry(exc=ex, countdown=15 * 2**retries) sentry_integration.send_to_sentry(ex) errors[branch] = str(ex) if errors: branch_errors = "" for branch, err in sorted( errors.items(), key=lambda branch_error: branch_error[0]): err_without_new_lines = err.replace("\n", " ") branch_errors += f"| `{branch}` | `{err_without_new_lines}` |\n" body_msg = ( f"Packit failed on creating pull-requests in dist-git:\n\n" f"| dist-git branch | error |\n" f"| --------------- | ----- |\n" f"{branch_errors}\n\n" "You can re-trigger the update by adding `/packit propose-update`" " to the issue comment.\n") self.project.create_issue( title= f"[packit] Propose update failed for release {self.data.tag_name}", body=body_msg, ) return TaskResults( success=False, details={ "msg": "Propose update failed.", "errors": errors }, ) return TaskResults(success=True, details={})