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

46 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-11-25 17:42 +0100

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

2from typing import Optional, Dict 

3from .base import GitProvider 

4from .exceptions import ProviderConfigError 

5 

6 

7class 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