PR dependency chain analysis with multi-language ecosystem support
pr-diff-walk analyzes pull requests and merge requests to trace how changed code entities ripple through your codebase. It identifies which files and entities depend on what was modified, helping developers understand the full impact of their changes before merging.
- Multi-language support: JavaScript, TypeScript, Python, Rust, Go, Java, C#, Dart, Swift, Kotlin, C, C++, Zig, PHP, HTML, CSS
- Multi-provider support: GitHub PRs and GitLab MRs
- Smart detection: Automatically detects which language integrations to use based on PR files
- Chain tracing: Follows import/export relationships to find all dependents of changed code
- Flexible output: Markdown reports, JSON data, or structured analysis results
- Local repo mode: Analyze PRs using a locally cloned repository
pip install pr-diff-walk# Clone the repository
git clone https://github.com/felixLandlord/prDiffWalk.git
cd prDiffWalk
# Install in development mode
pip install -e .git clone https://github.com/felixLandlord/prDiffWalk.git
cd prDiffWalk
pip install -e ".[dev]"- Python 3.10 or higher
- A GitHub or GitLab token for API access (see Authentication)
# Analyze a GitHub PR (will auto-detect integrations)
pr-diff-walk analyze owner/repo 123
# With explicit integrations
pr-diff-walk analyze owner/repo 123 --integration python,javascript
# GitLab merge request
pr-diff-walk analyze owner/repo 456 --provider gitlab --gitlab-url https://gitlab.example.comThe main command for analyzing pull requests and merge requests.
pr-diff-walk analyze <repo> <pr_number> [OPTIONS]Arguments:
repo- Repository in formatowner/repopr_number- PR/MR number to analyze
Options:
| Option | Short | Description | Default |
|---|---|---|---|
--token |
-t |
Git provider API token | From env/.env |
--local |
-l |
Local repository path | Use remote API |
--depth |
-d |
Maximum dependency chain depth | 8 |
--integration |
-i |
Language integrations (comma/space sep) | Auto-detect |
--provider |
-p |
Git provider: github, gitlab |
github |
--gitlab-url |
GitLab instance URL (for self-hosted) | https://gitlab.com |
|
--output |
-o |
Output file path | stdout |
--format |
-f |
Output format: report, json, data |
report |
Examples:
# Basic analysis with markdown report output
pr-diff-walk analyze octocat/Hello-World 42
# JSON output for programmatic use
pr-diff-walk analyze owner/repo 123 --format json --output analysis.json
# Using local repository (faster for repeated analysis)
pr-diff-walk analyze owner/repo 123 --local ./my-repo
# Limit chain depth for faster analysis
pr-diff-walk analyze owner/repo 123 --depth 4
# Explicit language integrations
pr-diff-walk analyze owner/repo 123 --integration python rust
# GitLab merge request
pr-diff-walk analyze group/project 789 --provider gitlabLists all available language integrations.
pr-diff-walk listOutput:
+--------------------+----------------------+----------------------------+
| Name | Languages | Extensions |
+--------------------+----------------------+----------------------------+
| javascript | JavaScript | .js, .jsx |
| typescript | TypeScript | .ts, .tsx |
| python | Python | .py |
| rust | Rust | .rs |
| golang | Go | .go |
| java | Java | .java |
| csharp | C# | .cs |
| dart | Dart/Flutter | .dart |
| swift | Swift | .swift |
| kotlin | Kotlin | .kt, .kts |
| c | C | .c, .h |
| cpp | C++ | .cpp, .cc, .cxx, .hpp, .h |
| zig | Zig | .zig |
| php | PHP | .php |
| html | HTML | .html |
| css | CSS | .css |
+--------------------+----------------------+----------------------------+
Generates a detailed markdown report (alias for analyze with --format report).
pr-diff-walk report <repo> <pr_number> [OPTIONS]Provides a quick summary table of dependency chains.
pr-diff-walk quick <repo> <pr_number> [OPTIONS]Example output:
Dependency Chains Summary
+------+------------------+----------------------+-----+
| Chain | Seed Entity | File | Hops|
+------+------------------+----------------------+-----+
| 1 | validate (func) | auth/validators.py | 5 |
| 2 | User (class) | models/user.py | 3 |
+------+------------------+----------------------+-----+
Total chains: 2
Integrations: python,javascript
Set via one of:
- Command line:
--token YOUR_TOKEN - Environment variable:
GITHUB_TOKENorGH_TOKEN .envfile: AddGITHUB_TOKEN=YOUR_TOKENin project root or local repo
Generate a token at: https://github.com/settings/tokens
Required scopes: repo (for private repos) or public_repo (for public repos)
Set via one of:
- Command line:
--token YOUR_TOKEN - Environment variable:
GITLAB_TOKENorGL_TOKEN .envfile: AddGITLAB_TOKEN=YOUR_TOKEN
Generate a token at: https://gitlab.com/-/profile/personal_access_tokens
Required scopes: api (for private repos) or read_api (for public repos)
Detailed markdown report containing:
- PR metadata (repository, PR number, branches)
- Full diff content
- Dependency chains with code snippets
- Cross-references between changed files
Structured JSON output for programmatic processing:
{
"repo_name": "owner/repo",
"pr_num": 123,
"head_ref": "feature-branch",
"base_ref": "main",
"provider": "github",
"integrations": "python,javascript",
"chains": [
{
"seed": {"file": "auth/validators.py", "name": "validate", "kind": "function"},
"hops": [
{
"depth": 1,
"from": {"file": "auth/routes.py", "name": "validate"},
"importer": "auth/routes.py",
"imported_as": "validate",
"line": 15,
"context": "login"
}
]
}
]
}Summary data with chain count:
{
"repo_name": "owner/repo",
"pr_num": 123,
"head_ref": "feature-branch",
"base_ref": "main",
"provider": "github",
"integrations": "python,javascript",
"chain_count": 5
}from pr_diff_walk import DiffChainService, analyze_pr
# Simple function call
result = analyze_pr("owner/repo", 123, github_token="ghp_xxx")
print(result["data"].chains)
print(result["report"])from pr_diff_walk import DiffChainService, get_integration
# Create service with custom configuration
service = DiffChainService(
repo_name="owner/repo",
pr_num=123,
github_token="ghp_xxx", # Or set GITHUB_TOKEN env var
local_repo_path="./my-repo", # Use local clone for speed
max_depth=10, # Increase depth for deeper analysis
integrations=["python", "javascript"],
provider="github", # or "gitlab"
gitlab_url="https://gitlab.example.com", # For GitLab self-hosted
)
# Run analysis
result = service.analyze()
# Access results
print(f"Found {len(result.chains)} dependency chains")
for chain in result.chains:
print(f"Seed: {chain.seed.name} in {chain.seed.file_path}")
for hop in chain.hops:
print(f" -> {hop.next_entity.name} in {hop.next_entity.file_path}")
# Generate report
report = service.generate_report(result)
print(report)from pr_diff_walk import (
get_git_client,
get_integration,
GitHubClient,
)
# Direct git client usage
client = GitHubClient(token="ghp_xxx")
pr = client.get_pr("owner/repo", 123)
files = client.get_pr_files("owner/repo", 123)
# Get specific language integration
python_integration = get_integration("python")pr-diff-walk works by analyzing how code entities in a PR interact with the rest of the codebase through import/export relationships.
┌─────────────┐ ┌──────────────┐ ┌────────────────┐
│ Fetch PR │────>│ Download │────>│ Load Repo │
│ metadata │ │ snapshot │ │ files │
└─────────────┘ └──────────────┘ └────────────────┘
│
v
┌─────────────┐ ┌──────────────┐ ┌────────────────┐
│ Output │<────│ Generate │<────│ Trace │
│ report │ │ chains │ │ dependencies │
└─────────────┘ └──────────────┘ └────────────────┘
The tool retrieves PR/MR information from the git provider API:
- PR title, description, and metadata
- List of changed files
- Diff patches for each file
- Branch information (head and base)
The full repository snapshot is downloaded (or read from local path):
- Files are scanned based on detected language integrations
- Each integration knows which file extensions to look for
- Common build/generated directories are excluded (e.g.,
node_modules,dist,target)
For each file in the repository:
-
Entity Detection: Language-specific parsers identify defined entities (functions, classes, variables, etc.) with their line ranges
-
Import Analysis: Parsers extract import statements and map them to source files
Example for Python:
# Entity: validate() function at lines 10-25
def validate(data):
...
# Import: uses validate from auth.validators
from auth.validators import validateThe diff patch is analyzed to find which lines changed:
- Parse the unified diff format to extract added/modified line numbers
- Map line numbers to the smallest enclosing entity (function, class, etc.)
- These become the "seed" entities for chain tracing
Starting from each changed entity (seed):
- Find dependents: Look for files that import this entity
- Breadth-first traversal: Follow the dependency graph up to
max_depth - Collect hops: Record each step in the chain with context (line number, calling code)
The chain tracer uses a queue-based breadth-first search:
Seed: validate() in auth/validators.py
Hop 1: imported by auth/routes.py (login function, line 15)
Hop 2: imported by api/middleware.py (auth check, line 42)
Hop 3: imported by app.py (main entry, line 100)
Each language integration recognizes different entity kinds:
| Language | Entity Kinds |
|---|---|
| Python | class, function, method, variable, async_function |
| JavaScript | function, const, let, var, class |
| TypeScript | Same as JS + interface, type, enum |
| Rust | fn, struct, enum, impl, trait, const, static |
| Go | func, type, const, var |
| Java | class, interface, enum, method, field |
| C# | class, interface, struct, enum, method, property |
| Dart | class, function, method, variable |
| Swift | class, struct, enum, func, let, var |
| Kotlin | class, fun, val, var, object |
| C/C++ | function, struct, union, enum, typedef |
| Zig | fn, const, var, struct, enum |
| PHP | function, class, interface, trait |
| HTML | element, id, class, attribute |
| CSS | selector, property, at-rule |
- Public and private repositories
- Personal access tokens (classic and fine-grained)
- Requires
reposcope for private repos
- GitLab.com and self-hosted instances
- Personal access tokens
- Requires
apiscope for private projects
The tool uses language-specific integrations to parse imports and entities:
| Integration | Extensions | Notes |
|---|---|---|
| JavaScript | .js, .jsx |
ES6 imports, CommonJS requires |
| TypeScript | .ts, .tsx |
Includes JS support, type imports |
| Python | .py |
from and import statements |
| Rust | .rs |
use and mod declarations |
| Go | .go |
import and require |
| Java | .java |
import declarations |
| C# | .cs |
using statements |
| Dart | .dart |
import and export |
| Swift | .swift |
import and struct/class |
| Kotlin | .kt, .kts |
import statements |
| C | .c, .h |
#include directives |
| C++ | .cpp, .cc, .cxx, .hpp, .h |
#include directives |
| Zig | .zig |
const, usingnamespace |
| PHP | .php |
use and require/include |
| HTML | .html |
Script/style src references |
| CSS | .css |
@import and url() references |
| Variable | Provider | Description |
|---|---|---|
GITHUB_TOKEN |
GitHub | GitHub personal access token |
GH_TOKEN |
GitHub | Alternative GitHub token env var |
GITLAB_TOKEN |
GitLab | GitLab personal access token |
GL_TOKEN |
GitLab | Alternative GitLab token env var |
Apache License 2.0 - see LICENSE file for details.
See CONTRIBUTING.md in the docs folder.