argus-review-code 0.1.0__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.
Files changed (550) hide show
  1. argus_review/__init__.py +0 -0
  2. argus_review/cli/__init__.py +0 -0
  3. argus_review/cli/commands/__init__.py +0 -0
  4. argus_review/cli/commands/run_clear_inline_review.py +6 -0
  5. argus_review/cli/commands/run_clear_summary_review.py +6 -0
  6. argus_review/cli/commands/run_context_review.py +7 -0
  7. argus_review/cli/commands/run_inline_reply_review.py +7 -0
  8. argus_review/cli/commands/run_inline_review.py +7 -0
  9. argus_review/cli/commands/run_review.py +8 -0
  10. argus_review/cli/commands/run_summary_reply_review.py +7 -0
  11. argus_review/cli/commands/run_summary_review.py +7 -0
  12. argus_review/cli/main.py +97 -0
  13. argus_review/clients/__init__.py +0 -0
  14. argus_review/clients/azure_devops/__init__.py +0 -0
  15. argus_review/clients/azure_devops/client.py +39 -0
  16. argus_review/clients/azure_devops/pr/__init__.py +0 -0
  17. argus_review/clients/azure_devops/pr/client.py +253 -0
  18. argus_review/clients/azure_devops/pr/schema/__init__.py +0 -0
  19. argus_review/clients/azure_devops/pr/schema/files.py +51 -0
  20. argus_review/clients/azure_devops/pr/schema/pull_request.py +38 -0
  21. argus_review/clients/azure_devops/pr/schema/threads.py +108 -0
  22. argus_review/clients/azure_devops/pr/schema/user.py +12 -0
  23. argus_review/clients/azure_devops/pr/types.py +66 -0
  24. argus_review/clients/azure_devops/schema.py +8 -0
  25. argus_review/clients/azure_devops/tools.py +40 -0
  26. argus_review/clients/azure_openai/__init__.py +0 -0
  27. argus_review/clients/azure_openai/client.py +61 -0
  28. argus_review/clients/azure_openai/schema.py +57 -0
  29. argus_review/clients/azure_openai/types.py +8 -0
  30. argus_review/clients/bedrock/__init__.py +0 -0
  31. argus_review/clients/bedrock/client.py +78 -0
  32. argus_review/clients/bedrock/schema.py +46 -0
  33. argus_review/clients/bedrock/types.py +8 -0
  34. argus_review/clients/bitbucket_cloud/__init__.py +0 -0
  35. argus_review/clients/bitbucket_cloud/client.py +38 -0
  36. argus_review/clients/bitbucket_cloud/pr/__init__.py +0 -0
  37. argus_review/clients/bitbucket_cloud/pr/client.py +192 -0
  38. argus_review/clients/bitbucket_cloud/pr/schema/__init__.py +0 -0
  39. argus_review/clients/bitbucket_cloud/pr/schema/comments.py +63 -0
  40. argus_review/clients/bitbucket_cloud/pr/schema/files.py +30 -0
  41. argus_review/clients/bitbucket_cloud/pr/schema/pull_request.py +34 -0
  42. argus_review/clients/bitbucket_cloud/pr/schema/user.py +7 -0
  43. argus_review/clients/bitbucket_cloud/pr/types.py +53 -0
  44. argus_review/clients/bitbucket_cloud/tools.py +6 -0
  45. argus_review/clients/bitbucket_server/__init__.py +0 -0
  46. argus_review/clients/bitbucket_server/client.py +38 -0
  47. argus_review/clients/bitbucket_server/pr/__init__.py +0 -0
  48. argus_review/clients/bitbucket_server/pr/client.py +194 -0
  49. argus_review/clients/bitbucket_server/pr/schema/__init__.py +0 -0
  50. argus_review/clients/bitbucket_server/pr/schema/activities.py +29 -0
  51. argus_review/clients/bitbucket_server/pr/schema/changes.py +36 -0
  52. argus_review/clients/bitbucket_server/pr/schema/comments.py +37 -0
  53. argus_review/clients/bitbucket_server/pr/schema/pull_request.py +48 -0
  54. argus_review/clients/bitbucket_server/pr/schema/user.py +13 -0
  55. argus_review/clients/bitbucket_server/pr/types.py +53 -0
  56. argus_review/clients/bitbucket_server/tools.py +6 -0
  57. argus_review/clients/claude/__init__.py +0 -0
  58. argus_review/clients/claude/client.py +52 -0
  59. argus_review/clients/claude/schema.py +44 -0
  60. argus_review/clients/claude/types.py +8 -0
  61. argus_review/clients/gemini/__init__.py +0 -0
  62. argus_review/clients/gemini/client.py +54 -0
  63. argus_review/clients/gemini/schema.py +78 -0
  64. argus_review/clients/gemini/types.py +8 -0
  65. argus_review/clients/gitea/__init__.py +0 -0
  66. argus_review/clients/gitea/client.py +38 -0
  67. argus_review/clients/gitea/pr/__init__.py +0 -0
  68. argus_review/clients/gitea/pr/client.py +237 -0
  69. argus_review/clients/gitea/pr/schema/__init__.py +0 -0
  70. argus_review/clients/gitea/pr/schema/comments.py +35 -0
  71. argus_review/clients/gitea/pr/schema/files.py +16 -0
  72. argus_review/clients/gitea/pr/schema/pull_request.py +18 -0
  73. argus_review/clients/gitea/pr/schema/reviews.py +56 -0
  74. argus_review/clients/gitea/pr/schema/user.py +6 -0
  75. argus_review/clients/gitea/pr/types.py +51 -0
  76. argus_review/clients/gitea/tools.py +6 -0
  77. argus_review/clients/github/__init__.py +0 -0
  78. argus_review/clients/github/client.py +38 -0
  79. argus_review/clients/github/pr/__init__.py +0 -0
  80. argus_review/clients/github/pr/client.py +219 -0
  81. argus_review/clients/github/pr/schema/__init__.py +0 -0
  82. argus_review/clients/github/pr/schema/comments.py +59 -0
  83. argus_review/clients/github/pr/schema/files.py +17 -0
  84. argus_review/clients/github/pr/schema/pull_request.py +27 -0
  85. argus_review/clients/github/pr/schema/user.py +6 -0
  86. argus_review/clients/github/pr/types.py +60 -0
  87. argus_review/clients/github/tools.py +6 -0
  88. argus_review/clients/gitlab/__init__.py +0 -0
  89. argus_review/clients/gitlab/client.py +38 -0
  90. argus_review/clients/gitlab/mr/__init__.py +0 -0
  91. argus_review/clients/gitlab/mr/client.py +196 -0
  92. argus_review/clients/gitlab/mr/schema/__init__.py +0 -0
  93. argus_review/clients/gitlab/mr/schema/changes.py +31 -0
  94. argus_review/clients/gitlab/mr/schema/discussions.py +38 -0
  95. argus_review/clients/gitlab/mr/schema/notes.py +29 -0
  96. argus_review/clients/gitlab/mr/schema/position.py +13 -0
  97. argus_review/clients/gitlab/mr/schema/user.py +7 -0
  98. argus_review/clients/gitlab/mr/types.py +46 -0
  99. argus_review/clients/gitlab/tools.py +5 -0
  100. argus_review/clients/ollama/__init__.py +0 -0
  101. argus_review/clients/ollama/client.py +48 -0
  102. argus_review/clients/ollama/schema.py +48 -0
  103. argus_review/clients/ollama/types.py +8 -0
  104. argus_review/clients/openai/__init__.py +0 -0
  105. argus_review/clients/openai/v1/__init__.py +0 -0
  106. argus_review/clients/openai/v1/client.py +50 -0
  107. argus_review/clients/openai/v1/schema.py +38 -0
  108. argus_review/clients/openai/v1/types.py +8 -0
  109. argus_review/clients/openai/v2/__init__.py +0 -0
  110. argus_review/clients/openai/v2/client.py +53 -0
  111. argus_review/clients/openai/v2/schema.py +48 -0
  112. argus_review/clients/openai/v2/types.py +11 -0
  113. argus_review/clients/openai_compatible/__init__.py +0 -0
  114. argus_review/clients/openai_compatible/client.py +45 -0
  115. argus_review/clients/openrouter/__init__.py +0 -0
  116. argus_review/clients/openrouter/client.py +57 -0
  117. argus_review/clients/openrouter/schema.py +36 -0
  118. argus_review/clients/openrouter/types.py +11 -0
  119. argus_review/config.py +68 -0
  120. argus_review/libs/__init__.py +0 -0
  121. argus_review/libs/asynchronous/__init__.py +0 -0
  122. argus_review/libs/asynchronous/gather.py +24 -0
  123. argus_review/libs/aws/__init__.py +0 -0
  124. argus_review/libs/aws/signv4.py +198 -0
  125. argus_review/libs/config/__init__.py +0 -0
  126. argus_review/libs/config/agent.py +20 -0
  127. argus_review/libs/config/artifacts.py +14 -0
  128. argus_review/libs/config/base.py +24 -0
  129. argus_review/libs/config/conventions.py +72 -0
  130. argus_review/libs/config/core.py +5 -0
  131. argus_review/libs/config/http.py +24 -0
  132. argus_review/libs/config/llm/__init__.py +0 -0
  133. argus_review/libs/config/llm/azure_openai.py +10 -0
  134. argus_review/libs/config/llm/base.py +114 -0
  135. argus_review/libs/config/llm/bedrock.py +13 -0
  136. argus_review/libs/config/llm/claude.py +10 -0
  137. argus_review/libs/config/llm/gemini.py +10 -0
  138. argus_review/libs/config/llm/meta.py +7 -0
  139. argus_review/libs/config/llm/nine_router.py +18 -0
  140. argus_review/libs/config/llm/ollama.py +15 -0
  141. argus_review/libs/config/llm/openai.py +14 -0
  142. argus_review/libs/config/llm/openai_compatible.py +24 -0
  143. argus_review/libs/config/llm/openrouter.py +12 -0
  144. argus_review/libs/config/logger.py +17 -0
  145. argus_review/libs/config/prompt.py +176 -0
  146. argus_review/libs/config/review.py +39 -0
  147. argus_review/libs/config/vcs/__init__.py +0 -0
  148. argus_review/libs/config/vcs/azure_devops.py +23 -0
  149. argus_review/libs/config/vcs/base.py +70 -0
  150. argus_review/libs/config/vcs/bitbucket_cloud.py +13 -0
  151. argus_review/libs/config/vcs/bitbucket_server.py +13 -0
  152. argus_review/libs/config/vcs/gitea.py +13 -0
  153. argus_review/libs/config/vcs/github.py +13 -0
  154. argus_review/libs/config/vcs/gitlab.py +12 -0
  155. argus_review/libs/config/vcs/pagination.py +6 -0
  156. argus_review/libs/constants/__init__.py +0 -0
  157. argus_review/libs/constants/llm_provider.py +19 -0
  158. argus_review/libs/constants/vcs_provider.py +10 -0
  159. argus_review/libs/crypto/__init__.py +0 -0
  160. argus_review/libs/crypto/sha.py +14 -0
  161. argus_review/libs/diff/__init__.py +0 -0
  162. argus_review/libs/diff/models.py +100 -0
  163. argus_review/libs/diff/parser.py +111 -0
  164. argus_review/libs/diff/tools.py +24 -0
  165. argus_review/libs/http/__init__.py +0 -0
  166. argus_review/libs/http/authentication/__init__.py +0 -0
  167. argus_review/libs/http/authentication/basic.py +5 -0
  168. argus_review/libs/http/client.py +31 -0
  169. argus_review/libs/http/event_hooks/__init__.py +0 -0
  170. argus_review/libs/http/event_hooks/base.py +13 -0
  171. argus_review/libs/http/event_hooks/logger.py +20 -0
  172. argus_review/libs/http/handlers.py +34 -0
  173. argus_review/libs/http/paginate.py +94 -0
  174. argus_review/libs/http/transports/__init__.py +0 -0
  175. argus_review/libs/http/transports/retry.py +51 -0
  176. argus_review/libs/json.py +16 -0
  177. argus_review/libs/llm/__init__.py +0 -0
  178. argus_review/libs/llm/output_json_parser.py +60 -0
  179. argus_review/libs/logger.py +19 -0
  180. argus_review/libs/resources.py +24 -0
  181. argus_review/libs/template/__init__.py +0 -0
  182. argus_review/libs/template/render.py +13 -0
  183. argus_review/libs/text.py +6 -0
  184. argus_review/prompts/__init__.py +0 -0
  185. argus_review/prompts/default_agent.md +37 -0
  186. argus_review/prompts/default_context.md +14 -0
  187. argus_review/prompts/default_inline.md +8 -0
  188. argus_review/prompts/default_inline_reply.md +10 -0
  189. argus_review/prompts/default_summary.md +3 -0
  190. argus_review/prompts/default_summary_reply.md +14 -0
  191. argus_review/prompts/default_system_agent.md +30 -0
  192. argus_review/prompts/default_system_context.md +27 -0
  193. argus_review/prompts/default_system_inline.md +25 -0
  194. argus_review/prompts/default_system_inline_reply.md +31 -0
  195. argus_review/prompts/default_system_summary.md +7 -0
  196. argus_review/prompts/default_system_summary_reply.md +13 -0
  197. argus_review/resources/__init__.py +0 -0
  198. argus_review/resources/pricing.yaml +117 -0
  199. argus_review/services/__init__.py +0 -0
  200. argus_review/services/agent/__init__.py +0 -0
  201. argus_review/services/agent/loop/__init__.py +0 -0
  202. argus_review/services/agent/loop/schema.py +76 -0
  203. argus_review/services/agent/loop/service.py +209 -0
  204. argus_review/services/agent/loop/types.py +13 -0
  205. argus_review/services/agent/tool/__init__.py +0 -0
  206. argus_review/services/agent/tool/service.py +85 -0
  207. argus_review/services/agent/tool/types.py +6 -0
  208. argus_review/services/artifacts/__init__.py +0 -0
  209. argus_review/services/artifacts/schema/__init__.py +0 -0
  210. argus_review/services/artifacts/schema/base.py +23 -0
  211. argus_review/services/artifacts/schema/llm.py +15 -0
  212. argus_review/services/artifacts/schema/vcs.py +41 -0
  213. argus_review/services/artifacts/service.py +129 -0
  214. argus_review/services/artifacts/types.py +59 -0
  215. argus_review/services/conventions/__init__.py +0 -0
  216. argus_review/services/conventions/schema.py +6 -0
  217. argus_review/services/conventions/service.py +74 -0
  218. argus_review/services/conventions/sources.py +100 -0
  219. argus_review/services/conventions/types.py +7 -0
  220. argus_review/services/cost/__init__.py +0 -0
  221. argus_review/services/cost/schema.py +49 -0
  222. argus_review/services/cost/service.py +58 -0
  223. argus_review/services/cost/types.py +11 -0
  224. argus_review/services/diff/__init__.py +0 -0
  225. argus_review/services/diff/renderers.py +156 -0
  226. argus_review/services/diff/schema.py +6 -0
  227. argus_review/services/diff/service.py +97 -0
  228. argus_review/services/diff/tools.py +59 -0
  229. argus_review/services/diff/types.py +28 -0
  230. argus_review/services/git/__init__.py +0 -0
  231. argus_review/services/git/service.py +85 -0
  232. argus_review/services/git/types.py +13 -0
  233. argus_review/services/hook/__init__.py +5 -0
  234. argus_review/services/hook/constants.py +46 -0
  235. argus_review/services/hook/service.py +306 -0
  236. argus_review/services/hook/types.py +53 -0
  237. argus_review/services/llm/__init__.py +0 -0
  238. argus_review/services/llm/azure_openai/__init__.py +0 -0
  239. argus_review/services/llm/azure_openai/client.py +26 -0
  240. argus_review/services/llm/bedrock/__init__.py +0 -0
  241. argus_review/services/llm/bedrock/client.py +27 -0
  242. argus_review/services/llm/claude/__init__.py +0 -0
  243. argus_review/services/llm/claude/client.py +26 -0
  244. argus_review/services/llm/factory.py +33 -0
  245. argus_review/services/llm/gemini/__init__.py +0 -0
  246. argus_review/services/llm/gemini/client.py +31 -0
  247. argus_review/services/llm/ollama/__init__.py +0 -0
  248. argus_review/services/llm/ollama/client.py +35 -0
  249. argus_review/services/llm/openai/__init__.py +0 -0
  250. argus_review/services/llm/openai/client.py +56 -0
  251. argus_review/services/llm/openai_compatible/__init__.py +0 -0
  252. argus_review/services/llm/openai_compatible/client.py +35 -0
  253. argus_review/services/llm/openrouter/__init__.py +0 -0
  254. argus_review/services/llm/openrouter/client.py +31 -0
  255. argus_review/services/llm/types.py +15 -0
  256. argus_review/services/policy/__init__.py +0 -0
  257. argus_review/services/policy/service.py +78 -0
  258. argus_review/services/policy/types.py +18 -0
  259. argus_review/services/prompt/__init__.py +0 -0
  260. argus_review/services/prompt/adapter.py +25 -0
  261. argus_review/services/prompt/schema.py +41 -0
  262. argus_review/services/prompt/service.py +169 -0
  263. argus_review/services/prompt/tools.py +71 -0
  264. argus_review/services/prompt/types.py +63 -0
  265. argus_review/services/review/__init__.py +0 -0
  266. argus_review/services/review/gateway/__init__.py +0 -0
  267. argus_review/services/review/gateway/review_agent_llm_gateway.py +56 -0
  268. argus_review/services/review/gateway/review_comment_gateway.py +159 -0
  269. argus_review/services/review/gateway/review_direct_llm_gateway.py +52 -0
  270. argus_review/services/review/gateway/review_dry_run_comment_gateway.py +81 -0
  271. argus_review/services/review/gateway/types.py +57 -0
  272. argus_review/services/review/internal/__init__.py +0 -0
  273. argus_review/services/review/internal/inline/__init__.py +0 -0
  274. argus_review/services/review/internal/inline/schema.py +53 -0
  275. argus_review/services/review/internal/inline/service.py +40 -0
  276. argus_review/services/review/internal/inline/types.py +8 -0
  277. argus_review/services/review/internal/inline_reply/__init__.py +0 -0
  278. argus_review/services/review/internal/inline_reply/schema.py +23 -0
  279. argus_review/services/review/internal/inline_reply/service.py +20 -0
  280. argus_review/services/review/internal/inline_reply/types.py +8 -0
  281. argus_review/services/review/internal/summary/__init__.py +0 -0
  282. argus_review/services/review/internal/summary/schema.py +19 -0
  283. argus_review/services/review/internal/summary/service.py +15 -0
  284. argus_review/services/review/internal/summary/types.py +8 -0
  285. argus_review/services/review/internal/summary_reply/__init__.py +0 -0
  286. argus_review/services/review/internal/summary_reply/schema.py +8 -0
  287. argus_review/services/review/internal/summary_reply/service.py +15 -0
  288. argus_review/services/review/internal/summary_reply/types.py +8 -0
  289. argus_review/services/review/runner/__init__.py +0 -0
  290. argus_review/services/review/runner/context.py +75 -0
  291. argus_review/services/review/runner/inline.py +83 -0
  292. argus_review/services/review/runner/inline_reply.py +80 -0
  293. argus_review/services/review/runner/summary.py +74 -0
  294. argus_review/services/review/runner/summary_reply.py +79 -0
  295. argus_review/services/review/runner/types.py +6 -0
  296. argus_review/services/review/service.py +162 -0
  297. argus_review/services/vcs/__init__.py +0 -0
  298. argus_review/services/vcs/azure_devops/__init__.py +0 -0
  299. argus_review/services/vcs/azure_devops/adapter.py +29 -0
  300. argus_review/services/vcs/azure_devops/client.py +370 -0
  301. argus_review/services/vcs/bitbucket_cloud/__init__.py +0 -0
  302. argus_review/services/vcs/bitbucket_cloud/adapter.py +27 -0
  303. argus_review/services/vcs/bitbucket_cloud/client.py +292 -0
  304. argus_review/services/vcs/bitbucket_server/__init__.py +0 -0
  305. argus_review/services/vcs/bitbucket_server/adapter.py +27 -0
  306. argus_review/services/vcs/bitbucket_server/client.py +295 -0
  307. argus_review/services/vcs/bitbucket_server/tools.py +14 -0
  308. argus_review/services/vcs/factory.py +27 -0
  309. argus_review/services/vcs/gitea/__init__.py +0 -0
  310. argus_review/services/vcs/gitea/adapter.py +37 -0
  311. argus_review/services/vcs/gitea/client.py +218 -0
  312. argus_review/services/vcs/github/__init__.py +0 -0
  313. argus_review/services/vcs/github/adapter.py +35 -0
  314. argus_review/services/vcs/github/client.py +260 -0
  315. argus_review/services/vcs/gitlab/__init__.py +0 -0
  316. argus_review/services/vcs/gitlab/adapter.py +28 -0
  317. argus_review/services/vcs/gitlab/client.py +260 -0
  318. argus_review/services/vcs/types.py +104 -0
  319. argus_review/tests/__init__.py +0 -0
  320. argus_review/tests/fixtures/__init__.py +0 -0
  321. argus_review/tests/fixtures/clients/__init__.py +0 -0
  322. argus_review/tests/fixtures/clients/azure_devops.py +282 -0
  323. argus_review/tests/fixtures/clients/azure_openai.py +82 -0
  324. argus_review/tests/fixtures/clients/bedrock.py +76 -0
  325. argus_review/tests/fixtures/clients/bitbucket_cloud.py +226 -0
  326. argus_review/tests/fixtures/clients/bitbucket_server.py +283 -0
  327. argus_review/tests/fixtures/clients/claude.py +67 -0
  328. argus_review/tests/fixtures/clients/gemini.py +73 -0
  329. argus_review/tests/fixtures/clients/gitea.py +215 -0
  330. argus_review/tests/fixtures/clients/github.py +209 -0
  331. argus_review/tests/fixtures/clients/gitlab.py +223 -0
  332. argus_review/tests/fixtures/clients/ollama.py +65 -0
  333. argus_review/tests/fixtures/clients/openai.py +141 -0
  334. argus_review/tests/fixtures/clients/openai_compatible.py +87 -0
  335. argus_review/tests/fixtures/clients/openrouter.py +72 -0
  336. argus_review/tests/fixtures/libs/__init__.py +0 -0
  337. argus_review/tests/fixtures/libs/llm/__init__.py +0 -0
  338. argus_review/tests/fixtures/libs/llm/output_json_parser.py +13 -0
  339. argus_review/tests/fixtures/services/__init__.py +0 -0
  340. argus_review/tests/fixtures/services/agent/__init__.py +0 -0
  341. argus_review/tests/fixtures/services/agent/loop.py +47 -0
  342. argus_review/tests/fixtures/services/agent/tool.py +31 -0
  343. argus_review/tests/fixtures/services/artifacts.py +72 -0
  344. argus_review/tests/fixtures/services/cost.py +47 -0
  345. argus_review/tests/fixtures/services/diff.py +46 -0
  346. argus_review/tests/fixtures/services/git.py +47 -0
  347. argus_review/tests/fixtures/services/hook.py +8 -0
  348. argus_review/tests/fixtures/services/llm.py +29 -0
  349. argus_review/tests/fixtures/services/policy.py +36 -0
  350. argus_review/tests/fixtures/services/prompt.py +138 -0
  351. argus_review/tests/fixtures/services/review/__init__.py +0 -0
  352. argus_review/tests/fixtures/services/review/base.py +41 -0
  353. argus_review/tests/fixtures/services/review/gateway/__init__.py +0 -0
  354. argus_review/tests/fixtures/services/review/gateway/review_agent_llm_gateway.py +42 -0
  355. argus_review/tests/fixtures/services/review/gateway/review_comment_gateway.py +118 -0
  356. argus_review/tests/fixtures/services/review/gateway/review_direct_llm_gateway.py +42 -0
  357. argus_review/tests/fixtures/services/review/gateway/review_dry_run_comment_gateway.py +123 -0
  358. argus_review/tests/fixtures/services/review/internal/__init__.py +0 -0
  359. argus_review/tests/fixtures/services/review/internal/inline.py +27 -0
  360. argus_review/tests/fixtures/services/review/internal/inline_reply.py +25 -0
  361. argus_review/tests/fixtures/services/review/internal/summary.py +21 -0
  362. argus_review/tests/fixtures/services/review/internal/summary_reply.py +19 -0
  363. argus_review/tests/fixtures/services/review/runner/__init__.py +0 -0
  364. argus_review/tests/fixtures/services/review/runner/context.py +50 -0
  365. argus_review/tests/fixtures/services/review/runner/inline.py +50 -0
  366. argus_review/tests/fixtures/services/review/runner/inline_reply.py +50 -0
  367. argus_review/tests/fixtures/services/review/runner/summary.py +50 -0
  368. argus_review/tests/fixtures/services/review/runner/summary_reply.py +50 -0
  369. argus_review/tests/fixtures/services/vcs.py +86 -0
  370. argus_review/tests/suites/__init__.py +0 -0
  371. argus_review/tests/suites/cli/__init__.py +0 -0
  372. argus_review/tests/suites/cli/test_main.py +111 -0
  373. argus_review/tests/suites/clients/__init__.py +0 -0
  374. argus_review/tests/suites/clients/azure_devops/__init__.py +0 -0
  375. argus_review/tests/suites/clients/azure_devops/test_client.py +14 -0
  376. argus_review/tests/suites/clients/azure_devops/test_tools.py +101 -0
  377. argus_review/tests/suites/clients/azure_openai/__init__.py +0 -0
  378. argus_review/tests/suites/clients/azure_openai/test_client.py +12 -0
  379. argus_review/tests/suites/clients/azure_openai/test_schema.py +116 -0
  380. argus_review/tests/suites/clients/bedrock/__init__.py +0 -0
  381. argus_review/tests/suites/clients/bedrock/test_client.py +12 -0
  382. argus_review/tests/suites/clients/bedrock/test_schema.py +67 -0
  383. argus_review/tests/suites/clients/bitbucket_cloud/__init__.py +0 -0
  384. argus_review/tests/suites/clients/bitbucket_cloud/test_client.py +14 -0
  385. argus_review/tests/suites/clients/bitbucket_cloud/test_tools.py +31 -0
  386. argus_review/tests/suites/clients/bitbucket_server/__init__.py +0 -0
  387. argus_review/tests/suites/clients/bitbucket_server/test_client.py +14 -0
  388. argus_review/tests/suites/clients/bitbucket_server/test_tools.py +38 -0
  389. argus_review/tests/suites/clients/claude/__init__.py +0 -0
  390. argus_review/tests/suites/clients/claude/test_client.py +12 -0
  391. argus_review/tests/suites/clients/claude/test_schema.py +59 -0
  392. argus_review/tests/suites/clients/gemini/__init__.py +0 -0
  393. argus_review/tests/suites/clients/gemini/test_client.py +12 -0
  394. argus_review/tests/suites/clients/gemini/test_schema.py +105 -0
  395. argus_review/tests/suites/clients/gitea/__init__.py +0 -0
  396. argus_review/tests/suites/clients/gitea/test_client.py +14 -0
  397. argus_review/tests/suites/clients/gitea/test_tools.py +26 -0
  398. argus_review/tests/suites/clients/github/__init__.py +0 -0
  399. argus_review/tests/suites/clients/github/test_client.py +14 -0
  400. argus_review/tests/suites/clients/github/test_tools.py +31 -0
  401. argus_review/tests/suites/clients/gitlab/__init__.py +0 -0
  402. argus_review/tests/suites/clients/gitlab/test_client.py +14 -0
  403. argus_review/tests/suites/clients/gitlab/test_tools.py +26 -0
  404. argus_review/tests/suites/clients/ollama/__init__.py +0 -0
  405. argus_review/tests/suites/clients/ollama/test_client.py +12 -0
  406. argus_review/tests/suites/clients/ollama/test_schema.py +65 -0
  407. argus_review/tests/suites/clients/openai/__init__.py +0 -0
  408. argus_review/tests/suites/clients/openai/v1/__init__.py +0 -0
  409. argus_review/tests/suites/clients/openai/v1/test_client.py +12 -0
  410. argus_review/tests/suites/clients/openai/v1/test_schema.py +66 -0
  411. argus_review/tests/suites/clients/openai/v2/__init__.py +0 -0
  412. argus_review/tests/suites/clients/openai/v2/test_client.py +12 -0
  413. argus_review/tests/suites/clients/openai/v2/test_schema.py +93 -0
  414. argus_review/tests/suites/clients/openrouter/__init__.py +0 -0
  415. argus_review/tests/suites/clients/openrouter/test_client.py +12 -0
  416. argus_review/tests/suites/clients/openrouter/test_schema.py +57 -0
  417. argus_review/tests/suites/libs/__init__.py +0 -0
  418. argus_review/tests/suites/libs/asynchronous/__init__.py +0 -0
  419. argus_review/tests/suites/libs/asynchronous/test_gather.py +46 -0
  420. argus_review/tests/suites/libs/aws/__init__.py +0 -0
  421. argus_review/tests/suites/libs/aws/test_signv4.py +262 -0
  422. argus_review/tests/suites/libs/config/__init__.py +0 -0
  423. argus_review/tests/suites/libs/config/llm/__init__.py +0 -0
  424. argus_review/tests/suites/libs/config/llm/test_openai.py +28 -0
  425. argus_review/tests/suites/libs/config/llm/test_openai_compatible.py +53 -0
  426. argus_review/tests/suites/libs/config/test_agent.py +55 -0
  427. argus_review/tests/suites/libs/config/test_conventions.py +55 -0
  428. argus_review/tests/suites/libs/config/test_prompt.py +192 -0
  429. argus_review/tests/suites/libs/crypto/__init__.py +0 -0
  430. argus_review/tests/suites/libs/crypto/test_sha.py +75 -0
  431. argus_review/tests/suites/libs/diff/__init__.py +0 -0
  432. argus_review/tests/suites/libs/diff/test_models.py +105 -0
  433. argus_review/tests/suites/libs/diff/test_parser.py +115 -0
  434. argus_review/tests/suites/libs/diff/test_tools.py +62 -0
  435. argus_review/tests/suites/libs/http/__init__.py +0 -0
  436. argus_review/tests/suites/libs/http/authentication/__init__.py +0 -0
  437. argus_review/tests/suites/libs/http/authentication/test_basic.py +30 -0
  438. argus_review/tests/suites/libs/http/test_paginate.py +208 -0
  439. argus_review/tests/suites/libs/llm/__init__.py +0 -0
  440. argus_review/tests/suites/libs/llm/test_output_json_parser.py +155 -0
  441. argus_review/tests/suites/libs/template/__init__.py +0 -0
  442. argus_review/tests/suites/libs/template/test_render.py +64 -0
  443. argus_review/tests/suites/libs/test_json.py +27 -0
  444. argus_review/tests/suites/libs/test_text.py +27 -0
  445. argus_review/tests/suites/packaging/__init__.py +1 -0
  446. argus_review/tests/suites/packaging/test_metadata.py +27 -0
  447. argus_review/tests/suites/services/__init__.py +0 -0
  448. argus_review/tests/suites/services/agent/__init__.py +0 -0
  449. argus_review/tests/suites/services/agent/loop/__init__.py +0 -0
  450. argus_review/tests/suites/services/agent/loop/test_schema.py +165 -0
  451. argus_review/tests/suites/services/agent/loop/test_service.py +300 -0
  452. argus_review/tests/suites/services/agent/tool/__init__.py +0 -0
  453. argus_review/tests/suites/services/agent/tool/test_service.py +154 -0
  454. argus_review/tests/suites/services/artifacts/__init__.py +0 -0
  455. argus_review/tests/suites/services/artifacts/test_service.py +270 -0
  456. argus_review/tests/suites/services/conventions/__init__.py +0 -0
  457. argus_review/tests/suites/services/conventions/test_service.py +107 -0
  458. argus_review/tests/suites/services/conventions/test_sources.py +120 -0
  459. argus_review/tests/suites/services/cost/__init__.py +0 -0
  460. argus_review/tests/suites/services/cost/test_schema.py +124 -0
  461. argus_review/tests/suites/services/cost/test_service.py +98 -0
  462. argus_review/tests/suites/services/diff/__init__.py +0 -0
  463. argus_review/tests/suites/services/diff/test_renderers.py +191 -0
  464. argus_review/tests/suites/services/diff/test_service.py +84 -0
  465. argus_review/tests/suites/services/diff/test_tools.py +127 -0
  466. argus_review/tests/suites/services/git/__init__.py +0 -0
  467. argus_review/tests/suites/services/git/test_service.py +200 -0
  468. argus_review/tests/suites/services/hook/__init__.py +0 -0
  469. argus_review/tests/suites/services/hook/test_service.py +194 -0
  470. argus_review/tests/suites/services/llm/__init__.py +0 -0
  471. argus_review/tests/suites/services/llm/azure_openai/__init__.py +0 -0
  472. argus_review/tests/suites/services/llm/azure_openai/test_client.py +22 -0
  473. argus_review/tests/suites/services/llm/bedrock/__init__.py +0 -0
  474. argus_review/tests/suites/services/llm/bedrock/test_client.py +22 -0
  475. argus_review/tests/suites/services/llm/claude/__init__.py +0 -0
  476. argus_review/tests/suites/services/llm/claude/test_client.py +22 -0
  477. argus_review/tests/suites/services/llm/gemini/__init__.py +0 -0
  478. argus_review/tests/suites/services/llm/gemini/test_client.py +22 -0
  479. argus_review/tests/suites/services/llm/ollama/__init__.py +0 -0
  480. argus_review/tests/suites/services/llm/ollama/test_client.py +22 -0
  481. argus_review/tests/suites/services/llm/openai/__init__.py +0 -0
  482. argus_review/tests/suites/services/llm/openai/test_client.py +39 -0
  483. argus_review/tests/suites/services/llm/openai_compatible/__init__.py +0 -0
  484. argus_review/tests/suites/services/llm/openai_compatible/test_client.py +36 -0
  485. argus_review/tests/suites/services/llm/openrouter/__init__.py +0 -0
  486. argus_review/tests/suites/services/llm/openrouter/test_client.py +22 -0
  487. argus_review/tests/suites/services/llm/test_factory.py +71 -0
  488. argus_review/tests/suites/services/policy/__init__.py +0 -0
  489. argus_review/tests/suites/services/policy/test_service.py +120 -0
  490. argus_review/tests/suites/services/prompt/__init__.py +0 -0
  491. argus_review/tests/suites/services/prompt/test_adapter.py +59 -0
  492. argus_review/tests/suites/services/prompt/test_conventions_integration.py +43 -0
  493. argus_review/tests/suites/services/prompt/test_language_integration.py +46 -0
  494. argus_review/tests/suites/services/prompt/test_schema.py +136 -0
  495. argus_review/tests/suites/services/prompt/test_service.py +266 -0
  496. argus_review/tests/suites/services/prompt/test_tools.py +227 -0
  497. argus_review/tests/suites/services/review/__init__.py +0 -0
  498. argus_review/tests/suites/services/review/gateway/__init__.py +0 -0
  499. argus_review/tests/suites/services/review/gateway/test_review_agent_llm_gateway.py +94 -0
  500. argus_review/tests/suites/services/review/gateway/test_review_comment_gateway.py +474 -0
  501. argus_review/tests/suites/services/review/gateway/test_review_direct_llm_gateway.py +91 -0
  502. argus_review/tests/suites/services/review/gateway/test_review_dry_run_comment_gateway.py +188 -0
  503. argus_review/tests/suites/services/review/internal/__init__.py +0 -0
  504. argus_review/tests/suites/services/review/internal/inline/__init__.py +0 -0
  505. argus_review/tests/suites/services/review/internal/inline/test_schema.py +66 -0
  506. argus_review/tests/suites/services/review/internal/inline/test_service.py +81 -0
  507. argus_review/tests/suites/services/review/internal/inline_reply/__init__.py +0 -0
  508. argus_review/tests/suites/services/review/internal/inline_reply/test_schema.py +57 -0
  509. argus_review/tests/suites/services/review/internal/inline_reply/test_service.py +72 -0
  510. argus_review/tests/suites/services/review/internal/summary/__init__.py +0 -0
  511. argus_review/tests/suites/services/review/internal/summary/test_schema.py +30 -0
  512. argus_review/tests/suites/services/review/internal/summary/test_service.py +19 -0
  513. argus_review/tests/suites/services/review/internal/summary_reply/__init__.py +0 -0
  514. argus_review/tests/suites/services/review/internal/summary_reply/test_schema.py +19 -0
  515. argus_review/tests/suites/services/review/internal/summary_reply/test_service.py +21 -0
  516. argus_review/tests/suites/services/review/runner/__init__.py +0 -0
  517. argus_review/tests/suites/services/review/runner/test_context.py +97 -0
  518. argus_review/tests/suites/services/review/runner/test_inline.py +104 -0
  519. argus_review/tests/suites/services/review/runner/test_inline_reply.py +109 -0
  520. argus_review/tests/suites/services/review/runner/test_summary.py +95 -0
  521. argus_review/tests/suites/services/review/runner/test_summary_reply.py +97 -0
  522. argus_review/tests/suites/services/review/test_service.py +129 -0
  523. argus_review/tests/suites/services/vcs/__init__.py +0 -0
  524. argus_review/tests/suites/services/vcs/azure_devops/__init__.py +0 -0
  525. argus_review/tests/suites/services/vcs/azure_devops/test_adapter.py +142 -0
  526. argus_review/tests/suites/services/vcs/azure_devops/test_client.py +321 -0
  527. argus_review/tests/suites/services/vcs/bitbucket_cloud/__init__.py +0 -0
  528. argus_review/tests/suites/services/vcs/bitbucket_cloud/test_adapter.py +109 -0
  529. argus_review/tests/suites/services/vcs/bitbucket_cloud/test_client.py +252 -0
  530. argus_review/tests/suites/services/vcs/bitbucket_server/__init__.py +0 -0
  531. argus_review/tests/suites/services/vcs/bitbucket_server/test_adapter.py +115 -0
  532. argus_review/tests/suites/services/vcs/bitbucket_server/test_client.py +249 -0
  533. argus_review/tests/suites/services/vcs/bitbucket_server/test_tools.py +111 -0
  534. argus_review/tests/suites/services/vcs/gitea/__init__.py +0 -0
  535. argus_review/tests/suites/services/vcs/gitea/test_adapter.py +115 -0
  536. argus_review/tests/suites/services/vcs/gitea/test_client.py +354 -0
  537. argus_review/tests/suites/services/vcs/github/__init__.py +0 -0
  538. argus_review/tests/suites/services/vcs/github/test_adapter.py +162 -0
  539. argus_review/tests/suites/services/vcs/github/test_client.py +260 -0
  540. argus_review/tests/suites/services/vcs/gitlab/__init__.py +0 -0
  541. argus_review/tests/suites/services/vcs/gitlab/test_adapter.py +134 -0
  542. argus_review/tests/suites/services/vcs/gitlab/test_client.py +279 -0
  543. argus_review/tests/suites/services/vcs/test_factory.py +51 -0
  544. argus_review_code-0.1.0.dist-info/METADATA +426 -0
  545. argus_review_code-0.1.0.dist-info/RECORD +550 -0
  546. argus_review_code-0.1.0.dist-info/WHEEL +5 -0
  547. argus_review_code-0.1.0.dist-info/entry_points.txt +2 -0
  548. argus_review_code-0.1.0.dist-info/licenses/LICENSE +202 -0
  549. argus_review_code-0.1.0.dist-info/licenses/NOTICE +16 -0
  550. argus_review_code-0.1.0.dist-info/top_level.txt +1 -0
