diff --git a/blamepercent.ps1 b/blamepercent.ps1 new file mode 100644 index 0000000..c53b3cd --- /dev/null +++ b/blamepercent.ps1 @@ -0,0 +1,60 @@ +param ( + [string]$FilePath +) + +# --- Add this block for error handling --- +if ([string]::IsNullOrEmpty($FilePath)) { + Write-Error "Error: No file path provided." + Write-Host "Usage: .\blamepercent.ps1 -FilePath " + Write-Host "Example: .\blamepercent.ps1 -FilePath '.\your_script.ps1'" + exit 1 +} +# --- End of added block --- + +if (-not (Test-Path $FilePath)) { + Write-Error "File '$FilePath' does not exist." + exit 1 +} + +# Set console output to UTF-8 +[Console]::OutputEncoding = [Text.UTF8Encoding]::new() + +# Run git blame on the file, get author names per line +$blameOutput = git blame --line-porcelain $FilePath | Where-Object { $_ -like 'author *' } | ForEach-Object { ($_ -replace 'author ', '').Trim() } + +if (-not $blameOutput) { + Write-Error "No git blame info found. Make sure this file is tracked by git." + exit 1 +} + +# Function to sanitize author names, removing problematic characters +function Clean-AuthorName { + param($name) + # Remove control characters and non-printable characters + $clean = -join ($name.ToCharArray() | Where-Object { + $c = [int][char]$_ + ($c -ge 32 -and $c -le 126) -or ($c -ge 160) # keep printable ASCII and extended UTF chars + }) + return $clean +} + +# Count lines per author +$authorCounts = @{} +$totalLines = 0 + +foreach ($author in $blameOutput) { + $cleanAuthor = Clean-AuthorName $author + if ($authorCounts.ContainsKey($cleanAuthor)) { + $authorCounts[$cleanAuthor] += 1 + } else { + $authorCounts[$cleanAuthor] = 1 + } + $totalLines++ +} + +# Calculate and display percentages +Write-Host "Code contribution percentages for file: $FilePath" +foreach ($author in $authorCounts.Keys) { + $percentage = [math]::Round(($authorCounts[$author] / $totalLines) * 100, 2) + Write-Host "$author : $percentage %" +} \ No newline at end of file diff --git a/blamepercent.sh b/blamepercent.sh new file mode 100644 index 0000000..f1e5559 --- /dev/null +++ b/blamepercent.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +# --- Input Parameter --- +# Check if file path is provided BEFORE enabling set -u +# This ensures a user-friendly message for missing arguments. +if [ -z "$1" ]; then + echo "Usage: $0 " + exit 1 +fi + +FILE_PATH="$1" + +# --- Error Handling --- +# Exit immediately if a command exits with a non-zero status. +set -e +# Treat unset variables as an error. +# Now that $1 is safely assigned (or the script exited), set -u is safe here. +set -u + +# Check if the file exists +if [ ! -f "$FILE_PATH" ]; then + echo "Error: File '$FILE_PATH' does not exist." + exit 1 +fi + +# Check if git is installed and available +if ! command -v git &> /dev/null; then + echo "Error: 'git' command not found. Please install Git." + exit 1 +fi + +# --- Main Logic --- + +# Run git blame on the file, extract author names +# We use --line-porcelain for detailed output, then grep for 'author ' lines, +# and finally use sed to extract just the author name. +# Sort and uniq -c will give us counts for each author. +blame_output=$(git blame --line-porcelain "$FILE_PATH" | \ + grep '^author ' | \ + sed 's/^author //g') + +if [ -z "$blame_output" ]; then + echo "Error: No git blame info found for '$FILE_PATH'. Make sure this file is tracked by git." + exit 1 +fi + +# Initialize associative array for author counts (Bash 4.0+ required) +declare -A author_counts + +total_lines=0 + +# Clean-AuthorName equivalent: remove control characters and non-printable characters. +# This sed expression keeps printable ASCII (0x20-0x7E) and multi-byte UTF-8 characters. +# It removes characters like carriage returns, newlines, and other control codes. +clean_author_name() { + local name="$1" + # Remove characters not in printable ASCII range or common extended characters. + # This might need refinement depending on the exact non-printable characters encountered. + # For simplicity, we'll focus on removing common control characters. + echo "$name" | tr -d '\0-\031\177' # Remove ASCII control characters and DEL +} + +# Count lines per author +while IFS= read -r author; do + # Call the cleaning function + cleaned_author=$(clean_author_name "$author") + + # DEBUGGING OUTPUT + echo "[DEBUG] Author='$author' Cleaned='$cleaned_author'" >&2 + + # Increment count for the cleaned author + if [[ -n "${author_counts[$cleaned_author]:-}" ]]; then + author_counts["$cleaned_author"]=$((author_counts["$cleaned_author"] + 1)) + else + author_counts["$cleaned_author"]=1 + fi + total_lines=$((total_lines + 1)) +done <<< "$blame_output" + +# Calculate and display percentages +echo "Code contribution percentages for file: $FILE_PATH" + +if [ "$total_lines" -eq 0 ]; then + echo "No lines found to analyze." + exit 0 +fi + +# Iterate over the keys (authors) in the associative array +for author in "${!author_counts[@]}"; do + count="${author_counts[$author]}" + # Use awk for floating-point arithmetic for percentage calculation + percentage=$(awk "BEGIN {printf \"%.2f\", (($count / $total_lines) * 100)}") + echo "$author : $percentage %" +done diff --git a/cogs/logging_cog.py b/cogs/logging_cog.py index 57833e9..e075851 100644 --- a/cogs/logging_cog.py +++ b/cogs/logging_cog.py @@ -207,7 +207,7 @@ class LoggingCog(commands.Cog): ) # log.debug(f"Sent log embed via webhook for guild {guild.id}") # Can be noisy except ValueError as e: - log.exception(f"Invalid logging webhook URL configured for guild {guild.id}. Error: {e}") + log.exception(f"ValueError sending log via webhook for guild {guild.id}. Error: {e}") # Consider notifying an admin or disabling logging for this guild temporarily # await settings_manager.set_logging_webhook(guild.id, None) # Example: Auto-disable on invalid URL except (discord.Forbidden, discord.NotFound):