def test_get_updates(upstream_n_distgit, expected_status, number_of_updates): u, d = upstream_n_distgit from bodhi.client.bindings import BodhiClient c = get_test_config() pc = get_local_package_config(str(u)) pc.downstream_project_url = str(d) pc.upstream_project_url = str(u) dg = DistGit(c, pc) pc = get_local_package_config(str(u)) flexmock(BodhiClient).should_receive("query").and_return(BODHI_UPDATES) status = Status(c, pc, u, dg) assert status table = status.get_updates(number_of_updates=number_of_updates) assert table assert len(table) == number_of_updates assert table == expected_status
def get_distgit_kls_from_repo( repo_path: Path, config: Config) -> Tuple[DistGit, Optional[str], Optional[str]]: """ :return: DistGit instance, centos package name, fedora package name """ path = Path(repo_path) pc = PackageConfig(downstream_package_name=path.name) lp = LocalProject(working_dir=path) if FEDORA_DOMAIN in lp.git_url: return DistGit(config, pc, local_project=lp), None, path.name elif CENTOS_DOMAIN in lp.git_url: return CentOS8DistGit(config, pc, local_project=lp), path.name, None elif CENTOS_STREAM_GITLAB in lp.git_url: return CentOS9DistGit(config, pc, local_project=lp), path.name, None raise PackitException( f"Dist-git URL {lp.git_url} not recognized, we expected one of: " f"{FEDORA_DOMAIN}, {CENTOS_DOMAIN} or {CENTOS_STREAM_GITLAB}")
def sync( self, distgit: DistGit, commit_msg: str, pr_title: str, pr_description: str, dist_git_branch: str, commit_msg_description: str = None, add_new_sources=False, ): if add_new_sources: archive = distgit.download_upstream_archive() distgit.upload_to_lookaside_cache(archive) distgit.commit(title=commit_msg, msg=commit_msg_description) # the branch may already be up, let's push forcefully distgit.push_to_fork(distgit.local_project.ref, force=True) distgit.create_pull( pr_title, pr_description, source_branch=distgit.local_project.ref, target_branch=dist_git_branch, )
def test_get_dg_versions(upstream_n_distgit, expected_versions): u, d = upstream_n_distgit c = get_test_config() pc = get_local_package_config(str(u)) pc.downstream_project_url = str(d) pc.upstream_project_url = str(u) dg = DistGit(c, pc) flexmock(dg.local_project.git_project).should_receive( "get_branches").and_return(expected_versions.keys()) flexmock(dg.specfile).should_receive("get_version").and_return("0.0.2") flexmock(dg).should_receive("checkout_branch").and_return(None) flexmock(dg).should_receive("create_branch").and_return(None) status = Status(c, pc, u, dg) dg_versions = status.get_dg_versions() assert dg_versions.keys() == expected_versions.keys() assert dg_versions == expected_versions
def dg(self): if self._dg is None: self.init_kerberos_ticket() if not self.package_config.downstream_package_name and ( self.downstream_local_project and self.downstream_local_project.working_dir): # the path to dist-git was passed but downstream_package_name is not set # we know that package names are equal to repo names self.package_config.downstream_package_name = ( self.downstream_local_project.working_dir.name) logger.info( "Package name was not set, we've got it from dist-git's " f"directory name: {self.package_config.downstream_package_name}" ) self._dg = DistGit( config=self.config, package_config=self.package_config, local_project=self.downstream_local_project, ) return self._dg
def test_downstream_pr(upstream_n_distgit, pr_list, number_prs): u, d = upstream_n_distgit c = get_test_config() pc = get_local_package_config(str(u)) pc.downstream_project_url = str(d) pc.upstream_project_url = str(u) dg = DistGit(c, pc) pc = get_local_package_config(str(u)) status = Status(c, pc, u, dg) flexmock( PagureProject, get_git_urls=lambda: {"git": "foo.git"}, fork_create=lambda: None, get_fork=lambda: PagureProject("", "", PagureService()), get_pr_list=pr_list, ) assert status table = status.get_downstream_prs(number_prs) assert table assert len(table) == number_prs
def test_update_on_cockpit_ostree(cockpit_ostree): upstream_path, dist_git_path = cockpit_ostree def mocked_new_sources(sources=None): if not Path(sources).is_file(): raise RuntimeError("archive does not exist") flexmock(FedPKG, init_ticket=lambda x=None: None, new_sources=mocked_new_sources) flexmock( DistGit, push_to_fork=lambda *args, **kwargs: None, is_archive_in_lookaside_cache=lambda archive_path: False, upload_to_lookaside_cache=lambda path: None, download_upstream_archive=lambda: "the-archive", ) flexmock( PackitAPI, push_and_create_pr=lambda pr_title, pr_description, dist_git_branch: None, ) pc = get_local_package_config(str(upstream_path)) up_lp = LocalProject(working_dir=str(upstream_path)) c = get_test_config() api = PackitAPI(c, pc, up_lp) api._dg = DistGit(c, pc) api._dg._local_project = LocalProject(working_dir=dist_git_path) with cwd(upstream_path): api.sync_release( "master", use_local_content=False, version="179", force_new_sources=False, create_pr=True, )
def _get_dist_git(self, ) -> DistGit: """ For given package names, clone the dist-git repo in the given directory and return the DistGit class :return: DistGit instance (CentOSDistGit if centos_package is set) """ if self.centos_package: self.dist_git_branch = self.dist_git_branch or "c8s" return CentOSDistGit.clone( self.config, self.package_config, self.dist_git_path, branch=self.dist_git_branch, ) self.dist_git_branch = self.dist_git_branch or "master" return DistGit.clone( self.config, self.package_config, self.dist_git_path, branch=self.dist_git_branch, )
def _get_dist_git(self, ) -> DistGit: """ For given package names, clone the dist-git repo in the given directory and return the DistGit class :return: DistGit instance """ if self.centos_package: self.dist_git_branch = self.dist_git_branch or "c9s" # let's be sure to cover anything 9 related, # even though "c9" will probably never be a thing if "c9" in self.dist_git_branch: return CentOS9DistGit.clone( config=self.config, package_config=self.package_config, path=self.dist_git_path, branch=self.dist_git_branch, ) return CentOS8DistGit.clone( config=self.config, package_config=self.package_config, path=self.dist_git_path, branch=self.dist_git_branch, ) else: # If self.dist_git_branch is None we will checkout/store repo's default branch dg = DistGit.clone( config=self.config, package_config=self.package_config, path=self.dist_git_path, branch=self.dist_git_branch, ) self.dist_git_branch = ( self.dist_git_branch or dg.local_project.git_project.default_branch) return dg
def sync_pr(self, pr_id, dist_git_branch: str, upstream_version: str = None): up = Upstream(config=self.config, package_config=self.package_config) dg = DistGit(config=self.config, package_config=self.package_config) up.checkout_pr(pr_id=pr_id) local_pr_branch = f"pull-request-{pr_id}-sync" # fetch and reset --hard upstream/$branch? dg.checkout_branch(dist_git_branch) dg.create_branch(local_pr_branch) dg.checkout_branch(local_pr_branch) dg.sync_files(up.local_project) patches = up.create_patches( upstream=upstream_version, destination=dg.local_project.working_dir ) dg.add_patches_to_specfile(patches) description = ( f"Upstream pr: {pr_id}\n" f"Upstream commit: {up.local_project.git_repo.head.commit}\n" ) self.sync( distgit=dg, commit_msg=f"Sync upstream pr: {pr_id}", pr_title=f"Upstream pr: {pr_id}", pr_description=description, dist_git_branch="master", add_new_sources=False, )
def distgit_mock(local_project_mock, config_mock, package_config_mock): distgit = DistGit( config=config_mock, package_config=package_config_mock, local_project=local_project_mock, ) flexmock(distgit) distgit.should_receive("is_dirty").and_return(False) distgit.should_receive("downstream_config").and_return(package_config_mock) distgit.should_receive("create_branch") distgit.should_receive("update_branch") distgit.should_receive("checkout_branch") distgit.should_receive("commit") distgit.should_receive("push") distgit.should_receive("absolute_specfile_dir").and_return(Path("/mock_path")) return distgit
def dg(self): if self._dg is None: self._dg = DistGit(config=self.config, package_config=self.package_config) return self._dg
class Status: """ This class provides methods to obtain status of the package """ def __init__(self, config: Config, package_config: PackageConfig): self.config = config self.package_config = package_config self.up = Upstream(config=self.config, package_config=self.package_config) self.dg = DistGit(config=self.config, package_config=self.package_config) def get_downstream_prs(self, number_of_prs: int = 5) -> None: """ Get specific number of latest downstream PRs :param number_of_prs: int :return: None """ pr_list = self.dg.local_project.git_project.get_pr_list() if len(pr_list) > 0: # take last `number_of_prs` PRs pr_list = (pr_list[:number_of_prs] if len(pr_list) > number_of_prs else pr_list) logger.info("Downstream PRs:") table = [[pr.id, pr.title, pr.url] for pr in pr_list] logger.info(tabulate(table, headers=["ID", "Title", "URL"])) else: logger.info("Downstream PRs: No open PRs.") def get_dg_versions(self) -> None: """ Get versions from all branches in Dist-git :return: None """ branches = self.dg.local_project.git_project.get_branches() for branch in branches: try: self.dg.create_branch(branch, base=f"remotes/origin/{branch}", setup_tracking=False) self.dg.checkout_branch(branch) except Exception as ex: logger.debug(f"Branch {branch} is not present: {ex}") continue try: logger.info(f"{branch}: {self.dg.specfile.get_version()}") except PackitException: logger.debug( f"Can't figure out the version of branch: {branch}") self.dg.checkout_branch("master") def get_up_releases(self, number_of_releases: int = 5) -> None: """ Get specific number of latest upstream releases :param number_of_releases: int :return: None """ latest_releases = self.up.local_project.git_project.get_releases() if len(latest_releases) > 0: logger.info("\nGitHub upstream releases:") # take last five releases latest_releases = (latest_releases[:number_of_releases] if len(latest_releases) > number_of_releases else latest_releases) upstream_releases_str = "\n".join(f"{release.tag_name}" for release in latest_releases) logger.info(upstream_releases_str) else: logger.info("\nGitHub upstream releases: No releases found.") def get_builds(self, number_of_builds: int = 3) -> None: """ Get specific number of latest builds from koji :param number_of_builds: int :return: None """ logger.info("\nLatest builds:") # https://github.com/fedora-infra/bodhi/issues/3058 from bodhi.client.bindings import BodhiClient b = BodhiClient() builds_d = b.latest_builds(self.dg.package_name) branches = self.dg.local_project.git_project.get_branches() branches.remove("master") # there is no master tag in koji for branch in branches: koji_tag = f"{branch}-updates-candidate" try: koji_builds = [builds_d[koji_tag]] # take last three builds koji_builds = (koji_builds[:number_of_builds] if len(koji_builds) > number_of_builds else koji_builds) koji_builds_str = "\n".join(f" - {b}" for b in koji_builds) logger.info(f"{branch}:\n{koji_builds_str}") except KeyError: logger.info(f"{branch}: No builds.") def get_updates(self, number_of_updates: int = 3) -> None: """ Get specific number of latest updates in bodhi :param number_of_updates: int :return: None """ logger.info("\nLatest bodhi updates:") # https://github.com/fedora-infra/bodhi/issues/3058 from bodhi.client.bindings import BodhiClient b = BodhiClient() results = b.query(packages=self.dg.package_name)["updates"] if len(results) > number_of_updates: results = results[:number_of_updates] table = [[result["title"], result["karma"], result["status"]] for result in results] logger.info(tabulate(table, headers=["Update", "Karma", "status"]))