File without changes
File without changes
File without changes
@@ -0,0 +1,6 @@
1
+ from argus_review.services.review.service import ReviewService
2
+
3
+
4
+ async def run_clear_inline_review():
5
+ review_service = ReviewService()
6
+ await review_service.run_clear_inline_review()
@@ -0,0 +1,6 @@
1
+ from argus_review.services.review.service import ReviewService
2
+
3
+
4
+ async def run_clear_summary_review():
5
+ review_service = ReviewService()
6
+ await review_service.run_clear_summary_review()
@@ -0,0 +1,7 @@
1
+ from argus_review.services.review.service import ReviewService
2
+
3
+
4
+ async def run_context_review_command():
5
+ review_service = ReviewService()
6
+ await review_service.run_context_review()
7
+ review_service.report_total_cost()
@@ -0,0 +1,7 @@
1
+ from argus_review.services.review.service import ReviewService
2
+
3
+
4
+ async def run_inline_reply_review_command():
5
+ review_service = ReviewService()
6
+ await review_service.run_inline_reply_review()
7
+ review_service.report_total_cost()
@@ -0,0 +1,7 @@
1
+ from argus_review.services.review.service import ReviewService
2
+
3
+
4
+ async def run_inline_review_command():
5
+ review_service = ReviewService()
6
+ await review_service.run_inline_review()
7
+ review_service.report_total_cost()
@@ -0,0 +1,8 @@
1
+ from argus_review.services.review.service import ReviewService
2
+
3
+
4
+ async def run_review_command():
5
+ review_service = ReviewService()
6
+ await review_service.run_inline_review()
7
+ await review_service.run_summary_review()
8
+ review_service.report_total_cost()
@@ -0,0 +1,7 @@
1
+ from argus_review.services.review.service import ReviewService
2
+
3
+
4
+ async def run_summary_reply_review_command():
5
+ review_service = ReviewService()
6
+ await review_service.run_summary_reply_review()
7
+ review_service.report_total_cost()
@@ -0,0 +1,7 @@
1
+ from argus_review.services.review.service import ReviewService
2
+
3
+
4
+ async def run_summary_review_command():
5
+ review_service = ReviewService()
6
+ await review_service.run_summary_review()
7
+ review_service.report_total_cost()
@@ -0,0 +1,97 @@
1
+ import asyncio
2
+
3
+ import typer
4
+
5
+ app = typer.Typer(help="ArgusReview CLI")
6
+
7
+
8
+ @app.command("run")
9
+ def run():
10
+ """Run the full AI review pipeline"""
11
+ from argus_review.cli.commands.run_review import run_review_command
12
+
13
+ typer.secho("Starting full AI review...", fg=typer.colors.CYAN, bold=True)
14
+ asyncio.run(run_review_command())
15
+ typer.secho("AI review completed successfully!", fg=typer.colors.GREEN, bold=True)
16
+
17
+
18
+ @app.command("run-inline")
19
+ def run_inline():
20
+ """Run only the inline review"""
21
+ from argus_review.cli.commands.run_inline_review import run_inline_review_command
22
+
23
+ typer.secho("Starting inline AI review...", fg=typer.colors.CYAN)
24
+ asyncio.run(run_inline_review_command())
25
+ typer.secho("AI review completed successfully!", fg=typer.colors.GREEN, bold=True)
26
+
27
+
28
+ @app.command("run-context")
29
+ def run_context():
30
+ """Run only the context review"""
31
+ from argus_review.cli.commands.run_context_review import run_context_review_command
32
+
33
+ typer.secho("Starting context AI review...", fg=typer.colors.CYAN)
34
+ asyncio.run(run_context_review_command())
35
+ typer.secho("AI review completed successfully!", fg=typer.colors.GREEN, bold=True)
36
+
37
+
38
+ @app.command("run-summary")
39
+ def run_summary():
40
+ """Run only the summary review"""
41
+ from argus_review.cli.commands.run_summary_review import run_summary_review_command
42
+
43
+ typer.secho("Starting summary AI review...", fg=typer.colors.CYAN)
44
+ asyncio.run(run_summary_review_command())
45
+ typer.secho("AI review completed successfully!", fg=typer.colors.GREEN, bold=True)
46
+
47
+
48
+ @app.command("run-inline-reply")
49
+ def run_inline_reply():
50
+ """Run only the inline reply review"""
51
+ from argus_review.cli.commands.run_inline_reply_review import run_inline_reply_review_command
52
+
53
+ typer.secho("Starting inline reply AI review...", fg=typer.colors.CYAN)
54
+ asyncio.run(run_inline_reply_review_command())
55
+ typer.secho("AI review completed successfully!", fg=typer.colors.GREEN, bold=True)
56
+
57
+
58
+ @app.command("run-summary-reply")
59
+ def run_summary_reply():
60
+ from argus_review.cli.commands.run_summary_reply_review import run_summary_reply_review_command
61
+
62
+ typer.secho("Starting summary reply AI review...", fg=typer.colors.CYAN)
63
+ asyncio.run(run_summary_reply_review_command())
64
+ typer.secho("AI review completed successfully!", fg=typer.colors.GREEN, bold=True)
65
+
66
+
67
+ @app.command("clear-inline")
68
+ def clear_inline():
69
+ """Remove all AI-generated inline review comments"""
70
+ from argus_review.cli.commands.run_clear_inline_review import run_clear_inline_review
71
+
72
+ typer.secho("Clearing inline AI review comments...", fg=typer.colors.YELLOW)
73
+ asyncio.run(run_clear_inline_review())
74
+ typer.secho("Inline AI comments cleared", fg=typer.colors.GREEN, bold=True)
75
+
76
+
77
+ @app.command("clear-summary")
78
+ def clear_summary():
79
+ """Remove all AI-generated summary review comments"""
80
+ from argus_review.cli.commands.run_clear_summary_review import run_clear_summary_review
81
+
82
+ typer.secho("Clearing summary AI review comments...", fg=typer.colors.YELLOW)
83
+ asyncio.run(run_clear_summary_review())
84
+ typer.secho("Summary AI comments cleared", fg=typer.colors.GREEN, bold=True)
85
+
86
+
87
+ @app.command("show-config")
88
+ def show_config():
89
+ """Show the current resolved configuration"""
90
+ from argus_review.config import settings
91
+
92
+ typer.secho("Loaded ArgusReview configuration:", fg=typer.colors.CYAN, bold=True)
93
+ typer.echo(settings.model_dump_json(indent=2, exclude_none=True))
94
+
95
+
96
+ if __name__ == "__main__":
97
+ app()
File without changes
File without changes
@@ -0,0 +1,39 @@
1
+ from httpx import AsyncClient, AsyncHTTPTransport
2
+
3
+ from argus_review.clients.azure_devops.pr.client import AzureDevOpsPullRequestsHTTPClient
4
+ from argus_review.clients.azure_devops.tools import build_azure_devops_headers
5
+ from argus_review.config import settings
6
+ from argus_review.libs.http.event_hooks.logger import LoggerEventHook
7
+ from argus_review.libs.http.transports.retry import RetryTransport
8
+ from argus_review.libs.logger import get_logger
9
+
10
+
11
+ class AzureDevOpsHTTPClient:
12
+ def __init__(self, client: AsyncClient):
13
+ self.pr = AzureDevOpsPullRequestsHTTPClient(client)
14
+
15
+
16
+ def get_azure_devops_http_client() -> AzureDevOpsHTTPClient:
17
+ logger = get_logger("AZURE_DEVOPS_HTTP_CLIENT")
18
+ logger_event_hook = LoggerEventHook(logger=logger)
19
+ retry_transport = RetryTransport(
20
+ logger=logger,
21
+ transport=AsyncHTTPTransport(
22
+ proxy=settings.vcs.http_client.proxy_url_value,
23
+ verify=settings.vcs.http_client.verify
24
+ )
25
+ )
26
+
27
+ client = AsyncClient(
28
+ verify=settings.vcs.http_client.verify,
29
+ timeout=settings.vcs.http_client.timeout,
30
+ headers=build_azure_devops_headers(),
31
+ base_url=settings.vcs.http_client.api_url_value,
32
+ transport=retry_transport,
33
+ event_hooks={
34
+ "request": [logger_event_hook.request],
35
+ "response": [logger_event_hook.response],
36
+ },
37
+ )
38
+
39
+ return AzureDevOpsHTTPClient(client=client)
File without changes
@@ -0,0 +1,253 @@
1
+ from httpx import Response, QueryParams
2
+
3
+ from argus_review.clients.azure_devops.pr.schema.files import (
4
+ AzureDevOpsPRChangeSchema,
5
+ AzureDevOpsGetPRFilesQuerySchema,
6
+ AzureDevOpsGetPRFilesResponseSchema,
7
+ )
8
+ from argus_review.clients.azure_devops.pr.schema.pull_request import AzureDevOpsGetPRResponseSchema
9
+ from argus_review.clients.azure_devops.pr.schema.threads import (
10
+ AzureDevOpsPRThreadSchema,
11
+ AzureDevOpsGetPRThreadsQuerySchema,
12
+ AzureDevOpsGetPRThreadsResponseSchema,
13
+ AzureDevOpsCreatePRThreadRequestSchema,
14
+ AzureDevOpsUpdatePRThreadRequestSchema,
15
+ AzureDevOpsCreatePRThreadResponseSchema,
16
+ AzureDevOpsCreatePRCommentRequestSchema,
17
+ AzureDevOpsCreatePRCommentResponseSchema,
18
+ )
19
+ from argus_review.clients.azure_devops.pr.types import AzureDevOpsPullRequestsHTTPClientProtocol
20
+ from argus_review.clients.azure_devops.schema import AzureDevOpsBaseQuerySchema
21
+ from argus_review.clients.azure_devops.tools import azure_devops_extract_continuation_token
22
+ from argus_review.config import settings
23
+ from argus_review.libs.http.client import HTTPClient
24
+ from argus_review.libs.http.handlers import handle_http_error, HTTPClientError
25
+ from argus_review.libs.http.paginate import paginate_with_token
26
+
27
+
28
+ class AzureDevOpsPullRequestsHTTPClientError(HTTPClientError):
29
+ pass
30
+
31
+
32
+ class AzureDevOpsPullRequestsHTTPClient(HTTPClient, AzureDevOpsPullRequestsHTTPClientProtocol):
33
+ @handle_http_error(client="AzureDevOpsPullRequestsHTTPClient", exception=AzureDevOpsPullRequestsHTTPClientError)
34
+ async def get_pull_request_api(
35
+ self, organization: str, project: str, repository_id: str, pull_request_id: int
36
+ ) -> Response:
37
+ url = f"/{organization}/{project}/_apis/git/repositories/{repository_id}/pullRequests/{pull_request_id}"
38
+ base_query = AzureDevOpsBaseQuerySchema(api_version=settings.vcs.http_client.api_version)
39
+ return await self.get(url=url, query=QueryParams(**base_query.model_dump(by_alias=True, exclude_none=True)))
40
+
41
+ @handle_http_error(client="AzureDevOpsPullRequestsHTTPClient", exception=AzureDevOpsPullRequestsHTTPClientError)
42
+ async def get_threads_api(
43
+ self,
44
+ organization: str,
45
+ project: str,
46
+ repository_id: str,
47
+ pull_request_id: int,
48
+ query: AzureDevOpsGetPRThreadsQuerySchema,
49
+ ) -> Response:
50
+ url = (
51
+ f"/{organization}/{project}/_apis/git/repositories/"
52
+ f"{repository_id}/pullRequests/{pull_request_id}/threads"
53
+ )
54
+ base_query = AzureDevOpsBaseQuerySchema(api_version=settings.vcs.http_client.api_version)
55
+ return await self.get(
56
+ url=url,
57
+ query=QueryParams(
58
+ **query.model_dump(by_alias=True, exclude_none=True),
59
+ **base_query.model_dump(by_alias=True, exclude_none=True),
60
+ ),
61
+ )
62
+
63
+ @handle_http_error(client="AzureDevOpsPullRequestsHTTPClient", exception=AzureDevOpsPullRequestsHTTPClientError)
64
+ async def create_thread_api(
65
+ self,
66
+ organization: str,
67
+ project: str,
68
+ repository_id: str,
69
+ pull_request_id: int,
70
+ request: AzureDevOpsCreatePRThreadRequestSchema,
71
+ ) -> Response:
72
+ url = (
73
+ f"/{organization}/{project}/_apis/git/repositories/"
74
+ f"{repository_id}/pullRequests/{pull_request_id}/threads"
75
+ )
76
+ base_query = AzureDevOpsBaseQuerySchema(api_version=settings.vcs.http_client.api_version)
77
+ return await self.post(
78
+ url=url,
79
+ json=request.model_dump(by_alias=True, exclude_none=True),
80
+ query=QueryParams(**base_query.model_dump(by_alias=True, exclude_none=True)),
81
+ )
82
+
83
+ @handle_http_error(client="AzureDevOpsPullRequestsHTTPClient", exception=AzureDevOpsPullRequestsHTTPClientError)
84
+ async def update_thread_api(
85
+ self,
86
+ organization: str,
87
+ project: str,
88
+ repository_id: str,
89
+ pull_request_id: int,
90
+ thread_id: int,
91
+ request: AzureDevOpsUpdatePRThreadRequestSchema,
92
+ ) -> Response:
93
+ url = (
94
+ f"/{organization}/{project}/_apis/git/repositories/"
95
+ f"{repository_id}/pullRequests/{pull_request_id}/threads/{thread_id}"
96
+ )
97
+ base_query = AzureDevOpsBaseQuerySchema(api_version=settings.vcs.http_client.api_version)
98
+
99
+ return await self.patch(
100
+ url=url,
101
+ json=request.model_dump(by_alias=True, exclude_none=True),
102
+ query=QueryParams(**base_query.model_dump(by_alias=True, exclude_none=True)),
103
+ )
104
+
105
+ @handle_http_error(client="AzureDevOpsPullRequestsHTTPClient", exception=AzureDevOpsPullRequestsHTTPClientError)
106
+ async def create_comment_api(
107
+ self,
108
+ organization: str,
109
+ project: str,
110
+ repository_id: str,
111
+ pull_request_id: int,
112
+ thread_id: int,
113
+ request: AzureDevOpsCreatePRCommentRequestSchema,
114
+ ) -> Response:
115
+ url = (
116
+ f"/{organization}/{project}/_apis/git/repositories/"
117
+ f"{repository_id}/pullRequests/{pull_request_id}/threads/{thread_id}/comments"
118
+ )
119
+ base_query = AzureDevOpsBaseQuerySchema(api_version=settings.vcs.http_client.api_version)
120
+ return await self.post(
121
+ url=url,
122
+ json=request.model_dump(by_alias=True, exclude_none=True),
123
+ query=QueryParams(**base_query.model_dump(by_alias=True, exclude_none=True)),
124
+ )
125
+
126
+ @handle_http_error(client="AzureDevOpsPullRequestsHTTPClient", exception=AzureDevOpsPullRequestsHTTPClientError)
127
+ async def get_files_api(
128
+ self,
129
+ organization: str,
130
+ project: str,
131
+ repository_id: str,
132
+ pull_request_id: int,
133
+ iteration_id: int,
134
+ query: AzureDevOpsGetPRFilesQuerySchema,
135
+ ) -> Response:
136
+ url = (
137
+ f"/{organization}/{project}/_apis/git/repositories/"
138
+ f"{repository_id}/pullRequests/{pull_request_id}/iterations/{iteration_id}/changes"
139
+ )
140
+ base_query = AzureDevOpsBaseQuerySchema(api_version=settings.vcs.http_client.api_version)
141
+ return await self.get(
142
+ url=url,
143
+ query=QueryParams(
144
+ **query.model_dump(by_alias=True, exclude_none=True),
145
+ **base_query.model_dump(by_alias=True, exclude_none=True),
146
+ ),
147
+ )
148
+
149
+ async def get_pull_request(
150
+ self,
151
+ organization: str,
152
+ project: str,
153
+ repository_id: str,
154
+ pull_request_id: int
155
+ ) -> AzureDevOpsGetPRResponseSchema:
156
+ response = await self.get_pull_request_api(organization, project, repository_id, pull_request_id)
157
+ return AzureDevOpsGetPRResponseSchema.model_validate_json(response.text)
158
+
159
+ async def get_threads(
160
+ self,
161
+ organization: str,
162
+ project: str,
163
+ repository_id: str,
164
+ pull_request_id: int
165
+ ) -> AzureDevOpsGetPRThreadsResponseSchema:
166
+ async def fetch_page(token: str | None) -> Response:
167
+ query = AzureDevOpsGetPRThreadsQuerySchema(
168
+ top=settings.vcs.pagination.per_page,
169
+ continuation_token=[token] if token else None
170
+ )
171
+ return await self.get_threads_api(organization, project, repository_id, pull_request_id, query)
172
+
173
+ def extract_items(response: Response) -> list[AzureDevOpsPRThreadSchema]:
174
+ parsed = AzureDevOpsGetPRThreadsResponseSchema.model_validate_json(response.text)
175
+ return parsed.value
176
+
177
+ items = await paginate_with_token(
178
+ max_pages=settings.vcs.pagination.max_pages,
179
+ fetch_page=fetch_page,
180
+ extract_items=extract_items,
181
+ extract_token=azure_devops_extract_continuation_token,
182
+ )
183
+ return AzureDevOpsGetPRThreadsResponseSchema(value=items)
184
+
185
+ async def get_files(
186
+ self,
187
+ organization: str,
188
+ project: str,
189
+ repository_id: str,
190
+ pull_request_id: int,
191
+ iteration_id: int
192
+ ) -> AzureDevOpsGetPRFilesResponseSchema:
193
+ async def fetch_page(token: str | None) -> Response:
194
+ query = AzureDevOpsGetPRFilesQuerySchema(
195
+ top=settings.vcs.pagination.per_page,
196
+ continuation_token=[token] if token else None
197
+ )
198
+ return await self.get_files_api(organization, project, repository_id, pull_request_id, iteration_id, query)
199
+
200
+ def extract_items(response: Response) -> list[AzureDevOpsPRChangeSchema]:
201
+ parsed = AzureDevOpsGetPRFilesResponseSchema.model_validate_json(response.text)
202
+ return parsed.change_entries
203
+
204
+ items = await paginate_with_token(
205
+ max_pages=settings.vcs.pagination.max_pages,
206
+ fetch_page=fetch_page,
207
+ extract_items=extract_items,
208
+ extract_token=azure_devops_extract_continuation_token,
209
+ )
210
+ return AzureDevOpsGetPRFilesResponseSchema(change_entries=items)
211
+
212
+ async def create_thread(
213
+ self,
214
+ organization: str,
215
+ project: str,
216
+ repository_id: str,
217
+ pull_request_id: int,
218
+ request: AzureDevOpsCreatePRThreadRequestSchema,
219
+ ) -> AzureDevOpsCreatePRThreadResponseSchema:
220
+ response = await self.create_thread_api(organization, project, repository_id, pull_request_id, request)
221
+ return AzureDevOpsCreatePRThreadResponseSchema.model_validate_json(response.text)
222
+
223
+ async def delete_thread(
224
+ self,
225
+ organization: str,
226
+ project: str,
227
+ repository_id: str,
228
+ pull_request_id: int,
229
+ thread_id: int,
230
+ ) -> None:
231
+ request = AzureDevOpsUpdatePRThreadRequestSchema(status="closed")
232
+ await self.update_thread_api(
233
+ organization=organization,
234
+ project=project,
235
+ repository_id=repository_id,
236
+ pull_request_id=pull_request_id,
237
+ thread_id=thread_id,
238
+ request=request,
239
+ )
240
+
241
+ async def create_comment(
242
+ self,
243
+ organization: str,
244
+ project: str,
245
+ repository_id: str,
246
+ pull_request_id: int,
247
+ thread_id: int,
248
+ request: AzureDevOpsCreatePRCommentRequestSchema,
249
+ ) -> AzureDevOpsCreatePRCommentResponseSchema:
250
+ response = await self.create_comment_api(
251
+ organization, project, repository_id, pull_request_id, thread_id, request
252
+ )
253
+ return AzureDevOpsCreatePRCommentResponseSchema.model_validate_json(response.text)
@@ -0,0 +1,51 @@
1
+ from pydantic import BaseModel, Field, ConfigDict, field_validator
2
+
3
+
4
+ class AzureDevOpsFilePositionSchema(BaseModel):
5
+ """Represents a specific position in a file (line and offset)."""
6
+ model_config = ConfigDict(populate_by_name=True)
7
+
8
+ line: int | None = Field(default=None)
9
+ offset: int | None = Field(default=None)
10
+ column: int | None = Field(default=None)
11
+
12
+
13
+ class AzureDevOpsPRItemSchema(BaseModel):
14
+ """Represents a file or item in a PR change entry."""
15
+ model_config = ConfigDict(populate_by_name=True)
16
+
17
+ path: str | None = None
18
+ object_id: str | None = Field(alias="objectId", default=None)
19
+
20
+ @field_validator("path")
21
+ def normalize_path(cls, value: str | None) -> str | None:
22
+ if value is None:
23
+ return None
24
+
25
+ return value.lstrip("/")
26
+
27
+
28
+ class AzureDevOpsPRChangeSchema(BaseModel):
29
+ """Represents a single file change within a PR iteration."""
30
+ model_config = ConfigDict(populate_by_name=True)
31
+
32
+ item: AzureDevOpsPRItemSchema
33
+ change_type: str = Field(alias="changeType")
34
+ change_tracking_id: int | None = Field(alias="changeTrackingId", default=None)
35
+
36
+
37
+ class AzureDevOpsGetPRFilesQuerySchema(BaseModel):
38
+ """Query params for fetching changed files in a PR iteration."""
39
+ model_config = ConfigDict(populate_by_name=True)
40
+
41
+ top: int = 100
42
+ continuation_token: list[str] | None = Field(alias="continuationToken", default=None)
43
+
44
+
45
+ class AzureDevOpsGetPRFilesResponseSchema(BaseModel):
46
+ """Response model for listing files changed in a PR iteration."""
47
+ model_config = ConfigDict(populate_by_name=True)
48
+
49
+ count: int | None = None
50
+ change_entries: list[AzureDevOpsPRChangeSchema] = Field(alias="changeEntries")
51
+ continuation_token: list[str] | None = Field(alias="continuationToken", default=None)
@@ -0,0 +1,38 @@
1
+ from datetime import datetime
2
+
3
+ from pydantic import BaseModel, Field, ConfigDict
4
+
5
+ from argus_review.clients.azure_devops.pr.schema.user import AzureDevOpsUserSchema
6
+
7
+
8
+ class AzureDevOpsCommitSchema(BaseModel):
9
+ """Represents a commit object associated with a PR (e.g., last merge commit)."""
10
+ model_config = ConfigDict(populate_by_name=True)
11
+
12
+ commit_id: str = Field(alias="commitId")
13
+
14
+
15
+ class AzureDevOpsRepositorySchema(BaseModel):
16
+ """Represents a repository in Azure DevOps."""
17
+ id: str
18
+ url: str | None = None
19
+ name: str
20
+
21
+
22
+ class AzureDevOpsGetPRResponseSchema(BaseModel):
23
+ """Represents the main Pull Request object returned by Azure DevOps API."""
24
+ model_config = ConfigDict(populate_by_name=True)
25
+
26
+ title: str
27
+ status: str | None = None
28
+ reviewers: list[AzureDevOpsUserSchema] = Field(default_factory=list)
29
+ created_by: AzureDevOpsUserSchema = Field(alias="createdBy")
30
+ repository: AzureDevOpsRepositorySchema
31
+ description: str | None = None
32
+ creation_date: datetime | None = Field(alias="creationDate", default=None)
33
+ pull_request_id: int = Field(alias="pullRequestId")
34
+ source_ref_name: str = Field(alias="sourceRefName")
35
+ target_ref_name: str = Field(alias="targetRefName")
36
+ last_merge_commit: AzureDevOpsCommitSchema | None = Field(alias="lastMergeCommit", default=None)
37
+ last_merge_source_commit: AzureDevOpsCommitSchema | None = Field(alias="lastMergeSourceCommit", default=None)
38
+ last_merge_target_commit: AzureDevOpsCommitSchema | None = Field(alias="lastMergeTargetCommit", default=None)
@@ -0,0 +1,108 @@
1
+ from datetime import datetime
2
+ from typing import Literal
3
+
4
+ from pydantic import BaseModel, Field, ConfigDict
5
+
6
+ from argus_review.clients.azure_devops.pr.schema.files import AzureDevOpsFilePositionSchema
7
+ from argus_review.clients.azure_devops.pr.schema.user import AzureDevOpsUserSchema
8
+
9
+
10
+ class AzureDevOpsPRCommentSchema(BaseModel):
11
+ """Represents a single comment in a PR thread."""
12
+ model_config = ConfigDict(populate_by_name=True)
13
+
14
+ id: int
15
+ author: AzureDevOpsUserSchema | None = None
16
+ content: str | None = Field(default=None)
17
+ is_deleted: bool = Field(alias="isDeleted", default=False)
18
+ published_date: datetime | None = Field(alias="publishedDate", default=None)
19
+ last_updated_date: datetime | None = Field(alias="lastUpdatedDate", default=None)
20
+
21
+
22
+ class AzureDevOpsThreadContextSchema(BaseModel):
23
+ """Represents the code location context for a thread (file path and line)."""
24
+ model_config = ConfigDict(populate_by_name=True)
25
+
26
+ file_path: str | None = Field(alias="filePath", default=None)
27
+ right_file_end: AzureDevOpsFilePositionSchema | None = Field(alias="rightFileEnd", default=None)
28
+ right_file_start: AzureDevOpsFilePositionSchema | None = Field(alias="rightFileStart", default=None)
29
+
30
+
31
+ class AzureDevOpsIterationContextSchema(BaseModel):
32
+ """Identifies the iteration range in which a thread applies."""
33
+ model_config = ConfigDict(populate_by_name=True)
34
+
35
+ first_comparing_iteration: int = Field(alias="firstComparingIteration")
36
+ second_comparing_iteration: int = Field(alias="secondComparingIteration")
37
+
38
+
39
+ class AzureDevOpsPullRequestThreadContextSchema(BaseModel):
40
+ """Provides iteration context for PR thread binding."""
41
+ model_config = ConfigDict(populate_by_name=True)
42
+
43
+ change_tracking_id: int | None = Field(alias="changeTrackingId", default=None)
44
+ iteration_context: AzureDevOpsIterationContextSchema | None = Field(alias="iterationContext", default=None)
45
+
46
+
47
+ class AzureDevOpsPRThreadSchema(BaseModel):
48
+ """Represents a discussion thread in a Pull Request."""
49
+ model_config = ConfigDict(populate_by_name=True)
50
+
51
+ id: int
52
+ status: str | None = None
53
+ comments: list[AzureDevOpsPRCommentSchema] = Field(default_factory=list)
54
+ is_deleted: bool = Field(alias="isDeleted", default=False)
55
+ thread_context: AzureDevOpsThreadContextSchema | None = Field(alias="threadContext", default=None)
56
+
57
+
58
+ class AzureDevOpsGetPRThreadsQuerySchema(BaseModel):
59
+ """Pagination and query params for fetching PR threads."""
60
+ model_config = ConfigDict(populate_by_name=True)
61
+
62
+ top: int = 100
63
+ continuation_token: list[str] | None = Field(alias="continuationToken", default=None)
64
+
65
+
66
+ class AzureDevOpsGetPRThreadsResponseSchema(BaseModel):
67
+ """Response model for fetching PR threads with comments."""
68
+ model_config = ConfigDict(populate_by_name=True)
69
+
70
+ value: list[AzureDevOpsPRThreadSchema]
71
+ count: int | None = None
72
+ continuation_token: list[str] | None = Field(alias="continuationToken", default=None)
73
+
74
+
75
+ class AzureDevOpsCreatePRCommentRequestSchema(BaseModel):
76
+ """Request for creating a new comment inside an existing thread."""
77
+ content: str
78
+
79
+
80
+ class AzureDevOpsCreatePRCommentResponseSchema(BaseModel):
81
+ """Response after creating a comment."""
82
+ id: int
83
+ content: str
84
+
85
+
86
+ class AzureDevOpsCreatePRThreadRequestSchema(BaseModel):
87
+ """Request for creating a new thread with an initial comment."""
88
+ model_config = ConfigDict(populate_by_name=True)
89
+
90
+ status: str = "active"
91
+ comments: list[AzureDevOpsCreatePRCommentRequestSchema]
92
+ thread_context: AzureDevOpsThreadContextSchema | None = Field(alias="threadContext", default=None)
93
+ pull_request_thread_context: AzureDevOpsPullRequestThreadContextSchema | None = Field(
94
+ alias="pullRequestThreadContext", default=None
95
+ )
96
+
97
+
98
+ class AzureDevOpsCreatePRThreadResponseSchema(BaseModel):
99
+ """Response after creating a new discussion thread."""
100
+ id: int
101
+ status: str
102
+ comments: list[AzureDevOpsPRCommentSchema]
103
+
104
+
105
+ class AzureDevOpsUpdatePRThreadRequestSchema(BaseModel):
106
+ model_config = ConfigDict(populate_by_name=True)
107
+
108
+ status: Literal["active", "fixed", "closed"] | None = None