gitpr-cli 1.4.4__tar.gz → 1.6.0__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 (254) hide show
  1. {gitpr_cli-1.4.4/gitpr_cli.egg-info → gitpr_cli-1.6.0}/PKG-INFO +20 -1
  2. gitpr_cli-1.4.4/PKG-INFO → gitpr_cli-1.6.0/README.md +19 -20
  3. gitpr_cli-1.4.4/README.md → gitpr_cli-1.6.0/gitpr_cli.egg-info/PKG-INFO +39 -0
  4. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/gitpr_cli.egg-info/SOURCES.txt +18 -0
  5. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/pyproject.toml +48 -48
  6. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/__init__.py +1 -1
  7. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/__init__.py +2 -2
  8. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/__init__.py +8 -8
  9. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/activate_policy_pack.py +122 -122
  10. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/baseline_gate.py +415 -415
  11. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/baseline_summary.py +259 -259
  12. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/calculate_risk.py +309 -309
  13. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/compare_against_baseline.py +41 -41
  14. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/create_baseline.py +710 -709
  15. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/generate_mentor_explanation.py +279 -279
  16. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/generate_pr_explanation.py +82 -82
  17. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/generate_test_file.py +247 -247
  18. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/install_policy_pack.py +71 -71
  19. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/publish_pull_request.py +272 -272
  20. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/resolve_effective_policy.py +208 -208
  21. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/run_check.py +449 -446
  22. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/suppress_finding.py +483 -483
  23. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/application/use_cases/validate_policy_pack.py +263 -263
  24. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/branding/__init__.py +1 -1
  25. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/branding/badge_builder.py +139 -139
  26. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/branding/badge_data.py +53 -53
  27. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/changelog_builder.py +272 -272
  28. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/commit_classifier.py +178 -178
  29. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/config.py +1264 -1369
  30. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/config_schema.py +398 -48
  31. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/core.py +580 -100
  32. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/demo/__init__.py +7 -7
  33. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/demo/demo_runner.py +336 -336
  34. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/demo/fake_ai_provider.py +112 -112
  35. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/demo/scenarios/__init__.py +128 -128
  36. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/demo/scenarios/laravel_bug_fix.py +443 -443
  37. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/demo/scenarios/security_issue.py +511 -511
  38. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/diff_parser.py +423 -321
  39. gitpr_cli-1.6.0/src/doc_links.py +53 -0
  40. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/baseline/__init__.py +143 -143
  41. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/baseline/baseline_comparator.py +268 -268
  42. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/baseline/baseline_fingerprint.py +103 -103
  43. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/baseline/baseline_manifest.py +291 -291
  44. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/baseline/baseline_types.py +289 -289
  45. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/baseline/suppression_policy.py +661 -661
  46. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/check/__init__.py +31 -31
  47. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/check/check_config.py +122 -122
  48. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/check/check_output.py +112 -112
  49. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/check/check_types.py +165 -165
  50. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/finding/__init__.py +5 -5
  51. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/finding/finding_types.py +25 -25
  52. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/linter/__init__.py +8 -8
  53. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/linter/sast_finding_mapper.py +83 -83
  54. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/mentor/__init__.py +15 -15
  55. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/mentor/mentor_explanation_builder.py +228 -228
  56. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/policy/__init__.py +116 -116
  57. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/policy/policy_checksum.py +60 -60
  58. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/policy/policy_compatibility.py +210 -210
  59. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/policy/policy_manifest.py +694 -694
  60. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/policy/policy_resolver.py +706 -706
  61. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/policy/policy_types.py +237 -237
  62. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/pr/__init__.py +14 -14
  63. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/pr/explain_section_builder.py +153 -153
  64. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/risk/__init__.py +18 -18
  65. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/risk/risk_calculator.py +144 -144
  66. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/risk/risk_explanation.py +78 -78
  67. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/risk/risk_rules.py +261 -261
  68. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/risk/risk_types.py +113 -113
  69. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/tests_generation/__init__.py +14 -14
  70. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/tests_generation/framework_detector.py +120 -120
  71. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/tests_generation/test_content_types.py +43 -43
  72. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/domain/tests_generation/test_scaffold_builder.py +92 -92
  73. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/fix/__init__.py +16 -16
  74. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/fix/apply_fix.py +479 -479
  75. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/fix/fix_history.py +153 -153
  76. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/fix/patch_applier.py +42 -42
  77. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/fix/patch_extractor.py +61 -61
  78. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/fix/patch_provenance.py +96 -96
  79. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/fix/patch_safety_classifier.py +101 -101
  80. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/fix/rollback_fix.py +69 -69
  81. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/github_api.py +112 -112
  82. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/i18n.py +142 -136
  83. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/__init__.py +1 -1
  84. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/baseline/__init__.py +28 -28
  85. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/baseline/local_baseline_repository.py +355 -355
  86. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/ci/__init__.py +11 -11
  87. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/ci/junit_builder.py +102 -102
  88. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/ci/masking.py +65 -65
  89. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/ci/sarif_builder.py +152 -152
  90. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/git/__init__.py +1 -1
  91. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/git/identity.py +155 -155
  92. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/git/patch_applier.py +209 -209
  93. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/git/risk_history_reader.py +93 -93
  94. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/git/selective_stager.py +198 -198
  95. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/git/test_matcher.py +78 -78
  96. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/linter/external/__init__.py +9 -9
  97. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/linter/external/bandit_bridge.py +127 -127
  98. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/linter/external/base_bridge.py +95 -95
  99. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/linter/external/gitleaks_bridge.py +168 -168
  100. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/linter/external/semgrep_bridge.py +139 -139
  101. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/policy/__init__.py +45 -45
  102. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/policy/local_policy_repository.py +142 -142
  103. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/policy/policy_pack_loader.py +240 -240
  104. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/scm/__init__.py +62 -62
  105. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/scm/azure_devops_provider.py +27 -0
  106. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/scm/base.py +421 -352
  107. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/scm/bitbucket_provider.py +41 -0
  108. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/scm/factory.py +109 -97
  109. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/scm/github_provider.py +564 -531
  110. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/scm/gitlab_provider.py +34 -0
  111. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/infrastructure/scm/web_links.py +103 -103
  112. gitpr_cli-1.6.0/src/issue_autoclose/__init__.py +12 -0
  113. gitpr_cli-1.6.0/src/issue_autoclose/insert_close_line.py +46 -0
  114. gitpr_cli-1.6.0/src/issue_autoclose/issue_registry.py +285 -0
  115. gitpr_cli-1.6.0/src/issue_autoclose/register_created_issue.py +81 -0
  116. gitpr_cli-1.6.0/src/issue_autoclose/resolve_close_issue.py +236 -0
  117. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ledger.py +7 -2
  118. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/linter_wizard.py +210 -210
  119. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/main.py +12492 -5931
  120. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/mcp_server.py +73 -36
  121. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/metrics.py +1352 -1105
  122. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/net.py +74 -74
  123. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/policy_packs/laravel-quality/CHANGELOG.md +25 -25
  124. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/policy_packs/laravel-quality/README.md +41 -41
  125. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/policy_packs/laravel-quality/linter.yml +61 -61
  126. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/policy_packs/laravel-quality/policy.yml +110 -110
  127. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/policy_packs/node-quality/README.md +27 -27
  128. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/policy_packs/node-quality/linter.yml +57 -57
  129. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/policy_packs/node-quality/policy.yml +82 -82
  130. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/policy_packs/php-security/README.md +33 -33
  131. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/policy_packs/php-security/linter.yml +69 -69
  132. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/policy_packs/php-security/policy.yml +75 -75
  133. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/policy_packs/vue-quality/README.md +29 -29
  134. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/policy_packs/vue-quality/linter.yml +50 -50
  135. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/policy_packs/vue-quality/policy.yml +78 -78
  136. gitpr_cli-1.6.0/src/project_config.py +484 -0
  137. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/release_engine.py +1060 -990
  138. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/review/__init__.py +13 -13
  139. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/review/diff_normalizer.py +8 -8
  140. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/review/diff_source.py +69 -69
  141. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/review/remote_pr.py +350 -350
  142. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/review/render.py +83 -83
  143. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/reviewer_resolution.py +159 -159
  144. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/reviewer_suggestion.py +260 -258
  145. gitpr_cli-1.6.0/src/scm_settings.py +441 -0
  146. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/security_ruleset.py +115 -108
  147. gitpr_cli-1.6.0/src/skill_frontmatter.py +70 -0
  148. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/spinner.py +4 -1
  149. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/split/__init__.py +17 -17
  150. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/split/apply_split_plan.py +251 -251
  151. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/split/generate_split_plan.py +222 -222
  152. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/split/hunk_grouper.py +347 -347
  153. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/split/hunk_parser.py +256 -256
  154. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/split/split_plan.py +153 -153
  155. gitpr_cli-1.6.0/src/suggest_reviewers.py +155 -0
  156. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/tui_issue.py +301 -281
  157. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/chat_app.py +15 -14
  158. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/commit_app.py +220 -220
  159. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/config_app.py +518 -22
  160. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/demo/__init__.py +1 -1
  161. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/demo/demo_app.py +91 -91
  162. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/demo/demo_help_screen.py +52 -52
  163. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/demo/demo_screens.py +60 -60
  164. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/help_screen.py +46 -46
  165. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/issue_app.py +260 -236
  166. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/linter_app.py +2 -0
  167. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/metrics_app.py +466 -456
  168. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/metrics_migration_app.py +173 -173
  169. gitpr_cli-1.6.0/src/ui/pr_base_app.py +98 -0
  170. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/pr_publish_app.py +1783 -1775
  171. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/pr_publish_help.py +50 -50
  172. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/updater.py +274 -274
  173. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/usage_log.py +127 -127
  174. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/version_bump.py +87 -87
  175. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_baseline_cli.py +946 -946
  176. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_blame_engine_ranges.py +140 -140
  177. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_blame_metrics.py +226 -226
  178. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_changelog_builder.py +286 -286
  179. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_check_cli.py +118 -118
  180. gitpr_cli-1.6.0/tests/test_cli_help.py +99 -0
  181. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_commit_app.py +248 -207
  182. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_commit_classifier.py +222 -222
  183. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_config_app.py +489 -25
  184. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_config_cli.py +116 -116
  185. gitpr_cli-1.6.0/tests/test_config_issue_autoclose.py +113 -0
  186. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_config_schema.py +568 -459
  187. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_config_store.py +189 -189
  188. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_config_suggest_reviewers.py +82 -82
  189. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_config_validation.py +317 -317
  190. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_diff_failure_cli.py +46 -46
  191. gitpr_cli-1.6.0/tests/test_doc_links.py +155 -0
  192. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_explain_command.py +55 -55
  193. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_external_linters.py +489 -489
  194. gitpr_cli-1.6.0/tests/test_full_diff_encoding.py +228 -0
  195. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_i18n.py +83 -30
  196. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_install_wizard.py +3 -0
  197. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_issue_engine.py +89 -89
  198. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_linter_metrics.py +120 -120
  199. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_linter_presets.py +92 -92
  200. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_main_suggest_reviewers.py +146 -146
  201. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_mcp_prompts.py +103 -103
  202. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_mcp_server.py +1629 -1562
  203. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_mcp_server_e2e.py +247 -247
  204. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_mentor_cli.py +101 -101
  205. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_metrics.py +207 -1
  206. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_net_timeouts.py +167 -167
  207. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_plugins.py +297 -297
  208. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_policy_cli.py +384 -384
  209. gitpr_cli-1.6.0/tests/test_pr_base_app.py +212 -0
  210. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_pr_publish_app.py +1223 -1166
  211. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_pr_publish_linter_modal.py +182 -182
  212. gitpr_cli-1.6.0/tests/test_project_config.py +601 -0
  213. gitpr_cli-1.6.0/tests/test_project_config_cli.py +139 -0
  214. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_release_cli.py +156 -156
  215. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_release_engine.py +118 -6
  216. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_reviewer_resolution.py +255 -255
  217. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_reviewer_suggestion.py +257 -257
  218. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_risk_cli.py +108 -108
  219. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_security_ruleset.py +470 -393
  220. gitpr_cli-1.6.0/tests/test_seed_command.py +186 -0
  221. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_skill_command.py +162 -162
  222. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_skill_context.py +124 -124
  223. gitpr_cli-1.6.0/tests/test_skill_frontmatter.py +60 -0
  224. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_skill_templates.py +36 -36
  225. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_smart_excludes.py +309 -271
  226. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_suggest_reviewers.py +813 -389
  227. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_tests_command.py +97 -97
  228. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_thinking_words.py +83 -83
  229. gitpr_cli-1.6.0/tests/test_tui_issue_token.py +189 -0
  230. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_updater.py +522 -519
  231. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_usage_log.py +255 -255
  232. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_version_bump.py +121 -121
  233. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_web_links.py +183 -183
  234. gitpr_cli-1.4.4/src/doc_links.py +0 -28
  235. gitpr_cli-1.4.4/src/suggest_reviewers.py +0 -146
  236. gitpr_cli-1.4.4/tests/test_full_diff_encoding.py +0 -83
  237. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/LICENSE +0 -0
  238. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/gitpr_cli.egg-info/dependency_links.txt +0 -0
  239. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/gitpr_cli.egg-info/entry_points.txt +0 -0
  240. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/gitpr_cli.egg-info/requires.txt +0 -0
  241. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/gitpr_cli.egg-info/top_level.txt +0 -0
  242. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/setup.cfg +0 -0
  243. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ai_providers.py +0 -0
  244. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/blame_engine.py +0 -0
  245. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/cache.py +0 -0
  246. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/chat_memory.py +0 -0
  247. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/issue_engine.py +0 -0
  248. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/linter_engine.py +0 -0
  249. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/security.py +0 -0
  250. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/src/ui/__init__.py +0 -0
  251. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_chat_backend.py +0 -0
  252. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_core.py +0 -0
  253. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_diff_parser.py +0 -0
  254. {gitpr_cli-1.4.4 → gitpr_cli-1.6.0}/tests/test_pre_save.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitpr-cli
