better-code-review-graph 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.
- better_code_review_graph-0.1.0/.agents/skills/build-graph/SKILL.md +38 -0
- better_code_review_graph-0.1.0/.agents/skills/review-delta/SKILL.md +46 -0
- better_code_review_graph-0.1.0/.agents/skills/review-pr/SKILL.md +66 -0
- better_code_review_graph-0.1.0/.claude-plugin/marketplace.json +21 -0
- better_code_review_graph-0.1.0/.claude-plugin/plugin.json +20 -0
- better_code_review_graph-0.1.0/.dockerignore +32 -0
- better_code_review_graph-0.1.0/.github/best_practices.md +25 -0
- better_code_review_graph-0.1.0/.github/workflows/cd.yml +232 -0
- better_code_review_graph-0.1.0/.github/workflows/ci.yml +247 -0
- better_code_review_graph-0.1.0/.gitignore +57 -0
- better_code_review_graph-0.1.0/.infisical.json +1 -0
- better_code_review_graph-0.1.0/.pre-commit-config.yaml +87 -0
- better_code_review_graph-0.1.0/AGENTS.md +96 -0
- better_code_review_graph-0.1.0/CHANGELOG.md +149 -0
- better_code_review_graph-0.1.0/CLAUDE.md +96 -0
- better_code_review_graph-0.1.0/Dockerfile +16 -0
- better_code_review_graph-0.1.0/LICENSE +21 -0
- better_code_review_graph-0.1.0/PKG-INFO +276 -0
- better_code_review_graph-0.1.0/README.md +251 -0
- better_code_review_graph-0.1.0/docs/COMMANDS.md +178 -0
- better_code_review_graph-0.1.0/docs/FEATURES.md +78 -0
- better_code_review_graph-0.1.0/docs/INDEX.md +11 -0
- better_code_review_graph-0.1.0/docs/LEGAL.md +13 -0
- better_code_review_graph-0.1.0/docs/LLM-OPTIMIZED-REFERENCE.md +72 -0
- better_code_review_graph-0.1.0/docs/ROADMAP.md +65 -0
- better_code_review_graph-0.1.0/docs/TROUBLESHOOTING.md +38 -0
- better_code_review_graph-0.1.0/docs/USAGE.md +93 -0
- better_code_review_graph-0.1.0/docs/architecture.md +112 -0
- better_code_review_graph-0.1.0/docs/assets/marketing-diagram.png +0 -0
- better_code_review_graph-0.1.0/docs/schema.md +177 -0
- better_code_review_graph-0.1.0/docs/superpowers/specs/2026-03-16-vscode-extension-design.md +308 -0
- better_code_review_graph-0.1.0/hooks/hooks.json +25 -0
- better_code_review_graph-0.1.0/hooks/session-start.sh +22 -0
- better_code_review_graph-0.1.0/pyproject.toml +76 -0
- better_code_review_graph-0.1.0/scripts/enforce-commit.sh +8 -0
- better_code_review_graph-0.1.0/semantic-release.toml +11 -0
- better_code_review_graph-0.1.0/server.json +25 -0
- better_code_review_graph-0.1.0/skills/build-graph/SKILL.md +38 -0
- better_code_review_graph-0.1.0/skills/review-delta/SKILL.md +46 -0
- better_code_review_graph-0.1.0/skills/review-pr/SKILL.md +66 -0
- better_code_review_graph-0.1.0/src/better_code_review_graph/__init__.py +1 -0
- better_code_review_graph-0.1.0/src/better_code_review_graph/__main__.py +5 -0
- better_code_review_graph-0.1.0/src/better_code_review_graph/cli.py +264 -0
- better_code_review_graph-0.1.0/src/better_code_review_graph/embeddings.py +580 -0
- better_code_review_graph-0.1.0/src/better_code_review_graph/graph.py +664 -0
- better_code_review_graph-0.1.0/src/better_code_review_graph/incremental.py +507 -0
- better_code_review_graph-0.1.0/src/better_code_review_graph/parser.py +1098 -0
- better_code_review_graph-0.1.0/src/better_code_review_graph/py.typed +0 -0
- better_code_review_graph-0.1.0/src/better_code_review_graph/server.py +256 -0
- better_code_review_graph-0.1.0/src/better_code_review_graph/tools.py +1077 -0
- better_code_review_graph-0.1.0/tests/__init__.py +0 -0
- better_code_review_graph-0.1.0/tests/conftest.py +77 -0
- better_code_review_graph-0.1.0/tests/fixtures/Sample.cs +48 -0
- better_code_review_graph-0.1.0/tests/fixtures/SampleJava.java +59 -0
- better_code_review_graph-0.1.0/tests/fixtures/caller_example.py +8 -0
- better_code_review_graph-0.1.0/tests/fixtures/multi_call_example.py +13 -0
- better_code_review_graph-0.1.0/tests/fixtures/sample.c +25 -0
- better_code_review_graph-0.1.0/tests/fixtures/sample.cpp +30 -0
- better_code_review_graph-0.1.0/tests/fixtures/sample.kt +27 -0
- better_code_review_graph-0.1.0/tests/fixtures/sample.php +43 -0
- better_code_review_graph-0.1.0/tests/fixtures/sample.rb +38 -0
- better_code_review_graph-0.1.0/tests/fixtures/sample.sol +218 -0
- better_code_review_graph-0.1.0/tests/fixtures/sample.swift +31 -0
- better_code_review_graph-0.1.0/tests/fixtures/sample_go.go +48 -0
- better_code_review_graph-0.1.0/tests/fixtures/sample_python.py +53 -0
- better_code_review_graph-0.1.0/tests/fixtures/sample_rust.rs +46 -0
- better_code_review_graph-0.1.0/tests/fixtures/sample_typescript.ts +41 -0
- better_code_review_graph-0.1.0/tests/fixtures/test_sample.py +19 -0
- better_code_review_graph-0.1.0/tests/test_cli.py +310 -0
- better_code_review_graph-0.1.0/tests/test_embeddings.py +548 -0
- better_code_review_graph-0.1.0/tests/test_embeddings_extra.py +60 -0
- better_code_review_graph-0.1.0/tests/test_graph.py +282 -0
- better_code_review_graph-0.1.0/tests/test_graph_extra.py +495 -0
- better_code_review_graph-0.1.0/tests/test_incremental.py +236 -0
- better_code_review_graph-0.1.0/tests/test_incremental_extra.py +555 -0
- better_code_review_graph-0.1.0/tests/test_multilang.py +471 -0
- better_code_review_graph-0.1.0/tests/test_parser.py +229 -0
- better_code_review_graph-0.1.0/tests/test_parser_extra.py +354 -0
- better_code_review_graph-0.1.0/tests/test_server.py +180 -0
- better_code_review_graph-0.1.0/tests/test_tools.py +211 -0
- better_code_review_graph-0.1.0/tests/test_tools_full.py +1303 -0
- better_code_review_graph-0.1.0/uv.lock +2121 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-graph
|
|
3
|
+
description: Build or update the code review knowledge graph. Run this first to initialize, or let hooks keep it updated automatically.
|
|
4
|
+
argument-hint: "[full]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Build Graph
|
|
8
|
+
|
|
9
|
+
Build or incrementally update the persistent code knowledge graph for this repository.
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. **Check graph status** by calling the `list_graph_stats_tool` MCP tool.
|
|
14
|
+
- If the graph has never been built (last_updated is null), proceed with a full build.
|
|
15
|
+
- If the graph exists, proceed with an incremental update.
|
|
16
|
+
|
|
17
|
+
2. **Build the graph** by calling the `build_or_update_graph_tool` MCP tool:
|
|
18
|
+
- For first-time setup: `build_or_update_graph_tool(full_rebuild=True)`
|
|
19
|
+
- For updates: `build_or_update_graph_tool()` (incremental by default)
|
|
20
|
+
|
|
21
|
+
3. **Verify** by calling `list_graph_stats_tool` again and report the results:
|
|
22
|
+
- Number of files parsed
|
|
23
|
+
- Number of nodes and edges created
|
|
24
|
+
- Languages detected
|
|
25
|
+
- Any errors encountered
|
|
26
|
+
|
|
27
|
+
## When to Use
|
|
28
|
+
|
|
29
|
+
- First time setting up the graph for a repository
|
|
30
|
+
- After major refactoring or branch switches
|
|
31
|
+
- If the graph seems stale or out of sync
|
|
32
|
+
- The graph auto-updates via hooks on edit/commit, so manual builds are rarely needed
|
|
33
|
+
|
|
34
|
+
## Notes
|
|
35
|
+
|
|
36
|
+
- The graph is stored as a SQLite database (`.code-review-graph/graph.db`) in the repo root
|
|
37
|
+
- Binary files, generated files, and patterns in `.code-review-graphignore` are skipped
|
|
38
|
+
- Supported languages: Python, TypeScript/JavaScript, Go, Rust, Java, C#, Ruby, Kotlin, Swift, PHP, C/C++
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: review-delta
|
|
3
|
+
description: Review only changes since last commit using impact analysis. Token-efficient delta review with automatic blast-radius detection.
|
|
4
|
+
argument-hint: "[file or function name]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Review Delta
|
|
8
|
+
|
|
9
|
+
Perform a focused, token-efficient code review of only the changed code and its blast radius.
|
|
10
|
+
|
|
11
|
+
**Token optimization:** Before starting, call `get_docs_section_tool(section_name="review-delta")` for the optimized workflow. Use ONLY changed nodes + 2-hop neighbors in context.
|
|
12
|
+
|
|
13
|
+
## Steps
|
|
14
|
+
|
|
15
|
+
1. **Ensure the graph is current** by calling `build_or_update_graph_tool()` (incremental update).
|
|
16
|
+
|
|
17
|
+
2. **Get review context** by calling `get_review_context_tool()`. This returns:
|
|
18
|
+
- Changed files (auto-detected from git diff)
|
|
19
|
+
- Impacted nodes and files (blast radius)
|
|
20
|
+
- Source code snippets for changed areas
|
|
21
|
+
- Review guidance (test coverage gaps, wide impact warnings, inheritance concerns)
|
|
22
|
+
|
|
23
|
+
3. **Analyze the blast radius** by reviewing the `impacted_nodes` and `impacted_files` in the context. Focus on:
|
|
24
|
+
- Functions whose callers changed (may need signature/behavior verification)
|
|
25
|
+
- Classes with inheritance changes (Liskov substitution concerns)
|
|
26
|
+
- Files with many dependents (high-risk changes)
|
|
27
|
+
|
|
28
|
+
4. **Perform the review** using the context. For each changed file:
|
|
29
|
+
- Review the source snippet for correctness, style, and potential bugs
|
|
30
|
+
- Check if impacted callers/dependents need updates
|
|
31
|
+
- Verify test coverage using `query_graph_tool(pattern="tests_for", target=<function_name>)`
|
|
32
|
+
- Flag any untested changed functions
|
|
33
|
+
|
|
34
|
+
5. **Report findings** in a structured format:
|
|
35
|
+
- **Summary**: One-line overview of the changes
|
|
36
|
+
- **Risk level**: Low / Medium / High (based on blast radius)
|
|
37
|
+
- **Issues found**: Bugs, style issues, missing tests
|
|
38
|
+
- **Blast radius**: List of impacted files/functions
|
|
39
|
+
- **Recommendations**: Actionable suggestions
|
|
40
|
+
|
|
41
|
+
## Advantages Over Full-Repo Review
|
|
42
|
+
|
|
43
|
+
- Only sends changed + impacted code to the model (5-10x fewer tokens)
|
|
44
|
+
- Automatically identifies blast radius without manual file searching
|
|
45
|
+
- Provides structural context (who calls what, inheritance chains)
|
|
46
|
+
- Flags untested functions automatically
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: review-pr
|
|
3
|
+
description: Review a PR or branch diff using the knowledge graph for full structural context. Outputs a structured review with blast-radius analysis.
|
|
4
|
+
argument-hint: "[PR number or branch name]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Review PR
|
|
8
|
+
|
|
9
|
+
Perform a comprehensive code review of a pull request or branch diff using the knowledge graph.
|
|
10
|
+
|
|
11
|
+
**Token optimization:** Before starting, call `get_docs_section_tool(section_name="review-pr")` for the optimized workflow. Never include full files unless explicitly asked.
|
|
12
|
+
|
|
13
|
+
## Steps
|
|
14
|
+
|
|
15
|
+
1. **Identify the changes** for the PR:
|
|
16
|
+
- If a PR number or branch is provided, use `git diff main...<branch>` to get changed files
|
|
17
|
+
- Otherwise auto-detect from the current branch vs main/master
|
|
18
|
+
|
|
19
|
+
2. **Update the graph** by calling `build_or_update_graph_tool(base="main")` to ensure the graph reflects the current state.
|
|
20
|
+
|
|
21
|
+
3. **Get the full review context** by calling `get_review_context_tool(base="main")`:
|
|
22
|
+
- This uses `main` (or the specified base branch) as the diff base
|
|
23
|
+
- Returns all changed files across all commits in the PR
|
|
24
|
+
|
|
25
|
+
4. **Analyze impact** by calling `get_impact_radius_tool(base="main")`:
|
|
26
|
+
- Review the blast radius across the entire PR
|
|
27
|
+
- Identify high-risk areas (widely depended-upon code)
|
|
28
|
+
|
|
29
|
+
5. **Deep-dive each changed file**:
|
|
30
|
+
- Read the full source of files with significant changes
|
|
31
|
+
- Use `query_graph_tool(pattern="callers_of", target=<func>)` for high-risk functions
|
|
32
|
+
- Use `query_graph_tool(pattern="tests_for", target=<func>)` to verify test coverage
|
|
33
|
+
- Check for breaking changes in public APIs
|
|
34
|
+
|
|
35
|
+
6. **Generate structured review output**:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
## PR Review: <title>
|
|
39
|
+
|
|
40
|
+
### Summary
|
|
41
|
+
<1-3 sentence overview>
|
|
42
|
+
|
|
43
|
+
### Risk Assessment
|
|
44
|
+
- **Overall risk**: Low / Medium / High
|
|
45
|
+
- **Blast radius**: X files, Y functions impacted
|
|
46
|
+
- **Test coverage**: N changed functions covered / M total
|
|
47
|
+
|
|
48
|
+
### File-by-File Review
|
|
49
|
+
#### <file_path>
|
|
50
|
+
- Changes: <description>
|
|
51
|
+
- Impact: <who depends on this>
|
|
52
|
+
- Issues: <bugs, style, concerns>
|
|
53
|
+
|
|
54
|
+
### Missing Tests
|
|
55
|
+
- <function_name> in <file> - no test coverage found
|
|
56
|
+
|
|
57
|
+
### Recommendations
|
|
58
|
+
1. <actionable suggestion>
|
|
59
|
+
2. <actionable suggestion>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Tips
|
|
63
|
+
|
|
64
|
+
- For large PRs, focus on the highest-impact files first (most dependents)
|
|
65
|
+
- Use `semantic_search_nodes_tool` to find related code the PR might have missed
|
|
66
|
+
- Check if renamed/moved functions have updated all callers
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "better-code-review-graph",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "n24q02m",
|
|
5
|
+
"url": "https://github.com/n24q02m"
|
|
6
|
+
},
|
|
7
|
+
"metadata": {
|
|
8
|
+
"description": "Persistent incremental knowledge graph for token-efficient, context-aware code reviews with Claude Code",
|
|
9
|
+
"version": "0.1.0"
|
|
10
|
+
},
|
|
11
|
+
"plugins": [
|
|
12
|
+
{
|
|
13
|
+
"name": "better-code-review-graph",
|
|
14
|
+
"source": "./",
|
|
15
|
+
"description": "Persistent incremental knowledge graph for token-efficient, context-aware code reviews with Claude Code",
|
|
16
|
+
"version": "0.1.0",
|
|
17
|
+
"category": "development",
|
|
18
|
+
"keywords": ["code-review", "knowledge-graph", "incremental", "tree-sitter", "mcp", "claude-code"]
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "better-code-review-graph",
|
|
3
|
+
"description": "Persistent incremental knowledge graph for token-efficient, context-aware code reviews with Claude Code",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "n24q02m",
|
|
7
|
+
"url": "https://github.com/n24q02m"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/n24q02m/better-code-review-graph",
|
|
10
|
+
"repository": "https://github.com/n24q02m/better-code-review-graph",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": ["code-review", "knowledge-graph", "incremental", "tree-sitter", "mcp", "claude-code"],
|
|
13
|
+
"mcpServers": {
|
|
14
|
+
"better-code-review-graph": {
|
|
15
|
+
"command": "uvx",
|
|
16
|
+
"args": ["--python", "3.13", "better-code-review-graph", "serve"]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"skills": "./skills/"
|
|
20
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Git
|
|
2
|
+
.git
|
|
3
|
+
.github
|
|
4
|
+
|
|
5
|
+
# IDE
|
|
6
|
+
.vscode
|
|
7
|
+
|
|
8
|
+
# Cache
|
|
9
|
+
.ruff_cache
|
|
10
|
+
.pytest_cache
|
|
11
|
+
__pycache__
|
|
12
|
+
|
|
13
|
+
# Development
|
|
14
|
+
tests/
|
|
15
|
+
temp/
|
|
16
|
+
docs/
|
|
17
|
+
*.md
|
|
18
|
+
!README.md
|
|
19
|
+
|
|
20
|
+
# Docker
|
|
21
|
+
Dockerfile
|
|
22
|
+
docker-compose.yml
|
|
23
|
+
|
|
24
|
+
# Config
|
|
25
|
+
.pre-commit-config.yaml
|
|
26
|
+
.editorconfig
|
|
27
|
+
.python-version
|
|
28
|
+
CODE_OF_CONDUCT.md
|
|
29
|
+
CONTRIBUTING.md
|
|
30
|
+
SECURITY.md
|
|
31
|
+
LICENSE
|
|
32
|
+
CHANGELOG.md
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Style Guide - better-code-review-graph
|
|
2
|
+
|
|
3
|
+
## Architecture
|
|
4
|
+
Knowledge graph MCP server for token-efficient code reviews. Python, single-package repo.
|
|
5
|
+
|
|
6
|
+
## Python
|
|
7
|
+
- Formatter/Linter: Ruff (default config)
|
|
8
|
+
- Type checker: ty
|
|
9
|
+
- Test: pytest + pytest-asyncio
|
|
10
|
+
- Package manager: uv
|
|
11
|
+
- SDK: fastmcp
|
|
12
|
+
- Core deps: tree-sitter, networkx, SQLite, qwen3-embed (ONNX), litellm
|
|
13
|
+
|
|
14
|
+
## Code Patterns
|
|
15
|
+
- Tree-sitter parsing for 12 languages
|
|
16
|
+
- SQLite graph storage with NetworkX BFS for impact analysis
|
|
17
|
+
- Dual-mode embedding: local ONNX (qwen3-embed) + LiteLLM cloud
|
|
18
|
+
- Incremental updates via git diff and file watching
|
|
19
|
+
- Call target resolution: bare names resolved to qualified names
|
|
20
|
+
|
|
21
|
+
## Commits
|
|
22
|
+
Conventional Commits (feat:, fix:, chore:, docs:, refactor:, test:).
|
|
23
|
+
|
|
24
|
+
## Security
|
|
25
|
+
Validate file paths. Bound graph traversal depth. Prevent unbounded output via pagination.
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
name: CD
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
release_type:
|
|
7
|
+
description: "Release type"
|
|
8
|
+
required: true
|
|
9
|
+
type: choice
|
|
10
|
+
options:
|
|
11
|
+
- beta
|
|
12
|
+
- stable
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: write
|
|
16
|
+
packages: write
|
|
17
|
+
id-token: write
|
|
18
|
+
|
|
19
|
+
env:
|
|
20
|
+
DOCKERHUB_IMAGE: ${{ secrets.DOCKERHUB_USERNAME }}/better-code-review-graph
|
|
21
|
+
GHCR_IMAGE: ghcr.io/${{ github.repository }}
|
|
22
|
+
|
|
23
|
+
concurrency:
|
|
24
|
+
group: release
|
|
25
|
+
cancel-in-progress: false
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
# =================== Release ===================
|
|
29
|
+
release:
|
|
30
|
+
name: Semantic Release
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
outputs:
|
|
33
|
+
released: ${{ steps.release.outputs.released }}
|
|
34
|
+
tag: ${{ steps.release.outputs.tag }}
|
|
35
|
+
version: ${{ steps.release.outputs.version }}
|
|
36
|
+
is_prerelease: ${{ steps.release.outputs.is_prerelease }}
|
|
37
|
+
steps:
|
|
38
|
+
- name: Harden Runner
|
|
39
|
+
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2
|
|
40
|
+
with:
|
|
41
|
+
egress-policy: audit
|
|
42
|
+
|
|
43
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
44
|
+
with:
|
|
45
|
+
token: ${{ secrets.GH_PAT }}
|
|
46
|
+
fetch-depth: 0
|
|
47
|
+
|
|
48
|
+
- uses: python-semantic-release/python-semantic-release@350c48fcb3ffcdfd2e0a235206bc2ecea6b69df0 # v10
|
|
49
|
+
id: release
|
|
50
|
+
with:
|
|
51
|
+
github_token: ${{ secrets.GH_PAT }}
|
|
52
|
+
prerelease: ${{ inputs.release_type == 'beta' }}
|
|
53
|
+
prerelease_token: beta
|
|
54
|
+
|
|
55
|
+
- uses: python-semantic-release/publish-action@310a9983a0ae878b29f3aac778d7c77c1db27378 # v10
|
|
56
|
+
if: steps.release.outputs.released == 'true'
|
|
57
|
+
with:
|
|
58
|
+
github_token: ${{ secrets.GH_PAT }}
|
|
59
|
+
tag: ${{ steps.release.outputs.tag }}
|
|
60
|
+
|
|
61
|
+
# =================== Publish to PyPI ===================
|
|
62
|
+
publish-pypi:
|
|
63
|
+
name: Publish to PyPI
|
|
64
|
+
needs: release
|
|
65
|
+
if: needs.release.outputs.released == 'true'
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
steps:
|
|
68
|
+
- name: Harden Runner
|
|
69
|
+
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2
|
|
70
|
+
with:
|
|
71
|
+
egress-policy: audit
|
|
72
|
+
|
|
73
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
74
|
+
with:
|
|
75
|
+
ref: ${{ needs.release.outputs.tag }}
|
|
76
|
+
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
|
|
77
|
+
- run: uv build
|
|
78
|
+
- name: Publish to PyPI
|
|
79
|
+
run: uv publish
|
|
80
|
+
env:
|
|
81
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
|
|
82
|
+
|
|
83
|
+
# =================== Build Docker ===================
|
|
84
|
+
build-docker:
|
|
85
|
+
name: Build Docker (${{ matrix.platform }})
|
|
86
|
+
needs: release
|
|
87
|
+
if: needs.release.outputs.released == 'true'
|
|
88
|
+
strategy:
|
|
89
|
+
fail-fast: false
|
|
90
|
+
matrix:
|
|
91
|
+
include:
|
|
92
|
+
- platform: linux/amd64
|
|
93
|
+
runner: ubuntu-latest
|
|
94
|
+
artifact: linux-amd64
|
|
95
|
+
- platform: linux/arm64
|
|
96
|
+
runner: ubuntu-24.04-arm
|
|
97
|
+
artifact: linux-arm64
|
|
98
|
+
runs-on: ${{ matrix.runner }}
|
|
99
|
+
steps:
|
|
100
|
+
- name: Harden Runner
|
|
101
|
+
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2
|
|
102
|
+
with:
|
|
103
|
+
egress-policy: audit
|
|
104
|
+
|
|
105
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
106
|
+
with:
|
|
107
|
+
ref: ${{ needs.release.outputs.tag }}
|
|
108
|
+
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
|
|
109
|
+
- uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4
|
|
110
|
+
with:
|
|
111
|
+
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
112
|
+
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
113
|
+
- uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4
|
|
114
|
+
with:
|
|
115
|
+
registry: ghcr.io
|
|
116
|
+
username: ${{ github.actor }}
|
|
117
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
118
|
+
- uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7
|
|
119
|
+
id: build
|
|
120
|
+
with:
|
|
121
|
+
context: .
|
|
122
|
+
platforms: ${{ matrix.platform }}
|
|
123
|
+
outputs: type=image,"name=${{ env.DOCKERHUB_IMAGE }},${{ env.GHCR_IMAGE }}",push-by-digest=true,name-canonical=true,push=true
|
|
124
|
+
cache-from: type=gha,scope=${{ github.ref_name }}-${{ matrix.artifact }}
|
|
125
|
+
cache-to: type=gha,mode=max,scope=${{ github.ref_name }}-${{ matrix.artifact }}
|
|
126
|
+
- run: |
|
|
127
|
+
mkdir -p ${{ runner.temp }}/digests
|
|
128
|
+
echo "${{ steps.build.outputs.digest }}" > "${{ runner.temp }}/digests/${{ matrix.artifact }}"
|
|
129
|
+
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
|
|
130
|
+
with:
|
|
131
|
+
name: digest-${{ matrix.artifact }}
|
|
132
|
+
path: ${{ runner.temp }}/digests/*
|
|
133
|
+
retention-days: 1
|
|
134
|
+
|
|
135
|
+
# =================== Merge Docker Manifests ===================
|
|
136
|
+
merge-docker:
|
|
137
|
+
name: Merge Docker Manifests
|
|
138
|
+
needs: [release, build-docker]
|
|
139
|
+
runs-on: ubuntu-latest
|
|
140
|
+
steps:
|
|
141
|
+
- name: Harden Runner
|
|
142
|
+
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2
|
|
143
|
+
with:
|
|
144
|
+
egress-policy: audit
|
|
145
|
+
|
|
146
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
147
|
+
with:
|
|
148
|
+
pattern: digest-*
|
|
149
|
+
path: ${{ runner.temp }}/digests
|
|
150
|
+
merge-multiple: true
|
|
151
|
+
- uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4
|
|
152
|
+
with:
|
|
153
|
+
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
154
|
+
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
155
|
+
- uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4
|
|
156
|
+
with:
|
|
157
|
+
registry: ghcr.io
|
|
158
|
+
username: ${{ github.actor }}
|
|
159
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
160
|
+
- name: Create and push manifests
|
|
161
|
+
env:
|
|
162
|
+
VERSION: ${{ needs.release.outputs.version }}
|
|
163
|
+
IS_PRERELEASE: ${{ needs.release.outputs.is_prerelease }}
|
|
164
|
+
run: |
|
|
165
|
+
# Build tag lists based on release type
|
|
166
|
+
if [ "$IS_PRERELEASE" = "true" ]; then
|
|
167
|
+
TAGS="beta ${VERSION}"
|
|
168
|
+
else
|
|
169
|
+
MAJOR=$(echo "$VERSION" | cut -d. -f1)
|
|
170
|
+
MINOR=$(echo "$VERSION" | cut -d. -f1-2)
|
|
171
|
+
TAGS="latest ${VERSION} ${MINOR} ${MAJOR}"
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
DIGESTS=$(cat ${{ runner.temp }}/digests/*)
|
|
175
|
+
|
|
176
|
+
for IMAGE in "$DOCKERHUB_IMAGE" "$GHCR_IMAGE"; do
|
|
177
|
+
TAG_ARGS=""
|
|
178
|
+
for TAG in $TAGS; do
|
|
179
|
+
TAG_ARGS="$TAG_ARGS -t ${IMAGE}:${TAG}"
|
|
180
|
+
done
|
|
181
|
+
docker buildx imagetools create $TAG_ARGS \
|
|
182
|
+
$(echo "$DIGESTS" | xargs -I{} echo "${IMAGE}@{}")
|
|
183
|
+
done
|
|
184
|
+
|
|
185
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
186
|
+
with:
|
|
187
|
+
sparse-checkout: README.md
|
|
188
|
+
- uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5
|
|
189
|
+
with:
|
|
190
|
+
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
191
|
+
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
192
|
+
repository: ${{ secrets.DOCKERHUB_USERNAME }}/better-code-review-graph
|
|
193
|
+
short-description: ${{ github.event.repository.description }}
|
|
194
|
+
readme-filepath: ./README.md
|
|
195
|
+
|
|
196
|
+
# =================== Publish to MCP Registry ===================
|
|
197
|
+
publish-mcp-registry:
|
|
198
|
+
name: Publish to MCP Registry
|
|
199
|
+
needs: [release, publish-pypi, merge-docker]
|
|
200
|
+
if: needs.release.outputs.released == 'true' && needs.release.outputs.is_prerelease != 'true'
|
|
201
|
+
runs-on: ubuntu-latest
|
|
202
|
+
steps:
|
|
203
|
+
- name: Harden Runner
|
|
204
|
+
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2
|
|
205
|
+
with:
|
|
206
|
+
egress-policy: audit
|
|
207
|
+
|
|
208
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
209
|
+
with:
|
|
210
|
+
ref: ${{ needs.release.outputs.tag }}
|
|
211
|
+
|
|
212
|
+
- name: Update server.json version
|
|
213
|
+
run: |
|
|
214
|
+
VERSION="${{ needs.release.outputs.version }}"
|
|
215
|
+
jq --arg v "$VERSION" '
|
|
216
|
+
.version = $v |
|
|
217
|
+
.packages = [.packages[] |
|
|
218
|
+
if .registryType == "oci" then del(.version)
|
|
219
|
+
else .version = $v
|
|
220
|
+
end
|
|
221
|
+
]
|
|
222
|
+
' server.json > server.json.tmp && mv server.json.tmp server.json
|
|
223
|
+
|
|
224
|
+
- name: Install MCP Publisher
|
|
225
|
+
run: |
|
|
226
|
+
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
|
|
227
|
+
|
|
228
|
+
- name: Login to MCP Registry
|
|
229
|
+
run: ./mcp-publisher login github-oidc
|
|
230
|
+
|
|
231
|
+
- name: Publish to MCP Registry
|
|
232
|
+
run: ./mcp-publisher publish
|