gitpr-cli 1.4.2__tar.gz → 1.4.3__tar.gz

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 (233) hide show
  1. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/PKG-INFO +1 -1
  2. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/gitpr_cli.egg-info/PKG-INFO +1 -1
  3. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/publish_pull_request.py +18 -16
  4. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/main.py +19 -0
  5. gitpr_cli-1.4.3/src/updater.py +274 -0
  6. gitpr_cli-1.4.3/tests/test_updater.py +519 -0
  7. gitpr_cli-1.4.2/src/updater.py +0 -145
  8. gitpr_cli-1.4.2/tests/test_updater.py +0 -231
  9. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/LICENSE +0 -0
  10. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/README.md +0 -0
  11. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/gitpr_cli.egg-info/SOURCES.txt +0 -0
  12. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/gitpr_cli.egg-info/dependency_links.txt +0 -0
  13. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/gitpr_cli.egg-info/entry_points.txt +0 -0
  14. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/gitpr_cli.egg-info/requires.txt +0 -0
  15. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/gitpr_cli.egg-info/top_level.txt +0 -0
  16. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/pyproject.toml +0 -0
  17. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/setup.cfg +0 -0
  18. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/__init__.py +0 -0
  19. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ai_providers.py +0 -0
  20. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/__init__.py +0 -0
  21. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/__init__.py +0 -0
  22. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/activate_policy_pack.py +0 -0
  23. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/baseline_gate.py +0 -0
  24. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/baseline_summary.py +0 -0
  25. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/calculate_risk.py +0 -0
  26. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/compare_against_baseline.py +0 -0
  27. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/create_baseline.py +0 -0
  28. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/generate_mentor_explanation.py +0 -0
  29. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/generate_pr_explanation.py +0 -0
  30. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/generate_test_file.py +0 -0
  31. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/install_policy_pack.py +0 -0
  32. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/resolve_effective_policy.py +0 -0
  33. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/run_check.py +0 -0
  34. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/suppress_finding.py +0 -0
  35. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/application/use_cases/validate_policy_pack.py +0 -0
  36. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/blame_engine.py +0 -0
  37. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/branding/__init__.py +0 -0
  38. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/branding/badge_builder.py +0 -0
  39. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/branding/badge_data.py +0 -0
  40. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/cache.py +0 -0
  41. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/changelog_builder.py +0 -0
  42. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/chat_memory.py +0 -0
  43. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/commit_classifier.py +0 -0
  44. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/config.py +0 -0
  45. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/config_schema.py +0 -0
  46. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/core.py +0 -0
  47. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/demo/__init__.py +0 -0
  48. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/demo/demo_runner.py +0 -0
  49. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/demo/fake_ai_provider.py +0 -0
  50. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/demo/scenarios/__init__.py +0 -0
  51. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/demo/scenarios/laravel_bug_fix.py +0 -0
  52. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/demo/scenarios/security_issue.py +0 -0
  53. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/diff_parser.py +0 -0
  54. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/doc_links.py +0 -0
  55. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/baseline/__init__.py +0 -0
  56. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/baseline/baseline_comparator.py +0 -0
  57. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/baseline/baseline_fingerprint.py +0 -0
  58. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/baseline/baseline_manifest.py +0 -0
  59. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/baseline/baseline_types.py +0 -0
  60. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/baseline/suppression_policy.py +0 -0
  61. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/check/__init__.py +0 -0
  62. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/check/check_config.py +0 -0
  63. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/check/check_output.py +0 -0
  64. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/check/check_types.py +0 -0
  65. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/finding/__init__.py +0 -0
  66. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/finding/finding_types.py +0 -0
  67. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/linter/__init__.py +0 -0
  68. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/linter/sast_finding_mapper.py +0 -0
  69. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/mentor/__init__.py +0 -0
  70. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/mentor/mentor_explanation_builder.py +0 -0
  71. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/policy/__init__.py +0 -0
  72. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/policy/policy_checksum.py +0 -0
  73. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/policy/policy_compatibility.py +0 -0
  74. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/policy/policy_manifest.py +0 -0
  75. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/policy/policy_resolver.py +0 -0
  76. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/policy/policy_types.py +0 -0
  77. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/pr/__init__.py +0 -0
  78. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/pr/explain_section_builder.py +0 -0
  79. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/risk/__init__.py +0 -0
  80. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/risk/risk_calculator.py +0 -0
  81. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/risk/risk_explanation.py +0 -0
  82. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/risk/risk_rules.py +0 -0
  83. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/risk/risk_types.py +0 -0
  84. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/tests_generation/__init__.py +0 -0
  85. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/tests_generation/framework_detector.py +0 -0
  86. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/tests_generation/test_content_types.py +0 -0
  87. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/domain/tests_generation/test_scaffold_builder.py +0 -0
  88. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/fix/__init__.py +0 -0
  89. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/fix/apply_fix.py +0 -0
  90. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/fix/fix_history.py +0 -0
  91. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/fix/patch_applier.py +0 -0
  92. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/fix/patch_extractor.py +0 -0
  93. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/fix/patch_provenance.py +0 -0
  94. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/fix/patch_safety_classifier.py +0 -0
  95. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/fix/rollback_fix.py +0 -0
  96. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/github_api.py +0 -0
  97. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/i18n.py +0 -0
  98. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/__init__.py +0 -0
  99. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/baseline/__init__.py +0 -0
  100. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/baseline/local_baseline_repository.py +0 -0
  101. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/ci/__init__.py +0 -0
  102. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/ci/junit_builder.py +0 -0
  103. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/ci/masking.py +0 -0
  104. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/ci/sarif_builder.py +0 -0
  105. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/git/__init__.py +0 -0
  106. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/git/identity.py +0 -0
  107. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/git/patch_applier.py +0 -0
  108. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/git/risk_history_reader.py +0 -0
  109. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/git/selective_stager.py +0 -0
  110. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/git/test_matcher.py +0 -0
  111. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/linter/external/__init__.py +0 -0
  112. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/linter/external/bandit_bridge.py +0 -0
  113. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/linter/external/base_bridge.py +0 -0
  114. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/linter/external/gitleaks_bridge.py +0 -0
  115. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/linter/external/semgrep_bridge.py +0 -0
  116. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/policy/__init__.py +0 -0
  117. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/policy/local_policy_repository.py +0 -0
  118. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/policy/policy_pack_loader.py +0 -0
  119. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/scm/__init__.py +0 -0
  120. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/scm/azure_devops_provider.py +0 -0
  121. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/scm/base.py +0 -0
  122. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/scm/bitbucket_provider.py +0 -0
  123. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/scm/factory.py +0 -0
  124. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/scm/github_provider.py +0 -0
  125. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/scm/gitlab_provider.py +0 -0
  126. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/infrastructure/scm/web_links.py +0 -0
  127. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/issue_engine.py +0 -0
  128. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ledger.py +0 -0
  129. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/linter_engine.py +0 -0
  130. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/linter_wizard.py +0 -0
  131. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/mcp_server.py +0 -0
  132. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/metrics.py +0 -0
  133. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/net.py +0 -0
  134. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/policy_packs/laravel-quality/CHANGELOG.md +0 -0
  135. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/policy_packs/laravel-quality/README.md +0 -0
  136. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/policy_packs/laravel-quality/linter.yml +0 -0
  137. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/policy_packs/laravel-quality/policy.yml +0 -0
  138. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/policy_packs/node-quality/README.md +0 -0
  139. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/policy_packs/node-quality/linter.yml +0 -0
  140. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/policy_packs/node-quality/policy.yml +0 -0
  141. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/policy_packs/php-security/README.md +0 -0
  142. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/policy_packs/php-security/linter.yml +0 -0
  143. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/policy_packs/php-security/policy.yml +0 -0
  144. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/policy_packs/vue-quality/README.md +0 -0
  145. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/policy_packs/vue-quality/linter.yml +0 -0
  146. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/policy_packs/vue-quality/policy.yml +0 -0
  147. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/release_engine.py +0 -0
  148. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/review/__init__.py +0 -0
  149. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/review/diff_normalizer.py +0 -0
  150. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/review/diff_source.py +0 -0
  151. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/review/remote_pr.py +0 -0
  152. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/review/render.py +0 -0
  153. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/reviewer_resolution.py +0 -0
  154. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/reviewer_suggestion.py +0 -0
  155. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/security.py +0 -0
  156. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/security_ruleset.py +0 -0
  157. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/spinner.py +0 -0
  158. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/split/__init__.py +0 -0
  159. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/split/apply_split_plan.py +0 -0
  160. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/split/generate_split_plan.py +0 -0
  161. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/split/hunk_grouper.py +0 -0
  162. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/split/hunk_parser.py +0 -0
  163. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/split/split_plan.py +0 -0
  164. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/suggest_reviewers.py +0 -0
  165. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/tui_issue.py +0 -0
  166. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/__init__.py +0 -0
  167. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/chat_app.py +0 -0
  168. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/config_app.py +0 -0
  169. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/demo/__init__.py +0 -0
  170. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/demo/demo_app.py +0 -0
  171. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/demo/demo_help_screen.py +0 -0
  172. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/demo/demo_screens.py +0 -0
  173. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/help_screen.py +0 -0
  174. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/issue_app.py +0 -0
  175. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/linter_app.py +0 -0
  176. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/metrics_app.py +0 -0
  177. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/metrics_migration_app.py +0 -0
  178. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/pr_publish_app.py +0 -0
  179. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/ui/pr_publish_help.py +0 -0
  180. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/usage_log.py +0 -0
  181. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/src/version_bump.py +0 -0
  182. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_baseline_cli.py +0 -0
  183. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_blame_engine_ranges.py +0 -0
  184. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_blame_metrics.py +0 -0
  185. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_changelog_builder.py +0 -0
  186. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_chat_backend.py +0 -0
  187. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_check_cli.py +0 -0
  188. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_commit_classifier.py +0 -0
  189. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_config_app.py +0 -0
  190. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_config_cli.py +0 -0
  191. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_config_schema.py +0 -0
  192. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_config_store.py +0 -0
  193. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_config_suggest_reviewers.py +0 -0
  194. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_config_validation.py +0 -0
  195. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_core.py +0 -0
  196. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_diff_failure_cli.py +0 -0
  197. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_diff_parser.py +0 -0
  198. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_explain_command.py +0 -0
  199. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_external_linters.py +0 -0
  200. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_full_diff_encoding.py +0 -0
  201. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_i18n.py +0 -0
  202. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_install_wizard.py +0 -0
  203. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_issue_engine.py +0 -0
  204. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_linter_metrics.py +0 -0
  205. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_linter_presets.py +0 -0
  206. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_main_suggest_reviewers.py +0 -0
  207. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_mcp_prompts.py +0 -0
  208. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_mcp_server.py +0 -0
  209. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_mcp_server_e2e.py +0 -0
  210. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_mentor_cli.py +0 -0
  211. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_metrics.py +0 -0
  212. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_net_timeouts.py +0 -0
  213. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_plugins.py +0 -0
  214. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_policy_cli.py +0 -0
  215. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_pr_publish_app.py +0 -0
  216. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_pr_publish_linter_modal.py +0 -0
  217. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_pre_save.py +0 -0
  218. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_release_cli.py +0 -0
  219. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_release_engine.py +0 -0
  220. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_reviewer_resolution.py +0 -0
  221. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_reviewer_suggestion.py +0 -0
  222. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_risk_cli.py +0 -0
  223. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_security_ruleset.py +0 -0
  224. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_skill_command.py +0 -0
  225. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_skill_context.py +0 -0
  226. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_skill_templates.py +0 -0
  227. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_smart_excludes.py +0 -0
  228. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_suggest_reviewers.py +0 -0
  229. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_tests_command.py +0 -0
  230. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_thinking_words.py +0 -0
  231. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_usage_log.py +0 -0
  232. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_version_bump.py +0 -0
  233. {gitpr_cli-1.4.2 → gitpr_cli-1.4.3}/tests/test_web_links.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitpr-cli
