def __handle_project_create_fail(self, exception: PagureAPIException, namespace: str) -> None: if (exception.pagure_response and exception.pagure_response["errors"]["namespace"][0] == "Not a valid choice"): request_url = self.get_api_url("group", namespace) try: self.call_api(request_url, data={"projects": False}) except PagureAPIException: raise OgrException(f"Namespace doesn't exist ({namespace}).") raise OgrException( f"Cannot create project in given namespace (permissions).") raise exception
def get_fork(self, create: bool = True) -> Optional["PagureProject"]: """ Provide GitProject instance of a fork of this project. Returns None if this is a fork. :param create: create a fork if it doesn't exist :return: instance of GitProject or None """ if self.is_fork: raise OgrException("Cannot create fork from fork.") for fork in self.get_forks(): fork_info = fork.get_project_info() if self._user in fork_info["user"]["name"]: return fork if not self.is_forked(): if create: return self.fork_create() else: logger.info( f"Fork of {self.repo}" " does not exist and we were asked not to create it." ) return None return self._construct_fork_project()
def get_project( url, service_mapping_update: Dict[str, Type[GitService]] = None, custom_instances: List[GitService] = None, **kwargs, ) -> GitProject: """ Return the project for the given url. :param url: str (url of the project, e.g. "https://github.com/packit-service/ogr") :param service_mapping_update: custom mapping from service url (str) to service class :param custom_instances: list of instances that will be used when creating a project instance :param kwargs: arguments forwarded to __init__ of the matching service :return: GitProject using the matching implementation """ kls = get_service_class(url=url, service_mapping_update=service_mapping_update) if custom_instances: for service_inst in custom_instances: if isinstance(service_inst, kls) and service_inst.instance_url in url: service = service_inst break else: raise OgrException( f"Instance of type {kls.__name__} " f"matching instance url '{url}' was not provided.") else: repo_url = parse_git_repo(potential_url=url) service = kls(instance_url=repo_url.get_instance_url(), **kwargs) project = service.get_project_from_url(url=url) return project
def get_token(self, namespace: str, repo: str) -> str: response = requests.get(f"{self._instance_url}/api/{namespace}/{repo}") if not response.ok: raise OgrException( f"Couldn't retrieve token from Tokman: ({response.status_code}) {response.text}" ) return response.json().get("access_token", None)
def get_project( url, service_mapping_update: Dict[str, Type[GitService]] = None, custom_instances: Iterable[GitService] = None, force_custom_instance: bool = True, **kwargs, ) -> GitProject: """ Return the project for the given URL. Args: url: URL of the project, e.g. `"https://github.com/packit/ogr"`. service_mapping_update: Custom mapping from service url (`str`) to service class. Defaults to no mapping. custom_instances: List of instances that will be used when creating a project instance. Defaults to `None`. force_custom_instance: Force picking a Git service from the `custom_instances` list, if there is any provided, raise an error if that is not possible. Defaults to `True`. **kwargs: Arguments forwarded to __init__ of the matching service. Returns: `GitProject` using the matching implementation. """ mapping = service_mapping_update.copy() if service_mapping_update else {} custom_instances = custom_instances or [] for instance in custom_instances: mapping[instance.instance_url] = instance.__class__ kls = get_service_class(url=url, service_mapping_update=mapping) parsed_repo_url = parse_git_repo(url) service = None if custom_instances: for service_inst in custom_instances: if (isinstance(service_inst, kls) and service_inst.hostname == parsed_repo_url.hostname): service = service_inst break else: if force_custom_instance: raise OgrException( f"Instance of type {kls.__name__} " f"matching instance url '{url}' was not provided.") if not service: service = kls(instance_url=parsed_repo_url.get_instance_url(), **kwargs) return service.get_project_from_url(url=url)
def private_key(self) -> str: if self._private_key: return self._private_key if self._private_key_path: if not Path(self._private_key_path).is_file(): raise OgrException(f"File with the github-app private key " f"({self._private_key_path}) " f"does not exist.") return Path(self._private_key_path).read_text() return None
def get_project_from_url(self, url: str) -> "GitProject": """ Args: url: URL of the git repository. Returns: Object that represents project from the parsed URL. """ repo_url = parse_git_repo(potential_url=url) if not repo_url: raise OgrException(f"Failed to find repository for url: {url}") return self.get_project(repo=repo_url.repo, namespace=repo_url.namespace)
def get_project_from_url(self, url: str) -> "PagureProject": repo_url = parse_git_repo(potential_url=url) if not repo_url: raise OgrException(f"Cannot parse project url: '{url}'") if not repo_url.is_fork: repo_url.username = None project = self.get_project( repo=repo_url.repo, namespace=repo_url.namespace, is_fork=repo_url.is_fork, username=repo_url.username, ) return project
def get_service_class( url: str, service_mapping_update: Dict[str, Type[GitService]] = None ) -> Type[GitService]: """ Get the matching service class from the url. :param url: str (url of the project, e.g. "https://github.com/packit-service/ogr") :param service_mapping_update: custom mapping from service url (str) to service class :return: Matched class (subclass of GitService) """ service_kls = get_service_class_or_none( url=url, service_mapping_update=service_mapping_update) if service_kls: return service_kls raise OgrException("No matching service was found.")
def get_fork(self, create: bool = True) -> Optional["PagureProject"]: if self.is_fork: raise OgrException("Cannot create fork from fork.") for fork in self.get_forks(): fork_info = fork.get_project_info() if self._user in fork_info["user"]["name"]: return fork if not self.is_forked(): if create: return self.fork_create() else: logger.info( f"Fork of {self.repo}" " does not exist and we were asked not to create it.") return None return self._construct_fork_project()
def get_project( url, service_mapping_update: Dict[str, Type[GitService]] = None, custom_instances: Iterable[GitService] = None, force_custom_instance: bool = True, **kwargs, ) -> GitProject: """ Return the project for the given url. :param url: str (url of the project, e.g. "https://github.com/packit/ogr") :param service_mapping_update: custom mapping from service url (str) to service class :param custom_instances: list of instances that will be used when creating a project instance :param force_custom_instance: force picking a Git service from the custom_instances list, if there is any provided, raise an error if that's not possible :param kwargs: arguments forwarded to __init__ of the matching service :return: GitProject using the matching implementation """ mapping = service_mapping_update.copy() if service_mapping_update else {} custom_instances = custom_instances or [] for instance in custom_instances: mapping[instance.instance_url] = instance.__class__ kls = get_service_class(url=url, service_mapping_update=mapping) parsed_repo_url = parse_git_repo(url) service = None if custom_instances: for service_inst in custom_instances: if ( isinstance(service_inst, kls) and service_inst.hostname == parsed_repo_url.hostname ): service = service_inst break else: if force_custom_instance: raise OgrException( f"Instance of type {kls.__name__} " f"matching instance url '{url}' was not provided." ) if not service: service = kls(instance_url=parsed_repo_url.get_instance_url(), **kwargs) return service.get_project_from_url(url=url)
def get_service_class( url: str, service_mapping_update: Dict[str, Type[GitService]] = None ) -> Type[GitService]: """ Get the matching service class from the url. :param url: str (url of the project, e.g. "https://github.com/packit-service/ogr") :param service_mapping_update: custom mapping from service url (str) to service class :return: Matched class (subclass of GitService) """ mapping = {} mapping.update(_SERVICE_MAPPING) if service_mapping_update: mapping.update(service_mapping_update) for service, service_kls in mapping.items(): if service in url: return service_kls raise OgrException("No matching service was found.")
def get_token(self, namespace: str, repo: str) -> str: if not self.private_key: return None inst_id = self.integration.get_installation(namespace, repo).id # PyGithub<1.52 returned an object for id, with a value attribute, # which was None or an ID. # This was changed in: # https://github.com/PyGithub/PyGithub/commit/61808da15e8e3bcb660acd0e7947326a4a6c0c7a#diff-b8f1ee87df332916352809a397ea259aL54 # 'id' is now None or an ID. inst_id = (inst_id if isinstance(inst_id, int) or inst_id is None else inst_id.value) if not inst_id: raise OgrException( f"No installation ID provided for {namespace}/{repo}: " "please make sure that you provided correct credentials of your GitHub app." ) inst_auth = self.integration.get_access_token(inst_id) return inst_auth.token
def github_instance(self): if not self._github_instance: if self.service.github_app_id and self.service.github_app_private_key: integration = GithubIntegration( self.service.github_app_id, self.service.github_app_private_key) inst_id = integration.get_installation(self.namespace, self.repo).id.value if not inst_id: raise OgrException( f"No installation ID provided for {self.namespace}/{self.repo}: " "please make sure that you provided correct credentials of your GitHub app." ) inst_auth = integration.get_access_token(inst_id) self._github_instance = github.Github( login_or_token=inst_auth.token) else: self._github_instance = self.service.github return self._github_instance
def get_service_class( url: str, service_mapping_update: Dict[str, Type[GitService]] = None ) -> Type[GitService]: """ Get the matching service class from the URL. Args: url: URL of the project, e.g. `"https://github.com/packit/ogr"`. service_mapping_update: Custom mapping from service url (str) to service class. Defaults to `None`. Returns: Matched class (subclass of `GitService`). """ service_kls = get_service_class_or_none( url=url, service_mapping_update=service_mapping_update) if service_kls: return service_kls raise OgrException("No matching service was found.")
def project_create( self, repo: str, namespace: Optional[str] = None, description: Optional[str] = None, ) -> PagureProject: request_url = self.get_api_url("new") parameters = {"name": repo, "description": description, "wait": True} if not description: parameters["description"] = repo if namespace: parameters["namespace"] = namespace try: self.call_api(request_url, "POST", data=parameters) except PagureAPIException as ex: if (ex.pagure_response and ex.pagure_response["errors"]["namespace"][0] == "Not a valid choice"): raise OgrException( f"Cannot create project in given namespace ({namespace}).") raise ex return PagureProject(repo=repo, namespace=namespace, service=self)
def get_project_from_url(self, url: str) -> "GitProject": repo_url = parse_git_repo(potential_url=url) if not repo_url: raise OgrException(f"Failed to find repository for url: {url}") return self.get_project(repo=repo_url.repo, namespace=repo_url.namespace)
def get_project_from_url(self, url: str) -> "GitProject": repo_url = parse_git_repo(potential_url=url) if not repo_url: raise OgrException(f"Cannot parse project url: '{url}'") return self.get_project(repo=repo_url.repo, namespace=repo_url.namespace)
def get_instances_from_dict(instances: Dict) -> Set[GitService]: """ Load the service instances from the dictionary in the following form: - `key` : hostname, url or name that can be mapped to the service-type - `value` : dictionary with arguments used when creating a new instance of the service (passed to the `__init__` method) e.g.: ```py get_instances_from_dict({ "github.com": {"token": "abcd"}, "pagure": { "token": "abcd", "instance_url": "https://src.fedoraproject.org", }, }) == { GithubService(token="abcd"), PagureService(token="abcd", instance_url="https://src.fedoraproject.org") } ``` When the mapping `key->service-type` is not recognised, you can add a `type` key to the dictionary and specify the type of the instance. (It can be either name, hostname or url. The used mapping is same as for key->service-type.) The provided `key` is used as an `instance_url` and passed to the `__init__` method as well. e.g.: ```py get_instances_from_dict({ "https://my.gtlb": {"token": "abcd", "type": "gitlab"}, }) == {GitlabService(token="abcd", instance_url="https://my.gtlb")} ``` Args: instances: Mapping from service name/url/hostname to attributes for the service creation. Returns: Set of the service instances. """ services = set() for key, value in instances.items(): service_kls = get_service_class_or_none(url=key) if not service_kls: if "type" not in value: raise OgrException( f"No matching service was found for url '{key}'. " f"Add the service name as a `type` attribute.") service_type = value["type"] if service_type not in _SERVICE_MAPPING: raise OgrException( f"No matching service was found for type '{service_type}'." ) service_kls = _SERVICE_MAPPING[service_type] value.setdefault("instance_url", key) del value["type"] service_instance = service_kls(**value) services.add(service_instance) return services