class Schmersion::Linter

Public Class Methods

new(repo) click to toggle source
# File lib/schmersion/linter.rb, line 9
def initialize(repo)
  @repo = repo
end

Public Instance Methods

prepare(path, source = nil) click to toggle source
# File lib/schmersion/linter.rb, line 13
def prepare(path, source = nil)
  previous_commit_message = read_previous_commit_message

  return unless source.nil?

  unless File.file?(path)
    raise Error, "No commit message file at the given path (#{path})"
  end

  lines = []

  if previous_commit_message
    lines << previous_commit_message
    lines << ''
  else
    lines << "\n"
  end

  lines << '# ====================================================================='
  lines << '# Commit messages must conform to conventional commit formatting.'
  lines << '# This means each commit message must be prefixed with an appropriate'
  lines << '# type and, optionally, a scope. Your message will be validated before'
  lines << '# the commit will be created. '
  lines << '#'

  add_list_for(lines, :types)

  unless @repo.config.scopes.empty?
    lines << '#'
    add_list_for(lines, :scopes)
  end

  lines << '# ====================================================================='

  lines = lines.join("\n")

  contents = File.read(path)
  File.write(path, "#{lines}\n#\n#{contents.strip}")
end
setup(force: false) click to toggle source
# File lib/schmersion/linter.rb, line 73
def setup(force: false)
  create_hook('lint-prepare', 'prepare-commit-msg', force: force)
  create_hook('lint-validate', 'commit-msg', force: force)
end
validate_file(path) click to toggle source
# File lib/schmersion/linter.rb, line 53
def validate_file(path)
  unless File.file?(path)
    raise Error, "No commit message file at the given path (#{path})"
  end

  contents = get_commit_message_from_file(File.read(path))
  return [] if contents.length.zero?

  message = Message.new(contents)

  validator = MessageValidator.new(@repo.config, message)

  unless validator.valid?
    # Save the commit message to a file if its invalid.
    save_commit_message(contents)
  end

  validator.errors
end

Private Instance Methods

add_list_for(lines, type) click to toggle source
# File lib/schmersion/linter.rb, line 93
def add_list_for(lines, type)
  lines << "# The following #{type.to_s.upcase} are available to choose from:"
  lines << '#'
  @repo.config.public_send(type).sort.each_slice(3) do |names|
    types = names.map { |t| " * #{t.to_s.ljust(16)}" }.join
    lines << "# #{types}".strip
  end
end
create_hook(command, name, force: false) click to toggle source
# File lib/schmersion/linter.rb, line 135
def create_hook(command, name, force: false)
  hook_path = File.join(@repo.path, '.git', 'hooks', name)
  if File.file?(hook_path) && !force
    raise Error, "Cannot install hook into #{name} because a hook file already exists."
  end

  File.write(hook_path, hook_file_contents(command))
  FileUtils.chmod('u+x', hook_path)
  hook_path
end
development?() click to toggle source
# File lib/schmersion/linter.rb, line 119
def development?
  !File.file?(File.join(schmersion_root, 'VERSION'))
end
get_commit_message_from_file(contents) click to toggle source
# File lib/schmersion/linter.rb, line 102
def get_commit_message_from_file(contents)
  contents = contents.split('------------------------ >8 ------------------------', 2)[0]
  contents.split("\n").reject { |l| l.start_with?('#') }.join("\n").strip
end
hook_file_contents(command) click to toggle source
# File lib/schmersion/linter.rb, line 127
    def hook_file_contents(command)
      <<~FILE
        #!/usr/bin/env bash

        #{path_to_schmersion} #{command} $1 $2 $3
      FILE
    end
path_to_schmersion() click to toggle source

Returns the path to schmersion for use in commit files. For production installs, we'll just call it `schmersion` and hope that it is included in the path. For development, we'll use the path to the binary in repository.

# File lib/schmersion/linter.rb, line 111
def path_to_schmersion
  if development?
    return File.join(schmersion_root, 'bin', 'schmersion')
  end

  'schmersion'
end
read_previous_commit_message() click to toggle source
# File lib/schmersion/linter.rb, line 80
def read_previous_commit_message
  path = '.git/SCHMERSION_EDITMSG'
  return unless File.file?(path)

  contents = File.read(path)
  FileUtils.rm(path)
  contents
end
save_commit_message(message) click to toggle source
# File lib/schmersion/linter.rb, line 89
def save_commit_message(message)
  File.write('.git/SCHMERSION_EDITMSG', message)
end
schmersion_root() click to toggle source
# File lib/schmersion/linter.rb, line 123
def schmersion_root
  File.expand_path('../../', __dir__)
end