gitpr-cli 1.4.3__tar.gz → 1.5.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 (245) hide show
  1. {gitpr_cli-1.4.3/gitpr_cli.egg-info → gitpr_cli-1.5.0}/PKG-INFO +20 -1
  2. gitpr_cli-1.4.3/PKG-INFO → gitpr_cli-1.5.0/README.md +19 -20
  3. gitpr_cli-1.4.3/README.md → gitpr_cli-1.5.0/gitpr_cli.egg-info/PKG-INFO +39 -0
  4. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/gitpr_cli.egg-info/SOURCES.txt +14 -0
  5. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/pyproject.toml +48 -48
  6. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/__init__.py +1 -1
  7. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/__init__.py +2 -2
  8. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/__init__.py +8 -8
  9. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/activate_policy_pack.py +122 -122
  10. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/baseline_gate.py +415 -415
  11. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/baseline_summary.py +259 -259
  12. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/calculate_risk.py +309 -309
  13. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/compare_against_baseline.py +41 -41
  14. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/create_baseline.py +709 -709
  15. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/generate_mentor_explanation.py +279 -279
  16. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/generate_pr_explanation.py +82 -82
  17. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/generate_test_file.py +247 -247
  18. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/install_policy_pack.py +71 -71
  19. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/publish_pull_request.py +272 -272
  20. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/resolve_effective_policy.py +208 -208
  21. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/run_check.py +448 -446
  22. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/suppress_finding.py +483 -483
  23. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/application/use_cases/validate_policy_pack.py +263 -263
  24. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/branding/__init__.py +1 -1
  25. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/branding/badge_builder.py +139 -139
  26. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/branding/badge_data.py +53 -53
  27. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/changelog_builder.py +272 -272
  28. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/commit_classifier.py +178 -178
  29. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/config.py +14 -0
  30. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/config_schema.py +1357 -1270
  31. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/core.py +82 -8
  32. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/demo/__init__.py +7 -7
  33. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/demo/demo_runner.py +336 -336
  34. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/demo/fake_ai_provider.py +112 -112
  35. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/demo/scenarios/__init__.py +128 -128
  36. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/demo/scenarios/laravel_bug_fix.py +443 -443
  37. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/demo/scenarios/security_issue.py +511 -511
  38. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/diff_parser.py +321 -321
  39. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/doc_links.py +28 -28
  40. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/baseline/__init__.py +143 -143
  41. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/baseline/baseline_comparator.py +268 -268
  42. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/baseline/baseline_fingerprint.py +103 -103
  43. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/baseline/baseline_manifest.py +291 -291
  44. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/baseline/baseline_types.py +289 -289
  45. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/baseline/suppression_policy.py +661 -661
  46. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/check/__init__.py +31 -31
  47. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/check/check_config.py +122 -122
  48. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/check/check_output.py +112 -112
  49. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/check/check_types.py +165 -165
  50. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/finding/__init__.py +5 -5
  51. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/finding/finding_types.py +25 -25
  52. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/linter/__init__.py +8 -8
  53. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/linter/sast_finding_mapper.py +83 -83
  54. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/mentor/__init__.py +15 -15
  55. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/mentor/mentor_explanation_builder.py +228 -228
  56. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/policy/__init__.py +116 -116
  57. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/policy/policy_checksum.py +60 -60
  58. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/policy/policy_compatibility.py +210 -210
  59. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/policy/policy_manifest.py +694 -694
  60. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/policy/policy_resolver.py +706 -706
  61. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/policy/policy_types.py +237 -237
  62. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/pr/__init__.py +14 -14
  63. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/pr/explain_section_builder.py +153 -153
  64. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/risk/__init__.py +18 -18
  65. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/risk/risk_calculator.py +144 -144
  66. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/risk/risk_explanation.py +78 -78
  67. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/risk/risk_rules.py +261 -261
  68. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/risk/risk_types.py +113 -113
  69. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/tests_generation/__init__.py +14 -14
  70. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/tests_generation/framework_detector.py +120 -120
  71. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/tests_generation/test_content_types.py +43 -43
  72. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/domain/tests_generation/test_scaffold_builder.py +92 -92
  73. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/fix/__init__.py +16 -16
  74. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/fix/apply_fix.py +479 -479
  75. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/fix/fix_history.py +153 -153
  76. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/fix/patch_applier.py +42 -42
  77. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/fix/patch_extractor.py +61 -61
  78. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/fix/patch_provenance.py +96 -96
  79. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/fix/patch_safety_classifier.py +101 -101
  80. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/fix/rollback_fix.py +69 -69
  81. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/github_api.py +112 -112
  82. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/__init__.py +1 -1
  83. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/baseline/__init__.py +28 -28
  84. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/baseline/local_baseline_repository.py +355 -355
  85. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/ci/__init__.py +11 -11
  86. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/ci/junit_builder.py +102 -102
  87. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/ci/masking.py +65 -65
  88. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/ci/sarif_builder.py +152 -152
  89. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/git/__init__.py +1 -1
  90. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/git/identity.py +155 -155
  91. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/git/patch_applier.py +209 -209
  92. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/git/risk_history_reader.py +93 -93
  93. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/git/selective_stager.py +198 -198
  94. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/git/test_matcher.py +78 -78
  95. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/linter/external/__init__.py +9 -9
  96. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/linter/external/bandit_bridge.py +127 -127
  97. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/linter/external/base_bridge.py +95 -95
  98. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/linter/external/gitleaks_bridge.py +168 -168
  99. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/linter/external/semgrep_bridge.py +139 -139
  100. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/policy/__init__.py +45 -45
  101. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/policy/local_policy_repository.py +142 -142
  102. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/policy/policy_pack_loader.py +240 -240
  103. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/scm/__init__.py +62 -62
  104. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/scm/azure_devops_provider.py +464 -464
  105. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/scm/base.py +420 -352
  106. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/scm/bitbucket_provider.py +402 -402
  107. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/scm/factory.py +97 -97
  108. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/scm/github_provider.py +564 -531
  109. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/scm/gitlab_provider.py +435 -435
  110. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/infrastructure/scm/web_links.py +103 -103
  111. gitpr_cli-1.5.0/src/issue_autoclose/__init__.py +12 -0
  112. gitpr_cli-1.5.0/src/issue_autoclose/insert_close_line.py +46 -0
  113. gitpr_cli-1.5.0/src/issue_autoclose/issue_registry.py +235 -0
  114. gitpr_cli-1.5.0/src/issue_autoclose/register_created_issue.py +80 -0
  115. gitpr_cli-1.5.0/src/issue_autoclose/resolve_close_issue.py +226 -0
  116. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/linter_wizard.py +210 -210
  117. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/main.py +363 -15
  118. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/mcp_server.py +52 -31
  119. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/metrics.py +1105 -1105
  120. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/net.py +74 -74
  121. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/policy_packs/laravel-quality/CHANGELOG.md +25 -25
  122. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/policy_packs/laravel-quality/README.md +41 -41
  123. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/policy_packs/laravel-quality/linter.yml +61 -61
  124. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/policy_packs/laravel-quality/policy.yml +110 -110
  125. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/policy_packs/node-quality/README.md +27 -27
  126. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/policy_packs/node-quality/linter.yml +57 -57
  127. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/policy_packs/node-quality/policy.yml +82 -82
  128. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/policy_packs/php-security/README.md +33 -33
  129. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/policy_packs/php-security/linter.yml +69 -69
  130. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/policy_packs/php-security/policy.yml +75 -75
  131. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/policy_packs/vue-quality/README.md +29 -29
  132. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/policy_packs/vue-quality/linter.yml +50 -50
  133. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/policy_packs/vue-quality/policy.yml +78 -78
  134. gitpr_cli-1.5.0/src/project_config.py +426 -0
  135. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/release_engine.py +990 -990
  136. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/review/__init__.py +13 -13
  137. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/review/diff_normalizer.py +84 -84
  138. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/review/diff_source.py +69 -69
  139. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/review/remote_pr.py +350 -350
  140. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/review/render.py +83 -83
  141. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/reviewer_resolution.py +159 -159
  142. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/reviewer_suggestion.py +258 -258
  143. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/security_ruleset.py +115 -108
  144. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/spinner.py +257 -257
  145. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/split/__init__.py +17 -17
  146. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/split/apply_split_plan.py +251 -251
  147. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/split/generate_split_plan.py +222 -222
  148. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/split/hunk_grouper.py +347 -347
  149. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/split/hunk_parser.py +256 -256
  150. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/split/split_plan.py +153 -153
  151. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/suggest_reviewers.py +146 -146
  152. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/tui_issue.py +281 -281
  153. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/chat_app.py +11 -11
  154. gitpr_cli-1.5.0/src/ui/commit_app.py +220 -0
  155. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/config_app.py +2043 -1835
  156. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/demo/__init__.py +1 -1
  157. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/demo/demo_app.py +91 -91
  158. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/demo/demo_help_screen.py +52 -52
  159. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/demo/demo_screens.py +60 -60
  160. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/issue_app.py +22 -0
  161. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/linter_app.py +46 -46
  162. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/metrics_app.py +456 -456
  163. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/metrics_migration_app.py +173 -173
  164. gitpr_cli-1.5.0/src/ui/pr_base_app.py +98 -0
  165. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/pr_publish_app.py +1783 -1775
  166. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/pr_publish_help.py +50 -50
  167. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/updater.py +274 -274
  168. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/usage_log.py +127 -127
  169. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/version_bump.py +87 -87
  170. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_baseline_cli.py +946 -946
  171. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_blame_engine_ranges.py +140 -140
  172. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_blame_metrics.py +226 -226
  173. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_changelog_builder.py +286 -286
  174. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_check_cli.py +118 -118
  175. gitpr_cli-1.5.0/tests/test_cli_help.py +99 -0
  176. gitpr_cli-1.5.0/tests/test_commit_app.py +207 -0
  177. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_commit_classifier.py +222 -222
  178. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_config_app.py +1929 -1665
  179. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_config_cli.py +116 -116
  180. gitpr_cli-1.5.0/tests/test_config_issue_autoclose.py +113 -0
  181. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_config_schema.py +488 -459
  182. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_config_store.py +189 -189
  183. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_config_suggest_reviewers.py +82 -82
  184. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_config_validation.py +317 -317
  185. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_diff_failure_cli.py +46 -46
  186. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_explain_command.py +55 -55
  187. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_external_linters.py +489 -489
  188. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_full_diff_encoding.py +83 -83
  189. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_i18n.py +384 -332
  190. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_install_wizard.py +98 -98
  191. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_issue_engine.py +89 -89
  192. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_linter_metrics.py +120 -120
  193. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_linter_presets.py +92 -92
  194. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_main_suggest_reviewers.py +146 -146
  195. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_mcp_prompts.py +103 -103
  196. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_mcp_server.py +1629 -1562
  197. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_mcp_server_e2e.py +247 -247
  198. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_mentor_cli.py +101 -101
  199. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_metrics.py +2205 -2205
  200. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_net_timeouts.py +167 -167
  201. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_plugins.py +297 -297
  202. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_policy_cli.py +384 -384
  203. gitpr_cli-1.5.0/tests/test_pr_base_app.py +212 -0
  204. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_pr_publish_app.py +1223 -1166
  205. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_pr_publish_linter_modal.py +182 -182
  206. gitpr_cli-1.5.0/tests/test_project_config.py +506 -0
  207. gitpr_cli-1.5.0/tests/test_project_config_cli.py +139 -0
  208. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_release_cli.py +156 -156
  209. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_release_engine.py +1193 -1193
  210. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_reviewer_resolution.py +255 -255
  211. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_reviewer_suggestion.py +257 -257
  212. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_risk_cli.py +108 -108
  213. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_security_ruleset.py +470 -393
  214. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_skill_command.py +162 -162
  215. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_skill_context.py +124 -124
  216. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_skill_templates.py +36 -36
  217. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_smart_excludes.py +271 -271
  218. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_suggest_reviewers.py +389 -389
  219. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_tests_command.py +97 -97
  220. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_thinking_words.py +83 -83
  221. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_updater.py +522 -519
  222. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_usage_log.py +255 -255
  223. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_version_bump.py +121 -121
  224. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_web_links.py +183 -183
  225. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/LICENSE +0 -0
  226. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/gitpr_cli.egg-info/dependency_links.txt +0 -0
  227. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/gitpr_cli.egg-info/entry_points.txt +0 -0
  228. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/gitpr_cli.egg-info/requires.txt +0 -0
  229. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/gitpr_cli.egg-info/top_level.txt +0 -0
  230. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/setup.cfg +0 -0
  231. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ai_providers.py +0 -0
  232. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/blame_engine.py +0 -0
  233. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/cache.py +0 -0
  234. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/chat_memory.py +0 -0
  235. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/i18n.py +0 -0
  236. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/issue_engine.py +0 -0
  237. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ledger.py +0 -0
  238. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/linter_engine.py +0 -0
  239. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/security.py +0 -0
  240. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/__init__.py +0 -0
  241. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/src/ui/help_screen.py +0 -0
  242. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_chat_backend.py +0 -0
  243. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_core.py +0 -0
  244. {gitpr_cli-1.4.3 → gitpr_cli-1.5.0}/tests/test_diff_parser.py +0 -0
  245. {gitpr_cli-1.4.3 → gitpr_cli-1.5.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.3
3
+ Version: 1.5.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.3
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.5.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,6 +29,7 @@ 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
@@ -136,6 +137,11 @@ src/infrastructure/scm/factory.py
136
137
  src/infrastructure/scm/github_provider.py
137
138
  src/infrastructure/scm/gitlab_provider.py
138
139
  src/infrastructure/scm/web_links.py
140
+ src/issue_autoclose/__init__.py
141
+ src/issue_autoclose/insert_close_line.py
142
+ src/issue_autoclose/issue_registry.py
143
+ src/issue_autoclose/register_created_issue.py
144
+ src/issue_autoclose/resolve_close_issue.py
139
145
  src/policy_packs/laravel-quality/CHANGELOG.md
140
146
  src/policy_packs/laravel-quality/README.md
141
147
  src/policy_packs/laravel-quality/linter.yml
@@ -162,12 +168,14 @@ src/split/hunk_parser.py
162
168
  src/split/split_plan.py
163
169
  src/ui/__init__.py
164
170
  src/ui/chat_app.py
171
+ src/ui/commit_app.py
165
172
  src/ui/config_app.py
166
173
  src/ui/help_screen.py
167
174
  src/ui/issue_app.py
168
175
  src/ui/linter_app.py
169
176
  src/ui/metrics_app.py
170
177
  src/ui/metrics_migration_app.py
178
+ src/ui/pr_base_app.py
171
179
  src/ui/pr_publish_app.py
172
180
  src/ui/pr_publish_help.py
173
181
  src/ui/demo/__init__.py
@@ -180,9 +188,12 @@ tests/test_blame_metrics.py
180
188
  tests/test_changelog_builder.py
181
189
  tests/test_chat_backend.py
182
190
  tests/test_check_cli.py
191
+ tests/test_cli_help.py
192
+ tests/test_commit_app.py
183
193
  tests/test_commit_classifier.py
184
194
  tests/test_config_app.py
185
195
  tests/test_config_cli.py
196
+ tests/test_config_issue_autoclose.py
186
197
  tests/test_config_schema.py
187
198
  tests/test_config_store.py
188
199
  tests/test_config_suggest_reviewers.py
@@ -207,9 +218,12 @@ tests/test_metrics.py
207
218
  tests/test_net_timeouts.py
208
219
  tests/test_plugins.py
209
220
  tests/test_policy_cli.py
221
+ tests/test_pr_base_app.py
210
222
  tests/test_pr_publish_app.py
211
223
  tests/test_pr_publish_linter_modal.py
212
224
  tests/test_pre_save.py
225
+ tests/test_project_config.py
226
+ tests/test_project_config_cli.py
213
227
  tests/test_release_cli.py
214
228
  tests/test_release_engine.py
215
229
  tests/test_reviewer_resolution.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
+ )