3
- Version: 1.4.2
3
+ Version: 1.4.3
4
4
  Summary: AI-powered PR automation, commit messages, and code review (Gemini, DeepSeek, and Ollama)
5
5
  Author-email: Natan Fiuza <contato@natanfiuza.dev.br>
6
6
  Requires-Python: >=3.10
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitpr-cli
3
- Version: 1.4.2
3
+ Version: 1.4.3
4
4
  Summary: AI-powered PR automation, commit messages, and code review (Gemini, DeepSeek, and Ollama)
5
5
  Author-email: Natan Fiuza <contato@natanfiuza.dev.br>
6
6
  Requires-Python: >=3.10
@@ -129,20 +129,20 @@ def publish_pull_request_use_case(
129
129
  message=__("PR description must not be empty."),
130
130
  )
131
131
 
132
- if not getattr(provider, "token", ""):
133
- return PublishPrOutcome(
134
- status="auth_required",
135
- provider=provider.name,
136
- source_branch=source_branch,
137
- target_branch=target_branch,
138
- http_status=401,
139
- message=__(
140
- "{provider} token is not configured. Run 'gitpr' in a terminal to authenticate.",
141
- provider=label,
142
- ),
143
- )
144
-
145
132
  if check_remote_state:
133
+ if not getattr(provider, "token", ""):
134
+ return PublishPrOutcome(
135
+ status="auth_required",
136
+ provider=provider.name,
137
+ source_branch=source_branch,
138
+ target_branch=target_branch,
139
+ http_status=401,
140
+ message=__(
141
+ "{provider} token is not configured. Run 'gitpr' in a terminal to authenticate.",
142
+ provider=label,
143
+ ),
144
+ )
145
+
146
146
  try:
147
147
  existing: Optional[PullRequestResult] = provider.check_existing_pull_request(
148
148
  repo_ref, source_branch
@@ -254,10 +254,12 @@ def publish_pull_request_use_case(
254
254
  message=mask_sensitive_text(str(exc)),
255
255
  )
256
256
 
257
+ pr_url = getattr(result, "url", "")
258
+ pr_number = getattr(result, "number", 0)
257
259
  return PublishPrOutcome(
258
260
  status="success",
259
- url=result.url,
260
- number=result.number,
261
+ url=pr_url,
262
+ number=pr_number,
261
263
  provider=provider.name,
262
264
  source_branch=source_branch,
263
265
  target_branch=target_branch,
@@ -265,6 +267,6 @@ def publish_pull_request_use_case(
265
267
  message=__(
266
268
  "PR successfully created on {provider}: {pr_url}",
267
269
  provider=label,
268
- pr_url=result.url,
270
+ pr_url=pr_url,
269
271
  ),
270
272
  )
@@ -75,6 +75,18 @@ def _may_ask_the_user(quiet=False, hook=False, mcp=False):
75
75
  return False
76
76
 
77
77
 
78
+ def _subcommand_help_in_argv(argv=None):
79
+ """Whether the raw command line asks for help.
80
+
81
+ Click clears the group context arguments before this callback runs, so by
82
+ the time the update gate below executes, ``gitpr release -h`` is
83
+ indistinguishable from ``gitpr release``. The raw tokens are the only
84
+ surviving record. The scan fails open, which costs at most one skipped gate.
85
+ """
86
+ tokens = sys.argv[1:] if argv is None else argv
87
+ return any(token in ("-h", "--help") for token in tokens)
88
+
89
+
78
90
  def print_banner():
79
91
  """Displays the project ASCII Art signature"""
80
92
  banner = r"""
@@ -677,6 +689,13 @@ def cli(
677
689
  # first, so everything below runs only when NO subcommand was requested —
678
690
  # the legacy flag surface stays byte-for-byte intact (ADR-002).
679
691
  if ctx.invoked_subcommand is not None:
692
+ # The mandatory update gate covers subcommands too, but only when the
693
+ # run may stop and ask the user: a release in CI, a pipe or a hook must
694
+ # never be blocked. Help tokens are read from the raw argv because
695
+ # Click clears the context arguments before this callback runs.
696
+ if may_ask and not update and not help_flag and not _subcommand_help_in_argv():
697
+ if enforce_update_required():
698
+ sys.exit(1)
680
699
  return
681
700
 
682
701
  # ============================================================
@@ -0,0 +1,274 @@
1
+ import json
2
+ import os
3
+ import tempfile
4
+ from datetime import datetime
5
+
6
+ import click
7
+ from packaging.version import InvalidVersion, Version
8
+
9
+ # Current version of your local executable (Update this on every new build!)
10
+ # ── Must stay ABOVE the i18n import: i18n.py lazily imports __lang_version__
11
+ # from here, and pyproject.toml reads __version__ via setuptools attr:.
12
+ __version__ = "1.4.3" # GitPR current version
13
+ __lang_version__ = "v0.0.35" # Language dictionary version control
14
+ __scripts_version__ = (
15
+ "v0.0.4" # Git Hook scripts version control (independent from __lang_version__)
16
+ )
17
+
18
+ from src.i18n import __
19
+ from src.net import bounded_urlopen
20
+
21
+ PYPI_API_URL = "https://pypi.org/pypi/gitpr-cli/json"
22
+
23
+ # How long a PyPI answer is trusted before the next check goes back online.
24
+ # A rolling window, not the local calendar day: a release published after the
25
+ # first run of the day used to stay invisible until midnight.
26
+ UPDATE_CACHE_TTL_SECONDS = 3600
27
+
28
+ # Wall-clock ceiling for the PyPI fetch, DNS resolution included.
29
+ UPDATE_FETCH_HARD_TIMEOUT = 3.0
30
+
31
+ # Environment switch used to mute the mandatory update check (test harness and
32
+ # offline automation). Parsed as a strict boolean: only _SKIP_TRUTHY_VALUES
33
+ # disable it, so `GITPR_SKIP_UPDATE_CHECK=false` still checks.
34
+ SKIP_UPDATE_CHECK_ENV = "GITPR_SKIP_UPDATE_CHECK"
35
+ _SKIP_TRUTHY_VALUES = ("1", "true", "yes", "on", "y")
36
+
37
+
38
+ def get_gitpr_dir():
39
+ """Returns the ~/.gitpr/ directory path."""
40
+ return os.path.join(os.path.expanduser("~"), ".gitpr")
41
+
42
+
43
+ def get_update_cache_file():
44
+ """Returns the path to the update cache file."""
45
+ return os.path.join(get_gitpr_dir(), "update_cache.json")
46
+
47
+
48
+ def _coerce_version(value):
49
+ """Parses *value* as a PEP 440 version, or returns None when it is not one."""
50
+ if not isinstance(value, str):
51
+ return None
52
+ text = value.strip()
53
+ # packaging rejects a leading "v"; the old helper stripped every "v" in the
54
+ # string, which corrupted suffixes such as 1.2.3-dev.
55
+ if text[:1] in ("v", "V"):
56
+ text = text[1:]
57
+ if not text:
58
+ return None
59
+ try:
60
+ return Version(text)
61
+ except InvalidVersion:
62
+ return None
63
+
64
+
65
+ def parse_version(version_str):
66
+ """Converts 'v0.1.0' or '0.1.0' into a tuple (0, 1, 0) for version math.
67
+
68
+ Kept for compatibility with outside callers. The tuple is lossy for
69
+ pre/post/dev markers, so the update gate itself compares Version objects
70
+ through _is_newer() instead.
71
+ """
72
+ parsed = _coerce_version(version_str)
73
+ return parsed.release if parsed is not None else (0, 0, 0)
74
+
75
+
76
+ def is_update_check_disabled():
77
+ """Returns True when the update check must be muted for this execution."""
78
+ value = os.environ.get(SKIP_UPDATE_CHECK_ENV, "")
79
+ return value.strip().lower() in _SKIP_TRUTHY_VALUES
80
+
81
+
82
+ def _cache_is_fresh(cache_data, now=None):
83
+ """Whether *cache_data* carries a timestamp inside the freshness window.
84
+
85
+ A timestamp in the future (the clock moved backwards) counts as stale, so
86
+ a clock jump can never freeze the cache on an old answer indefinitely.
87
+ """
88
+ checked_at = cache_data.get("checked_at")
89
+ if not isinstance(checked_at, str):
90
+ return False
91
+ try:
92
+ written_at = datetime.fromisoformat(checked_at)
93
+ current = datetime.now() if now is None else now
94
+ age = (current - written_at).total_seconds()
95
+ except (TypeError, ValueError):
96
+ # Not a valid timestamp, or a timezone-aware stamp this cache never writes.
97
+ return False
98
+ return 0 <= age < UPDATE_CACHE_TTL_SECONDS
99
+
100
+
101
+ def _read_cached_version(cache_file):
102
+ """Returns the cached PyPI version while it is still fresh, else "".
103
+
104
+ Only the current schema is read: a document from the former calendar-day
105
+ cache has no ``checked_at`` and therefore counts as expired.
106
+ """
107
+ try:
108
+ with open(cache_file, "r", encoding="utf-8", errors="replace") as f:
109
+ cache_data = json.load(f)
110
+ except Exception:
111
+ return ""
112
+
113
+ if not isinstance(cache_data, dict) or not _cache_is_fresh(cache_data):
114
+ return ""
115
+
116
+ version = cache_data.get("version")
117
+ if isinstance(version, str) and version.strip():
118
+ return version.strip()
119
+ return ""
120
+
121
+
122
+ def _write_cached_version(cache_file, version):
123
+ """Writes the cache atomically; the caller treats a failure as non-fatal."""
124
+ folder = os.path.dirname(cache_file)
125
+ if folder:
126
+ os.makedirs(folder, exist_ok=True)
127
+
128
+ payload = {"checked_at": datetime.now().isoformat(), "version": version}
129
+ handle = tempfile.NamedTemporaryFile(
130
+ "w",
131
+ encoding="utf-8",
132
+ dir=folder or ".",
133
+ prefix=".update-cache-",
134
+ suffix=".tmp",
135
+ delete=False,
136
+ )
137
+ try:
138
+ with handle:
139
+ json.dump(payload, handle)
140
+ os.replace(handle.name, cache_file)
141
+ except Exception:
142
+ try:
143
+ os.unlink(handle.name)
144
+ except OSError:
145
+ pass
146
+ raise
147
+
148
+
149
+ def _fetch_pypi_version():
150
+ """Returns the version published on PyPI, or "" when it cannot be read."""
151
+ raw = bounded_urlopen(
152
+ PYPI_API_URL,
153
+ timeout=3,
154
+ hard_timeout=UPDATE_FETCH_HARD_TIMEOUT,
155
+ headers={"User-Agent": "GitPR-Updater"},
156
+ )
157
+ if not raw:
158
+ return ""
159
+
160
+ try:
161
+ data = json.loads(raw.decode("utf-8", errors="replace"))
162
+ version = data["info"]["version"]
163
+ except Exception:
164
+ return ""
165
+
166
+ # Only a parseable version is trusted: a captive portal or a malformed
167
+ # mirror must not poison the cache for a whole hour.
168
+ if _coerce_version(version) is None:
169
+ return ""
170
+ return version.strip()
171
+
172
+
173
+ def get_latest_remote_version(force=False):
174
+ """Fetches the latest version published on PyPI, with a one-hour cache.
175
+
176
+ ``force=True`` (the ``--update`` flag) always asks PyPI: that command
177
+ promises an immediate verification, so it must not answer from the cache.
178
+ Returns "" when the remote version is unknown — offline, stalled DNS, or a
179
+ body that is not a version — and the caller then lets the run proceed.
180
+ """
181
+ cache_file = get_update_cache_file()
182
+
183
+ if not force:
184
+ cached = _read_cached_version(cache_file)
185
+ if cached:
186
+ return cached
187
+
188
+ latest_version = _fetch_pypi_version()
189
+ if latest_version:
190
+ try:
191
+ _write_cached_version(cache_file, latest_version)
192
+ except Exception:
193
+ pass # A read-only home or a locked file must not hide the answer
194
+ return latest_version
195
+
196
+
197
+ def _is_newer(remote_version, local_version=None):
198
+ """Whether *remote_version* is a version this install should upgrade to.
199
+
200
+ PEP 440 ordering instead of a tuple comparison, so 1.4.10 > 1.4.9 and
201
+ pre/post/dev markers follow the standard. A remote pre-release is ignored
202
+ while the local install is stable: pip will not install it without --pre,
203
+ so blocking would tell the user to run a command that does nothing. An
204
+ unparseable version on either side is "unknown", never "newer".
205
+ """
206
+ remote = _coerce_version(remote_version)
207
+ local = _coerce_version(__version__ if local_version is None else local_version)
208
+ if remote is None or local is None:
209
+ return False
210
+ if remote.is_prerelease and not local.is_prerelease:
211
+ return False
212
+ return remote > local
213
+
214
+
215
+ def enforce_update_required():
216
+ """Blocks execution while a newer GitPR version is published on PyPI.
217
+
218
+ Prints the upgrade instructions and returns True when the caller must stop.
219
+ Returns False when the local version is current, when the remote version is
220
+ unknown (offline, so the user could not upgrade anyway), when it is a
221
+ pre-release a stable install cannot move to, or when the check is disabled
222
+ via GITPR_SKIP_UPDATE_CHECK.
223
+ """
224
+ if is_update_check_disabled():
225
+ return False
226
+
227
+ latest_version = get_latest_remote_version()
228
+
229
+ if not _is_newer(latest_version):
230
+ return False
231
+
232
+ click.echo("")
233
+ click.secho(
234
+ __(
235
+ "⚠️ A new version of GitPR is available: {current_version} -> {latest_version}",
236
+ current_version=__version__,
237
+ latest_version=latest_version,
238
+ ),
239
+ fg="yellow",
240
+ bold=True,
241
+ )
242
+ click.secho(
243
+ __("GitPR must be updated before it can run: pip install --upgrade gitpr-cli"),
244
+ fg="cyan",
245
+ bold=True,
246
+ )
247
+ click.echo("")
248
+ return True
249
+
250
+
251
+ def check_and_update():
252
+ """Function triggered only when the user forces the --update flag."""
253
+ latest_version = get_latest_remote_version(force=True)
254
+
255
+ if not latest_version:
256
+ click.secho(__("❌ Could not check for updates at this moment."), fg="red")
257
+ return
258
+
259
+ if _is_newer(latest_version):
260
+ click.secho(
261
+ __(
262
+ "\n🚀 New GitPR version found (v{latest_version})!",
263
+ latest_version=latest_version,
264
+ ),
265
+ fg="green",
266
+ bold=True,
267
+ )
268
+ click.secho(
269
+ __("Run to update: pip install --upgrade gitpr-cli"), fg="cyan", bold=True
270
+ )
271
+ else:
272
+ click.secho(
273
+ __("✅ You are already using the latest version of GitPR."), fg="green"
274
+ )