Coverage for repo_ctx/providers/factory.py: 70%

1"""Factory for creating provider instances."""

2 from typing import Optional, Dict

3 from .base import GitProvider

4 from .exceptions import ProviderConfigError

5

6

7 class ProviderFactory:

8 """Factory for creating provider instances."""

9

10 # Registry of provider classes

11 _providers: Dict[str, type] = {}

12

13 @classmethod

14 def register(cls, name: str, provider_class: type):

15 """

16 Register a provider class.

17

18 Args:

19 name: Provider name (gitlab, github, local, etc.)

20 provider_class: Provider class implementing GitProvider

21 """

22 cls._providers[name] = provider_class

23

24 @classmethod

25 def create(

26 cls,

27 provider_type: str,

28 **kwargs

29 ) -> GitProvider:

30 """

31 Create provider instance.

32

33 Args:

34 provider_type: Provider type (gitlab, github, local, etc.)

35 **kwargs: Provider-specific configuration

36

37 Returns:

38 Provider instance

39

40 Raises:

41 ProviderConfigError: Provider type not registered or invalid config

42

43 Examples:

44 factory.create("gitlab", url="...", token="...")

45 factory.create("github", url="...", token="...")

46 factory.create("local")

47 """

48 if provider_type not in cls._providers:

49 available = ", ".join(cls._providers.keys())

50 raise ProviderConfigError(

51 f"Unknown provider type: {provider_type}. "

52 f"Available providers: {available}"

53 )

54

55 provider_class = cls._providers[provider_type]

56

57 try:

58 return provider_class(**kwargs)

59 except TypeError as e:

60 raise ProviderConfigError(

61 f"Invalid configuration for provider {provider_type}: {e}"

62 )

63

64 @classmethod

65 def create_gitlab(cls, url: str, token: str) -> GitProvider:

66 """

67 Create GitLab provider instance.

68

69 Args:

70 url: GitLab instance URL

71 token: Personal access token

72

73 Returns:

74 GitLab provider instance

75 """

76 return cls.create("gitlab", url=url, token=token)

77

78 @classmethod

79 def create_github(

80 cls,

81 url: str = "https://api.github.com",

82 token: Optional[str] = None

83 ) -> GitProvider:

84 """

85 Create GitHub provider instance.

86

87 Args:

88 url: GitHub API URL (default: public GitHub)

89 token: Personal access token (optional for public repos)

90

91 Returns:

92 GitHub provider instance

93 """

94 return cls.create("github", url=url, token=token)

95

96 @classmethod

97 def create_local(cls) -> GitProvider:

98 """

99 Create local Git provider instance.

100

101 Returns:

102 Local provider instance

103 """

104 return cls.create("local")

105

106 @classmethod

107 def from_config(cls, config, provider_type: str) -> GitProvider:

108 """

109 Create provider from configuration object.

110

111 Args:

112 config: Config object with provider settings

113 provider_type: Provider type to create

114

115 Returns:

116 Provider instance

117

118 Raises:

119 ProviderConfigError: Invalid provider type or missing config

120

121 Note:

122 Config object should have providers attribute with

123 gitlab, github, local sub-objects containing url/token

124 """

125 if provider_type == "gitlab":

126 if not hasattr(config, 'gitlab_url') or not hasattr(config, 'gitlab_token'):

127 raise ProviderConfigError(

128 "GitLab provider requires gitlab_url and gitlab_token in config"

129 )

130 return cls.create_gitlab(

131 url=config.gitlab_url,

132 token=config.gitlab_token

133 )

134

135 elif provider_type == "github":

136 # GitHub token is optional for public repos

137 url = getattr(config, 'github_url', "https://api.github.com")

138 token = getattr(config, 'github_token', None)

139 return cls.create_github(url=url, token=token)

140

141 elif provider_type == "local":

142 return cls.create_local()

143

144 else:

145 raise ProviderConfigError(f"Unknown provider type: {provider_type}")

146

147 @classmethod

148 def list_providers(cls) -> list[str]:

149 """

150 List all registered provider types.

151

152 Returns:

153 List of provider names

154 """

155 return list(cls._providers.keys())

156

157 @classmethod

158 def is_registered(cls, provider_type: str) -> bool:

159 """

160 Check if provider type is registered.

161

162 Args:

163 provider_type: Provider type to check

164

165 Returns:

166 True if registered, False otherwise

167 """

168 return provider_type in cls._providers