require "ruby_git_hooks"
class CopyrightCheckHook < RubyGitHooks::Hook
COPYRIGHT_REGEXP = /Copyright\s+\(C\)\s*(?<pre_year>.*)-?(?<cur_year>\d{4})\s+(?<company>.+)/i
EXTENSIONS = [
"c", "cpp", "cc", "cp",
"h", "hp", "hpp",
"m", "mm",
"java",
"bat",
"sh",
"ps1",
"rb",
]
OPTIONS = [ "domain", "from", "subject", "via", "via_options", "intro",
"no_send", "company_check", "exclude_files" ]
Hook = RubyGitHooks::Hook
attr_accessor :cur_year
def initialize(options = {})
bad_options = options.keys - OPTIONS
raise "CopyrightCheckHook created with unrecognized options: " +
"#{bad_options.inspect}!" if bad_options.size > 0
@options = options
@options["domain"] ||= "mydomain.com"
@options["from"] ||= "Copyright Cop <noreply@#{@options["domain"]}>"
@options["subject"] ||= "Copyright Your Files, Please!"
@options["via"] ||= "no_send"
@options["via_options"] ||= {}
@options["exclude_files"] ||= [] @cur_year = Time.now.strftime("%Y")
end
def check
no_notice = []
outdated_notice = []
outdated_company = []
cur_year = Time.now.strftime("%Y")
files_changed.each do |filename|
extension = (filename.split(".") || [])[-1]
next unless EXTENSIONS.include?(extension)
next if file_contents[filename] == "" next if @options["exclude_files"].include? filename
if file_contents[filename] =~ COPYRIGHT_REGEXP
parsed_cur_year = $~["cur_year"]
parsed_company = $~["company"]
unless parsed_cur_year == cur_year
outdated_notice << filename
end
if @options["company_check"] &&
!(parsed_company[@options["company_check"]])
outdated_company << filename
end
else
no_notice << filename
end
end
bad_num = no_notice.size + outdated_notice.size + outdated_company.size
return true if bad_num < 1
desc = build_description(no_notice, outdated_notice, outdated_company)
recipients = {}
self.commits.each do |commit|
author = Hook.shell!("git log -n 1 --pretty=format:\"%aE %aN\" #{commit}")
email, name = author.chomp.split(" ", 2)
recipients[name] = email
end
STDERR.puts "Warnings for commit from Copyright Check:\n--#{desc}\n--"
unless @options["no_send"] || @options["via"] == "no_send"
require "pony" recipients.each do |name, email|
email_str = "#{name} <#{email}>"
STDERR.puts "Sending warning email to #{email_str}"
ret = Pony.mail :to => email_str,
:from => @options["from"],
:subject => @options["subject"],
:body => desc,
:via => @options["via"],
:via_options => @options["via_options"]
end
end
false
end
protected
def commit_list
self.commits.map {|c| c[0..6]}.join(", ")
end
def current_repo
full_path = Hook.shell!("git rev-parse --show-toplevel").chomp
File.basename full_path.sub(/.git\z/, "")
end
def build_description(no_notice, outdated_notice, outdated_company)
description = @options["intro"] || ""
description.concat <<DESCRIPTION
In repository: #{current_repo}
commit(s): #{commit_list}
You have outdated, inaccurate or missing copyright notices.
Specifically:
=============
DESCRIPTION
if outdated_notice.size > 0
description.concat <<DESCRIPTION
The following files do not list #{cur_year} as the most recent copyright year:
#{outdated_notice.join("\n ")}
-----
DESCRIPTION
end
if outdated_company.size > 0
description.concat <<DESCRIPTION
The following files do not properly list your company as the holder of copyright:
#{outdated_company.join("\n ")}
DESCRIPTION
end
if no_notice.size > 0
description.concat <<DESCRIPTION
The following files have no notice or a notice I didn't recognize:
#{no_notice.join("\n ")}
DESCRIPTION
end
description
end
end