auto-coder 0.1.398__py3-none-any.whl → 0.1.400__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of auto-coder might be problematic. Click here for more details.

Files changed (86) hide show
  1. auto_coder-0.1.400.dist-info/METADATA +396 -0
  2. {auto_coder-0.1.398.dist-info → auto_coder-0.1.400.dist-info}/RECORD +82 -29
  3. {auto_coder-0.1.398.dist-info → auto_coder-0.1.400.dist-info}/WHEEL +1 -1
  4. {auto_coder-0.1.398.dist-info → auto_coder-0.1.400.dist-info}/entry_points.txt +2 -0
  5. autocoder/agent/base_agentic/base_agent.py +2 -2
  6. autocoder/agent/base_agentic/tools/replace_in_file_tool_resolver.py +1 -1
  7. autocoder/agent/entry_command_agent/__init__.py +29 -0
  8. autocoder/agent/entry_command_agent/auto_tool.py +61 -0
  9. autocoder/agent/entry_command_agent/chat.py +475 -0
  10. autocoder/agent/entry_command_agent/designer.py +53 -0
  11. autocoder/agent/entry_command_agent/generate_command.py +50 -0
  12. autocoder/agent/entry_command_agent/project_reader.py +58 -0
  13. autocoder/agent/entry_command_agent/voice2text.py +71 -0
  14. autocoder/auto_coder.py +23 -548
  15. autocoder/auto_coder_runner.py +511 -8
  16. autocoder/chat/rules_command.py +1 -1
  17. autocoder/chat_auto_coder.py +6 -1
  18. autocoder/common/ac_style_command_parser/__init__.py +15 -0
  19. autocoder/common/ac_style_command_parser/example.py +7 -0
  20. autocoder/{command_parser.py → common/ac_style_command_parser/parser.py} +28 -45
  21. autocoder/common/ac_style_command_parser/test_parser.py +516 -0
  22. autocoder/common/auto_coder_lang.py +78 -0
  23. autocoder/common/command_completer_v2.py +1 -1
  24. autocoder/common/command_file_manager/examples.py +22 -8
  25. autocoder/common/command_file_manager/manager.py +37 -6
  26. autocoder/common/conversations/get_conversation_manager.py +143 -0
  27. autocoder/common/conversations/manager.py +122 -11
  28. autocoder/common/conversations/storage/index_manager.py +89 -0
  29. autocoder/common/pull_requests/__init__.py +256 -0
  30. autocoder/common/pull_requests/base_provider.py +191 -0
  31. autocoder/common/pull_requests/config.py +66 -0
  32. autocoder/common/pull_requests/example.py +1 -0
  33. autocoder/common/pull_requests/exceptions.py +46 -0
  34. autocoder/common/pull_requests/manager.py +201 -0
  35. autocoder/common/pull_requests/models.py +164 -0
  36. autocoder/common/pull_requests/providers/__init__.py +23 -0
  37. autocoder/common/pull_requests/providers/gitcode_provider.py +19 -0
  38. autocoder/common/pull_requests/providers/gitee_provider.py +20 -0
  39. autocoder/common/pull_requests/providers/github_provider.py +214 -0
  40. autocoder/common/pull_requests/providers/gitlab_provider.py +29 -0
  41. autocoder/common/pull_requests/test_module.py +1 -0
  42. autocoder/common/pull_requests/utils.py +344 -0
  43. autocoder/common/tokens/__init__.py +62 -0
  44. autocoder/common/tokens/counter.py +211 -0
  45. autocoder/common/tokens/file_detector.py +105 -0
  46. autocoder/common/tokens/filters.py +111 -0
  47. autocoder/common/tokens/models.py +28 -0
  48. autocoder/common/v2/agent/agentic_edit.py +312 -85
  49. autocoder/common/v2/agent/agentic_edit_types.py +11 -0
  50. autocoder/common/v2/code_auto_generate_editblock.py +10 -2
  51. autocoder/dispacher/__init__.py +10 -0
  52. autocoder/rags.py +0 -27
  53. autocoder/run_context.py +1 -0
  54. autocoder/sdk/__init__.py +188 -0
  55. autocoder/sdk/cli/__init__.py +15 -0
  56. autocoder/sdk/cli/__main__.py +26 -0
  57. autocoder/sdk/cli/completion_wrapper.py +38 -0
  58. autocoder/sdk/cli/formatters.py +211 -0
  59. autocoder/sdk/cli/handlers.py +175 -0
  60. autocoder/sdk/cli/install_completion.py +301 -0
  61. autocoder/sdk/cli/main.py +286 -0
  62. autocoder/sdk/cli/options.py +73 -0
  63. autocoder/sdk/constants.py +102 -0
  64. autocoder/sdk/core/__init__.py +20 -0
  65. autocoder/sdk/core/auto_coder_core.py +880 -0
  66. autocoder/sdk/core/bridge.py +500 -0
  67. autocoder/sdk/example.py +0 -0
  68. autocoder/sdk/exceptions.py +72 -0
  69. autocoder/sdk/models/__init__.py +19 -0
  70. autocoder/sdk/models/messages.py +209 -0
  71. autocoder/sdk/models/options.py +196 -0
  72. autocoder/sdk/models/responses.py +311 -0
  73. autocoder/sdk/session/__init__.py +32 -0
  74. autocoder/sdk/session/session.py +106 -0
  75. autocoder/sdk/session/session_manager.py +56 -0
  76. autocoder/sdk/utils/__init__.py +24 -0
  77. autocoder/sdk/utils/formatters.py +216 -0
  78. autocoder/sdk/utils/io_utils.py +302 -0
  79. autocoder/sdk/utils/validators.py +287 -0
  80. autocoder/version.py +2 -1
  81. auto_coder-0.1.398.dist-info/METADATA +0 -111
  82. autocoder/common/conversations/compatibility.py +0 -303
  83. autocoder/common/conversations/conversation_manager.py +0 -502
  84. autocoder/common/conversations/example.py +0 -152
  85. {auto_coder-0.1.398.dist-info → auto_coder-0.1.400.dist-info/licenses}/LICENSE +0 -0
  86. {auto_coder-0.1.398.dist-info → auto_coder-0.1.400.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,256 @@
1
+ """
2
+ Pull Request 统一管理模块
3
+
4
+ 统一的 Pull Request 创建和管理模块,支持 GitHub、GitLab、Gitee、GitCode 四大代码托管平台的 PR 操作。
5
+ """
6
+ from typing import Optional, List, Dict, Any
7
+ from loguru import logger
8
+
9
+ from .models import (
10
+ PRConfig, PRResult, PRInfo, PRData, RepoInfo, PlatformType,
11
+ DEFAULT_TEMPLATES
12
+ )
13
+ from .manager import PullRequestManager, get_global_manager, set_global_config
14
+ from .exceptions import (
15
+ PRError, AuthenticationError, RepositoryNotFoundError,
16
+ BranchNotFoundError, NetworkError, RateLimitError,
17
+ ValidationError, PlatformNotSupportedError, ConfigurationError
18
+ )
19
+ from .config import get_config
20
+ from .utils import (
21
+ parse_git_url, detect_platform_from_repo, get_repo_info_from_path,
22
+ get_current_branch, branch_exists, is_git_repo, get_default_remote_branch,
23
+ ensure_branch_exists_remotely, is_main_branch, create_and_checkout_branch,
24
+ generate_auto_branch_name
25
+ )
26
+
27
+
28
+ def create_pull_request(
29
+ repo_path: str,
30
+ title: str,
31
+ source_branch: Optional[str] = None,
32
+ target_branch: Optional[str] = None,
33
+ description: str = "",
34
+ labels: Optional[List[str]] = None,
35
+ assignees: Optional[List[str]] = None,
36
+ reviewers: Optional[List[str]] = None,
37
+ draft: bool = False,
38
+ template_type: Optional[str] = None,
39
+ template_vars: Optional[Dict[str, str]] = None,
40
+ platform: Optional[str] = None,
41
+ token: Optional[str] = None,
42
+ **kwargs
43
+ ) -> PRResult:
44
+ """
45
+ 创建 Pull Request(主要接口函数)
46
+
47
+ Args:
48
+ repo_path: 仓库路径
49
+ title: PR标题
50
+ source_branch: 源分支(可选,默认为当前分支)
51
+ target_branch: 目标分支(可选,默认为远程默认分支或main)
52
+ description: PR描述
53
+ labels: 标签列表
54
+ assignees: 负责人列表
55
+ reviewers: 审查者列表
56
+ draft: 是否为草稿PR
57
+ template_type: 模板类型
58
+ template_vars: 模板变量
59
+ platform: 平台类型(可选,会自动检测)
60
+ token: 访问令牌(可选)
61
+ **kwargs: 其他配置参数
62
+
63
+ Returns:
64
+ PR创建结果
65
+ """
66
+ # 处理可选的分支参数
67
+ if source_branch is None:
68
+ source_branch = get_current_branch(repo_path)
69
+ if not source_branch:
70
+ raise ValidationError("无法获取当前分支,请指定source_branch参数")
71
+
72
+ # 从当前分支,自动创建新分支
73
+ auto_branch_name = generate_auto_branch_name()
74
+ logger.info(f"检测到当前分支 '{source_branch}' 为主分支,自动创建新分支: {auto_branch_name}")
75
+
76
+ if not create_and_checkout_branch(repo_path, auto_branch_name):
77
+ raise ValidationError(f"无法从主分支 '{source_branch}' 创建新分支 '{auto_branch_name}'")
78
+
79
+ source_branch = auto_branch_name
80
+ logger.info(f"已切换到新分支: {source_branch}")
81
+
82
+ if target_branch is None:
83
+ target_branch = get_default_remote_branch(repo_path)
84
+ if not target_branch:
85
+ target_branch = "main" # 默认值
86
+
87
+ # 验证仓库是否为Git仓库
88
+ if not is_git_repo(repo_path):
89
+ raise ValidationError(f"路径 {repo_path} 不是一个有效的Git仓库")
90
+
91
+ # 检查源分支和目标分支是否相同
92
+ if source_branch == target_branch:
93
+ raise ValidationError(f"源分支和目标分支不能相同: {source_branch}")
94
+
95
+ # 确保源分支存在于远程仓库,如果不存在则自动推送
96
+ if not ensure_branch_exists_remotely(repo_path, source_branch):
97
+ raise BranchNotFoundError(
98
+ f"源分支 '{source_branch}' 在本地不存在或推送失败。"
99
+ f"请检查分支是否存在或网络连接是否正常。"
100
+ )
101
+
102
+ # 检查目标分支是否存在于远程仓库
103
+ if not branch_exists(repo_path, target_branch, remote=True):
104
+ raise BranchNotFoundError(
105
+ f"目标分支 '{target_branch}' 在远程仓库中不存在。"
106
+ )
107
+
108
+ # 如果提供了token,创建临时配置
109
+ manager = get_global_manager()
110
+
111
+ if token:
112
+ # 自动检测平台或使用指定平台
113
+ if not platform:
114
+ detected_platform = detect_platform_from_repo(repo_path)
115
+ if detected_platform:
116
+ platform = detected_platform.value
117
+ else:
118
+ raise ValidationError("无法检测平台类型,请指定platform参数")
119
+
120
+ # 创建临时配置
121
+ temp_config = PRConfig(platform=PlatformType(platform), token=token)
122
+ temp_manager = PullRequestManager(temp_config)
123
+
124
+ return temp_manager.create_pull_request(
125
+ repo_path=repo_path,
126
+ source_branch=source_branch,
127
+ target_branch=target_branch,
128
+ title=title,
129
+ description=description,
130
+ labels=labels,
131
+ assignees=assignees,
132
+ reviewers=reviewers,
133
+ draft=draft,
134
+ template_type=template_type,
135
+ template_vars=template_vars,
136
+ platform=platform
137
+ )
138
+ else:
139
+ # 使用全局管理器
140
+ return manager.create_pull_request(
141
+ repo_path=repo_path,
142
+ source_branch=source_branch,
143
+ target_branch=target_branch,
144
+ title=title,
145
+ description=description,
146
+ labels=labels,
147
+ assignees=assignees,
148
+ reviewers=reviewers,
149
+ draft=draft,
150
+ template_type=template_type,
151
+ template_vars=template_vars,
152
+ platform=platform
153
+ )
154
+
155
+
156
+ def get_pull_request(
157
+ repo_path: str,
158
+ pr_number: int,
159
+ platform: Optional[str] = None,
160
+ token: Optional[str] = None,
161
+ **kwargs
162
+ ) -> PRResult:
163
+ """获取 Pull Request 信息"""
164
+ manager = get_global_manager()
165
+
166
+ if token:
167
+ if not platform:
168
+ detected_platform = detect_platform_from_repo(repo_path)
169
+ if detected_platform:
170
+ platform = detected_platform.value
171
+ else:
172
+ raise ValidationError("无法检测平台类型,请指定platform参数")
173
+
174
+ config_data = {"token": token}
175
+ config_data.update(kwargs)
176
+ temp_config = PRConfig(platform=platform, **config_data)
177
+ temp_manager = PullRequestManager(temp_config)
178
+
179
+ return temp_manager.get_pull_request(repo_path, pr_number, platform)
180
+ else:
181
+ return manager.get_pull_request(repo_path, pr_number, platform)
182
+
183
+
184
+ def list_pull_requests(
185
+ repo_path: str,
186
+ state: str = "open",
187
+ per_page: int = 30,
188
+ page: int = 1,
189
+ platform: Optional[str] = None,
190
+ token: Optional[str] = None,
191
+ **kwargs
192
+ ) -> List[PRInfo]:
193
+ """列出 Pull Requests"""
194
+ manager = get_global_manager()
195
+
196
+ if token:
197
+ if not platform:
198
+ detected_platform = detect_platform_from_repo(repo_path)
199
+ if detected_platform:
200
+ platform = detected_platform.value
201
+ else:
202
+ raise ValidationError("无法检测平台类型,请指定platform参数")
203
+
204
+ config_data = {"token": token}
205
+ config_data.update(kwargs)
206
+ temp_config = PRConfig(platform=platform, **config_data)
207
+ temp_manager = PullRequestManager(temp_config)
208
+
209
+ return temp_manager.list_pull_requests(repo_path, state, per_page, page, platform)
210
+ else:
211
+ return manager.list_pull_requests(repo_path, state, per_page, page, platform)
212
+
213
+
214
+ # 导出所有公共接口
215
+ __all__ = [
216
+ # 主要函数
217
+ 'create_pull_request',
218
+ 'get_pull_request',
219
+ 'list_pull_requests',
220
+
221
+ # 类和模型
222
+ 'PullRequestManager',
223
+ 'PRConfig',
224
+ 'PRResult',
225
+ 'PRInfo',
226
+ 'PRData',
227
+ 'RepoInfo',
228
+ 'PlatformType',
229
+
230
+ # 异常
231
+ 'PRError',
232
+ 'AuthenticationError',
233
+ 'RepositoryNotFoundError',
234
+ 'BranchNotFoundError',
235
+ 'NetworkError',
236
+ 'RateLimitError',
237
+ 'ValidationError',
238
+ 'PlatformNotSupportedError',
239
+ 'ConfigurationError',
240
+
241
+ # 工具函数
242
+ 'parse_git_url',
243
+ 'detect_platform_from_repo',
244
+ 'get_repo_info_from_path',
245
+ 'get_current_branch',
246
+ 'branch_exists',
247
+ 'is_git_repo',
248
+
249
+ # 配置函数
250
+ 'get_config',
251
+ 'set_global_config',
252
+ 'get_global_manager',
253
+
254
+ # 模板
255
+ 'DEFAULT_TEMPLATES'
256
+ ]
@@ -0,0 +1,191 @@
1
+ """
2
+ Pull Request 平台提供者基类
3
+ """
4
+ from abc import ABC, abstractmethod
5
+ from typing import Optional, Dict, Any, List
6
+ import requests
7
+ import time
8
+ from loguru import logger
9
+
10
+ from .models import RepoInfo, PRData, PRResult, PRInfo, PRConfig
11
+ from .exceptions import (
12
+ PRError, NetworkError, AuthenticationError, RateLimitError,
13
+ RepositoryNotFoundError, ValidationError
14
+ )
15
+
16
+
17
+ class BasePlatformProvider(ABC):
18
+ """平台提供者基类,定义统一接口"""
19
+
20
+ def __init__(self, config: PRConfig):
21
+ self.config = config
22
+ self.session = self._create_session()
23
+
24
+ def _create_session(self) -> requests.Session:
25
+ """创建HTTP会话"""
26
+ session = requests.Session()
27
+ session.headers.update({
28
+ 'User-Agent': 'AutoCoder-PR/1.0',
29
+ 'Authorization': self._get_auth_header(),
30
+ 'Accept': 'application/json',
31
+ 'Content-Type': 'application/json'
32
+ })
33
+ session.verify = self.config.verify_ssl
34
+ return session
35
+
36
+ @abstractmethod
37
+ def _get_auth_header(self) -> str:
38
+ """获取认证头"""
39
+ pass
40
+
41
+ def _make_request(
42
+ self,
43
+ method: str,
44
+ url: str,
45
+ data: Optional[Dict[str, Any]] = None,
46
+ params: Optional[Dict[str, str]] = None,
47
+ retry_count: Optional[int] = None
48
+ ) -> requests.Response:
49
+ """发送HTTP请求,包含重试逻辑"""
50
+
51
+ if retry_count is None:
52
+ retry_count = self.config.retry_count
53
+
54
+ last_exception = None
55
+
56
+ for attempt in range(retry_count + 1):
57
+ try:
58
+ response = self.session.request(
59
+ method=method,
60
+ url=url,
61
+ json=data,
62
+ params=params,
63
+ timeout=self.config.timeout
64
+ )
65
+
66
+ if response.status_code == 401:
67
+ raise AuthenticationError("认证失败,请检查token是否正确")
68
+ elif response.status_code == 404:
69
+ raise RepositoryNotFoundError("仓库或资源不存在")
70
+ elif response.status_code == 429:
71
+ retry_after = int(response.headers.get('Retry-After', 60))
72
+ raise RateLimitError(f"API限流,请等待{retry_after}秒后重试", retry_after=retry_after)
73
+ elif response.status_code == 422:
74
+ # 422 通常是验证错误,尝试解析响应内容获取详细错误信息
75
+ try:
76
+ error_data = response.json()
77
+ if 'errors' in error_data:
78
+ errors = error_data['errors']
79
+ error_msgs = []
80
+ for error in errors:
81
+ if isinstance(error, dict):
82
+ field = error.get('field', '')
83
+ code = error.get('code', '')
84
+ message = error.get('message', str(error))
85
+ if field and code:
86
+ error_msgs.append(f"{field}: {message} (code: {code})")
87
+ else:
88
+ error_msgs.append(message)
89
+ else:
90
+ error_msgs.append(str(error))
91
+ raise ValidationError(f"请求验证失败: {'; '.join(error_msgs)}")
92
+ elif 'message' in error_data:
93
+ raise ValidationError(f"请求验证失败: {error_data['message']}")
94
+ else:
95
+ raise ValidationError(f"请求验证失败: {response.text}")
96
+ except (ValueError, KeyError):
97
+ raise ValidationError(f"请求验证失败: HTTP 422 - {response.text}")
98
+ elif response.status_code >= 400:
99
+ try:
100
+ error_data = response.json()
101
+ if 'message' in error_data:
102
+ raise PRError(f"API请求失败: HTTP {response.status_code} - {error_data['message']}")
103
+ else:
104
+ raise PRError(f"API请求失败: HTTP {response.status_code} - {response.text}")
105
+ except (ValueError, KeyError):
106
+ raise PRError(f"API请求失败: HTTP {response.status_code} - {response.text}")
107
+
108
+ return response
109
+
110
+ except (requests.exceptions.RequestException, ConnectionError) as e:
111
+ last_exception = NetworkError(f"网络请求失败: {str(e)}")
112
+
113
+ if attempt < retry_count:
114
+ delay = 2 ** attempt
115
+ logger.warning(f"请求失败,{delay}秒后重试")
116
+ time.sleep(delay)
117
+ continue
118
+
119
+ except RateLimitError as e:
120
+ if attempt < retry_count:
121
+ logger.warning(f"遇到限流,等待{e.retry_after}秒后重试")
122
+ time.sleep(e.retry_after)
123
+ continue
124
+ raise
125
+
126
+ if last_exception:
127
+ raise last_exception
128
+
129
+ raise PRError("请求失败,已达到最大重试次数")
130
+
131
+ def _validate_pr_data(self, pr_data: PRData) -> None:
132
+ """验证PR数据"""
133
+ if not pr_data.title.strip():
134
+ raise ValidationError("PR标题不能为空")
135
+ if not pr_data.source_branch.strip():
136
+ raise ValidationError("源分支不能为空")
137
+ if not pr_data.target_branch.strip():
138
+ raise ValidationError("目标分支不能为空")
139
+ if pr_data.source_branch == pr_data.target_branch:
140
+ raise ValidationError("源分支和目标分支不能相同")
141
+
142
+ def _validate_repo_info(self, repo_info: RepoInfo) -> None:
143
+ """验证仓库信息"""
144
+ if not repo_info.owner.strip():
145
+ raise ValidationError("仓库所有者不能为空")
146
+ if not repo_info.name.strip():
147
+ raise ValidationError("仓库名称不能为空")
148
+
149
+ @abstractmethod
150
+ def create_pr(self, repo_info: RepoInfo, pr_data: PRData) -> PRResult:
151
+ """创建 Pull Request"""
152
+ pass
153
+
154
+ @abstractmethod
155
+ def get_pr(self, repo_info: RepoInfo, pr_number: int) -> PRResult:
156
+ """获取 PR 信息"""
157
+ pass
158
+
159
+ @abstractmethod
160
+ def update_pr(self, repo_info: RepoInfo, pr_number: int, **kwargs) -> PRResult:
161
+ """更新 PR"""
162
+ pass
163
+
164
+ @abstractmethod
165
+ def close_pr(self, repo_info: RepoInfo, pr_number: int) -> PRResult:
166
+ """关闭 PR"""
167
+ pass
168
+
169
+ @abstractmethod
170
+ def merge_pr(self, repo_info: RepoInfo, pr_number: int, **kwargs) -> PRResult:
171
+ """合并 PR"""
172
+ pass
173
+
174
+ @abstractmethod
175
+ def list_prs(
176
+ self,
177
+ repo_info: RepoInfo,
178
+ state: str = "open",
179
+ per_page: int = 30,
180
+ page: int = 1
181
+ ) -> List[PRInfo]:
182
+ """列出仓库的PR"""
183
+ pass
184
+
185
+ def health_check(self) -> bool:
186
+ """检查连接和认证状态"""
187
+ try:
188
+ response = self._make_request('GET', f"{self.config.base_url}/user")
189
+ return response.status_code == 200
190
+ except Exception:
191
+ return False
@@ -0,0 +1,66 @@
1
+ """
2
+ Pull Request 配置管理
3
+ """
4
+ import os
5
+ from typing import Dict, Any, Optional
6
+ from .models import PRConfig, PlatformType
7
+ from .exceptions import ConfigurationError
8
+
9
+
10
+ def get_config(platform: str, **overrides) -> PRConfig:
11
+ """
12
+ 获取平台配置
13
+
14
+ Args:
15
+ platform: 平台名称
16
+ **overrides: 配置覆盖参数
17
+
18
+ Returns:
19
+ 配置对象
20
+ """
21
+ # 从环境变量加载配置
22
+ env_config = _load_from_env(platform)
23
+
24
+ # 合并配置
25
+ merged_config = {}
26
+ if env_config:
27
+ merged_config.update(env_config)
28
+ merged_config.update(overrides)
29
+
30
+ # 验证必需的配置
31
+ if 'token' not in merged_config:
32
+ raise ConfigurationError(f"平台 {platform} 缺少必需的 token 配置")
33
+
34
+ return PRConfig(platform=PlatformType(platform), **merged_config)
35
+
36
+
37
+ def _load_from_env(platform: str) -> Dict[str, Any]:
38
+ """从环境变量加载配置"""
39
+ env_mappings = {
40
+ 'github': {
41
+ 'token': 'GITHUB_TOKEN',
42
+ 'base_url': 'GITHUB_BASE_URL'
43
+ },
44
+ 'gitlab': {
45
+ 'token': 'GITLAB_TOKEN',
46
+ 'base_url': 'GITLAB_BASE_URL'
47
+ },
48
+ 'gitee': {
49
+ 'token': 'GITEE_TOKEN',
50
+ 'base_url': 'GITEE_BASE_URL'
51
+ },
52
+ 'gitcode': {
53
+ 'token': 'GITCODE_TOKEN',
54
+ 'base_url': 'GITCODE_BASE_URL'
55
+ }
56
+ }
57
+
58
+ mapping = env_mappings.get(platform, {})
59
+ config = {}
60
+
61
+ for key, env_var in mapping.items():
62
+ value = os.getenv(env_var)
63
+ if value:
64
+ config[key] = value
65
+
66
+ return config
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,46 @@
1
+ """
2
+ Pull Request 模块自定义异常类
3
+ """
4
+ from typing import Optional
5
+
6
+ class PRError(Exception):
7
+ """Pull Request 操作基础异常"""
8
+ def __init__(self, message: str, error_code: Optional[str] = None, platform: Optional[str] = None):
9
+ self.message = message
10
+ self.error_code = error_code
11
+ self.platform = platform
12
+ super().__init__(message)
13
+
14
+ class AuthenticationError(PRError):
15
+ """认证失败异常"""
16
+ pass
17
+
18
+ class RepositoryNotFoundError(PRError):
19
+ """仓库不存在异常"""
20
+ pass
21
+
22
+ class BranchNotFoundError(PRError):
23
+ """分支不存在异常"""
24
+ pass
25
+
26
+ class NetworkError(PRError):
27
+ """网络错误异常"""
28
+ pass
29
+
30
+ class RateLimitError(PRError):
31
+ """API 限流异常"""
32
+ def __init__(self, message: str, retry_after: int = 60, **kwargs):
33
+ self.retry_after = retry_after
34
+ super().__init__(message, **kwargs)
35
+
36
+ class ValidationError(PRError):
37
+ """参数验证错误异常"""
38
+ pass
39
+
40
+ class PlatformNotSupportedError(PRError):
41
+ """平台不支持异常"""
42
+ pass
43
+
44
+ class ConfigurationError(PRError):
45
+ """配置错误异常"""
46
+ pass