gitpr-cli 1.2.0__py3-none-any.whl → 1.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gitpr_cli-1.2.0.dist-info → gitpr_cli-1.4.0.dist-info}/METADATA +146 -15
- gitpr_cli-1.4.0.dist-info/RECORD +163 -0
- src/application/__init__.py +2 -0
- src/application/use_cases/__init__.py +8 -0
- src/application/use_cases/activate_policy_pack.py +122 -0
- src/application/use_cases/baseline_gate.py +415 -0
- src/application/use_cases/baseline_summary.py +259 -0
- src/application/use_cases/calculate_risk.py +309 -0
- src/application/use_cases/compare_against_baseline.py +41 -0
- src/application/use_cases/create_baseline.py +709 -0
- src/application/use_cases/generate_mentor_explanation.py +279 -0
- src/application/use_cases/generate_pr_explanation.py +73 -0
- src/application/use_cases/generate_test_file.py +227 -0
- src/application/use_cases/install_policy_pack.py +71 -0
- src/application/use_cases/resolve_effective_policy.py +208 -0
- src/application/use_cases/suppress_finding.py +483 -0
- src/application/use_cases/validate_policy_pack.py +263 -0
- src/branding/__init__.py +1 -0
- src/branding/badge_builder.py +139 -0
- src/branding/badge_data.py +53 -0
- src/changelog_builder.py +88 -15
- src/commit_classifier.py +45 -0
- src/config.py +462 -3
- src/config_schema.py +224 -0
- src/core.py +169 -8
- src/demo/__init__.py +7 -0
- src/demo/demo_runner.py +336 -0
- src/demo/fake_ai_provider.py +112 -0
- src/demo/scenarios/__init__.py +128 -0
- src/demo/scenarios/laravel_bug_fix.py +443 -0
- src/demo/scenarios/security_issue.py +511 -0
- src/domain/baseline/__init__.py +143 -0
- src/domain/baseline/baseline_comparator.py +268 -0
- src/domain/baseline/baseline_fingerprint.py +103 -0
- src/domain/baseline/baseline_manifest.py +291 -0
- src/domain/baseline/baseline_types.py +289 -0
- src/domain/baseline/suppression_policy.py +661 -0
- src/domain/finding/__init__.py +5 -0
- src/domain/finding/finding_types.py +25 -0
- src/domain/linter/__init__.py +8 -0
- src/domain/linter/sast_finding_mapper.py +83 -0
- src/domain/mentor/__init__.py +15 -0
- src/domain/mentor/mentor_explanation_builder.py +228 -0
- src/domain/policy/__init__.py +116 -0
- src/domain/policy/policy_checksum.py +60 -0
- src/domain/policy/policy_compatibility.py +210 -0
- src/domain/policy/policy_manifest.py +694 -0
- src/domain/policy/policy_resolver.py +706 -0
- src/domain/policy/policy_types.py +237 -0
- src/domain/pr/__init__.py +14 -0
- src/domain/pr/explain_section_builder.py +124 -0
- src/domain/risk/__init__.py +18 -0
- src/domain/risk/risk_calculator.py +144 -0
- src/domain/risk/risk_explanation.py +78 -0
- src/domain/risk/risk_rules.py +261 -0
- src/domain/risk/risk_types.py +113 -0
- src/domain/tests_generation/__init__.py +14 -0
- src/domain/tests_generation/framework_detector.py +120 -0
- src/domain/tests_generation/test_content_types.py +43 -0
- src/domain/tests_generation/test_scaffold_builder.py +92 -0
- src/fix/__init__.py +1 -1
- src/fix/patch_applier.py +38 -168
- src/i18n.py +5 -1
- src/infrastructure/baseline/__init__.py +28 -0
- src/infrastructure/baseline/local_baseline_repository.py +355 -0
- src/infrastructure/git/__init__.py +1 -0
- src/infrastructure/git/identity.py +155 -0
- src/infrastructure/git/patch_applier.py +209 -0
- src/infrastructure/git/risk_history_reader.py +93 -0
- src/infrastructure/git/selective_stager.py +198 -0
- src/infrastructure/git/test_matcher.py +78 -0
- src/infrastructure/linter/external/__init__.py +9 -0
- src/infrastructure/linter/external/bandit_bridge.py +127 -0
- src/infrastructure/linter/external/base_bridge.py +95 -0
- src/infrastructure/linter/external/gitleaks_bridge.py +168 -0
- src/infrastructure/linter/external/semgrep_bridge.py +139 -0
- src/infrastructure/policy/__init__.py +45 -0
- src/infrastructure/policy/local_policy_repository.py +142 -0
- src/infrastructure/policy/policy_pack_loader.py +240 -0
- src/infrastructure/scm/__init__.py +11 -0
- src/infrastructure/scm/azure_devops_provider.py +73 -10
- src/infrastructure/scm/base.py +90 -4
- src/infrastructure/scm/bitbucket_provider.py +76 -9
- src/infrastructure/scm/github_provider.py +77 -19
- src/infrastructure/scm/gitlab_provider.py +62 -9
- src/infrastructure/scm/web_links.py +103 -0
- src/ledger.py +1124 -0
- src/linter_engine.py +316 -13
- src/main.py +3139 -134
- src/mcp_server.py +202 -1
- src/metrics.py +1105 -628
- src/policy_packs/laravel-quality/CHANGELOG.md +25 -0
- src/policy_packs/laravel-quality/README.md +41 -0
- src/policy_packs/laravel-quality/linter.yml +61 -0
- src/policy_packs/laravel-quality/policy.yml +110 -0
- src/policy_packs/node-quality/README.md +27 -0
- src/policy_packs/node-quality/linter.yml +57 -0
- src/policy_packs/node-quality/policy.yml +82 -0
- src/policy_packs/php-security/README.md +33 -0
- src/policy_packs/php-security/linter.yml +69 -0
- src/policy_packs/php-security/policy.yml +75 -0
- src/policy_packs/vue-quality/README.md +29 -0
- src/policy_packs/vue-quality/linter.yml +50 -0
- src/policy_packs/vue-quality/policy.yml +78 -0
- src/release_engine.py +423 -23
- src/review/remote_pr.py +33 -2
- src/review/render.py +18 -10
- src/security_ruleset.py +108 -0
- src/split/__init__.py +17 -0
- src/split/apply_split_plan.py +251 -0
- src/split/generate_split_plan.py +222 -0
- src/split/hunk_grouper.py +347 -0
- src/split/hunk_parser.py +256 -0
- src/split/split_plan.py +153 -0
- src/ui/chat_app.py +35 -9
- src/ui/demo/__init__.py +1 -0
- src/ui/demo/demo_app.py +91 -0
- src/ui/demo/demo_help_screen.py +52 -0
- src/ui/demo/demo_screens.py +60 -0
- src/ui/metrics_app.py +230 -224
- src/ui/metrics_migration_app.py +173 -0
- src/updater.py +3 -3
- src/usage_log.py +13 -61
- gitpr_cli-1.2.0.dist-info/RECORD +0 -67
- {gitpr_cli-1.2.0.dist-info → gitpr_cli-1.4.0.dist-info}/WHEEL +0 -0
- {gitpr_cli-1.2.0.dist-info → gitpr_cli-1.4.0.dist-info}/entry_points.txt +0 -0
- {gitpr_cli-1.2.0.dist-info → gitpr_cli-1.4.0.dist-info}/licenses/LICENSE +0 -0
- {gitpr_cli-1.2.0.dist-info → gitpr_cli-1.4.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitpr-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.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
|
|
@@ -15,6 +15,7 @@ Requires-Dist: pyyaml
|
|
|
15
15
|
Requires-Dist: textual
|
|
16
16
|
Requires-Dist: requests
|
|
17
17
|
Requires-Dist: mcp>=1.0.0
|
|
18
|
+
Requires-Dist: packaging>=23.0
|
|
18
19
|
Dynamic: license-file
|
|
19
20
|
|
|
20
21
|
|
|
@@ -24,6 +25,10 @@ Dynamic: license-file
|
|
|
24
25
|
<img src="https://raw.githubusercontent.com/natanfiuza/gitpr/main/docs/logo.png" alt="GitPR Logo" width="150">
|
|
25
26
|
</p>
|
|
26
27
|
|
|
28
|
+
<p align="center">
|
|
29
|
+
<a href="https://gitpr.natanfiuza.dev.br/"><img src="https://img.shields.io/badge/GitPR-quality--checked-blue" alt="GitPR"></a>
|
|
30
|
+
</p>
|
|
31
|
+
|
|
27
32
|
GitPR CLI is a command-line automation tool that uses **Google Gemini**, **DeepSeek**, and **Ollama** artificial intelligence to analyze your code changes (git diff) or entire files. The tool automatically generates commit messages in the *Conventional Commits* standard, detailed Pull Request descriptions, and deep Code Reviews aimed at reducing technical debt.
|
|
28
33
|
|
|
29
34
|
🌐 **Website:** [gitpr.natanfiuza.dev.br](https://gitpr.natanfiuza.dev.br/) · 📂 **Repository:** [https://github.com/gitpr-cli/gitpr.git](https://github.com/gitpr-cli/gitpr.git)
|
|
@@ -40,7 +45,18 @@ Install GitPR CLI using `pip`:
|
|
|
40
45
|
pip install gitpr-cli
|
|
41
46
|
```
|
|
42
47
|
|
|
43
|
-
### **2.
|
|
48
|
+
### **2. Seeing It Work (No Configuration)**
|
|
49
|
+
|
|
50
|
+
GitPR ships a guided tour over an example diff. It needs no API key, no Git repository and no connection:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
gitpr demo
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
> **Guided Tour:** Six screens walking through a real example — the diff, the commit message, the code review and the pull request description — with the answers recorded once and replayed. Add `--no-tui` for plain text, `--scenario security-issue` for the other example.
|
|
57
|
+
> 📖 **Full Documentation:** [https://gitpr.natanfiuza.dev.br/docs/demo?lang=en_us](https://gitpr.natanfiuza.dev.br/docs/demo?lang=en_us)
|
|
58
|
+
|
|
59
|
+
### **3. Initializing in a Repository**
|
|
44
60
|
|
|
45
61
|
To set up GitPR in a folder of a new repository, run:
|
|
46
62
|
|
|
@@ -113,15 +129,19 @@ Pytest will automatically detect files inside the `tests/` folder and display a
|
|
|
113
129
|
|
|
114
130
|
### From Source Code
|
|
115
131
|
|
|
116
|
-
1. Clone the repository: `git clone https://github.com/gitpr-cli/gitpr.git
|
|
132
|
+
1. Clone the repository: `git clone https://github.com/gitpr-cli/gitpr.git`
|
|
117
133
|
|
|
118
134
|
2. Enter the folder: `cd gitpr`
|
|
119
135
|
|
|
120
|
-
3.
|
|
136
|
+
3. Install in editable mode:
|
|
121
137
|
```bash
|
|
122
|
-
|
|
138
|
+
pip install -e .
|
|
123
139
|
```
|
|
124
|
-
4. Run:
|
|
140
|
+
4. Run: `gitpr`
|
|
141
|
+
|
|
142
|
+
> Prefer an isolated environment? Install the dependencies with `pipenv install google-genai openai python-dotenv click cryptography` and run `pipenv run python src/main.py` instead.
|
|
143
|
+
>
|
|
144
|
+
> **Note on the update gate:** a source install reports the version found in your checkout, so a tree behind the published release is stopped at startup. See [Installing GitPR from Source](docs/tutorial/install-from-source.md).
|
|
125
145
|
|
|
126
146
|
## **💻 How to Use**
|
|
127
147
|
|
|
@@ -137,9 +157,22 @@ The tool will sync with the remote (`git fetch`), compare your changes with the
|
|
|
137
157
|
### **Advanced Options and Commands**
|
|
138
158
|
You can pass the following *flags* for specific actions:
|
|
139
159
|
|
|
160
|
+
* `gitpr demo`: **Guided tour** over an example diff that ships with the tool — the commit message, the code review and the pull request description, produced by the real pipeline on a recorded example. Needs no API key, no Git repository and no connection, which makes it the first thing to run on a new machine. Use `--scenario <name>` for another example, `--lang <code>` for another language, `--no-tui` for plain text. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/demo.md)
|
|
161
|
+
* `gitpr badge`: **Adoption badge for your README.** Prints the Markdown snippet — `--readme` prints only the line, `--style` picks the shields.io style (`flat`, `flat-square`, `for-the-badge`). Nothing is written to your README. Published pull requests carry a badge of their own, with the linter counts of the diff; `GITPR_BADGE=false` turns it off. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/badge.md)
|
|
162
|
+
* `gitpr config`: **Interactive configuration screen.** Opens a master-detail TUI to view, edit, search, and validate all settings stored in `~/.gitpr/.env` (with secret encryption and live validation). 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/config-tui.md)
|
|
163
|
+
* `gitpr release`: **Changelog and Release Notes generator.** Scans commits since the previous version, categorizes them according to Conventional Commits, suggests a semantic version bump, generates an AI executive summary, and optionally publishes the release to your forge. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/release-notes.md)
|
|
164
|
+
* `gitpr fix [<finding_id>]`: **Review findings patch application & rollback.** Turns findings from the last code review (`gitpr -r`) into safe, reviewable unified diffs. Includes safety classification (`safe`, `review_required`, `experimental`), `--all-safe` batching, `--force` validation, and `--rollback <patch-id>`. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/fix-command.md)
|
|
165
|
+
* `gitpr split`: **Atomic commit splitter.** Reads uncommitted working tree changes, groups hunks by intent using AI, and proposes ordered atomic commits without altering your working tree files (`--dry-run`, `--apply`). 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/split-command.md)
|
|
166
|
+
* `gitpr tests generate`: **AI test suite generation & scaffolding.** Analyzes your diff, a target file (`--file`), or a review finding (`--finding`) and generates complete, executable test suites (supporting pytest, jest, vitest, phpunit, pest). Use `--apply` to write to disk.
|
|
167
|
+
* `gitpr mentor [<finding_id>]`: **Junior Mentor Pedagogical Explanations.** Breaks down code review findings with educational context ("why this matters", real-world analogy, guided questions, and key takeaway) to foster growth and mentor developers. Works standalone over the latest review findings or with `--finding <id>`. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/mentor-mode.md)
|
|
168
|
+
* `gitpr explain`: **Reviewer Guide generator.** Generates a concise summary explaining what changed, why it changed, where reviewers should focus, and potential regression risks. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/pull-request-publication.md)
|
|
169
|
+
* `gitpr review-pr <pr_number>`: **Remote Pull Request review.** Fetches and reviews an open pull request directly from the forge (GitHub, GitLab, Bitbucket, Azure DevOps) without checking out the branch locally. Use `--post-comment` to post the review directly to the PR. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/review-pr.md)
|
|
170
|
+
* `gitpr risk`: **Local Risk Scoring for Diffs.** Computes a deterministic, explainable risk score (0.0 to 100.0) and badge (`LOW 🟢`, `MEDIUM 🟡`, `HIGH 🟠`, `CRITICAL 🔴`) using local repository signals (critical paths, missing tests, migrations, bug history, and static findings). Use `--file <path>`, `--format json`, `--base <ref>`, or `--no-history`. Automatically included in code reviews (`GITPR_RISK_INCLUDE_IN_REVIEW=true`). 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/risk-scoring.md)
|
|
171
|
+
* `gitpr policy`: **Shared quality policy for the repository.** Adopts a versioned YAML **Policy Pack** — review skills, linter rules, severity overrides, critical paths, risk weights and PR/commit conventions — and records the choice in `.gitpr/policy.lock.yml`, so the review, the linter and the risk score all run under the same policy, with a checksum per pack. `list`, `validate`, `show`, `use`, `init`, `install`, `off`. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/policy-packs.md)
|
|
172
|
+
* `gitpr baseline`: **Baseline and auditable suppressions for legacy adoption.** Records the findings a repository already has in `.gitpr/baseline.json`, so a run classifies every finding as `new`, `existing`, `resolved`, `ignored` or `accepted_debt` and **only `new` blocks**. Every suppression carries a reason, and accepted debt carries an owner and an optional deadline. `create`, `show`, `validate`, `update`, `suppress`, `unsuppress`. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/baseline-suppressions.md)
|
|
140
173
|
* `-c` or `--commit`: Runs a local `git diff` and displays **only the suggested commit message**.
|
|
141
|
-
* `-r` or `--review`: Performs a detailed **Code Review** of local changes.
|
|
142
|
-
* `-f` or `--fullreview`: Performs a **Full Code Review** analyzing all changes since the remote branch.
|
|
174
|
+
* `-r` or `--review`: Performs a detailed **Code Review** of local changes. Use with `--mentor` to append pedagogical mentoring explanations for each finding.
|
|
175
|
+
* `-f` or `--fullreview`: Performs a **Full Code Review** analyzing all changes since the remote branch. Use with `--mentor` to append pedagogical mentoring explanations.
|
|
143
176
|
* `-i <file>` or `--input <file>`: **Full File Audit.** Must be used together with `-r` or `-f`; it ignores git history and does a Code Review of the entire file. Excellent for acting as a consultant on legacy code refactoring.
|
|
144
177
|
* `--provider <gemini|deepseek|ollama>`: Forces the use of a specific AI only for this execution, ignoring your default saved in `.env`.
|
|
145
178
|
* `--lang <code>`: Forces the interface language for this execution (e.g.: `en_us`, `pt_br`). Overrides `GITPR_LANG` in `.env` without persisting the change.
|
|
@@ -147,8 +180,11 @@ You can pass the following *flags* for specific actions:
|
|
|
147
180
|
* `-l` or `--linter`: Runs **only the local static linter** (no AI calls). Ideal for use in CI/CD pipelines to block non-compliant code.
|
|
148
181
|
* `--status`: Lists uncommitted file changes categorized as **new**, **modified**, and **deleted** — fast, no AI, no network. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/git-status.md)
|
|
149
182
|
* `--no-unstaged-check`: Skips the unstaged files verification before AI processing for a single invocation. Equivalent to `GITPR_SKIP_UNSTAGED_CHECK=true` for one run. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/git-status.md)
|
|
183
|
+
* `--no-suggest-reviewers`: Disables the suggested reviewers computation in the interactive PR publisher (default ON). 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/suggested-reviewers.md)
|
|
184
|
+
* `--explain`: Includes the Reviewer Guide section ("Explain my PR") in the Pull Request description.
|
|
185
|
+
* `--init`: **Interactive SCM forge wizard.** Detects the repository's forge (GitHub, GitLab, Bitbucket Cloud, Azure DevOps), configures the provider, and stores the access token encrypted. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/scm-multiforge.md)
|
|
150
186
|
* `--linter-setup`: **Interactive external linter wizard.** Guides you through installing and configuring external linters (ESLint, PHPCS, Stylelint) as a Checkstyle XML bridge. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/linter-regras-customizadas.md)
|
|
151
|
-
* `--mcp`: Starts GitPR as an **MCP server** (Model Context Protocol) on stdio transport. Enables integration with VS Code, Cursor, Claude Desktop, and other MCP-compatible editors — exposing all GitPR AI capabilities as
|
|
187
|
+
* `--mcp`: Starts GitPR as an **MCP server** (Model Context Protocol) on stdio transport. Enables integration with VS Code, Cursor, Claude Desktop, and other MCP-compatible editors — exposing all GitPR AI capabilities as 16 annotated tools, 19 resources, and 7 pre-built prompts directly inside your IDE. Also available as the standalone `gitpr-mcp` command.
|
|
152
188
|
* `--plugins`: Lists all **globally installed plugins** — custom linter packs from `~/.gitpr/plugins/linter/` and MCP prompt templates from `~/.gitpr/plugins/prompts/`. These plugins apply across all your projects without duplication. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/plugins-system.md)
|
|
153
189
|
* `--install`: **Interactive Setup Wizard.** Runs a guided 4-step setup: downloads skill templates, installs Git hooks, configures MCP for detected editors, and checks/requests your AI provider API key. Each step asks for confirmation before proceeding.
|
|
154
190
|
* `-ih` or `--installhooks`: Automatically installs **local Git Hooks** (`pre-commit` and `prepare-commit-msg`) in your repository.
|
|
@@ -157,7 +193,7 @@ You can pass the following *flags* for specific actions:
|
|
|
157
193
|
* **New Code Issue (`gitpr -is`):** Reads the current `git diff`. **Why use:** Ideal for quickly documenting the task you just finished programming, before committing.
|
|
158
194
|
* **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.
|
|
159
195
|
* **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.
|
|
160
|
-
|
|
196
|
+
* **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://github.com/gitpr-cli/gitpr.git/blob/main/docs/pull-request-publication.md)
|
|
161
197
|
* `-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.
|
|
162
198
|
* `-u` or `--update`: Checks the latest version of GitPR on PyPI and shows how to update it (Auto-Updater).
|
|
163
199
|
|
|
@@ -171,7 +207,7 @@ When your diff is too large for a single AI call (over ~90k estimated tokens), G
|
|
|
171
207
|
|
|
172
208
|
📚 Full documentation: [docs/map-reduce-diff.md](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/map-reduce-diff.md)
|
|
173
209
|
|
|
174
|
-
## 🛡️ Local Linter (Static Analysis)
|
|
210
|
+
## 🛡️ Local Linter (Static Analysis & Security)
|
|
175
211
|
|
|
176
212
|
GitPR CLI allows you to define strict rules that will be validated instantly during `--review` or `--fullreview`, without depending on AI. This is ideal for preventing common errors (like `console.log` or test IPs) from reaching the repository.
|
|
177
213
|
|
|
@@ -192,9 +228,9 @@ rules:
|
|
|
192
228
|
|
|
193
229
|
The Linter analyzes only the **added lines** in your `git diff`, ensuring a focused and extremely fast execution. If there are violations, they will appear highlighted at the top of your review file.
|
|
194
230
|
|
|
195
|
-
### External Linters (Checkstyle Bridge)
|
|
231
|
+
### External Linters & SAST Bridges (Checkstyle Bridge)
|
|
196
232
|
|
|
197
|
-
If your project already uses tools like ESLint, PHP_CodeSniffer or
|
|
233
|
+
If your project already uses tools like ESLint, PHP_CodeSniffer, Stylelint, Semgrep, Gitleaks, or Bandit, GitPR can act as a bridge — running them in the background and filtering errors **only for the lines you changed** in your current diff. Any linter or SAST scanner that emits reports in the `checkstyle` format is supported. In addition, GitPR includes embedded secret scanning rules to catch leaked API keys, tokens, and credentials before they leave your machine.
|
|
198
234
|
|
|
199
235
|
Instead of configuring the YAML manually, use the interactive wizard:
|
|
200
236
|
|
|
@@ -204,7 +240,75 @@ gitpr --linter-setup
|
|
|
204
240
|
|
|
205
241
|
The wizard shows pre-configured presets (PHPCS, ESLint, Stylelint — controlled remotely via `templates/gitpr.linter-presets.json`), guides you through the native installation command (e.g.: `npm install --save-dev eslint`), and injects the correct `external_linters` block into your `.gitpr.linter.yml`.
|
|
206
242
|
|
|
207
|
-
Every run — manual via `--linter` or automatic before commits — consolidates the Regex Rules and External Linters into a single Markdown report saved at `.gitpr/reports/linter/` (customizable via `OUTPUT_FILE_NAME_LINTER`). The report is generated only when violations are found — clean runs create no files.
|
|
243
|
+
Every run — manual via `--linter` or automatic before commits — consolidates the Regex Rules, Embedded Security Rules, and External Linters into a single Markdown report saved at `.gitpr/reports/linter/` (customizable via `OUTPUT_FILE_NAME_LINTER`). The report is generated only when violations are found — clean runs create no files.
|
|
244
|
+
|
|
245
|
+
## ⚡ Local Risk Scoring (gitpr risk)
|
|
246
|
+
|
|
247
|
+
GitPR computes a local, deterministic, and explainable risk score (from `0.0` to `100.0`) for individual modified files and the pull request as a whole. It requires no network calls, consumes zero AI tokens, and evaluates repository and Git signals offline:
|
|
248
|
+
|
|
249
|
+
* **Critical Paths & Security (`+25`):** Authentication, billing, credentials, and sensitive operational modules.
|
|
250
|
+
* **Database & Infra (`+20`):** Migrations, schema definitions, CI/CD workflows, Docker, and Kubernetes configs.
|
|
251
|
+
* **Missing Tests (`+15`):** Executable production code modified without matching test updates in the diff.
|
|
252
|
+
* **History Signals (`+10` to `+20`):** Files associated with recent bug fixes, reverts, or high commit churn.
|
|
253
|
+
* **Findings:** Blocker (`+25`) or critical (`+15`) findings reported by static linters and secret scanners.
|
|
254
|
+
* **Test Presence (`-10`):** Mitigating credit when test files are added or modified alongside code changes.
|
|
255
|
+
|
|
256
|
+
### Risk Levels & Badges
|
|
257
|
+
|
|
258
|
+
| Level | Score Range | Badge | Meaning |
|
|
259
|
+
|---|---|---|---|
|
|
260
|
+
| **LOW** | 0.0 – 24.0 | `LOW 🟢` | Routine changes with low regression likelihood |
|
|
261
|
+
| **MEDIUM** | 25.0 – 49.0 | `MEDIUM 🟡` | Moderate changes requiring normal review vigilance |
|
|
262
|
+
| **HIGH** | 50.0 – 79.0 | `HIGH 🟠` | Significant changes touching critical areas or lacking tests |
|
|
263
|
+
| **CRITICAL** | 80.0 – 100.0 | `CRITICAL 🔴` | High regression exposure, blockers, or sensitive architectural impacts |
|
|
264
|
+
|
|
265
|
+
### Aggregation Formula (50 / 30 / 20)
|
|
266
|
+
|
|
267
|
+
The aggregate PR score combines:
|
|
268
|
+
* **50%**: Maximum individual file score
|
|
269
|
+
* **30%**: Weighted average of file scores by lines changed
|
|
270
|
+
* **20%**: Aggregated critical evidence score
|
|
271
|
+
|
|
272
|
+
### Review Integration
|
|
273
|
+
|
|
274
|
+
When enabled (`GITPR_RISK_INCLUDE_IN_REVIEW=true` in `~/.gitpr/.env`), GitPR automatically appends a `## ⚡ Risk Assessment` section to generated code review reports (`-r`, `-f`, `gitpr review-pr`) and primes the AI review prompt with critical risk areas.
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
gitpr risk # Compute risk for current diff
|
|
278
|
+
gitpr risk --file src/auth.py # Decompose risk for a single file
|
|
279
|
+
gitpr risk --format json # Output JSON for CI/CD pipelines
|
|
280
|
+
gitpr risk --base main # Evaluate against specific git base ref
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
📖 **Full documentation:** [docs/risk-scoring.md](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/risk-scoring.md)
|
|
284
|
+
|
|
285
|
+
## 🧾 Adopting GitPR in a Legacy Repository (gitpr baseline)
|
|
286
|
+
|
|
287
|
+
Adopting GitPR in a repository that already carries hundreds of findings is the moment the tool is least useful: the gate fails on problems nobody in this change introduced, and the alternatives are turning it off or spending a sprint fixing code nobody is touching. A **baseline** is the record of what the repository already has, committed to Git, so that every run classifies what it finds instead of starting from zero.
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
gitpr baseline create # Record the findings of the current diff
|
|
291
|
+
gitpr baseline show # The findings, the decisions and the counts
|
|
292
|
+
gitpr baseline validate # Every defect in the file — exit 1 on any
|
|
293
|
+
gitpr baseline update # Re-record today's diff, keeping decisions
|
|
294
|
+
gitpr baseline suppress <id> --reason "…" # A decision about one finding
|
|
295
|
+
gitpr baseline unsuppress <id> # Take a decision back
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
A suppression is not a silent filter: it carries a **reason**, an author and a date, and accepted debt carries an **owner** and an optional **deadline**. `--scope finding|line|file|rule` widens a decision beyond one finding, and anything wider than a single finding lives in `.gitpr/baseline.overrides.yml`, where it is reviewed with the code. A checksum over the record catches an edit made outside GitPR — `gitpr baseline validate` names the divergence instead of applying the file. A **Policy Pack** may carry a `baseline:` block of its own, applied in memory and attributed to the pack.
|
|
299
|
+
|
|
300
|
+
Four variables in `~/.gitpr/.env`, also editable through `gitpr config` in the section **Baseline**:
|
|
301
|
+
|
|
302
|
+
| Key | Default | Effect |
|
|
303
|
+
|---|---|---|
|
|
304
|
+
| `GITPR_BASELINE_ENABLED` | `true` | `false` → no run reads the baseline: the behaviour of every earlier version, byte for byte |
|
|
305
|
+
| `GITPR_BASELINE_PATH` | *(empty)* | `.gitpr/baseline.json`; a relative path resolves from the repository root |
|
|
306
|
+
| `GITPR_BASELINE_REQUIRE_LOCKFILE_CHECKSUM_MATCH` | `true` | A divergent checksum makes the record unusable: the blocking flows refuse and exit non-zero |
|
|
307
|
+
| `GITPR_BASELINE_ALLOW_LOCAL_OVERRIDES` | `true` | `false` → `.gitpr/baseline.overrides.yml` is not read |
|
|
308
|
+
|
|
309
|
+
Only a `new` error-level finding exits non-zero, and only `new` findings carry risk points — everything else reaches the risk report as zero-point evidence with its status. The baseline is never sent to the AI, and no entry stores code or a secret: the file is committed, so only a digest of the offending line is kept.
|
|
310
|
+
|
|
311
|
+
📖 **Full documentation:** [docs/baseline-suppressions.md](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/baseline-suppressions.md)
|
|
208
312
|
|
|
209
313
|
## 🤝 Co-Author Signature
|
|
210
314
|
|
|
@@ -218,6 +322,22 @@ The trailer is appended programmatically (never by the AI) in all flows: console
|
|
|
218
322
|
|
|
219
323
|
📖 **Full documentation:** [docs/commit-message-ia.md](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/commit-message-ia.md)
|
|
220
324
|
|
|
325
|
+
## 🏷️ Pull Request Badge
|
|
326
|
+
|
|
327
|
+
Every pull request GitPR publishes carries a badge at the foot of the body, with what the local linter counted on that very diff:
|
|
328
|
+
|
|
329
|
+
```text
|
|
330
|
+
GitPR | 0 errors · 2 warnings
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
It is built from a real measurement, never from a claim: red when a blocking finding is there, yellow for advice, green when the rules found nothing — and **no badge at all when no linter rules are configured**, because a green badge over a diff nobody checked would say something GitPR cannot back. It is on by default; `GITPR_BADGE=false` turns it off, and `gitpr --skill` is what gives it rules to count.
|
|
334
|
+
|
|
335
|
+
For your own README there is a static badge. `gitpr badge --readme` prints the line and writes nothing — pasting it is your call:
|
|
336
|
+
|
|
337
|
+
[](https://gitpr.natanfiuza.dev.br/)
|
|
338
|
+
|
|
339
|
+
📖 **Full documentation:** [docs/badge.md](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/badge.md)
|
|
340
|
+
|
|
221
341
|
## 🧠 Multi-Model Architecture (AI-Agnostic)
|
|
222
342
|
|
|
223
343
|
GitPR is not tied to a single Artificial Intelligence. During initial setup, the user can choose their default engine. We currently support:
|
|
@@ -237,6 +357,7 @@ Instead of hiding AI instructions in the source code, GitPR uses local Markdown
|
|
|
237
357
|
* `.gitpr.filereview.md`: Defines strict cohesion and coupling rules for full file auditing (used with `--input`).
|
|
238
358
|
* `.gitpr.issue.md`: Defines the structure and level of detail required for generating standardized Issues (used with `--issue`).
|
|
239
359
|
* `.gitpr.blame.md`: Defines the focus of archaeological analysis for legacy code tracing (used with `--blame`).
|
|
360
|
+
* `.gitpr.mentor.md`: Defines pedagogical coaching style, analogy framing, and tone for Junior Mentor Mode (used with `gitpr mentor` or `--mentor`).
|
|
240
361
|
|
|
241
362
|
## 🌐 Internationalization (i18n)
|
|
242
363
|
|
|
@@ -430,6 +551,8 @@ If you want to implement GitPR as an automated quality barrier in your team, che
|
|
|
430
551
|
|
|
431
552
|
### Core Features
|
|
432
553
|
|
|
554
|
+
* [**Guided Tour (gitpr demo)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/demo.md) — How the `gitpr demo` subcommand walks through the commit message, the code review and the pull request description over a recorded example, with no API key, no repository and no network.
|
|
555
|
+
* [**Pull Request Badge**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/badge.md) — What the badge GitPR attaches to published pull requests says, where it is attached, when it is left out, and how to print the static one for your own README.
|
|
433
556
|
* [**Pull Request (Default Mode)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/pr-descricao-padrao.md) — Complete flow for generating PR descriptions without flags.
|
|
434
557
|
* [**Pull Request Publisher TUI**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/pull-request-publication.md) — How to review and publish Pull Requests directly to GitHub from the terminal.
|
|
435
558
|
* [**AI Code Review**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/code-review-ia.md) — Guide to review modes (`--review`, `--fullreview`), file auditing (`--input`) and remote pull request review (`gitpr review-pr`).
|
|
@@ -438,11 +561,19 @@ If you want to implement GitPR as an automated quality barrier in your team, che
|
|
|
438
561
|
* [**Issue Generation and TUI Interface**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/issue-tui-help.md) — How to use the terminal graphical interface (TUI) and the 3 context engines to manage structured Issues.
|
|
439
562
|
* [**Code Archaeologist (Git Blame)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/blame-arqueologo.md) — How to trace the origin of business rules with `git blame` and AI.
|
|
440
563
|
* [**Skills and Templates System**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/skill-template.md) — How to customize AI behavior with `.gitpr.*.md` files.
|
|
441
|
-
* [**Release Notes & Changelog (gitpr release)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/release-notes.md) — How the `gitpr release` subcommand generates the changelog / release notes of a repository, suggests the next semantic version and publishes releases on the forge.
|
|
564
|
+
* [**Release Notes & Changelog (gitpr release)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/release-notes.md) — 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.
|
|
442
565
|
* [**Fix Command (gitpr fix)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/fix-command.md) — How the `gitpr fix` subcommand turns the findings of the last review into patches you read before they touch your tree, classifies each one by safety, and undoes an applied patch on demand.
|
|
566
|
+
* [**Split Command (gitpr split)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/split-command.md) — How the `gitpr split` subcommand reads a working tree holding several concerns, groups the hunks by intent with AI, and turns them into ordered atomic commits without ever writing to your files.
|
|
567
|
+
* [**Local Risk Scoring (gitpr risk)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/risk-scoring.md) — How the `gitpr risk` command evaluates regression risk, decomposes signals (50/30/20 formula), and highlights high-risk areas in code reviews offline.
|
|
568
|
+
* [**Policy Packs (gitpr policy)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/policy-packs.md) — How a repository adopts a versioned Policy Pack that carries skills, linter rules, severity overrides, critical paths and risk weights together, the precedence ladder that combines packs, the lockfile the team commits, and the three failures that abort instead of silently degrading.
|
|
569
|
+
* [**Baseline & Auditable Suppressions (gitpr baseline)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/baseline-suppressions.md) — How a legacy repository records the findings it already has, how a run classifies them as `new`, `existing`, `resolved`, `ignored` or `accepted_debt`, why only `new` blocks, what the fingerprint hashes and what it deliberately leaves out, the four scopes of a suppression, the checksum that catches a hand edit, and the `baseline:` block a Policy Pack may carry.
|
|
443
570
|
|
|
444
571
|
### Configuration & Infrastructure
|
|
445
572
|
|
|
573
|
+
* [**Interactive Configuration TUI (gitpr config)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/config-tui.md) — Master-detail terminal interface to view, edit, and validate settings in `~/.gitpr/.env`.
|
|
574
|
+
* [**Multi-Forge SCM Integration**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/scm-multiforge.md) — Unified SCM provider layer for GitHub, GitLab, Bitbucket Cloud, and Azure DevOps with `--init` wizard.
|
|
575
|
+
* [**Suggested Reviewers**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/suggested-reviewers.md) — Automatic reviewer suggestion via Git blame of added lines mapped to forge logins.
|
|
576
|
+
* [**Usage Telemetry & Audit Log**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/usage-log.md) — Local invocation logging and audit history for tracking CLI executions.
|
|
446
577
|
* [**Install Wizard**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/install-wizard.md) — Step-by-step guided setup for configuring GitPR in a new project.
|
|
447
578
|
* [**AI Providers**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/providers-ia.md) — Configuration and selection between Google Gemini, DeepSeek, and Ollama.
|
|
448
579
|
* [**Auto-Updater**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/auto-update.md) — How GitPR's automatic update and the mandatory update block work.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
gitpr_cli-1.4.0.dist-info/licenses/LICENSE,sha256=UQzLC6mwqb-ZNDkBBAqOxC-SMQcEID0gaM6oFcu6u48,27030
|
|
2
|
+
src/__init__.py,sha256=WZW9x8P5CYnru29UiarFa8q1nQzuwYWyIodSOlruCWI,29
|
|
3
|
+
src/ai_providers.py,sha256=QyFEOsXyA59lZziO5bl-4nlYFJpxBcxU9aLhcTBnkWE,14633
|
|
4
|
+
src/blame_engine.py,sha256=Zov1hxrt7Dcmf56ovJKz3QmHIfzDKtSub2iItXeg9-A,17104
|
|
5
|
+
src/cache.py,sha256=GC2ZT0ThAtH22aRRZapIeauATv_nqBfiRsXjqeMhAiI,6368
|
|
6
|
+
src/changelog_builder.py,sha256=8GicvIhREWo3B8XhQugVi2_OWzhN_ik_2GxpxmiJVTg,9650
|
|
7
|
+
src/chat_memory.py,sha256=PcohnyspAfIwwwbsp9U2Wk_1AylJMFEMoWqRSJe_w30,8949
|
|
8
|
+
src/commit_classifier.py,sha256=pgZRj8JvkCBgwgzDFNjjNKJKzddVB4HoPBcFM1F0zjE,6742
|
|
9
|
+
src/config.py,sha256=5bs6jxxg-CwmtGfJB2eoMUbwRddOnc_MCcadOOcMbHg,53637
|
|
10
|
+
src/config_schema.py,sha256=z-JC5rULAVkaQG4ppmVcdeNKLGpuXFqglzvCBgZjHVo,43308
|
|
11
|
+
src/core.py,sha256=rw_S8_QEv6kljpC6X4CEJLPjKtd91SogtH5G9-c2_PA,84823
|
|
12
|
+
src/diff_parser.py,sha256=62X69ves4tlzNgVKXNsfWdOMwqn2h16RkUOPqszMU7k,11252
|
|
13
|
+
src/doc_links.py,sha256=DuovU-RF9kjbisBdEoGAsuavQ2y0MYDhqy6Sz6vbrGI,1157
|
|
14
|
+
src/github_api.py,sha256=ILm7e03UP80swc3XuJvIJJvhLp81-V_3kQQ1EuAcN8Q,3836
|
|
15
|
+
src/i18n.py,sha256=PdUmtZlH1zogbiDc3j6xiwtnvUd7XiNbiS-xKjYK4WM,4844
|
|
16
|
+
src/issue_engine.py,sha256=XwW9C5uX84eOWWZMerm0DvE8LpLRcjhrLsXtt7yftak,10872
|
|
17
|
+
src/ledger.py,sha256=s10Sm0qcA1b916X7m8d2osDThCmSK0UQnmUrkyj8Eao,43663
|
|
18
|
+
src/linter_engine.py,sha256=hIxht8M09Fnm6NiJZOqjI6dyqnFoHUDVA8Ve4dWZV4s,25214
|
|
19
|
+
src/linter_wizard.py,sha256=7J_nQFghVwCaKG6QI3K45KcOaxHSH1oTCAvP_6tnCQM,7424
|
|
20
|
+
src/main.py,sha256=jgRHRpbTYkhCaamnXJacThdXPih2iE3005GVhbqYWW8,210498
|
|
21
|
+
src/mcp_server.py,sha256=rLkN8rJAjqSaguCXksbQsLBYu8XKkWdXKps_zl6dwOQ,99398
|
|
22
|
+
src/metrics.py,sha256=M4Yqa__giuhmkElT-XOWrTfHGsjK_URVLhIZvErD2f0,39560
|
|
23
|
+
src/net.py,sha256=f0MOkXyIxi4HVetsybtWpV_yHjiC17T2JMWySBdoV2I,2774
|
|
24
|
+
src/release_engine.py,sha256=xgsoZUYnFohxemwzRSPymoLvgYsK0Y4HRRtZaItkZEg,37433
|
|
25
|
+
src/reviewer_resolution.py,sha256=lZ3csSJHN6Y5TJ3U3p9uuXikOgG7fH4qqx7X9-4F7pc,5754
|
|
26
|
+
src/reviewer_suggestion.py,sha256=jk9FAyp7WkkJbi-yepz7LDF1_tSHxJEEjcajMKF5HdY,8501
|
|
27
|
+
src/security.py,sha256=fkWy-r4tdISH0xOyWZyR8ZCFyLuYqu8fn9sKsIeNAso,1351
|
|
28
|
+
src/security_ruleset.py,sha256=L754S4RlVoZGWm0nuCoeli9-49mKydZpwi31V319DQ0,4337
|
|
29
|
+
src/spinner.py,sha256=63pEotiDa3TVwBr-sn0MJoDPQ_uWJTTwINXieJIDDKc,8964
|
|
30
|
+
src/suggest_reviewers.py,sha256=-wRe0HYksx4FWQZ-eDvU9Ghdk5gqtEt457KQP7sE31Y,5181
|
|
31
|
+
src/tui_issue.py,sha256=WEFxT4kzWQ_KbSDsOnS_iuYXasZySB-68jryGNm0peg,10331
|
|
32
|
+
src/updater.py,sha256=mjlTehzEo4u23dOezGA-iMrw1GzAENUqQuZx7JZJLHs,4771
|
|
33
|
+
src/usage_log.py,sha256=FdfSmZKL_I5BcG750rD4gl3pNHx0jqV8Shij5XkAnzc,4381
|
|
34
|
+
src/version_bump.py,sha256=OjqJe9OL1-1dT5od7-SgU5ZN_dTtR_aKX_oSjSY64YQ,2954
|
|
35
|
+
src/application/__init__.py,sha256=0GADzpCB3CdCzw-d3az0DVOtTvXfCppt-0hY-Js5a1U,29
|
|
36
|
+
src/application/use_cases/__init__.py,sha256=7rwBoDbGxnsjVe32j7yj9yCA9g2E-DWGeokOfDbl_O0,284
|
|
37
|
+
src/application/use_cases/activate_policy_pack.py,sha256=lsR_AbIEykN7xWBB7qWNJpstnYFm3FKH117VZJx9jlM,4505
|
|
38
|
+
src/application/use_cases/baseline_gate.py,sha256=akVGhWKen5Cv_JExHu05yH6ahEc0AiPRc-rCStzKbkw,16319
|
|
39
|
+
src/application/use_cases/baseline_summary.py,sha256=SBcSv8EPjacckKOZjBpwjq07TRS9hY8CvUgUGxuknvc,10291
|
|
40
|
+
src/application/use_cases/calculate_risk.py,sha256=oh327qPomI_sO8JXErAHATafu_21KQKV4O_LLLHQ-tk,13204
|
|
41
|
+
src/application/use_cases/compare_against_baseline.py,sha256=qgidzsloF5b84LXGb42ae4bDdRGBbGTRepLm1Yb9FmA,1875
|
|
42
|
+
src/application/use_cases/create_baseline.py,sha256=LpXHlF9IkD4P4FL4VKJOh5YyCgfAD6hjt_0bQLy1pqI,25928
|
|
43
|
+
src/application/use_cases/generate_mentor_explanation.py,sha256=KNj5cDm-i7aPJxxbbLm4Hvtv7g5CI59-pbX7tHPcEtM,9428
|
|
44
|
+
src/application/use_cases/generate_pr_explanation.py,sha256=5BYUPgGBdR29P-9zt75IcKO4KOwGhZnapws7Y6A4574,3202
|
|
45
|
+
src/application/use_cases/generate_test_file.py,sha256=WlHnhwCWHe-XBrL9m1xvJOkn1wqr8vnsE3s3x9wgUi0,8615
|
|
46
|
+
src/application/use_cases/install_policy_pack.py,sha256=U1XvkHt0elXvyM2VRc6TPNukhUomSI2BSWj09hmLC_8,2745
|
|
47
|
+
src/application/use_cases/resolve_effective_policy.py,sha256=nTbjRR4di1GnCRV7l3yDNw27CQV3heAd45sftHxNyNc,7563
|
|
48
|
+
src/application/use_cases/suppress_finding.py,sha256=juj2jjk2BLjrAcx6WTKJNr5VMTJQ4Gb3GaEjDNGjM64,17809
|
|
49
|
+
src/application/use_cases/validate_policy_pack.py,sha256=g8jt8HYUcGae69tzfT84A22usbvF9JB3T2ZoG5oyw0A,9643
|
|
50
|
+
src/branding/__init__.py,sha256=6ORCsJHtd422jUiQNMCf6eL8kwW4QMf6dJ9Z4Gf9bEc,80
|
|
51
|
+
src/branding/badge_builder.py,sha256=ZO-rXMPoSPYodvILfY2wHufYs0ZQwgFxSs0SkHd6m4A,4899
|
|
52
|
+
src/branding/badge_data.py,sha256=eamUtEKeg3NwF9MCipb5EXFlwL8vgJnR6yUw2TrFlEw,1925
|
|
53
|
+
src/demo/__init__.py,sha256=lF-kdDOqylPXRiuSmT3XwqdghMlRIiOuzpNYs7ElGiE,370
|
|
54
|
+
src/demo/demo_runner.py,sha256=lqnJZB27GSJan7bwV3Gf1wnCBYn7Wws_DEOFdB5PADc,10721
|
|
55
|
+
src/demo/fake_ai_provider.py,sha256=9slMebDqKvHv6wmhms_YhEqPhQJBlxYwAiCzehpkR3A,4038
|
|
56
|
+
src/demo/scenarios/__init__.py,sha256=t8PRSdgNM9f0tb53lBSkehiQ_liI-azts7BdhMdUZrs,4041
|
|
57
|
+
src/demo/scenarios/laravel_bug_fix.py,sha256=lU3XoKaGvcDIlMmzZFeWvEI6tGjgz5bWGflBbUNvgHU,20461
|
|
58
|
+
src/demo/scenarios/security_issue.py,sha256=sI8YykXcYOkpgHygAOX6pYLHwSkHZoE5OjrYsRqOCXQ,23821
|
|
59
|
+
src/domain/baseline/__init__.py,sha256=g-zsXskjG1FY4ok0N4CRWxRLPh-fowr-2_sTiFj9kLA,3802
|
|
60
|
+
src/domain/baseline/baseline_comparator.py,sha256=dB8ydnKFiSSq4qPalLKq4RNpDi27ZB6mSx42fBhE5WA,8702
|
|
61
|
+
src/domain/baseline/baseline_fingerprint.py,sha256=06i-rxVcElr0md4eveKycl7etsHaECdI9vOZ_TAWPYQ,4370
|
|
62
|
+
src/domain/baseline/baseline_manifest.py,sha256=jYy_AHBNP6adFr8FNfZtqQmdZteGNzTlToXHg-BP3RI,10429
|
|
63
|
+
src/domain/baseline/baseline_types.py,sha256=_su74m5HuBu0Z5jxm_elva_CX7EP_6025lbX5EjH2o8,11220
|
|
64
|
+
src/domain/baseline/suppression_policy.py,sha256=GNZ0WN7ww4HcUq82vtiqd8Ere7EuP51VuSCoPzEkLOU,22489
|
|
65
|
+
src/domain/finding/__init__.py,sha256=Y9n2tmT8zybkv3zkBAoI_2k8C4ode2CWHm6l28BhH9w,166
|
|
66
|
+
src/domain/finding/finding_types.py,sha256=Nocd7SmXMAk3q0gVM6yeh2AW6rmJS6CxOCOIQsmsF-Y,833
|
|
67
|
+
src/domain/linter/__init__.py,sha256=WoLci3LhRc7S2IlytrveRPbEQVrAwI4bqazVmGP08Ak,236
|
|
68
|
+
src/domain/linter/sast_finding_mapper.py,sha256=C7SdwVz7-pJNCPeF5kchWjAmL4qs4m1yJQoAKrO-omM,3336
|
|
69
|
+
src/domain/mentor/__init__.py,sha256=4Ii3I9g-fQWv5wgxd5xe5sRdtTinF0Uvqd_b1CxL9ao,357
|
|
70
|
+
src/domain/mentor/mentor_explanation_builder.py,sha256=VGvHEWQuneZDA8epa2txRD5w2U4vU6rgVzmxM5tChg0,6776
|
|
71
|
+
src/domain/policy/__init__.py,sha256=rXn1lKH67Lx-p-9imYIjwqfEp3XAPLxq7djSWFusOIs,3501
|
|
72
|
+
src/domain/policy/policy_checksum.py,sha256=SIwVmMpb3FH1ziWBc9NJN6jqDqBLoagdf-QGO-Qf6N0,2282
|
|
73
|
+
src/domain/policy/policy_compatibility.py,sha256=rd90TLg4wyB9gI-RKMI94NxwxeFk9uKxBsJ9Tm9QM3c,8267
|
|
74
|
+
src/domain/policy/policy_manifest.py,sha256=hXIM4u-tKYXTcEu0rBEGJYBuv4dysn9NEjhxXVPSkk4,26292
|
|
75
|
+
src/domain/policy/policy_resolver.py,sha256=5oTVHysPIwRJibRtRp3U3zOJpS07EBRfkhsmpfI6wcE,28883
|
|
76
|
+
src/domain/policy/policy_types.py,sha256=lhGxapRFAPiVCjmZtwZ9EVViSkDYCJ6UiKNVsaPKvDw,9875
|
|
77
|
+
src/domain/pr/__init__.py,sha256=O9C2dQpbMnbF3mOXTMUvHPmIAF0G-QxhDlVXjB_wShs,274
|
|
78
|
+
src/domain/pr/explain_section_builder.py,sha256=RMPErD_X8nLhbfCwxHCBmI3AFLilO_eNPpEDZE6pyns,3799
|
|
79
|
+
src/domain/risk/__init__.py,sha256=9vbLfhIomCarCbEw_DCZzri9lzV-lFIXBN-FAq6oSPY,283
|
|
80
|
+
src/domain/risk/risk_calculator.py,sha256=zjIoLIRdXi3pHNbq0QcRwOznArtNtQQWV8ReLaW6Zn4,5037
|
|
81
|
+
src/domain/risk/risk_explanation.py,sha256=YuPMBT27x7rnZnmvttIWBsfbTjsIXjMUEP9WLU4VlvE,3005
|
|
82
|
+
src/domain/risk/risk_rules.py,sha256=2hueo89tvHOpLcCfKVEro8Z8AMgVeyUYG8xf6wcpcAI,8705
|
|
83
|
+
src/domain/risk/risk_types.py,sha256=O3l6woRgnpocGffucFiI22LoOrxM-qS70HDg2hSHGO4,4041
|
|
84
|
+
src/domain/tests_generation/__init__.py,sha256=OcHvtEilwu_8z_PV_prq2x_GGBGxmlsCW2XM1xU8dl0,251
|
|
85
|
+
src/domain/tests_generation/framework_detector.py,sha256=DyJZcttvpRkZMEx8a9X3ksveJ-PNub49XXNzqERQSU4,4439
|
|
86
|
+
src/domain/tests_generation/test_content_types.py,sha256=jnPywEMAGtm340e8V1kuHbx9Nxa9nhC7mKnubduxEZM,1019
|
|
87
|
+
src/domain/tests_generation/test_scaffold_builder.py,sha256=NkTbYswWiuWikLfz6nRi34zU8e7HvzMzkbj3q2W__Ws,3800
|
|
88
|
+
src/fix/__init__.py,sha256=haZFtazOc4v9SmtqBtyPNUvYrEQXNaChTIZiOpZlNSc,937
|
|
89
|
+
src/fix/apply_fix.py,sha256=yMinMW50Fw62V-k7hRwN1lsikCJbz6xV5iX4IH0sdxY,17912
|
|
90
|
+
src/fix/fix_history.py,sha256=pHXHpt-SstitbLDmlPloDVKlH79FUD8hqKjVK5xKLMA,5626
|
|
91
|
+
src/fix/patch_applier.py,sha256=3tIXwp8yPwelngXvhmQhvCYVpEOPfvCUwrnG_B9Yf0c,1235
|
|
92
|
+
src/fix/patch_extractor.py,sha256=gEiwSvxGNHM74TnubTN22NBpbXDwvNpB2vMqgpF7hQQ,2514
|
|
93
|
+
src/fix/patch_provenance.py,sha256=sF934ntcZjJCTzzhtuR2Pi-vMUdXFElKcuw5riwPnUk,3195
|
|
94
|
+
src/fix/patch_safety_classifier.py,sha256=StZvh_0Y-ZCdf_LwFoVAdfhpi0b7v1TOxTRoG86_63M,4121
|
|
95
|
+
src/fix/rollback_fix.py,sha256=rMBYewuvlhJOFdo-Ke_SPfu1O-yd6NJzEYiO5o-LcKk,2501
|
|
96
|
+
src/infrastructure/__init__.py,sha256=zTIcY3cscsdkXogSGXoJbH0mVGFbKYTRK32fg26wr9U,81
|
|
97
|
+
src/infrastructure/baseline/__init__.py,sha256=VCnAq7MgyvIAwjd2jznSEvyY42Xg5tmnz4VWBxFA5YI,614
|
|
98
|
+
src/infrastructure/baseline/local_baseline_repository.py,sha256=lE9f2D-6XBPRNi5e32jUA6aG6TUxgAN12ihz-tH3KaM,13460
|
|
99
|
+
src/infrastructure/git/__init__.py,sha256=j9zQUXKNp5NcOzTK-qHGNh75YkufGlw5rgH1wgRknX4,87
|
|
100
|
+
src/infrastructure/git/identity.py,sha256=fClwWTkGIypquE19dUjwwDQCifdsGQmmRMgVobuBIa8,5722
|
|
101
|
+
src/infrastructure/git/patch_applier.py,sha256=RgbrpAp-6x401Eydz6yLMTOXKn5E9LQzV9ZB_n7E90M,7988
|
|
102
|
+
src/infrastructure/git/risk_history_reader.py,sha256=EqIvVPqw5gCFHnHSjIioMSg3BTSk9fXvynZJi0ajfyY,2733
|
|
103
|
+
src/infrastructure/git/selective_stager.py,sha256=sMRPZmq2EWipcabCCETeMu_0in66BFSzQAqZ7h1y2hc,8038
|
|
104
|
+
src/infrastructure/git/test_matcher.py,sha256=wsbMrPAdBqfRz8W_DNjdIE1yQi3Y56Mi9Jfv0DOeMos,2586
|
|
105
|
+
src/infrastructure/linter/external/__init__.py,sha256=6qz3sZ-ObiSOiTfakgGoIRefJnHaWSh4M9Hvh1XNWxw,317
|
|
106
|
+
src/infrastructure/linter/external/bandit_bridge.py,sha256=gTixkOj0wERfe4Bp53w1hjpSrEH4F6bxCfEwYX0Cy0M,4330
|
|
107
|
+
src/infrastructure/linter/external/base_bridge.py,sha256=sHiKZnLitCMoMhMy9tVXVggIQWhE5IcpECYx_JQ_FnY,3063
|
|
108
|
+
src/infrastructure/linter/external/gitleaks_bridge.py,sha256=rgsYTcfvHDeekWuXU2D73apq-4NyMlVi_E5S5cHbOWU,5881
|
|
109
|
+
src/infrastructure/linter/external/semgrep_bridge.py,sha256=gifKH4T22ZunoYRZROD2mwv46CCYgGLT6ikmO9VnnrM,4504
|
|
110
|
+
src/infrastructure/policy/__init__.py,sha256=37VsNF-kYx3Z7UQQo_LT8nQhrfU-v4JUwaLGBKgU11Y,1039
|
|
111
|
+
src/infrastructure/policy/local_policy_repository.py,sha256=bBRWrz8cDJB34c_QwVnCUFK4NESjQTKUiPPuJ4uDpII,5644
|
|
112
|
+
src/infrastructure/policy/policy_pack_loader.py,sha256=sutt_l-_SGBkR0VAaeZ9YwFPC4WAcX4H89J7E7_Br8s,9319
|
|
113
|
+
src/infrastructure/scm/__init__.py,sha256=kNiYljRCJRwi5WoPckn8NbZt6qbEQZFMwaBY3-kepRo,1825
|
|
114
|
+
src/infrastructure/scm/azure_devops_provider.py,sha256=L9nKlwayUj80jZxOeeGFKbgos3He-lVRVh5U7Nkoopg,17920
|
|
115
|
+
src/infrastructure/scm/base.py,sha256=wbHFUNBtxXrRcEBiT0qmgBScWr-Ep_eJSIeP279KOQI,13921
|
|
116
|
+
src/infrastructure/scm/bitbucket_provider.py,sha256=ooHt7qilk_LHwOSJK81WMm-ZPBZJomyIZL5NEWeMoak,15151
|
|
117
|
+
src/infrastructure/scm/factory.py,sha256=Qeearq8eWnF_4boI68rVBkoGEiS-xRGD4V-O_FF0204,3856
|
|
118
|
+
src/infrastructure/scm/github_provider.py,sha256=Ju1QzU6oiUft1hGT1zqaIx1vUJIr0oy3GCYm3y0YfcM,19342
|
|
119
|
+
src/infrastructure/scm/gitlab_provider.py,sha256=06jWqEk_A8ERYf0KalGxXdLZBL4ZemYz9KuDMiK7YcY,16595
|
|
120
|
+
src/infrastructure/scm/web_links.py,sha256=9DHFCwYc6TVzO3INe0rvEicgoD2-kxQSrgq3vt_p5Ow,3621
|
|
121
|
+
src/policy_packs/laravel-quality/CHANGELOG.md,sha256=ztrTTZhzScFdPEWOSkQoQ7vnaTu5LkqyJZc43k6G8qg,1129
|
|
122
|
+
src/policy_packs/laravel-quality/README.md,sha256=GSeluNUTR80dwhm1qZrrYFaaPjrdhTkWmfJdv3hDWes,1811
|
|
123
|
+
src/policy_packs/laravel-quality/linter.yml,sha256=OoJg-i5jDnaXwVYd_nZe2HMinVt0n2op7KvUzG7fqKQ,3130
|
|
124
|
+
src/policy_packs/laravel-quality/policy.yml,sha256=z41BBUM_rAWLTIstNoI3E5pa4Y_Uy21lsrPBWOuH_VY,3703
|
|
125
|
+
src/policy_packs/node-quality/README.md,sha256=eGb8bZBBwniM4fKBDQoHhrpXxcijHpxEiwffJupgvZg,1286
|
|
126
|
+
src/policy_packs/node-quality/linter.yml,sha256=LqKDpnIcO4jSe2VihaEAfncevZNl9fJYQF7n_vpNLAw,2817
|
|
127
|
+
src/policy_packs/node-quality/policy.yml,sha256=MVXsPk-AYx2mchum0lOnKQqCfy_3HdkVPogAas-Qcmk,3137
|
|
128
|
+
src/policy_packs/php-security/README.md,sha256=7R7NrqoEN0WjVCJf6l38zxurBI9af7veWj9NvI1XTAc,1456
|
|
129
|
+
src/policy_packs/php-security/linter.yml,sha256=3aSXdmLZCkVwE7vRl4doXEO1yohc9A-GLmcRCWk-UTY,3191
|
|
130
|
+
src/policy_packs/php-security/policy.yml,sha256=sycGc-AhsHrx_kYwcbaVwAO5gMmj9zmC-9YdjBpMg0A,3183
|
|
131
|
+
src/policy_packs/vue-quality/README.md,sha256=hHKAPxNMfkBOdqe4lhL5-LLYEUM82mJ10zdhxP4yQxE,1264
|
|
132
|
+
src/policy_packs/vue-quality/linter.yml,sha256=UFZY6G7N7G484mStiQVL0u9p6yzoVPzdvdYTHc5ABpc,2458
|
|
133
|
+
src/policy_packs/vue-quality/policy.yml,sha256=WMfnCoWxWAqwrPn28QJ1oOvY0emoxoLEXmxzGlDLq_4,3021
|
|
134
|
+
src/review/__init__.py,sha256=XVyQZFf6UAqIKi8Gb1pQ4dKjcrC50soUvNuKu1DBspc,687
|
|
135
|
+
src/review/diff_normalizer.py,sha256=PRXQ7b81EBH1nx_8_Tm9G7Kjdax_6hIVtFgEixicT0E,3551
|
|
136
|
+
src/review/diff_source.py,sha256=O8bIlff0Zr7wPMzCKAVk_LF2pMDr3sc9KAuyA3OvHG0,2664
|
|
137
|
+
src/review/remote_pr.py,sha256=BswcOgZA1GZdfQ1NXKA9lWsZA60fKmUUndMIG97CJg0,13319
|
|
138
|
+
src/review/render.py,sha256=Wrfp3gPfzT7_IS-yScABYI2ptSb0ntoJkpEw27xpzhA,3111
|
|
139
|
+
src/split/__init__.py,sha256=JuXxPxoG1NrWtLAQARSBh59tsNXvrUoS-T-vHcHeDPM,912
|
|
140
|
+
src/split/apply_split_plan.py,sha256=-ESEEl973Ai9czEOVfS697Dy196QX8EKbVrNZlgrQhY,10678
|
|
141
|
+
src/split/generate_split_plan.py,sha256=I370yLCxqeZRemIIcLswYVI07fet5JJMRxxht21HlOA,8786
|
|
142
|
+
src/split/hunk_grouper.py,sha256=rNH64CJQ80ue6YjTTaVxwtQug1tY6yCjEEScjj8wL2o,14249
|
|
143
|
+
src/split/hunk_parser.py,sha256=Lvmpd8qPYT2a0pw-XCSvUJqm_b9P5tAw9Kj_DlbBWTk,10010
|
|
144
|
+
src/split/split_plan.py,sha256=rim_iUlyQO8EpqXjN-YzRFv5mbo2pwZlXdrkuZ7PGxM,6419
|
|
145
|
+
src/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
146
|
+
src/ui/chat_app.py,sha256=O21d4-_6u87pHeFKtBJbTpQxkBQWmaNa617CO0f4-0Q,26777
|
|
147
|
+
src/ui/config_app.py,sha256=xgppZbEBFrFijgLGo1b1PN1vTGCg8xpI8gpMYBv2KzU,73417
|
|
148
|
+
src/ui/help_screen.py,sha256=EvbP8kFZ6Sdehi7bJ6Wo_YcTTk5MTkgneeidWwefYrA,1890
|
|
149
|
+
src/ui/issue_app.py,sha256=eINMmamloeopbtwyS1rCPwosaHeZW5oLebnEV4TfamY,9281
|
|
150
|
+
src/ui/linter_app.py,sha256=Y5vwU7D5PQIR_HaY6t40jZy7Guc8z2w-auyosCQqoro,1566
|
|
151
|
+
src/ui/metrics_app.py,sha256=r5JSS70Fkir0qQ4Q03T6c1R2-WGrvYMNTlHMhjAR2Tc,16303
|
|
152
|
+
src/ui/metrics_migration_app.py,sha256=-56HhWZhtVpGCO53NhUnOpZI9bDesfwy2_w7f31cMsU,5923
|
|
153
|
+
src/ui/pr_publish_app.py,sha256=cZ9xr1TSZF6fjvQPlAdSjzSNykufHF1l7hsmo3Ib2j0,67311
|
|
154
|
+
src/ui/pr_publish_help.py,sha256=fBiUtD97ngxbSfAvPVGGXU19r5kbALCKyi4QeKqyQ2c,1891
|
|
155
|
+
src/ui/demo/__init__.py,sha256=PGXenIwpS1lVDE164CZ55q8_65XtJq5H300NIpnqOh0,58
|
|
156
|
+
src/ui/demo/demo_app.py,sha256=EDeuqxh_v9KrPhib49TyirmFlHZN7I5NQkg9AjDGhcs,3074
|
|
157
|
+
src/ui/demo/demo_help_screen.py,sha256=m8SuvhzGmkMsahUBA6Aq7ull4W65nS0KOX4hLx-GGps,2056
|
|
158
|
+
src/ui/demo/demo_screens.py,sha256=3Ntp-A7OB43yEtniRqV1UKWc-p5lHRyxeadpe8bxJpM,1937
|
|
159
|
+
gitpr_cli-1.4.0.dist-info/METADATA,sha256=UElFetNIOs54YQZ92CqK1LxNKFSAp-0VG-azLmnsgF0,51335
|
|
160
|
+
gitpr_cli-1.4.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
161
|
+
gitpr_cli-1.4.0.dist-info/entry_points.txt,sha256=TstGnMUzdOI5qNmpM97EPDBPuMqOZxoo6EoLxHSOMSQ,71
|
|
162
|
+
gitpr_cli-1.4.0.dist-info/top_level.txt,sha256=74rtVfumQlgAPzR5_2CgYN24MB0XARCg0t-gzk6gTrM,4
|
|
163
|
+
gitpr_cli-1.4.0.dist-info/RECORD,,
|
|
@@ -0,0 +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
|
+
]
|
|
@@ -0,0 +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
|
+
)
|