# Git commit message generator # Generates a commit message file based on current changes without creating a commit # Generate commit message file based on staged and unstaged changes export def "generate-commit-message" [ --file (-f): string = "COMMIT_MSG.txt" # Output file for commit message --staged (-s): bool = false # Only consider staged changes --unstaged (-u): bool = false # Only consider unstaged changes ] -> nothing { # Determine what changes to analyze let analyze_staged = if $staged or (not $unstaged) { true } else { false } let analyze_unstaged = if $unstaged or (not $staged) { true } else { false } # Get git status let git_status = (git status --porcelain | lines | where { $in | str length > 0 }) if ($git_status | is-empty) { print "No changes to commit" return } # Analyze changes mut changes = [] mut files_modified = [] mut files_added = [] mut files_deleted = [] for line in $git_status { let status_code = ($line | str substring 0..2) let file_path = ($line | str substring 3..) # Parse git status codes match $status_code { " M" => { if $analyze_unstaged { $files_modified = ($files_modified | append $file_path) } } "M " => { if $analyze_staged { $files_modified = ($files_modified | append $file_path) } } "MM" => { $files_modified = ($files_modified | append $file_path) } "A " => { if $analyze_staged { $files_added = ($files_added | append $file_path) } } "??" => { if $analyze_unstaged { $files_added = ($files_added | append $file_path) } } " D" => { if $analyze_unstaged { $files_deleted = ($files_deleted | append $file_path) } } "D " => { if $analyze_staged { $files_deleted = ($files_deleted | append $file_path) } } _ => {} } } # Get recent commit messages for style reference let recent_commits = try { git log --oneline -5 | lines } catch { [] } # Analyze file types and changes let config_files = ($files_modified | where { $in | str ends-with ".toml" or $in | str ends-with ".nu" or $in | str ends-with ".yaml" }) let core_files = ($files_modified | where { $in | str contains "core/" }) let provider_files = ($files_modified | where { $in | str contains "provider" }) # Generate commit message based on changes mut commit_type = "chore" mut commit_scope = "" mut commit_description = "" # Determine commit type and scope if (not ($files_added | is-empty)) { $commit_type = "feat" $commit_description = "add new functionality" } else if (not ($files_deleted | is-empty)) { $commit_type = "refactor" $commit_description = "remove unused components" } else if (not ($config_files | is-empty)) { $commit_type = "config" $commit_scope = "system" $commit_description = "update configuration settings" } else if (not ($core_files | is-empty)) { $commit_type = "refactor" $commit_scope = "core" $commit_description = "improve core functionality" } else if (not ($provider_files | is-empty)) { $commit_type = "feat" $commit_scope = "providers" $commit_description = "enhance provider capabilities" } else { $commit_type = "chore" $commit_description = "update project files" } # Build commit message mut commit_message = if ($commit_scope | is-empty) { $"($commit_type): ($commit_description)" } else { $"($commit_type)\(($commit_scope)\): ($commit_description)" } # Add details section mut details = [] if (not ($files_added | is-empty)) { $details = ($details | append $"- Add: ($files_added | str join ', ')") } if (not ($files_modified | is-empty)) { $details = ($details | append $"- Update: ($files_modified | str join ', ')") } if (not ($files_deleted | is-empty)) { $details = ($details | append $"- Remove: ($files_deleted | str join ', ')") } # Create full commit message let full_message = if ($details | is-empty) { $commit_message } else { $"($commit_message)\n\n($details | str join '\n')" } # Write to file $full_message | save $file print $"Commit message generated and saved to: ($file)" print "\nGenerated message:" print "==================" print $full_message } # Show current git changes that would be included in commit message export def "show-commit-changes" [] -> table { let status_output = (git status --porcelain | lines | where { $in | str length > 0 }) $status_output | each { |line| let status_code = ($line | str substring 0..2) let file_path = ($line | str substring 3..) let change_type = match $status_code { " M" => "Modified (unstaged)" "M " => "Modified (staged)" "MM" => "Modified (both)" "A " => "Added (staged)" "??" => "Untracked" " D" => "Deleted (unstaged)" "D " => "Deleted (staged)" _ => $status_code } { file: $file_path, status: $change_type, code: $status_code } } }