Module: LicenseUtils
- Defined in:
- lib/ratatui_ruby/devtools/tasks/license/license_utils.rb
Overview
Extracts contributor information from git history.
License headers need accurate copyright years and contributor names. Git blame provides line-level authorship. Commit messages contain Co-Authored-By trailers. Combining these sources manually is tedious.
This module queries git blame and parses commit messages. It returns contributor names with their latest modification years. Use it when generating or updating SPDX headers.
Defined Under Namespace
Classes: Contributor
Class Method Summary collapse
-
.get_contributors_for_lines(filepath, start_line = nil, end_line = nil) ⇒ Object
Get all contributors who touched lines in a file (or range of lines).
-
.get_other_contributors(filepath, your_identifiers, start_line = nil, end_line = nil) ⇒ Object
Get all contributors EXCEPT you, with their latest years.
-
.get_your_latest_year(filepath, your_identifiers, start_line = nil, end_line = nil) ⇒ Object
Get YOUR latest year contribution to the file/lines.
Class Method Details
.get_contributors_for_lines(filepath, start_line = nil, end_line = nil) ⇒ Object
Get all contributors who touched lines in a file (or range of lines). Returns a Hash of { “Name <email>” => year } mapping each contributor to their latest year.
This considers both the commit author AND any Co-Authored-By trailers in commit messages.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/ratatui_ruby/devtools/tasks/license/license_utils.rb', line 40 def get_contributors_for_lines(filepath, start_line = nil, end_line = nil) blame_cmd = if start_line && end_line %W[git blame -L #{start_line},#{end_line} --porcelain -- #{filepath}] else %W[git blame --porcelain -- #{filepath}] end output, _status = Open3.capture2(*blame_cmd) contributors = {} # "Name <email>" => year commit_cache = {} # commit_hash => { year:, author:, co_authors: [] } current_commit = nil output.each_line do |line| if line =~ /^([a-f0-9]{40})/ current_commit = $1 elsif line =~ /^author (.+)$/ commit_cache[current_commit] ||= {} commit_cache[current_commit][:author_name] = $1 elsif line =~ /^author-mail <(.+)>$/ commit_cache[current_commit] ||= {} commit_cache[current_commit][:author_email] = $1 elsif line =~ /^author-time (\d+)$/ commit_cache[current_commit] ||= {} = $1.to_i commit_cache[current_commit][:year] = Time.at().year end end # Now fetch co-authors for each unique commit commit_cache.each do |commit_hash, data| next if commit_hash == "0" * 40 # Skip uncommitted lines # Get commit message for Co-Authored-By parsing msg_output, _status = Open3.capture2("git", "log", "-1", "--format=%B", commit_hash) = (msg_output) data[:co_authors] = # Add author if data[:author_name] && data[:author_email] key = "#{data[:author_name]} <#{data[:author_email]}>" year = data[:year] || Date.today.year contributors[key] = [contributors[key] || 0, year].max end # Add co-authors with same year as commit .each do |ca| key = "#{ca[:name]} <#{ca[:email]}>" year = data[:year] || Date.today.year contributors[key] = [contributors[key] || 0, year].max end end contributors end |
.get_other_contributors(filepath, your_identifiers, start_line = nil, end_line = nil) ⇒ Object
Get all contributors EXCEPT you, with their latest years. Returns array of { name:, email:, year: }
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/ratatui_ruby/devtools/tasks/license/license_utils.rb', line 114 def get_other_contributors(filepath, your_identifiers, start_line = nil, end_line = nil) contributors = get_contributors_for_lines(filepath, start_line, end_line) others = [] contributors.each do |contributor, year| next if your_identifiers.any? { |id| contributor.include?(id) } # Parse "Name <email>" format if contributor =~ /^(.+?)\s*<(.+)>$/ others << { name: $1.strip, email: $2.strip, year: } end end others end |
.get_your_latest_year(filepath, your_identifiers, start_line = nil, end_line = nil) ⇒ Object
Get YOUR latest year contribution to the file/lines. your_identifiers should be an array of strings that identify you (name, email fragments).
99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/ratatui_ruby/devtools/tasks/license/license_utils.rb', line 99 def get_your_latest_year(filepath, your_identifiers, start_line = nil, end_line = nil) contributors = get_contributors_for_lines(filepath, start_line, end_line) your_year = nil contributors.each do |contributor, year| if your_identifiers.any? { |id| contributor.include?(id) } your_year = [your_year || 0, year].max end end your_year || Date.today.year end |