Skip to content

Commit

Permalink
feat: add new patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
asafkorem committed Nov 4, 2024
1 parent 5353a8a commit 627364c
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 40 deletions.
1 change: 1 addition & 0 deletions src/components/PatternCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export const PatternCard: React.FC<PatternCardProps> = ({ pattern }) => {
) : (
<input
type="text"
placeholder={param.placeholder}
value={String(params[param.name])}
onChange={(e) => handleParamChange(param, e.target.value)}
className="w-full bg-[#0d1117] border border-[#30363d] rounded-lg px-3 py-2 text-[#c9d1d9] text-sm
Expand Down
167 changes: 127 additions & 40 deletions src/config/patterns.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Flame, Skull } from 'lucide-react';
import { Flame, Skull, Link } from 'lucide-react';
import { PatternDefinition } from '@/types/git-patterns';
import { createGitCommand } from '@/utils/git-commands';

Expand All @@ -20,7 +20,8 @@ export const hotspotPattern: PatternDefinition = {
name: 'keywords',
label: 'Filter by commit messages',
type: 'text',
defaultValue: 'fix,bug,refactor',
defaultValue: '',
placeholder: 'e.g., fix,bug,hotfix,patch',
description: 'Optional: filter by keywords in commit messages, separated by commas (leave empty for all)'
},
{
Expand All @@ -29,17 +30,20 @@ export const hotspotPattern: PatternDefinition = {
type: 'number',
min: 5,
max: 50,
defaultValue: 10
defaultValue: 10,
placeholder: 'e.g., 10'
}
],
generateCommand: (params) => `
# Find most frequently changed files
echo "Finding most frequently changed files..."
${createGitCommand.countFileChanges(params.timeWindow as string, params.keywords as string)} | \\
grep -v "^$" | \\
sort | \\
uniq -c | \\
sort -nr | \\
head -${params.limit}
`
sort -rn | \\
head -${params.limit} | \\
awk '{printf "%5d changes: %s\\n", $1, $2}'
`
};

export const dungeonPattern: PatternDefinition = {
Expand All @@ -60,7 +64,8 @@ export const dungeonPattern: PatternDefinition = {
name: 'keywords',
label: 'Filter by commit messages',
type: 'text',
defaultValue: 'fix,bug,refactor',
defaultValue: '',
placeholder: 'e.g., fix,feature,test,docs',
description: 'Optional: filter by keywords in commit messages, separated by commas (leave empty for all)'
},
{
Expand All @@ -69,53 +74,135 @@ export const dungeonPattern: PatternDefinition = {
type: 'number',
min: 1,
max: 100,
defaultValue: 5
defaultValue: 5,
placeholder: 'e.g., 5',
description: 'Minimum number of changes to consider a file'
},
{
name: 'maxAuthors',
label: 'Maximum authors',
type: 'number',
min: 1,
max: 10,
defaultValue: 2
defaultValue: 2,
placeholder: 'e.g., 2',
description: 'Maximum number of unique authors for a file to be considered a dungeon'
}
],
generateCommand: (params) => `
# Get all unique files from git history
files=$(${createGitCommand.countFileChanges(params.timeWindow as string, params.keywords as string)} | sort -u)
echo "Creating temporary workspace..."
tmpdir=$(mktemp -d 2>/dev/null || mktemp -d -t 'tmpdir')
trap 'rm -rf "$tmpdir"' EXIT
echo "Getting list of files that match minimum changes..."
${createGitCommand.countFileChanges(params.timeWindow as string, params.keywords as string)} | \\
grep -v "^$" | \\
sort | \\
uniq -c | \\
sort -rn | \\
awk '$1 >= ${params.minChanges} {print $2}' > "$tmpdir/files"
# For each file, check changes and authors
echo "$files" | while read -r file; do
if [ ! -z "$file" ]; then
# Count changes
changes=$(${createGitCommand.countFileChanges(params.timeWindow as string, params.keywords as string)} | grep -c "^$file" || echo 0)
# If changes meet minimum threshold
if [ "$changes" -ge ${params.minChanges} ]; then
# Count unique authors
author_count=$(${createGitCommand.getAuthors("$file", params.timeWindow as string)} | wc -l)
# If author count is within maximum
if [ "$author_count" -le ${params.maxAuthors} ]; then
echo "File: $file"
echo "Changes: $changes"
echo "Authors: "
${createGitCommand.getAuthorContributions("$file", params.timeWindow as string)} | \\
awk '{
count=$1
author=$2
for(i=3;i<=NF;i++) author=author " " $i
printf " %s: %d changes\\n", author, count
}'
echo "---"
fi
fi
echo "Analyzing author patterns..."
while IFS= read -r file; do
[ ! -f "$file" ] && continue
author_count=$(${createGitCommand.getAuthors("$file", params.timeWindow as string)} | \\
sort | \\
uniq | \\
wc -l | \\
tr -d '[:space:]')
if [ "$author_count" -le ${params.maxAuthors} ]; then
echo "\\nFile: $file"
echo "Changes in last ${params.timeWindow}:"
${createGitCommand.getAuthorContributions("$file", params.timeWindow as string)} | \\
awk '{
count=$1
author=$2
for(i=3;i<=NF;i++) author=author " " $i
printf " %s: %d changes\\n", author, count
}'
fi
done
done < "$tmpdir/files"
`
};

export const dependencyMagnetPattern: PatternDefinition = {
id: 'dependency-magnets',
icon: Link,
iconColor: '#8b5cf6',
title: 'Dependency Magnets',
description: 'Find files that frequently change together with other files',
params: [
{
name: 'timeWindow',
label: 'Time Window',
type: 'select',
options: ['1 month', '3 months', '6 months', '1 year', '2 years'],
defaultValue: '6 months'
},
{
name: 'minCoChanges',
label: 'Minimum co-changes',
type: 'number',
min: 2,
max: 20,
defaultValue: 3,
placeholder: 'e.g., 3',
description: 'Minimum number of files changed together to identify coupled changes'
},
{
name: 'showRelated',
label: 'Show related files',
type: 'number',
min: 1,
max: 20,
defaultValue: 5,
placeholder: 'e.g., 5',
description: 'Number of most frequently co-changed files to display'
}
],
generateCommand: (params) => `
echo "Creating temporary workspace..."
tmpdir=$(mktemp -d 2>/dev/null || mktemp -d -t 'tmpdir')
trap 'rm -rf "$tmpdir"' EXIT
echo "Defining helper function..."
get_related_files() {
local target_file="$1"
git log --since="${params.timeWindow} ago" --name-only --pretty=format:"%h" | \\
grep -v "^$" | \\
grep -v "^[a-f0-9]\\{7,\\}$" | \\
grep -v "^$target_file$" | \\
sort | \\
uniq -c | \\
sort -rn | \\
head -${params.showRelated} | \\
awk '{printf " %d co-changes: %s\\n", $1, $2}'
}
echo "Finding files with frequent co-changes..."
git log --since="${params.timeWindow} ago" --name-only --pretty=format:"%h" | \\
grep -v "^$" | \\
grep -v "^[a-f0-9]\\{7,\\}$" | \\
sort | \\
uniq -c | \\
sort -rn | \\
awk '$1 >= ${params.minCoChanges} {print $2}' > "$tmpdir/files"
echo "Analyzing dependencies..."
while IFS= read -r file; do
[ ! -f "$file" ] && continue
echo "\\nDependency Magnet: $file"
echo "Related files:"
get_related_files "$file"
done < "$tmpdir/files"
`
};

export const patterns = [
hotspotPattern,
dungeonPattern
dungeonPattern,
dependencyMagnetPattern
] as const;
1 change: 1 addition & 0 deletions src/types/git-patterns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface ParamConfig {
label: string;
type: 'text' | 'number' | 'select';
defaultValue: string | number;
placeholder?: string;
options?: string[];
min?: number;
max?: number;
Expand Down

0 comments on commit 627364c

Please sign in to comment.