3
- Version: 1.4.4
3
+ Version: 1.6.0
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
@@ -194,6 +194,7 @@ You can pass the following *flags* for specific actions:
194
194
  * **New Code Issue (`gitpr -is`):** Reads the current `git diff`. **Why use:** Ideal for quickly documenting the task you just finished programming, before committing.
195
195
  * **Epic/Release Issue (`gitpr -is -ht`):** Reads the full history of the current branch (Git Log + PR Cache). **Why use:** Ideal for generating consolidated documentation of an entire release or a large *feature* that took several days/commits to complete.
196
196
  * **Archaeological/Technical Debt Issue (`gitpr -is -b file:lines`):** Reads the timeline of a specific business rule. **Why use:** Ideal for documenting technical debt, explaining how a legacy code block evolved and why it needs to be refactored.
197
+ * `--close-issue` / `--no-close-issue`: Control the **automatic issue closure**. After `gitpr -is` creates an issue on GitHub, the next `gitpr` run offers to add `close #N` to the Pull Request description — the record lives in `.gitpr/conf/github.yml`, which GitPR adds to `.gitignore` automatically. `--close-issue` accepts without asking, `--no-close-issue` skips the check for the run, and `GITPR_ISSUE_AUTOCLOSE=false` turns the feature off. 📖 [Full docs](https://gitpr.natanfiuza.dev.br/docs/issue-autoclose)
197
198
  * **PR Publisher (default):** Running `gitpr` generates the PR description with AI, saves the `.md` file to `.gitpr/reports/pr_desc/`, and opens an interactive terminal interface (TUI) to review, edit, and publish the Pull Request directly to GitHub, GitLab, Bitbucket, or Azure DevOps via REST API. Before generation, it checks for unstaged files, calculates suggested reviewers, and offers a modal to manage them. Use `--no-publish` to save only the PR file locally without opening the publisher, or `--no-edit` to auto-commit pending changes (with lint validation), auto-push, and publish immediately — handling existing PR updates, optional auto-merge, and clear error feedback when merge conflicts occur. Use `--base <branch>` to change the target branch. 📖 [Full docs](https://gitpr.natanfiuza.dev.br/docs/pull-request-publication)
198
199
  * `-h` or `--help`: Shows the general help with all options. Use together with another flag for **contextual help** (e.g.: `gitpr -h --issue`, `gitpr -h --linter`) with a direct link to the detailed documentation of each feature.
199
200
  * `-u` or `--update`: Checks the latest version of GitPR on PyPI and shows how to update it (Auto-Updater).
@@ -339,6 +340,23 @@ For your own README there is a static badge. `gitpr badge --readme` prints the l
339
340
 
340
341
  📖 **Full documentation:** [gitpr.natanfiuza.dev.br/docs/badge](https://gitpr.natanfiuza.dev.br/docs/badge)
341
342
 
343
+ ## 🔗 Automatic Issue Closure (--close-issue)
344
+
345
+ `gitpr -is` creates an issue, and the pull request is where it gets closed. This feature carries the number between the two: when `F3` creates the issue on GitHub, GitPR records it in `.gitpr/conf/github.yml` (added to `.gitignore` automatically) — one issue at a time, the last one wins.
346
+
347
+ On the next `gitpr` run, before the description is generated, GitPR checks the recorded issue on GitHub. While it is still open, it offers to add `close #N` to the pull request body; the line becomes its own paragraph at the end and is never duplicated. Merging the pull request then closes the issue automatically.
348
+
349
+ | Flag / setting | Effect |
350
+ |---|---|
351
+ | `--close-issue` | Adds the line without asking (the issue is still checked) |
352
+ | `--no-close-issue` | Skips the check for this run — no record is read and no forge call is made |
353
+ | `GITPR_ISSUE_AUTOCLOSE=false` | Turns the feature off for every run; `--close-issue` does not override it |
354
+ | `GITPR_ISSUE_AUTOCLOSE_TIMEOUT` | Seconds to wait for the forge while checking the issue (default `5`) |
355
+
356
+ GitHub only; the other forges skip the feature in silence. A run with no terminal does not ask — use `--close-issue` to opt in. The record survives a failed or cancelled publish and is cleared only after the body reaches the forge; a closed, deleted or pull-request number forgets itself, and a record from another repository is ignored and kept.
357
+
358
+ 📖 **Full documentation:** [gitpr.natanfiuza.dev.br/docs/issue-autoclose](https://gitpr.natanfiuza.dev.br/docs/issue-autoclose)
359
+
342
360
  ## 🧠 Multi-Model Architecture (AI-Agnostic)
343
361
 
344
362
  GitPR is not tied to a single Artificial Intelligence. During initial setup, the user can choose their default engine. We currently support:
@@ -564,6 +582,7 @@ If you want to implement GitPR as an automated quality barrier in your team, che
564
582
  * [**Remote Pull Request Review (gitpr review-pr)**](https://gitpr.natanfiuza.dev.br/docs/review-pr) — How the `gitpr review-pr` subcommand reviews a pull request that is already open on the forge, fetching its diff from the API without checking out its branch.
565
583
  * [**AI Commit Messages**](https://gitpr.natanfiuza.dev.br/docs/commit-message-ia) — How to generate messages in the Conventional Commits standard and integrate with Git Hooks.
566
584
  * [**Issue Generation and TUI Interface**](https://gitpr.natanfiuza.dev.br/docs/issue-tui-help) — How to use the terminal graphical interface (TUI) and the 3 context engines to manage structured Issues.
585
+ * [**Automatic Issue Closure (--close-issue)**](https://gitpr.natanfiuza.dev.br/docs/issue-autoclose) — How the issue created by `gitpr -is` is recorded in `.gitpr/conf/github.yml`, the gate order that decides when the next pull request offers `close #N`, why the record survives a failed publish, and how the line is kept from being duplicated.
567
586
  * [**Code Archaeologist (Git Blame)**](https://gitpr.natanfiuza.dev.br/docs/blame-arqueologo) — How to trace the origin of business rules with `git blame` and AI.
568
587
  * [**Skills and Templates System**](https://gitpr.natanfiuza.dev.br/docs/skill-template) — How to customize AI behavior with `.gitpr.*.md` files.
569
588
  * [**Release Notes & Changelog (gitpr release)**](https://gitpr.natanfiuza.dev.br/docs/release-notes) — How the `gitpr release` subcommand generates the changelog / release notes of a repository from the delta of the previous version, links every commit, pull request and contributor, suggests the next semantic version and publishes releases on the forge.
@@ -1,23 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: gitpr-cli
3
- Version: 1.4.4
4
- Summary: AI-powered PR automation, commit messages, and code review (Gemini, DeepSeek, and Ollama)
5
- Author-email: Natan Fiuza <contato@natanfiuza.dev.br>
6
- Requires-Python: >=3.10
7
- Description-Content-Type: text/markdown
8
- License-File: LICENSE
9
- Requires-Dist: click>=8.0.0
10
- Requires-Dist: google-genai
11
- Requires-Dist: openai
12
- Requires-Dist: python-dotenv
13
- Requires-Dist: cryptography
14
- Requires-Dist: pyyaml
15
- Requires-Dist: textual
16
- Requires-Dist: requests
17
- Requires-Dist: mcp>=1.0.0
18
- Requires-Dist: packaging>=23.0
19
- Dynamic: license-file
20
-
21
1
 
22
2
  # **GitPR CLI 🚀**
23
3
 
@@ -194,6 +174,7 @@ You can pass the following *flags* for specific actions:
194
174
  * **New Code Issue (`gitpr -is`):** Reads the current `git diff`. **Why use:** Ideal for quickly documenting the task you just finished programming, before committing.
195
175
  * **Epic/Release Issue (`gitpr -is -ht`):** Reads the full history of the current branch (Git Log + PR Cache). **Why use:** Ideal for generating consolidated documentation of an entire release or a large *feature* that took several days/commits to complete.
196
176
  * **Archaeological/Technical Debt Issue (`gitpr -is -b file:lines`):** Reads the timeline of a specific business rule. **Why use:** Ideal for documenting technical debt, explaining how a legacy code block evolved and why it needs to be refactored.
177
+ * `--close-issue` / `--no-close-issue`: Control the **automatic issue closure**. After `gitpr -is` creates an issue on GitHub, the next `gitpr` run offers to add `close #N` to the Pull Request description — the record lives in `.gitpr/conf/github.yml`, which GitPR adds to `.gitignore` automatically. `--close-issue` accepts without asking, `--no-close-issue` skips the check for the run, and `GITPR_ISSUE_AUTOCLOSE=false` turns the feature off. 📖 [Full docs](https://gitpr.natanfiuza.dev.br/docs/issue-autoclose)
197
178
  * **PR Publisher (default):** Running `gitpr` generates the PR description with AI, saves the `.md` file to `.gitpr/reports/pr_desc/`, and opens an interactive terminal interface (TUI) to review, edit, and publish the Pull Request directly to GitHub, GitLab, Bitbucket, or Azure DevOps via REST API. Before generation, it checks for unstaged files, calculates suggested reviewers, and offers a modal to manage them. Use `--no-publish` to save only the PR file locally without opening the publisher, or `--no-edit` to auto-commit pending changes (with lint validation), auto-push, and publish immediately — handling existing PR updates, optional auto-merge, and clear error feedback when merge conflicts occur. Use `--base <branch>` to change the target branch. 📖 [Full docs](https://gitpr.natanfiuza.dev.br/docs/pull-request-publication)
198
179
  * `-h` or `--help`: Shows the general help with all options. Use together with another flag for **contextual help** (e.g.: `gitpr -h --issue`, `gitpr -h --linter`) with a direct link to the detailed documentation of each feature.
199
180
  * `-u` or `--update`: Checks the latest version of GitPR on PyPI and shows how to update it (Auto-Updater).
@@ -339,6 +320,23 @@ For your own README there is a static badge. `gitpr badge --readme` prints the l
339
320
 
340
321
  📖 **Full documentation:** [gitpr.natanfiuza.dev.br/docs/badge](https://gitpr.natanfiuza.dev.br/docs/badge)
341
322
 
323
+ ## 🔗 Automatic Issue Closure (--close-issue)
324
+
325
+ `gitpr -is` creates an issue, and the pull request is where it gets closed. This feature carries the number between the two: when `F3` creates the issue on GitHub, GitPR records it in `.gitpr/conf/github.yml` (added to `.gitignore` automatically) — one issue at a time, the last one wins.
326
+
327
+ On the next `gitpr` run, before the description is generated, GitPR checks the recorded issue on GitHub. While it is still open, it offers to add `close #N` to the pull request body; the line becomes its own paragraph at the end and is never duplicated. Merging the pull request then closes the issue automatically.
328
+
329
+ | Flag / setting | Effect |
330
+ |---|---|
331
+ | `--close-issue` | Adds the line without asking (the issue is still checked) |
332
+ | `--no-close-issue` | Skips the check for this run — no record is read and no forge call is made |
333
+ | `GITPR_ISSUE_AUTOCLOSE=false` | Turns the feature off for every run; `--close-issue` does not override it |
334
+ | `GITPR_ISSUE_AUTOCLOSE_TIMEOUT` | Seconds to wait for the forge while checking the issue (default `5`) |
335
+
336
+ GitHub only; the other forges skip the feature in silence. A run with no terminal does not ask — use `--close-issue` to opt in. The record survives a failed or cancelled publish and is cleared only after the body reaches the forge; a closed, deleted or pull-request number forgets itself, and a record from another repository is ignored and kept.
337
+
338
+ 📖 **Full documentation:** [gitpr.natanfiuza.dev.br/docs/issue-autoclose](https://gitpr.natanfiuza.dev.br/docs/issue-autoclose)
339
+
342
340
  ## 🧠 Multi-Model Architecture (AI-Agnostic)
343
341
 
344
342
  GitPR is not tied to a single Artificial Intelligence. During initial setup, the user can choose their default engine. We currently support:
@@ -564,6 +562,7 @@ If you want to implement GitPR as an automated quality barrier in your team, che
564
562
  * [**Remote Pull Request Review (gitpr review-pr)**](https://gitpr.natanfiuza.dev.br/docs/review-pr) — How the `gitpr review-pr` subcommand reviews a pull request that is already open on the forge, fetching its diff from the API without checking out its branch.
565
563
  * [**AI Commit Messages**](https://gitpr.natanfiuza.dev.br/docs/commit-message-ia) — How to generate messages in the Conventional Commits standard and integrate with Git Hooks.
566
564
  * [**Issue Generation and TUI Interface**](https://gitpr.natanfiuza.dev.br/docs/issue-tui-help) — How to use the terminal graphical interface (TUI) and the 3 context engines to manage structured Issues.
565
+ * [**Automatic Issue Closure (--close-issue)**](https://gitpr.natanfiuza.dev.br/docs/issue-autoclose) — How the issue created by `gitpr -is` is recorded in `.gitpr/conf/github.yml`, the gate order that decides when the next pull request offers `close #N`, why the record survives a failed publish, and how the line is kept from being duplicated.
567
566
  * [**Code Archaeologist (Git Blame)**](https://gitpr.natanfiuza.dev.br/docs/blame-arqueologo) — How to trace the origin of business rules with `git blame` and AI.
568
567
  * [**Skills and Templates System**](https://gitpr.natanfiuza.dev.br/docs/skill-template) — How to customize AI behavior with `.gitpr.*.md` files.
569
568
  * [**Release Notes & Changelog (gitpr release)**](https://gitpr.natanfiuza.dev.br/docs/release-notes) — How the `gitpr release` subcommand generates the changelog / release notes of a repository from the delta of the previous version, links every commit, pull request and contributor, suggests the next semantic version and publishes releases on the forge.
@@ -1,3 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: gitpr-cli
3
+ Version: 1.6.0
4
+ Summary: AI-powered PR automation, commit messages, and code review (Gemini, DeepSeek, and Ollama)
5
+ Author-email: Natan Fiuza <contato@natanfiuza.dev.br>
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: click>=8.0.0
10
+ Requires-Dist: google-genai
11
+ Requires-Dist: openai
12
+ Requires-Dist: python-dotenv
13
+ Requires-Dist: cryptography
14
+ Requires-Dist: pyyaml
15
+ Requires-Dist: textual
16
+ Requires-Dist: requests
17
+ Requires-Dist: mcp>=1.0.0
18
+ Requires-Dist: packaging>=23.0
19
+ Dynamic: license-file
20
+
1
21
 
2
22
  # **GitPR CLI 🚀**
3
23
 
@@ -174,6 +194,7 @@ You can pass the following *flags* for specific actions:
174
194
  * **New Code Issue (`gitpr -is`):** Reads the current `git diff`. **Why use:** Ideal for quickly documenting the task you just finished programming, before committing.
175
195
  * **Epic/Release Issue (`gitpr -is -ht`):** Reads the full history of the current branch (Git Log + PR Cache). **Why use:** Ideal for generating consolidated documentation of an entire release or a large *feature* that took several days/commits to complete.
176
196
  * **Archaeological/Technical Debt Issue (`gitpr -is -b file:lines`):** Reads the timeline of a specific business rule. **Why use:** Ideal for documenting technical debt, explaining how a legacy code block evolved and why it needs to be refactored.
197
+ * `--close-issue` / `--no-close-issue`: Control the **automatic issue closure**. After `gitpr -is` creates an issue on GitHub, the next `gitpr` run offers to add `close #N` to the Pull Request description — the record lives in `.gitpr/conf/github.yml`, which GitPR adds to `.gitignore` automatically. `--close-issue` accepts without asking, `--no-close-issue` skips the check for the run, and `GITPR_ISSUE_AUTOCLOSE=false` turns the feature off. 📖 [Full docs](https://gitpr.natanfiuza.dev.br/docs/issue-autoclose)
177
198
  * **PR Publisher (default):** Running `gitpr` generates the PR description with AI, saves the `.md` file to `.gitpr/reports/pr_desc/`, and opens an interactive terminal interface (TUI) to review, edit, and publish the Pull Request directly to GitHub, GitLab, Bitbucket, or Azure DevOps via REST API. Before generation, it checks for unstaged files, calculates suggested reviewers, and offers a modal to manage them. Use `--no-publish` to save only the PR file locally without opening the publisher, or `--no-edit` to auto-commit pending changes (with lint validation), auto-push, and publish immediately — handling existing PR updates, optional auto-merge, and clear error feedback when merge conflicts occur. Use `--base <branch>` to change the target branch. 📖 [Full docs](https://gitpr.natanfiuza.dev.br/docs/pull-request-publication)
178
199
  * `-h` or `--help`: Shows the general help with all options. Use together with another flag for **contextual help** (e.g.: `gitpr -h --issue`, `gitpr -h --linter`) with a direct link to the detailed documentation of each feature.
179
200
  * `-u` or `--update`: Checks the latest version of GitPR on PyPI and shows how to update it (Auto-Updater).
@@ -319,6 +340,23 @@ For your own README there is a static badge. `gitpr badge --readme` prints the l
319
340
 
320
341
  📖 **Full documentation:** [gitpr.natanfiuza.dev.br/docs/badge](https://gitpr.natanfiuza.dev.br/docs/badge)
321
342
 
343
+ ## 🔗 Automatic Issue Closure (--close-issue)
344
+
345
+ `gitpr -is` creates an issue, and the pull request is where it gets closed. This feature carries the number between the two: when `F3` creates the issue on GitHub, GitPR records it in `.gitpr/conf/github.yml` (added to `.gitignore` automatically) — one issue at a time, the last one wins.
346
+
347
+ On the next `gitpr` run, before the description is generated, GitPR checks the recorded issue on GitHub. While it is still open, it offers to add `close #N` to the pull request body; the line becomes its own paragraph at the end and is never duplicated. Merging the pull request then closes the issue automatically.
348
+
349
+ | Flag / setting | Effect |
350
+ |---|---|
351
+ | `--close-issue` | Adds the line without asking (the issue is still checked) |
352
+ | `--no-close-issue` | Skips the check for this run — no record is read and no forge call is made |
353
+ | `GITPR_ISSUE_AUTOCLOSE=false` | Turns the feature off for every run; `--close-issue` does not override it |
354
+ | `GITPR_ISSUE_AUTOCLOSE_TIMEOUT` | Seconds to wait for the forge while checking the issue (default `5`) |
355
+
356
+ GitHub only; the other forges skip the feature in silence. A run with no terminal does not ask — use `--close-issue` to opt in. The record survives a failed or cancelled publish and is cleared only after the body reaches the forge; a closed, deleted or pull-request number forgets itself, and a record from another repository is ignored and kept.
357
+
358
+ 📖 **Full documentation:** [gitpr.natanfiuza.dev.br/docs/issue-autoclose](https://gitpr.natanfiuza.dev.br/docs/issue-autoclose)
359
+
322
360
  ## 🧠 Multi-Model Architecture (AI-Agnostic)
323
361
 
324
362
  GitPR is not tied to a single Artificial Intelligence. During initial setup, the user can choose their default engine. We currently support:
@@ -544,6 +582,7 @@ If you want to implement GitPR as an automated quality barrier in your team, che
544
582
  * [**Remote Pull Request Review (gitpr review-pr)**](https://gitpr.natanfiuza.dev.br/docs/review-pr) — How the `gitpr review-pr` subcommand reviews a pull request that is already open on the forge, fetching its diff from the API without checking out its branch.
545
583
  * [**AI Commit Messages**](https://gitpr.natanfiuza.dev.br/docs/commit-message-ia) — How to generate messages in the Conventional Commits standard and integrate with Git Hooks.
546
584
  * [**Issue Generation and TUI Interface**](https://gitpr.natanfiuza.dev.br/docs/issue-tui-help) — How to use the terminal graphical interface (TUI) and the 3 context engines to manage structured Issues.
585
+ * [**Automatic Issue Closure (--close-issue)**](https://gitpr.natanfiuza.dev.br/docs/issue-autoclose) — How the issue created by `gitpr -is` is recorded in `.gitpr/conf/github.yml`, the gate order that decides when the next pull request offers `close #N`, why the record survives a failed publish, and how the line is kept from being duplicated.
547
586
  * [**Code Archaeologist (Git Blame)**](https://gitpr.natanfiuza.dev.br/docs/blame-arqueologo) — How to trace the origin of business rules with `git blame` and AI.
548
587
  * [**Skills and Templates System**](https://gitpr.natanfiuza.dev.br/docs/skill-template) — How to customize AI behavior with `.gitpr.*.md` files.
549
588
  * [**Release Notes & Changelog (gitpr release)**](https://gitpr.natanfiuza.dev.br/docs/release-notes) — How the `gitpr release` subcommand generates the changelog / release notes of a repository from the delta of the previous version, links every commit, pull request and contributor, suggests the next semantic version and publishes releases on the forge.
@@ -29,11 +29,14 @@ src/main.py
29
29
  src/mcp_server.py
30
30
  src/metrics.py
31
31
  src/net.py
32
+ src/project_config.py
32
33
  src/release_engine.py
33
34
  src/reviewer_resolution.py
34
35
  src/reviewer_suggestion.py
36
+ src/scm_settings.py
35
37
  src/security.py
36
38
  src/security_ruleset.py
39
+ src/skill_frontmatter.py
37
40
  src/spinner.py
38
41
  src/suggest_reviewers.py
39
42
  src/tui_issue.py
@@ -136,6 +139,11 @@ src/infrastructure/scm/factory.py
136
139
  src/infrastructure/scm/github_provider.py
137
140
  src/infrastructure/scm/gitlab_provider.py
138
141
  src/infrastructure/scm/web_links.py
142
+ src/issue_autoclose/__init__.py
143
+ src/issue_autoclose/insert_close_line.py
144
+ src/issue_autoclose/issue_registry.py
145
+ src/issue_autoclose/register_created_issue.py
146
+ src/issue_autoclose/resolve_close_issue.py
139
147
  src/policy_packs/laravel-quality/CHANGELOG.md
140
148
  src/policy_packs/laravel-quality/README.md
141
149
  src/policy_packs/laravel-quality/linter.yml
@@ -169,6 +177,7 @@ src/ui/issue_app.py
169
177
  src/ui/linter_app.py
170
178
  src/ui/metrics_app.py
171
179
  src/ui/metrics_migration_app.py
180
+ src/ui/pr_base_app.py
172
181
  src/ui/pr_publish_app.py
173
182
  src/ui/pr_publish_help.py
174
183
  src/ui/demo/__init__.py
@@ -181,10 +190,12 @@ tests/test_blame_metrics.py
181
190
  tests/test_changelog_builder.py
182
191
  tests/test_chat_backend.py
183
192
  tests/test_check_cli.py
193
+ tests/test_cli_help.py
184
194
  tests/test_commit_app.py
185
195
  tests/test_commit_classifier.py
186
196
  tests/test_config_app.py
187
197
  tests/test_config_cli.py
198
+ tests/test_config_issue_autoclose.py
188
199
  tests/test_config_schema.py
189
200
  tests/test_config_store.py
190
201
  tests/test_config_suggest_reviewers.py
@@ -192,6 +203,7 @@ tests/test_config_validation.py
192
203
  tests/test_core.py
193
204
  tests/test_diff_failure_cli.py
194
205
  tests/test_diff_parser.py
206
+ tests/test_doc_links.py
195
207
  tests/test_explain_command.py
196
208
  tests/test_external_linters.py
197
209
  tests/test_full_diff_encoding.py
@@ -209,22 +221,28 @@ tests/test_metrics.py
209
221
  tests/test_net_timeouts.py
210
222
  tests/test_plugins.py
211
223
  tests/test_policy_cli.py
224
+ tests/test_pr_base_app.py
212
225
  tests/test_pr_publish_app.py
213
226
  tests/test_pr_publish_linter_modal.py
214
227
  tests/test_pre_save.py
228
+ tests/test_project_config.py
229
+ tests/test_project_config_cli.py
215
230
  tests/test_release_cli.py
216
231
  tests/test_release_engine.py
217
232
  tests/test_reviewer_resolution.py
218
233
  tests/test_reviewer_suggestion.py
219
234
  tests/test_risk_cli.py
220
235
  tests/test_security_ruleset.py
236
+ tests/test_seed_command.py
221
237
  tests/test_skill_command.py
222
238
  tests/test_skill_context.py
239
+ tests/test_skill_frontmatter.py
223
240
  tests/test_skill_templates.py
224
241
  tests/test_smart_excludes.py
225
242
  tests/test_suggest_reviewers.py
226
243
  tests/test_tests_command.py
227
244
  tests/test_thinking_words.py
245
+ tests/test_tui_issue_token.py
228
246
  tests/test_updater.py
229
247
  tests/test_usage_log.py
230
248
  tests/test_version_bump.py
@@ -1,49 +1,49 @@
1
- [build-system]
2
- requires = ["setuptools>=61.0"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name = "gitpr-cli"
7
- dynamic = ["version"]
8
- description = "AI-powered PR automation, commit messages, and code review (Gemini, DeepSeek, and Ollama)"
9
- readme = "README.md"
10
- requires-python = ">=3.10"
11
- authors = [
12
- {name = "Natan Fiuza", email = "contato@natanfiuza.dev.br"}
13
- ]
14
- dependencies = [
15
- "click>=8.0.0",
16
- "google-genai",
17
- "openai",
18
- "python-dotenv",
19
- "cryptography",
20
- "pyyaml",
21
- "textual",
22
- "requests",
23
- "mcp>=1.0.0",
24
- "packaging>=23.0"
25
- ]
26
-
27
- [project.scripts]
28
- gitpr = "src.main:cli"
29
- gitpr-mcp = "src.mcp_server:main"
30
-
31
- [tool.setuptools.packages.find]
32
- where = ["."]
33
- include = ["src", "src.*"]
34
-
35
- # The bundled policy packs are data, not code: the four directories under
36
- # src/policy_packs ship inside the wheel, and without this block a built package
37
- # would find no packs at all while the source tree found four. MANIFEST.in is
38
- # not used anywhere in this project, so there is one place to look.
39
- [tool.setuptools.package-data]
40
- "src.policy_packs" = ["**/*.yml", "**/*.yaml", "**/*.md"]
41
-
42
- [tool.setuptools.dynamic]
43
- version = {attr = "src.updater.__version__"}
44
-
45
- [tool.pyright]
46
- include = ["src"]
47
- executionEnvironments = [
48
- { root = "." }
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "gitpr-cli"
7
+ dynamic = ["version"]
8
+ description = "AI-powered PR automation, commit messages, and code review (Gemini, DeepSeek, and Ollama)"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ authors = [
12
+ {name = "Natan Fiuza", email = "contato@natanfiuza.dev.br"}
13
+ ]
14
+ dependencies = [
15
+ "click>=8.0.0",
16
+ "google-genai",
17
+ "openai",
18
+ "python-dotenv",
19
+ "cryptography",
20
+ "pyyaml",
21
+ "textual",
22
+ "requests",
23
+ "mcp>=1.0.0",
24
+ "packaging>=23.0"
25
+ ]
26
+
27
+ [project.scripts]
28
+ gitpr = "src.main:cli"
29
+ gitpr-mcp = "src.mcp_server:main"
30
+
31
+ [tool.setuptools.packages.find]
32
+ where = ["."]
33
+ include = ["src", "src.*"]
34
+
35
+ # The bundled policy packs are data, not code: the four directories under
36
+ # src/policy_packs ship inside the wheel, and without this block a built package
37
+ # would find no packs at all while the source tree found four. MANIFEST.in is
38
+ # not used anywhere in this project, so there is one place to look.
39
+ [tool.setuptools.package-data]
40
+ "src.policy_packs" = ["**/*.yml", "**/*.yaml", "**/*.md"]
41
+
42
+ [tool.setuptools.dynamic]
43
+ version = {attr = "src.updater.__version__"}
44
+
45
+ [tool.pyright]
46
+ include = ["src"]
47
+ executionEnvironments = [
48
+ { root = "." }
49
49
  ]
@@ -1 +1 @@
1
- # Módulo principal do GitPR
1
+ # Módulo principal do GitPR
@@ -1,2 +1,2 @@
1
- # Application layer markers
2
-
1
+ # Application layer markers
2
+
@@ -1,8 +1,8 @@
1
- from src.application.use_cases.generate_test_file import generate_test_file, validate_test_syntax
2
- from src.application.use_cases.generate_pr_explanation import generate_pr_explanation
3
-
4
- __all__ = [
5
- "generate_test_file",
6
- "validate_test_syntax",
7
- "generate_pr_explanation",
8
- ]
1
+ from src.application.use_cases.generate_test_file import generate_test_file, validate_test_syntax
2
+ from src.application.use_cases.generate_pr_explanation import generate_pr_explanation
3
+
4
+ __all__ = [
5
+ "generate_test_file",
6
+ "validate_test_syntax",
7
+ "generate_pr_explanation",
8
+ ]
@@ -1,122 +1,122 @@
1
- """Use case: record which pack a repository follows.
2
-
3
- The record is ``.gitpr/policy.lock.yml``, a file meant to be committed: it is
4
- what makes the policy the same for everyone on the team and what lets a later
5
- run notice that a pack changed under it.
6
-
7
- Activation is **one pack per repository**. Choosing a second one replaces the
8
- first rather than adding to it, so there is never a question about which pack
9
- owns a value — the graph below the root is reached through ``extends``, and only
10
- through it.
11
-
12
- Building the lockfile and writing it are separate functions because the CLI has
13
- to show the user what will be written *before* asking whether to write it. A
14
- command that writes first and asks afterwards is not asking.
15
- """
16
-
17
- import os
18
- from datetime import datetime, timezone
19
- from typing import Any
20
-
21
- from src.domain.policy import set_active_policy
22
- from src.domain.policy.policy_resolver import resolve_graph
23
- from src.i18n import __
24
- from src.infrastructure.policy.local_policy_repository import (
25
- LOCKFILE_SCHEMA_VERSION,
26
- lockfile_path,
27
- write_lockfile,
28
- )
29
- from src.infrastructure.policy.policy_pack_loader import (
30
- load_pack_by_reference,
31
- make_loader,
32
- )
33
-
34
- from src.application.use_cases.validate_policy_pack import split_reference
35
-
36
-
37
- def _relative_to_repo(absolute: str, repo_path: str) -> str | None:
38
- """*absolute* as a repository-relative POSIX path, or None when outside.
39
-
40
- Only packs that live inside the repository are recorded by path. A pack in
41
- ``~/.gitpr/policies/`` is recorded by name and version instead, so the
42
- lockfile stays valid for a teammate who has it installed somewhere else.
43
- """
44
- try:
45
- relative = os.path.relpath(absolute, repo_path)
46
- except ValueError:
47
- # Different drives on Windows.
48
- return None
49
- parts = relative.split(os.sep)
50
- if not relative or parts[0] == "..":
51
- return None
52
- return relative.replace(os.sep, "/")
53
-
54
-
55
- def _lockfile_entry(pack: Any, repo_path: str) -> dict[str, Any]:
56
- entry: dict[str, Any] = {
57
- "name": pack.reference.name,
58
- "version": pack.reference.version,
59
- "source": pack.reference.source.value,
60
- "checksum": pack.reference.checksum,
61
- }
62
- if pack.reference.path:
63
- relative = _relative_to_repo(pack.reference.path, repo_path)
64
- if relative:
65
- entry["path"] = relative
66
- return entry
67
-
68
-
69
- def build_lockfile(root_reference: str, repo_path: str | None = None) -> dict[str, Any]:
70
- """Resolves *root_reference* and the lockfile that would pin it.
71
-
72
- Raises ``PolicyError`` when the pack cannot be found or its graph does not
73
- resolve, and writes nothing. The CLI calls this first, shows the result, and
74
- only then decides whether to call :func:`activate_policy_pack`.
75
- """
76
- from src.updater import __version__
77
-
78
- repo = os.path.abspath(repo_path or os.getcwd())
79
- name, version_range = split_reference(root_reference)
80
- root = load_pack_by_reference(name, version_range, repo)
81
- packs = resolve_graph(root, make_loader(repo))
82
-
83
- return {
84
- "schema_version": LOCKFILE_SCHEMA_VERSION,
85
- "gitpr_version": __version__,
86
- "activated_at": datetime.now(timezone.utc).isoformat(timespec="seconds"),
87
- "root": _lockfile_entry(root, repo),
88
- "packs": [_lockfile_entry(pack, repo) for pack in packs],
89
- }
90
-
91
-
92
- def activate_policy_pack(root_reference: str, repo_path: str | None = None) -> str:
93
- """Pins *root_reference* for the repository and returns the lockfile path."""
94
- data = build_lockfile(root_reference, repo_path)
95
- return write_lockfile(data, repo_path)
96
-
97
-
98
- def deactivate_policy_pack(repo_path: str | None = None) -> bool:
99
- """Removes the lockfile. Returns whether there was one to remove.
100
-
101
- The overrides file and the packs themselves are left alone: they are the
102
- user's material, and a decision to stop following a pack is not a decision to
103
- delete it.
104
- """
105
- target = lockfile_path(repo_path)
106
- if not os.path.isfile(target):
107
- return False
108
- os.remove(target)
109
- set_active_policy(None)
110
- return True
111
-
112
-
113
- def describe_lockfile(data: dict[str, Any]) -> str:
114
- """A one-line summary for the confirmation prompt."""
115
- root = data.get("root") or {}
116
- dependencies = [p for p in data.get("packs", []) if p.get("name") != root.get("name")]
117
- return __(
118
- "{pack}@{version} with {count} dependency pack(s)",
119
- pack=root.get("name", "?"),
120
- version=root.get("version", "?"),
121
- count=len(dependencies),
122
- )
1
+ """Use case: record which pack a repository follows.
2
+
3
+ The record is ``.gitpr/policy.lock.yml``, a file meant to be committed: it is
4
+ what makes the policy the same for everyone on the team and what lets a later
5
+ run notice that a pack changed under it.
6
+
7
+ Activation is **one pack per repository**. Choosing a second one replaces the
8
+ first rather than adding to it, so there is never a question about which pack
9
+ owns a value — the graph below the root is reached through ``extends``, and only
10
+ through it.
11
+
12
+ Building the lockfile and writing it are separate functions because the CLI has
13
+ to show the user what will be written *before* asking whether to write it. A
14
+ command that writes first and asks afterwards is not asking.
15
+ """
16
+
17
+ import os
18
+ from datetime import datetime, timezone
19
+ from typing import Any
20
+
21
+ from src.domain.policy import set_active_policy
22
+ from src.domain.policy.policy_resolver import resolve_graph
23
+ from src.i18n import __
24
+ from src.infrastructure.policy.local_policy_repository import (
25
+ LOCKFILE_SCHEMA_VERSION,
26
+ lockfile_path,
27
+ write_lockfile,
28
+ )
29
+ from src.infrastructure.policy.policy_pack_loader import (
30
+ load_pack_by_reference,
31
+ make_loader,
32
+ )
33
+
34
+ from src.application.use_cases.validate_policy_pack import split_reference
35
+
36
+
37
+ def _relative_to_repo(absolute: str, repo_path: str) -> str | None:
38
+ """*absolute* as a repository-relative POSIX path, or None when outside.
39
+
40
+ Only packs that live inside the repository are recorded by path. A pack in
41
+ ``~/.gitpr/policies/`` is recorded by name and version instead, so the
42
+ lockfile stays valid for a teammate who has it installed somewhere else.
43
+ """
44
+ try:
45
+ relative = os.path.relpath(absolute, repo_path)
46
+ except ValueError:
47
+ # Different drives on Windows.
48
+ return None
49
+ parts = relative.split(os.sep)
50
+ if not relative or parts[0] == "..":
51
+ return None
52
+ return relative.replace(os.sep, "/")
53
+
54
+
55
+ def _lockfile_entry(pack: Any, repo_path: str) -> dict[str, Any]:
56
+ entry: dict[str, Any] = {
57
+ "name": pack.reference.name,
58
+ "version": pack.reference.version,
59
+ "source": pack.reference.source.value,
60
+ "checksum": pack.reference.checksum,
61
+ }
62
+ if pack.reference.path:
63
+ relative = _relative_to_repo(pack.reference.path, repo_path)
64
+ if relative:
65
+ entry["path"] = relative
66
+ return entry
67
+
68
+
69
+ def build_lockfile(root_reference: str, repo_path: str | None = None) -> dict[str, Any]:
70
+ """Resolves *root_reference* and the lockfile that would pin it.
71
+
72
+ Raises ``PolicyError`` when the pack cannot be found or its graph does not
73
+ resolve, and writes nothing. The CLI calls this first, shows the result, and
74
+ only then decides whether to call :func:`activate_policy_pack`.
75
+ """
76
+ from src.updater import __version__
77
+
78
+ repo = os.path.abspath(repo_path or os.getcwd())
79
+ name, version_range = split_reference(root_reference)
80
+ root = load_pack_by_reference(name, version_range, repo)
81
+ packs = resolve_graph(root, make_loader(repo))
82
+
83
+ return {
84
+ "schema_version": LOCKFILE_SCHEMA_VERSION,
85
+ "gitpr_version": __version__,
86
+ "activated_at": datetime.now(timezone.utc).isoformat(timespec="seconds"),
87
+ "root": _lockfile_entry(root, repo),
88
+ "packs": [_lockfile_entry(pack, repo) for pack in packs],
89
+ }
90
+
91
+
92
+ def activate_policy_pack(root_reference: str, repo_path: str | None = None) -> str:
93
+ """Pins *root_reference* for the repository and returns the lockfile path."""
94
+ data = build_lockfile(root_reference, repo_path)
95
+ return write_lockfile(data, repo_path)
96
+
97
+
98
+ def deactivate_policy_pack(repo_path: str | None = None) -> bool:
99
+ """Removes the lockfile. Returns whether there was one to remove.
100
+
101
+ The overrides file and the packs themselves are left alone: they are the
102
+ user's material, and a decision to stop following a pack is not a decision to
103
+ delete it.
104
+ """
105
+ target = lockfile_path(repo_path)
106
+ if not os.path.isfile(target):
107
+ return False
108
+ os.remove(target)
109
+ set_active_policy(None)
110
+ return True
111
+
112
+
113
+ def describe_lockfile(data: dict[str, Any]) -> str:
114
+ """A one-line summary for the confirmation prompt."""
115
+ root = data.get("root") or {}
116
+ dependencies = [p for p in data.get("packs", []) if p.get("name") != root.get("name")]
117
+ return __(
118
+ "{pack}@{version} with {count} dependency pack(s)",
119
+ pack=root.get("name", "?"),
120
+ version=root.get("version", "?"),
121
+ count=len(dependencies),
122
+ )