#!/usr/bin/env ruby
#
# Enforce rules of good commit message style
# http://chris.beams.io/posts/git-commit/#seven-rules

message_file = ARGV[0]
full_message = File.read(message_file)
message_lines = full_message.split("\n")
# Omit comment lines - they don't need to be validated!
message_lines = message_lines.select { |i| i.empty? || i[/^[^#]/] }

$errors = 0 # rubocop:disable Style/GlobalVars

def failure(msg)
  if STDOUT.tty?
    puts "\t...[ \033[31mFAIL\033[0m ] #{msg}"
  else
    puts msg
  end
  $errors += 1 # rubocop:disable Style/GlobalVars
end

# 1. Separate subject from body with a blank line
if message_lines.length > 1
  unless message_lines[1].empty?
    failure 'Separate subject (first line) from body with a blank line'
  end
end

# 2. Limit the subject line to 50 characters
if message_lines.first.length > 50
  failure 'First line of commit message should be no more than 50 characters'
  puts message_lines.first
  puts '^' * 50
end

# 3. Capitalize the subject line
unless message_lines.first =~ /^[A-Z]/
  failure 'Begin commit message subject line with a capital letter'
end

# 4. Do not end the subject line with a period
if message_lines.first =~ /[!.,;]\s*$/
  failure 'Do not end the subject line with punctuation'
end

# 5. Use the imperative mood in the subject line
# This is very hard to enforce by automation, so
# let's just check some likely cases:
non_imperatives = [/adds$/,
                   /added$/,
                   /change[ds]$/,
                   /fixe[ds]$/,
                   /merge[ds]$/,
                   /remove[ds]$/,
                   /update[ds]$/,
                  ]
s = message_lines.first.split(' ').first.downcase
if non_imperatives.any? { |re| re.match(s) }
  failure 'Use the imperative mood in the subject line'
end

# 6. Wrap the body at 72 characters
if message_lines.any? { |line| line.length > 72 }
  failure 'Wrap the body at 72 characters'
  puts '-' * 72
  puts message_lines.select { |line| line.length > 72 }.join("\n")
  puts '-' * 72
end

# 7. Use the body to explain what and why vs. how
# The user will just need to exercise judgment on this one :)

if $errors > 0 # rubocop:disable Style/GlobalVars
  puts 'Rejected commit message:'
  puts '{'
  puts message_lines.join("\n")
  puts '}'

  fd = IO.sysopen('/dev/tty', 'w+')
  a = IO.new(fd, 'w+')
  a.puts 'Continue anyway? [y/N] '
  response = a.gets.chomp
  # rubocop:disable Style/GlobalVars
  $errors = 0 if response.downcase[0] == 'y'
  # rubocop:enable Style/GlobalVars
end

exit $errors # rubocop:disable Style/GlobalVars
