codepulse-cli 0.1.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.
@@ -0,0 +1,52 @@
1
+ name: CodePulse risk gate
2
+
3
+ # Scores what each pull request changes against the repo's history and posts
4
+ # the result as a sticky PR comment. Fails the check on HIGH risk.
5
+
6
+ on:
7
+ pull_request:
8
+
9
+ permissions:
10
+ contents: read
11
+ pull-requests: write
12
+
13
+ jobs:
14
+ risk:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ with:
19
+ fetch-depth: 0 # full history is required to build the risk map
20
+
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.12"
24
+
25
+ - name: Install CodePulse
26
+ run: pip install -e .
27
+
28
+ - name: Build risk comment
29
+ run: |
30
+ codepulse . --changed "origin/${{ github.base_ref }}" \
31
+ --format markdown > comment.md
32
+ cat comment.md
33
+
34
+ - name: Post sticky PR comment
35
+ env:
36
+ GH_TOKEN: ${{ github.token }}
37
+ PR: ${{ github.event.pull_request.number }}
38
+ run: |
39
+ # Update our previous comment if one exists, else create it.
40
+ id=$(gh api "repos/${{ github.repository }}/issues/$PR/comments" \
41
+ --jq '.[] | select(.body | startswith("<!-- codepulse -->")) | .id' \
42
+ | head -1)
43
+ if [ -n "$id" ]; then
44
+ gh api --method PATCH \
45
+ "repos/${{ github.repository }}/issues/comments/$id" \
46
+ -f body="$(cat comment.md)" >/dev/null
47
+ else
48
+ gh pr comment "$PR" --body-file comment.md
49
+ fi
50
+
51
+ - name: Enforce risk gate
52
+ run: codepulse . --changed "origin/${{ github.base_ref }}" --fail-on HIGH
@@ -0,0 +1,19 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ strategy:
11
+ matrix:
12
+ python-version: ["3.10", "3.12"]
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: ${{ matrix.python-version }}
18
+ - run: pip install -e ".[dev]"
19
+ - run: pytest -q
@@ -0,0 +1,13 @@
1
+ # CodePulse output
2
+ codepulse-report.html
3
+ *-report.html
4
+
5
+ # Python
6
+ __pycache__/
7
+ *.py[cod]
8
+ .venv/
9
+ venv/
10
+ *.egg-info/
11
+ dist/
12
+ build/
13
+ .pytest_cache/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mehouelley
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,227 @@
1
+ Metadata-Version: 2.5
2
+ Name: codepulse-cli
3
+ Version: 0.1.0
4
+ Summary: Reveal a codebase's health from its git history — hotspots, bus factor, hidden coupling, and a CI risk gate.
5
+ Project-URL: Homepage, https://github.com/Mehouelley/codepulse
6
+ Project-URL: Repository, https://github.com/Mehouelley/codepulse
7
+ Project-URL: Issues, https://github.com/Mehouelley/codepulse/issues
8
+ Author-email: Mehouelley <fabricemehouelley43@gmail.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: code-health,code-quality,devops,git,hotspots,static-analysis,technical-debt
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Topic :: Software Development :: Quality Assurance
19
+ Classifier: Topic :: Software Development :: Version Control :: Git
20
+ Requires-Python: >=3.10
21
+ Provides-Extra: dev
22
+ Requires-Dist: build>=1.0; extra == 'dev'
23
+ Requires-Dist: pytest>=7; extra == 'dev'
24
+ Requires-Dist: twine>=5.0; extra == 'dev'
25
+ Description-Content-Type: text/markdown
26
+
27
+ # 🩺 CodePulse
28
+
29
+ [![GitHub Marketplace](https://img.shields.io/badge/Marketplace-CodePulse-2088FF?logo=github&logoColor=white)](https://github.com/marketplace/actions/codepulse-risk-gate)
30
+ [![tests](https://github.com/Mehouelley/codepulse/actions/workflows/tests.yml/badge.svg)](https://github.com/Mehouelley/codepulse/actions/workflows/tests.yml)
31
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
32
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
33
+ [![Zero dependencies](https://img.shields.io/badge/dependencies-none-brightgreen.svg)](pyproject.toml)
34
+
35
+ **Reveal a codebase's health from its git history.**
36
+
37
+ Linters read your code. CodePulse reads your code's *history* — and that reveals
38
+ things no linter can see: where bugs are born, what knowledge lives in one
39
+ person's head, and which files are secretly glued together.
40
+
41
+ Because it works purely from git history, **CodePulse works on any language**,
42
+ with **zero dependencies** beyond git and Python.
43
+
44
+ ---
45
+
46
+ ## Demo
47
+
48
+ <!-- Render docs/demo.gif from demo.tape with `vhs demo.tape`, then:
49
+ ![demo](docs/demo.gif) -->
50
+
51
+ ```console
52
+ $ codepulse . --badge
53
+ Grade: B (83/100)
54
+ -2 bus factor (9 fichiers à auteur unique)
55
+ -15 pression hotspots en hausse
56
+ ![code health](https://img.shields.io/badge/code%20health-B%20(83)-green)
57
+
58
+ $ codepulse . --changed origin/main
59
+ 🔴 Release risk: HIGH (100/100)
60
+ 56 changed files · 2 high-risk
61
+ [100] crates/ui-egui/src/lib.rs (hotspot majeur)
62
+ [ 70] crates/layout/src/para.rs (zone active, auteur unique)
63
+ 👥 Relecteurs suggérés: Valentin Klein (29/37 fichiers), Dmitrii Khlapov (22/37)
64
+
65
+ $ codepulse . --who crates/ui-egui/src/canvas.rs
66
+ crates/ui-egui/src/canvas.rs — 64 commits, 22 auteur(s), dernier changement 2026-10-12
67
+ 45% 29 commits Valentin Klein
68
+ 11% 7 commits Dmitrii Khlapov
69
+ ```
70
+
71
+ > A recordable [`demo.tape`](demo.tape) (for [VHS](https://github.com/charmbracelet/vhs))
72
+ > generates an animated `docs/demo.gif` of the above.
73
+
74
+ ---
75
+
76
+ ## What it shows
77
+
78
+ | Signal | Question it answers |
79
+ |---|---|
80
+ | 🔥 **Hotspots** | *Where do I refactor first?* Files that are both complex and changed constantly — the birthplace of most bugs. |
81
+ | 👥 **Bus factor** | *What breaks if someone leaves?* Files actively maintained by a single person. |
82
+ | 🔗 **Hidden coupling** | *What really depends on what?* Files that almost always change together, even when the code doesn't show a link. |
83
+ | 🏆 **Contributors** | Who is active across the analyzed window. |
84
+
85
+ The result is a single self-contained **HTML dashboard** you can open anywhere
86
+ or email to your team.
87
+
88
+ ---
89
+
90
+ ## Quick start
91
+
92
+ ```bash
93
+ # From a git repository:
94
+ python -m codepulse /path/to/repo --open
95
+
96
+ # Common options:
97
+ python -m codepulse . --since "6 months ago" --top 30 -o health.html
98
+ ```
99
+
100
+ > Running from the source checkout? Prefix with `PYTHONPATH=src`, or install it:
101
+ > `pip install -e .` then just run `codepulse`.
102
+
103
+ ### Options
104
+
105
+ | Flag | Meaning |
106
+ |---|---|
107
+ | `repo` | Path to a git repository (default: current directory) |
108
+ | `-o, --output` | Output HTML path (default: `codepulse-report.html`) |
109
+ | `--since` | Only commits after a date, e.g. `"6 months ago"` |
110
+ | `--max-count N` | Limit to the N most recent commits |
111
+ | `--top N` | Rows per table (default: 20) |
112
+ | `--open` | Open the report in a browser when done |
113
+ | `--who PATH` | Show who knows a file best (from history) and exit |
114
+ | `--badge` | Print a shields.io health-badge snippet and exit |
115
+ | `--ignore GLOB` | Exclude paths matching a glob (repeatable) |
116
+
117
+ ---
118
+
119
+ ## Use in CI (the risk gate)
120
+
121
+ CodePulse can score *only the files a change touches* against the repo's risk
122
+ map, then set an exit code so your pipeline can warn or block.
123
+
124
+ ```bash
125
+ # Score what this branch changed vs main; fail the job on HIGH risk.
126
+ python -m codepulse . --changed origin/main --fail-on HIGH
127
+
128
+ # Machine-readable output for dashboards / PR comments:
129
+ python -m codepulse . --changed origin/main --format json
130
+ ```
131
+
132
+ Output (JSON):
133
+
134
+ ```json
135
+ {
136
+ "level": "HIGH",
137
+ "score": 100,
138
+ "high_risk_count": 1,
139
+ "files": [
140
+ { "path": "auth.py", "risk": 100, "commits": 6, "loc": 7,
141
+ "reasons": ["hotspot majeur", "auteur unique (Alice)"] }
142
+ ]
143
+ }
144
+ ```
145
+
146
+ ### GitHub Action (two lines)
147
+
148
+ Add CodePulse to any repository as a reusable Action — it scores each PR, posts
149
+ a **sticky comment** (updated in place, never spammed), and fails the check on
150
+ `HIGH` risk:
151
+
152
+ ```yaml
153
+ name: CodePulse
154
+ on: pull_request
155
+ permissions:
156
+ contents: read
157
+ pull-requests: write
158
+ jobs:
159
+ risk:
160
+ runs-on: ubuntu-latest
161
+ steps:
162
+ - uses: actions/checkout@v4
163
+ with: { fetch-depth: 0 } # full history is required
164
+ - uses: Mehouelley/codepulse@v0.1.0
165
+ with:
166
+ fail-on: HIGH # or MEDIUM / LOW / '' to never fail
167
+ ```
168
+
169
+ The PR comment looks like:
170
+
171
+ > 🩺 **CodePulse — Risque : 🔴 HIGH (100/100)**
172
+ > 38 fichiers modifiés · 1 à risque élevé
173
+ >
174
+ > 👥 **Relecteurs suggérés** : Valentin Klein (29/37 fichiers), Dmitrii Khlapov (22/37)
175
+
176
+ Prefer a plain workflow with no external action? One ships in
177
+ [`.github/workflows/codepulse.yml`](.github/workflows/codepulse.yml) — copy it in as-is.
178
+
179
+ **Why DevOps cares:** a release is roughly as risky as its riskiest file.
180
+ Touching a well-known hotspot — or a file only one person understands — is
181
+ exactly where change-failure-rate (a DORA metric) comes from. The gate makes
182
+ that risk visible *before* merge, not after an incident.
183
+
184
+ ---
185
+
186
+ ## How it works
187
+
188
+ 1. Parses `git log --numstat` into commits and file changes (no merges).
189
+ 2. Accumulates per-file history: commit count, authors, size on disk.
190
+ 3. Derives the signals:
191
+ - **Hotspot score** = `commits × complexity`, where complexity estimates
192
+ decision points (branch keywords + boolean operators) — far better than
193
+ raw line count at telling "big but simple" from "dense and risky".
194
+ - **Bus factor risk** = files with ≥3 commits but exactly one author.
195
+ - **Coupling degree** = `commits-together / min(individual commits)`,
196
+ ignoring bulk commits that touch many files at once.
197
+
198
+ Inspired by the "code as a crime scene" approach to software analysis, made
199
+ simple enough to run in one command.
200
+
201
+ ---
202
+
203
+ ## Roadmap
204
+
205
+ - [x] Risk gate: score a change set, JSON output, CI exit code
206
+ - [x] Ignore globs / path filters for generated & data files
207
+ - [x] Post the gate result as a sticky PR comment (GitHub Action)
208
+ - [x] Trend over time (adaptive day/week/month buckets + hotspot-pressure verdict)
209
+ - [x] Complexity-based hotspots (decision-point estimate instead of line count)
210
+ - [x] Suggested PR reviewers from code ownership (in gate text/json/comment)
211
+ - [x] `--who <file>` — who knows this code best
212
+ - [x] `--badge` — shareable A–F health badge for your README
213
+ - [x] Orphaned-code section — complex files nobody touches anymore
214
+
215
+ ## Development
216
+
217
+ ```bash
218
+ pip install -e ".[dev]"
219
+ pytest
220
+ ```
221
+
222
+ The suite covers the complexity estimator, git parsing, every analyzer, and an
223
+ end-to-end run against a throwaway git repo. CI runs it on Python 3.10 and 3.12.
224
+
225
+ ## License
226
+
227
+ MIT
@@ -0,0 +1,201 @@
1
+ # 🩺 CodePulse
2
+
3
+ [![GitHub Marketplace](https://img.shields.io/badge/Marketplace-CodePulse-2088FF?logo=github&logoColor=white)](https://github.com/marketplace/actions/codepulse-risk-gate)
4
+ [![tests](https://github.com/Mehouelley/codepulse/actions/workflows/tests.yml/badge.svg)](https://github.com/Mehouelley/codepulse/actions/workflows/tests.yml)
5
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
7
+ [![Zero dependencies](https://img.shields.io/badge/dependencies-none-brightgreen.svg)](pyproject.toml)
8
+
9
+ **Reveal a codebase's health from its git history.**
10
+
11
+ Linters read your code. CodePulse reads your code's *history* — and that reveals
12
+ things no linter can see: where bugs are born, what knowledge lives in one
13
+ person's head, and which files are secretly glued together.
14
+
15
+ Because it works purely from git history, **CodePulse works on any language**,
16
+ with **zero dependencies** beyond git and Python.
17
+
18
+ ---
19
+
20
+ ## Demo
21
+
22
+ <!-- Render docs/demo.gif from demo.tape with `vhs demo.tape`, then:
23
+ ![demo](docs/demo.gif) -->
24
+
25
+ ```console
26
+ $ codepulse . --badge
27
+ Grade: B (83/100)
28
+ -2 bus factor (9 fichiers à auteur unique)
29
+ -15 pression hotspots en hausse
30
+ ![code health](https://img.shields.io/badge/code%20health-B%20(83)-green)
31
+
32
+ $ codepulse . --changed origin/main
33
+ 🔴 Release risk: HIGH (100/100)
34
+ 56 changed files · 2 high-risk
35
+ [100] crates/ui-egui/src/lib.rs (hotspot majeur)
36
+ [ 70] crates/layout/src/para.rs (zone active, auteur unique)
37
+ 👥 Relecteurs suggérés: Valentin Klein (29/37 fichiers), Dmitrii Khlapov (22/37)
38
+
39
+ $ codepulse . --who crates/ui-egui/src/canvas.rs
40
+ crates/ui-egui/src/canvas.rs — 64 commits, 22 auteur(s), dernier changement 2026-10-12
41
+ 45% 29 commits Valentin Klein
42
+ 11% 7 commits Dmitrii Khlapov
43
+ ```
44
+
45
+ > A recordable [`demo.tape`](demo.tape) (for [VHS](https://github.com/charmbracelet/vhs))
46
+ > generates an animated `docs/demo.gif` of the above.
47
+
48
+ ---
49
+
50
+ ## What it shows
51
+
52
+ | Signal | Question it answers |
53
+ |---|---|
54
+ | 🔥 **Hotspots** | *Where do I refactor first?* Files that are both complex and changed constantly — the birthplace of most bugs. |
55
+ | 👥 **Bus factor** | *What breaks if someone leaves?* Files actively maintained by a single person. |
56
+ | 🔗 **Hidden coupling** | *What really depends on what?* Files that almost always change together, even when the code doesn't show a link. |
57
+ | 🏆 **Contributors** | Who is active across the analyzed window. |
58
+
59
+ The result is a single self-contained **HTML dashboard** you can open anywhere
60
+ or email to your team.
61
+
62
+ ---
63
+
64
+ ## Quick start
65
+
66
+ ```bash
67
+ # From a git repository:
68
+ python -m codepulse /path/to/repo --open
69
+
70
+ # Common options:
71
+ python -m codepulse . --since "6 months ago" --top 30 -o health.html
72
+ ```
73
+
74
+ > Running from the source checkout? Prefix with `PYTHONPATH=src`, or install it:
75
+ > `pip install -e .` then just run `codepulse`.
76
+
77
+ ### Options
78
+
79
+ | Flag | Meaning |
80
+ |---|---|
81
+ | `repo` | Path to a git repository (default: current directory) |
82
+ | `-o, --output` | Output HTML path (default: `codepulse-report.html`) |
83
+ | `--since` | Only commits after a date, e.g. `"6 months ago"` |
84
+ | `--max-count N` | Limit to the N most recent commits |
85
+ | `--top N` | Rows per table (default: 20) |
86
+ | `--open` | Open the report in a browser when done |
87
+ | `--who PATH` | Show who knows a file best (from history) and exit |
88
+ | `--badge` | Print a shields.io health-badge snippet and exit |
89
+ | `--ignore GLOB` | Exclude paths matching a glob (repeatable) |
90
+
91
+ ---
92
+
93
+ ## Use in CI (the risk gate)
94
+
95
+ CodePulse can score *only the files a change touches* against the repo's risk
96
+ map, then set an exit code so your pipeline can warn or block.
97
+
98
+ ```bash
99
+ # Score what this branch changed vs main; fail the job on HIGH risk.
100
+ python -m codepulse . --changed origin/main --fail-on HIGH
101
+
102
+ # Machine-readable output for dashboards / PR comments:
103
+ python -m codepulse . --changed origin/main --format json
104
+ ```
105
+
106
+ Output (JSON):
107
+
108
+ ```json
109
+ {
110
+ "level": "HIGH",
111
+ "score": 100,
112
+ "high_risk_count": 1,
113
+ "files": [
114
+ { "path": "auth.py", "risk": 100, "commits": 6, "loc": 7,
115
+ "reasons": ["hotspot majeur", "auteur unique (Alice)"] }
116
+ ]
117
+ }
118
+ ```
119
+
120
+ ### GitHub Action (two lines)
121
+
122
+ Add CodePulse to any repository as a reusable Action — it scores each PR, posts
123
+ a **sticky comment** (updated in place, never spammed), and fails the check on
124
+ `HIGH` risk:
125
+
126
+ ```yaml
127
+ name: CodePulse
128
+ on: pull_request
129
+ permissions:
130
+ contents: read
131
+ pull-requests: write
132
+ jobs:
133
+ risk:
134
+ runs-on: ubuntu-latest
135
+ steps:
136
+ - uses: actions/checkout@v4
137
+ with: { fetch-depth: 0 } # full history is required
138
+ - uses: Mehouelley/codepulse@v0.1.0
139
+ with:
140
+ fail-on: HIGH # or MEDIUM / LOW / '' to never fail
141
+ ```
142
+
143
+ The PR comment looks like:
144
+
145
+ > 🩺 **CodePulse — Risque : 🔴 HIGH (100/100)**
146
+ > 38 fichiers modifiés · 1 à risque élevé
147
+ >
148
+ > 👥 **Relecteurs suggérés** : Valentin Klein (29/37 fichiers), Dmitrii Khlapov (22/37)
149
+
150
+ Prefer a plain workflow with no external action? One ships in
151
+ [`.github/workflows/codepulse.yml`](.github/workflows/codepulse.yml) — copy it in as-is.
152
+
153
+ **Why DevOps cares:** a release is roughly as risky as its riskiest file.
154
+ Touching a well-known hotspot — or a file only one person understands — is
155
+ exactly where change-failure-rate (a DORA metric) comes from. The gate makes
156
+ that risk visible *before* merge, not after an incident.
157
+
158
+ ---
159
+
160
+ ## How it works
161
+
162
+ 1. Parses `git log --numstat` into commits and file changes (no merges).
163
+ 2. Accumulates per-file history: commit count, authors, size on disk.
164
+ 3. Derives the signals:
165
+ - **Hotspot score** = `commits × complexity`, where complexity estimates
166
+ decision points (branch keywords + boolean operators) — far better than
167
+ raw line count at telling "big but simple" from "dense and risky".
168
+ - **Bus factor risk** = files with ≥3 commits but exactly one author.
169
+ - **Coupling degree** = `commits-together / min(individual commits)`,
170
+ ignoring bulk commits that touch many files at once.
171
+
172
+ Inspired by the "code as a crime scene" approach to software analysis, made
173
+ simple enough to run in one command.
174
+
175
+ ---
176
+
177
+ ## Roadmap
178
+
179
+ - [x] Risk gate: score a change set, JSON output, CI exit code
180
+ - [x] Ignore globs / path filters for generated & data files
181
+ - [x] Post the gate result as a sticky PR comment (GitHub Action)
182
+ - [x] Trend over time (adaptive day/week/month buckets + hotspot-pressure verdict)
183
+ - [x] Complexity-based hotspots (decision-point estimate instead of line count)
184
+ - [x] Suggested PR reviewers from code ownership (in gate text/json/comment)
185
+ - [x] `--who <file>` — who knows this code best
186
+ - [x] `--badge` — shareable A–F health badge for your README
187
+ - [x] Orphaned-code section — complex files nobody touches anymore
188
+
189
+ ## Development
190
+
191
+ ```bash
192
+ pip install -e ".[dev]"
193
+ pytest
194
+ ```
195
+
196
+ The suite covers the complexity estimator, git parsing, every analyzer, and an
197
+ end-to-end run against a throwaway git repo. CI runs it on Python 3.10 and 3.12.
198
+
199
+ ## License
200
+
201
+ MIT
@@ -0,0 +1,69 @@
1
+ name: 'CodePulse Risk Gate'
2
+ description: 'Score pull-request changes against your git history, comment the risk, and gate on it.'
3
+ author: 'Mehouelley'
4
+
5
+ branding:
6
+ icon: 'activity'
7
+ color: 'red'
8
+
9
+ inputs:
10
+ path:
11
+ description: 'Path to the repository to analyze'
12
+ required: false
13
+ default: '.'
14
+ fail-on:
15
+ description: 'Fail the job when risk reaches this level (LOW|MEDIUM|HIGH). Leave empty to never fail.'
16
+ required: false
17
+ default: 'HIGH'
18
+ base-ref:
19
+ description: 'Base ref to diff against. Defaults to the PR base branch.'
20
+ required: false
21
+ default: ''
22
+ comment:
23
+ description: 'Post/update a sticky risk comment on the PR (true|false).'
24
+ required: false
25
+ default: 'true'
26
+
27
+ runs:
28
+ using: 'composite'
29
+ steps:
30
+ - uses: actions/setup-python@v5
31
+ with:
32
+ python-version: '3.12'
33
+
34
+ - name: Install CodePulse
35
+ shell: bash
36
+ run: pip install "${{ github.action_path }}"
37
+
38
+ - name: Resolve base ref
39
+ id: base
40
+ shell: bash
41
+ run: |
42
+ base="${{ inputs.base-ref }}"
43
+ if [ -z "$base" ]; then base="origin/${{ github.base_ref }}"; fi
44
+ echo "ref=$base" >> "$GITHUB_OUTPUT"
45
+
46
+ - name: Comment risk on PR
47
+ if: ${{ inputs.comment == 'true' && github.event.pull_request.number }}
48
+ shell: bash
49
+ env:
50
+ GH_TOKEN: ${{ github.token }}
51
+ PR: ${{ github.event.pull_request.number }}
52
+ REPO: ${{ github.repository }}
53
+ run: |
54
+ codepulse "${{ inputs.path }}" --changed "${{ steps.base.outputs.ref }}" \
55
+ --format markdown > "$RUNNER_TEMP/codepulse.md"
56
+ cat "$RUNNER_TEMP/codepulse.md"
57
+ id=$(gh api "repos/$REPO/issues/$PR/comments" \
58
+ --jq '.[] | select(.body | startswith("<!-- codepulse -->")) | .id' | head -1)
59
+ if [ -n "$id" ]; then
60
+ gh api --method PATCH "repos/$REPO/issues/comments/$id" \
61
+ -f body="$(cat "$RUNNER_TEMP/codepulse.md")" >/dev/null
62
+ else
63
+ gh pr comment "$PR" --body-file "$RUNNER_TEMP/codepulse.md"
64
+ fi
65
+
66
+ - name: Enforce risk gate
67
+ if: ${{ inputs.fail-on != '' }}
68
+ shell: bash
69
+ run: codepulse "${{ inputs.path }}" --changed "${{ steps.base.outputs.ref }}" --fail-on "${{ inputs.fail-on }}"
@@ -0,0 +1,28 @@
1
+ # CodePulse demo recording.
2
+ #
3
+ # Renders docs/demo.gif. Install VHS (https://github.com/charmbracelet/vhs),
4
+ # then from a checkout of a repo WITH REAL HISTORY run:
5
+ #
6
+ # vhs demo.tape
7
+ #
8
+ # (Run it inside a mature repo so hotspots/reviewers have data to show.)
9
+
10
+ Output docs/demo.gif
11
+
12
+ Set FontSize 16
13
+ Set Width 1120
14
+ Set Height 660
15
+ Set Padding 20
16
+ Set Theme "Dracula"
17
+
18
+ Type "# 1. An A–F health badge for your README" Enter
19
+ Type "codepulse . --badge" Sleep 500ms Enter
20
+ Sleep 3s
21
+
22
+ Type "# 2. Score what a pull request changes" Enter
23
+ Type "codepulse . --changed HEAD~20" Sleep 500ms Enter
24
+ Sleep 4s
25
+
26
+ Type "# 3. Who knows this file best?" Enter
27
+ Type "codepulse . --who src/codepulse/cli.py" Sleep 500ms Enter
28
+ Sleep 4s
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "codepulse-cli"
7
+ version = "0.1.0"
8
+ description = "Reveal a codebase's health from its git history — hotspots, bus factor, hidden coupling, and a CI risk gate."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Mehouelley", email = "fabricemehouelley43@gmail.com" }]
13
+ keywords = ["git", "code-health", "hotspots", "technical-debt", "static-analysis", "devops", "code-quality"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Environment :: Console",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python :: 3",
21
+ "Topic :: Software Development :: Quality Assurance",
22
+ "Topic :: Software Development :: Version Control :: Git",
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/Mehouelley/codepulse"
27
+ Repository = "https://github.com/Mehouelley/codepulse"
28
+ Issues = "https://github.com/Mehouelley/codepulse/issues"
29
+
30
+ [project.optional-dependencies]
31
+ dev = ["pytest>=7", "build>=1.0", "twine>=5.0"]
32
+
33
+ [project.scripts]
34
+ codepulse = "codepulse.cli:main"
35
+
36
+ [tool.hatch.build.targets.wheel]
37
+ packages = ["src/codepulse"]
38
+
39
+ [tool.pytest.ini_options]
40
+ pythonpath = ["src"]
41
+ testpaths = ["tests"]
@@ -0,0 +1,3 @@
1
+ """CodePulse — reveal a codebase's health from its git history."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())