Feature request
I would like to make the Git provider system in PR-Agent fully extensible.
Currently, adding support for another Git hosting platform requires modifying PR-Agent itself and adding the provider to a central list of supported providers.
Instead, I would like to treat the Git provider system as a dynamic registry that can discover providers at runtime.
This would allow third-party projects or hosting platforms to provide their own Git provider as a separate Python package without requiring any changes to PR-Agent.
Maybe use Python package entry points to register Git providers dynamically.
[project.entry-points."pr_agent.git_providers"]
github = "pr_agent.git_providers.github_provider:GithubProvider"
gitlab = "pr_agent.git_providers.gitlab_provider:GitLabProvider"
bitbucket = "pr_agent.git_providers.bitbucket_provider:BitbucketProvider"
bitbucket_server = "pr_agent.git_providers.bitbucket_server_provider:BitbucketServerProvider"
azure = "pr_agent.git_providers.azuredevops_provider:AzureDevopsProvider"
codecommit = "pr_agent.git_providers.codecommit_provider:CodeCommitProvider"
local = "pr_agent.git_providers.local_git_provider:LocalGitProvider"
gerrit = "pr_agent.git_providers.gerrit_provider:GerritProvider"
gitea = "pr_agent.git_providers.gitea_provider:GiteaProvider"
plain-diff = "pr_agent.git_providers.plain_diff_provider:PlainDiffGitProvider"
from __future__ import annotations
from importlib.metadata import entry_points
from typing import Type
from pr_agent.git_providers.git_provider import GitProvider
ENTRY_POINT_GROUP = "pr_agent.git_providers"
def get_git_provider_classes() -> dict[str, Type[GitProvider]]:
providers: dict[str, Type[GitProvider]] = {}
for entry_point in entry_points(group=ENTRY_POINT_GROUP):
provider = entry_point.load()
if not isinstance(provider, type):
raise TypeError(
f"Git provider entry point {entry_point.name!r} "
f"must point to a class"
)
if not issubclass(provider, GitProvider):
raise TypeError(
f"Git provider {entry_point.name!r} "
f"must inherit from GitProvider"
)
provider_id = getattr(provider, "provider_id", None)
if not provider_id:
raise ValueError(
f"Git provider {provider.__name__!r} "
f"does not define provider_id"
)
if provider_id in providers:
raise ValueError(
f"Duplicate git provider id: {provider_id!r}"
)
providers[provider_id] = provider
return providers
def get_git_provider_class(provider_id: str) -> Type[GitProvider]:
providers = get_git_provider_classes()
try:
return providers[provider_id]
except KeyError as e:
available = ", ".join(sorted(providers)) or "<none>"
raise ValueError(
f"Unknown git provider: {provider_id!r}. "
f"Available providers: {available}"
) from e
def _get_provider_id() -> str:
try:
provider_id = get_settings().config.git_provider
except AttributeError as e:
raise ValueError(
"git_provider is a required attribute in the configuration file"
) from e
if get_settings().get("plain_diff.content", None):
return "plain-diff"
return provider_id
def get_git_provider() -> type[GitProvider]:
return get_git_provider_class(_get_provider_id())
def get_git_provider_with_context(pr_url) -> GitProvider:
"""
Get a GitProvider instance for the given PR URL.
If the GitProvider instance is already in the context, return it.
"""
is_context_env = None
try:
is_context_env = context.get("settings", None)
except Exception:
pass
if is_context_env and context.get("git_provider", {}).get(pr_url):
return context["git_provider"][pr_url]
try:
provider_id = _get_provider_id()
provider_class = get_git_provider_class(provider_id)
git_provider = provider_class(pr_url)
if is_context_env:
context["git_provider"] = {
pr_url: git_provider,
}
return git_provider
except Exception as e:
raise ValueError(
f"Failed to get git provider for {pr_url}"
) from e
Motivation
This allows:
- Custom git provider with special settings
- Easier development of new git provider until it can be merged
Feature request
I would like to make the Git provider system in PR-Agent fully extensible.
Currently, adding support for another Git hosting platform requires modifying PR-Agent itself and adding the provider to a central list of supported providers.
Instead, I would like to treat the Git provider system as a dynamic registry that can discover providers at runtime.
This would allow third-party projects or hosting platforms to provide their own Git provider as a separate Python package without requiring any changes to PR-Agent.
Maybe use Python package entry points to register Git providers dynamically.
Motivation
This allows: