# coding: utf-8
def escape_wikitext text
replacements = {
'"' => '"', '&' => '&', "'" => ''', '<' => '<',
'=' => '=', '>' => '>', '[' => '[', ']' => ']',
'{' => '{', '|' => '|', '}' => '}', ';' => ';',
}
text.gsub Regexp.union(replacements.keys), replacements
end
prolific_only = ARGV[0] == '--prolific'
data = `git log --notes=review --no-merges --format="format:%H%n%ae%n%N"`
table = {}
mailmap = File.readlines('.mailmap').map{|ln|
_, canonical, other = *ln.match(/<(.+?)>(?:.+?<(.+?)>)?/)
other ? [other, canonical] : nil
}
mailmap = Hash[ mailmap.compact ]
data.split(/(\r?\n){2}/).each_with_index do |item, i|
next if item.strip == ''
lines = item.split(/\r?\n/)
hash, author, *rest = *lines
next if rest.join("\n").strip == ''
submitter = rest.join("\n")[/^Code-Review\+2: .+? <(.+)>/, 1]
next if !submitter
author = mailmap[author] || author
submitter = mailmap[submitter] || submitter
table[author] ||= {}
table[author][submitter] ||= []
table[author][submitter] << hash
end
all_authors = table.keys.sort
all_submitters = table.values.map{|subs_for_author| subs_for_author.keys }.flatten.uniq.sort
author_totals = Hash[ table.map{|k, v| [k, v.values.map(&:length).inject(:+)] } ]
submitter_totals = Hash[ all_submitters.map{|sub|
submitter_total = table.values.map{|table_aut| table_aut[sub] }.compact.map(&:length).inject(:+)
[sub, submitter_total]
} ]
if prolific_only
all_authors.select!{|aut| author_totals[aut] + (submitter_totals[aut]||0) >= 100 }
all_submitters.select!{|sub| (author_totals[sub]||0) + submitter_totals[sub] >= 100 }
end
output = []
output << "{| class='wikitable' style='text-align: center;'"
output << '! style="width: 20em; height: 20em;" | Author \ Submitter'
output += all_submitters.map{|sub|
cell_style = 'max-width: 1.5em; vertical-align: bottom;'
inner_style = 'float: right; margin-right: 1.5em; white-space: nowrap; transform: rotate(90deg); transform-origin: 100% 100%; -webkit-transform: rotate(90deg); -webkit-transform-origin: 100% 100%;'
"! style='#{cell_style}' | <div style='#{inner_style}'>#{sub}</div>"
}
output << "! style='vertical-align: bottom;' | Total authored"
all_authors.each do |aut|
output << '|-'
output << "! style='text-align: right;' | #{escape_wikitext aut}"
output += all_submitters.map{|sub|
num = table[aut][sub] ? table[aut][sub].length : 0
title = "Patches by #{escape_wikitext aut} accepted by #{escape_wikitext sub}"
style = aut == sub ? ' style="background-color: lightgray;"' : nil
out = num == 0 ? '' : num < 10 ? "#{num}" : "'''#{num}'''"
if num == 0
out = style ? "|#{style} |" : "|"
else
out = "| title='#{title}'#{style} | #{out}"
end
out
}
output << "| #{author_totals[aut]}"
end
output << '|-'
output << "! style='text-align: right;' | Total submitted"
output += all_submitters.map{|sub| "| #{submitter_totals[sub]}" }
output << "| style='background-color: lightgray;' | #{prolific_only ? '' : submitter_totals.values.inject(:+)}"
output << "|}"
puts "This is a collaboration matrix for master branch of the mediawiki/core repository.
#{prolific_only ?
'This matrix only includes contributors with 100 actions or more. See also [[User:Matma Rex/Collaborations|the full version]].' :
'See also [[User:Matma Rex/Collaborations/Prolific|matrix of the most prolific contributors only]].'}
Commit authors are listed in rows, commit reviewers are listed in columns. Each table cell
represents the number of patches made by given author that were accepted by given reviewer. Empty
cell signifies 0 commits, grey cells are the ones where the author and reviewer is the same person,
bold cells are the ones where the value is more than 9.
Last updated #{Time.now.strftime '%Y-%m-%d'}.
#{output.join "\n"}
[[Category:Statistics]]"