plugins/git/skills/suggest-reviewers/SKILL.md
Git blame analysis helper for the suggest-reviewers command
npx skillsauth add openshift-eng/ai-helpers suggest-reviewersInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill provides a Python helper script that analyzes git blame data for the /git:suggest-reviewers command. The script handles the complex task of identifying which lines were changed and who authored the original code.
Use this skill when implementing the /git:suggest-reviewers command. The helper script should be invoked during Step 3 of the command implementation (analyzing git blame for changed lines).
DO NOT implement git blame analysis manually - always use the provided analyze_blame.py script.
The analyze_blame.py script automates the complex process of:
For uncommitted changes:
python3 ${CLAUDE_PLUGIN_ROOT}/skills/suggest-reviewers/analyze_blame.py \
--mode uncommitted \
--file path/to/file1.go \
--file path/to/file2.py \
--output json
For committed changes on a feature branch:
python3 ${CLAUDE_PLUGIN_ROOT}/skills/suggest-reviewers/analyze_blame.py \
--mode committed \
--base-branch main \
--file path/to/file1.go \
--file path/to/file2.py \
--output json
--mode: Required. Either uncommitted or committed
uncommitted: Analyzes unstaged/staged changes against HEADcommitted: Analyzes committed changes against a base branch--base-branch: Required when mode is committed. The base branch to compare against (e.g., main, master)
--file: Can be specified multiple times. Each file to analyze for blame information. Only changed files should be passed.
--output: Output format. Default is json. Options:
json: Machine-readable JSON outputtext: Human-readable text output{
"Author Name": {
"line_count": 45,
"most_recent_date": "2024-10-15T14:23:10",
"files": ["file1.go", "file2.go"],
"email": "[email protected]"
},
"Another Author": {
"line_count": 23,
"most_recent_date": "2024-09-20T09:15:33",
"files": ["file3.py"],
"email": "[email protected]"
}
}
line_count: Total number of modified lines authored by this personmost_recent_date: ISO 8601 timestamp of their most recent contribution to the changed codefiles: Array of files where this author has contributions in the changed linesemail: Author's email address from git commitsThe script automatically filters out common bot accounts:
dependabot[bot], renovate[bot])openshift-ci-robot, k8s-ci-robot)[bot] or ending in -bot)Before invoking the script, collect the list of changed files based on the scenario:
Uncommitted changes:
# Get staged and unstaged files
files=$(git diff --name-only --diff-filter=d HEAD)
files+=" $(git diff --name-only --diff-filter=d --cached)"
Committed changes:
# Get files changed from base branch
files=$(git diff --name-only --diff-filter=d ${base_branch}...HEAD)
Build the command with the appropriate mode and all changed files:
# Start building the command
cmd="python3 ${CLAUDE_PLUGIN_ROOT}/skills/suggest-reviewers/analyze_blame.py"
# Add mode
if [ "$has_uncommitted" = true ] || [ "$on_base_branch" = true ]; then
cmd="$cmd --mode uncommitted"
else
cmd="$cmd --mode committed --base-branch $base_branch"
fi
# Add each file
for file in $files; do
cmd="$cmd --file $file"
done
# Add output format
cmd="$cmd --output json"
# Execute and capture JSON output
blame_data=$($cmd)
The JSON output can be parsed using Python, jq, or any JSON parser:
# Example using jq to get top contributor
echo "$blame_data" | jq -r 'to_entries | sort_by(-.value.line_count) | .[0].key'
# Example using Python
python3 << EOF
import json
import sys
data = json.loads('''$blame_data''')
# Sort by line count
sorted_authors = sorted(data.items(), key=lambda x: x[1]['line_count'], reverse=True)
for author, stats in sorted_authors:
print(f"{author}: {stats['line_count']} lines, last modified {stats['most_recent_date']}")
EOF
After getting blame data, merge it with OWNERS file information to produce the final ranked list of reviewers.
If no files are passed to the script:
Error: No files specified. Use --file option at least once.
Resolution: Ensure you've detected changed files (via git diff --name-only) before invoking the script.
If an invalid mode is specified:
Error: Invalid mode 'invalid'. Must be 'uncommitted' or 'committed'.
Resolution: Use either --mode uncommitted or --mode committed.
If --mode committed is used without --base-branch:
Error: --base-branch is required when mode is 'committed'.
Resolution: Provide the base branch: --base-branch main
If a specified file is not tracked by git:
Warning: File 'path/to/file' is not tracked by git, skipping.
Resolution: This is a warning and can be safely ignored. The script will skip untracked files.
If git blame returns no data for any files:
{}
Resolution: This can happen if:
In this case, fall back to OWNERS-only suggestions.
$ python3 analyze_blame.py --mode uncommitted --file src/main.go --file src/utils.go --output json
{
"Alice Developer": {
"line_count": 45,
"most_recent_date": "2024-10-15T14:23:10",
"files": ["src/main.go", "src/utils.go"],
"email": "[email protected]"
},
"Bob Engineer": {
"line_count": 12,
"most_recent_date": "2024-09-20T09:15:33",
"files": ["src/main.go"],
"email": "[email protected]"
}
}
$ python3 analyze_blame.py --mode committed --base-branch main --file pkg/controller/manager.go --output json
{
"Charlie Contributor": {
"line_count": 78,
"most_recent_date": "2024-10-01T11:42:55",
"files": ["pkg/controller/manager.go"],
"email": "[email protected]"
}
}
$ python3 analyze_blame.py --mode uncommitted --file README.md --output text
Blame Analysis Results:
=======================
Alice Developer ([email protected])
Lines: 23
Most recent: 2024-10-15T14:23:10
Files: README.md
Bob Engineer ([email protected])
Lines: 5
Most recent: 2024-08-12T16:30:21
Files: README.md
$ python3 analyze_blame.py --mode committed --base-branch release-4.15 \
--file vendor/k8s.io/client-go/kubernetes/clientset.go \
--file pkg/controller/node.go \
--file docs/README.md \
--output json
{
"Diana Developer": {
"line_count": 156,
"most_recent_date": "2024-09-28T13:15:42",
"files": ["vendor/k8s.io/client-go/kubernetes/clientset.go", "pkg/controller/node.go"],
"email": "[email protected]"
},
"Eve Technical Writer": {
"line_count": 34,
"most_recent_date": "2024-10-10T10:22:18",
"files": ["docs/README.md"],
"email": "[email protected]"
}
}
Determine diff range: Based on mode, calculates what to compare:
uncommitted: Compares working directory against HEADcommitted: Compares HEAD against base branchParse diff output: Runs git diff with unified format to identify:
Run git blame: For each file and line range:
git blame -L start,end --line-porcelain fileFilter and aggregate:
Output results: Formats as JSON or text based on --output parameter
/git:suggest-reviewers in plugins/git/commands/suggest-reviewers.mdtesting
Snapshot OpenShift payload data (release controller, PR diffs, comments, CI jobs, JUnit results, regression tracking) to a local directory for offline analysis
research
Shared engine for analyzing Jira issue activity and generating status summaries
tools
This skill should be used before any Snowflake command to verify MCP connectivity, guide users through access provisioning, and set the session context. Invoke this skill proactively whenever a command needs Snowflake data access.
development
Analyze a payload snapshot to identify root causes of blocking job failures, score candidate PRs, and produce an HTML report with revert recommendations