Files
Claude-Code-Workflow/.claude/scripts/detect_changed_modules.sh
catlog22 813bfa8f97 fix(claude): 修复 ccw tool exec 命令格式 - 位置参数改为JSON格式
修复内容:
- 将位置参数格式改为JSON格式: ccw tool exec tool '{"param":"value"}'
- 修复双引号字符串内的JSON引号转义问题
- 更新deprecated脚本的使用示例

受影响文件:
- commands/memory/update-full.md, docs-full-cli.md, docs-related-cli.md, update-related.md
- commands/workflow/ui-design/generate.md, import-from-code.md
- scripts/*.sh (9个deprecated脚本)
- skills/command-guide/reference/* (通过analyze_commands.py自动同步)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 21:09:21 +08:00

162 lines
6.0 KiB
Bash

#!/bin/bash
# ⚠️ DEPRECATED: This script is deprecated.
# Please use: ccw tool exec detect_changed_modules '{"baseBranch":"main","format":"list"}'
# This file will be removed in a future version.
# Detect modules affected by git changes or recent modifications
# Usage: detect_changed_modules.sh [format]
# format: list|grouped|paths (default: paths)
#
# Features:
# - Respects .gitignore patterns (current directory or git root)
# - Detects git changes (staged, unstaged, or last commit)
# - Falls back to recently modified files (last 24 hours)
# Build exclusion filters from .gitignore
build_exclusion_filters() {
local filters=""
# Common system/cache directories to exclude
local system_excludes=(
".git" "__pycache__" "node_modules" ".venv" "venv" "env"
"dist" "build" ".cache" ".pytest_cache" ".mypy_cache"
"coverage" ".nyc_output" "logs" "tmp" "temp"
)
for exclude in "${system_excludes[@]}"; do
filters+=" -not -path '*/$exclude' -not -path '*/$exclude/*'"
done
# Find and parse .gitignore (current dir first, then git root)
local gitignore_file=""
# Check current directory first
if [ -f ".gitignore" ]; then
gitignore_file=".gitignore"
else
# Try to find git root and check for .gitignore there
local git_root=$(git rev-parse --show-toplevel 2>/dev/null)
if [ -n "$git_root" ] && [ -f "$git_root/.gitignore" ]; then
gitignore_file="$git_root/.gitignore"
fi
fi
# Parse .gitignore if found
if [ -n "$gitignore_file" ]; then
while IFS= read -r line; do
# Skip empty lines and comments
[[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue
# Remove trailing slash and whitespace
line=$(echo "$line" | sed 's|/$||' | xargs)
# Skip wildcards patterns (too complex for simple find)
[[ "$line" =~ \* ]] && continue
# Add to filters
filters+=" -not -path '*/$line' -not -path '*/$line/*'"
done < "$gitignore_file"
fi
echo "$filters"
}
detect_changed_modules() {
local format="${1:-paths}"
local changed_files=""
local affected_dirs=""
local exclusion_filters=$(build_exclusion_filters)
# Step 1: Try to get git changes (staged + unstaged)
if git rev-parse --git-dir > /dev/null 2>&1; then
changed_files=$(git diff --name-only HEAD 2>/dev/null; git diff --name-only --cached 2>/dev/null)
# If no changes in working directory, check last commit
if [ -z "$changed_files" ]; then
changed_files=$(git diff --name-only HEAD~1 HEAD 2>/dev/null)
fi
fi
# Step 2: If no git changes, find recently modified source files (last 24 hours)
# Apply exclusion filters from .gitignore
if [ -z "$changed_files" ]; then
changed_files=$(eval "find . -type f \( \
-name '*.md' -o \
-name '*.js' -o -name '*.ts' -o -name '*.jsx' -o -name '*.tsx' -o \
-name '*.py' -o -name '*.go' -o -name '*.rs' -o \
-name '*.java' -o -name '*.cpp' -o -name '*.c' -o -name '*.h' -o \
-name '*.sh' -o -name '*.ps1' -o \
-name '*.json' -o -name '*.yaml' -o -name '*.yml' \
\) $exclusion_filters -mtime -1 2>/dev/null")
fi
# Step 3: Extract unique parent directories
if [ -n "$changed_files" ]; then
affected_dirs=$(echo "$changed_files" | \
sed 's|/[^/]*$||' | \
grep -v '^\.$' | \
sort -u)
# Add current directory if files are in root
if echo "$changed_files" | grep -q '^[^/]*$'; then
affected_dirs=$(echo -e ".\n$affected_dirs" | sort -u)
fi
fi
# Step 4: Output in requested format
case "$format" in
"list")
if [ -n "$affected_dirs" ]; then
echo "$affected_dirs" | while read dir; do
if [ -d "$dir" ]; then
local file_count=$(find "$dir" -maxdepth 1 -type f 2>/dev/null | wc -l)
local depth=$(echo "$dir" | tr -cd '/' | wc -c)
if [ "$dir" = "." ]; then depth=0; fi
local types=$(find "$dir" -maxdepth 1 -type f -name "*.*" 2>/dev/null | \
grep -E '\.[^/]*$' | sed 's/.*\.//' | sort -u | tr '\n' ',' | sed 's/,$//')
local has_claude="no"
[ -f "$dir/CLAUDE.md" ] && has_claude="yes"
echo "depth:$depth|path:$dir|files:$file_count|types:[$types]|has_claude:$has_claude|status:changed"
fi
done
fi
;;
"grouped")
if [ -n "$affected_dirs" ]; then
echo "📊 Affected modules by changes:"
# Group by depth
echo "$affected_dirs" | while read dir; do
if [ -d "$dir" ]; then
local depth=$(echo "$dir" | tr -cd '/' | wc -c)
if [ "$dir" = "." ]; then depth=0; fi
local claude_indicator=""
[ -f "$dir/CLAUDE.md" ] && claude_indicator=" [✓]"
echo "$depth:$dir$claude_indicator"
fi
done | sort -n | awk -F: '
{
if ($1 != prev_depth) {
if (prev_depth != "") print ""
print " 📁 Depth " $1 ":"
prev_depth = $1
}
print " - " $2 " (changed)"
}'
else
echo "📊 No recent changes detected"
fi
;;
"paths"|*)
echo "$affected_dirs"
;;
esac
}
# Execute function if script is run directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
detect_changed_modules "$@"
fi