User:Matma Rex/Collaborations/collaborations.rb

From mediawiki.org
# coding: utf-8

def escape_wikitext text
	replacements = {
		'"' => '&#34;', '&' => '&#38;', "'" => '&#39;', '<' => '&#60;',
		'=' => '&#61;', '>' => '&#62;', '[' => '&#91;', ']' => '&#93;',
		'{' => '&#123;', '|' => '&#124;', '}' => '&#125;', ';' => '&#59;',
	}
	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]]"