fit-commit 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 81b67790de7d999eae5047a8acb714c14257f91d
4
+ data.tar.gz: 57e990996a4c9e9d704d483730cbc85ce2b46e65
5
+ SHA512:
6
+ metadata.gz: 621591bb43cd64e82dd41161c3375bf6bdabc1a3487899151e52837bbee44cbf149a030529d3a1129632c88609e75e9e5cd4ec01fa054b21e3240efbcf096e50
7
+ data.tar.gz: abb255557aa5b523d4ee9fa21eb1a46dd48362013536f3d93dc54d850032589bcf56fbf76311d1a7c4db3287f1324ef1532e9d6dead1496eef718add794615ec
data/.gitignore ADDED
@@ -0,0 +1,25 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+ /bin/
12
+
13
+ ## Environment normalisation:
14
+ /.bundle/
15
+ /vendor/bundle
16
+ /lib/bundler/man/
17
+
18
+ # for a library or gem, you might want to ignore these files since the code is
19
+ # intended to run in multiple environments; otherwise, check them in:
20
+ # Gemfile.lock
21
+ # .ruby-version
22
+ # .ruby-gemset
23
+
24
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
25
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,25 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fit-commit (1.0.0)
5
+ swearjar (~> 1.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ fuzzyhash (0.0.11)
11
+ minitest (5.8.0)
12
+ rake (10.4.2)
13
+ swearjar (1.0.0)
14
+ fuzzyhash (~> 0.0.11)
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ fit-commit!
21
+ minitest (~> 5.8)
22
+ rake (~> 10.4)
23
+
24
+ BUNDLED WITH
25
+ 1.10.6
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Mike Foley
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # Fit Commit
2
+
3
+ A Git hook to validate your commit messages, based largely on Tim Pope's [authoritative guide](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
4
+
5
+ ## Example
6
+
7
+ ```
8
+ $ git commit
9
+ Adding a cool feature
10
+ foobar foobar foobar,
11
+ foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar
12
+
13
+ 1: Error: Message must use present imperative tense.
14
+ 2: Error: Second line must be blank.
15
+ 3: Error: Lines should be <= 72 chars. (76)
16
+
17
+ Force commit? [y/n] ▊
18
+ ```
19
+
20
+ ## Prerequisites
21
+
22
+ * Ruby
23
+
24
+ ## Installation
25
+
26
+ Install the gem:
27
+
28
+ $ gem install fit-commit
29
+
30
+ Install the hook in your Git repo:
31
+
32
+ $ fit-commit install
33
+
34
+ This creates a `.git/hooks/commit-msg` script which will automatically check your Git commit messages.
35
+
36
+ ## Validations
37
+
38
+ * **Line Length**: All lines must be <= 72 chars (URLs excluded). First line should be <= 50 chars. Second line must be blank.
39
+ * **Tense**: Message must use present imperative tense.
40
+ * **Summary Period**: Do not end your summary with a period.
41
+ * **WIP**: Do not commit WIPs to master.
42
+ * **Frat House**: No frat house commit messages in master.
43
+
44
+ ## Credits
45
+
46
+ Author: [Mike Foley](https://github.com/m1foley)
47
+
48
+ Inspiration taken from: [Tim Pope](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), [Jason Fox](https://gist.github.com/jasonrobertfox/8057124), [Addam Hardy](http://addamhardy.com/blog/2013/06/05/good-commit-messages-and-enforcing-them-with-git-hooks/), [pre-commit](https://github.com/jish/pre-commit)
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |test|
5
+ test.libs << "test"
6
+ test.pattern = "test/**/*_test.rb"
7
+ test.verbose = false
8
+ end
9
+
10
+ task :default => :test
data/TODO.txt ADDED
@@ -0,0 +1 @@
1
+ - Configuration to disable validations.
data/bin/fit-commit ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fit-commit/cli'
4
+
5
+ if !File.exists?(".git")
6
+ abort "No .git directory found."
7
+ end
8
+
9
+ FitCommit::Cli.new(*ARGV).execute or exit 1
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/fit-commit/version", __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "fit-commit"
6
+ gem.version = FitCommit::VERSION
7
+ gem.license = "MIT"
8
+ gem.authors = ["Michael Foley"]
9
+ gem.email = ["foley3@gmail.com"]
10
+ gem.homepage = "https://github.com/m1foley/fit-commit"
11
+ gem.summary = "A Git hook to validate your commit messages"
12
+ gem.description = "A Git hook to validate your commit messages, based largely on Tim Pope's authoritative guide."
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.executables = ["fit-commit"]
15
+ gem.default_executable = "fit-commit"
16
+ gem.test_files = `git ls-files -- test/*`.split("\n")
17
+ gem.require_paths = ["lib"]
18
+ gem.extra_rdoc_files = ["README.md"]
19
+ gem.rdoc_options = ["--main", "README.md"]
20
+
21
+ gem.post_install_message == <<-EOF
22
+ Thank you for installing fit-commit!
23
+ Install the hook in each git repo you want to scan using:
24
+
25
+ > fit-commit install
26
+
27
+ Read more: https://github.com/m1foley/fit-commit#readme
28
+ EOF
29
+
30
+ gem.add_dependency("swearjar", "~> 1.0")
31
+ gem.add_development_dependency("minitest", "~> 5.8")
32
+ gem.add_development_dependency("rake", "~> 10.4")
33
+ end
@@ -0,0 +1,20 @@
1
+ require "fit-commit/installer"
2
+
3
+ module FitCommit
4
+ class Cli
5
+ attr_accessor :args
6
+ def initialize(*args)
7
+ self.args = args
8
+ end
9
+
10
+ def execute
11
+ action_name = args.shift
12
+ if action_name == "install"
13
+ FitCommit::Installer.new.install
14
+ else
15
+ warn "Usage: fit-commit install"
16
+ false
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,36 @@
1
+ # Mixin for adding errors & warnings
2
+ module FitCommit
3
+ module HasErrors
4
+ def errors
5
+ @errors ||= Hash.new([])
6
+ end
7
+
8
+ def warnings
9
+ @warnings ||= Hash.new([])
10
+ end
11
+
12
+ def add_error(lineno, message)
13
+ errors[lineno] += [message]
14
+ end
15
+
16
+ def add_warning(lineno, message)
17
+ warnings[lineno] += [message]
18
+ end
19
+
20
+ def merge_errors(other_errors)
21
+ merge_hashes(errors, other_errors)
22
+ end
23
+
24
+ def merge_warnings(other_warnings)
25
+ merge_hashes(warnings, other_warnings)
26
+ end
27
+
28
+ private
29
+
30
+ def merge_hashes(error_hash, other_hash)
31
+ error_hash.merge!(other_hash) do |_lineno, messages, other_messages|
32
+ messages + other_messages
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,29 @@
1
+ require "fileutils"
2
+
3
+ module FitCommit
4
+ class Installer
5
+ HOOK_TEMPLATE_PATH = File.expand_path("../../../templates/hooks/commit-msg", __FILE__)
6
+
7
+ def install
8
+ FileUtils.mkdir_p(File.dirname(hook_path))
9
+ FileUtils.cp(HOOK_TEMPLATE_PATH, hook_path)
10
+ FileUtils.chmod(0755, hook_path)
11
+ puts "Installed hook to #{hook_path}"
12
+ true
13
+ end
14
+
15
+ private
16
+
17
+ def hook_path
18
+ @hook_path ||= File.join(gitdir, "hooks/commit-msg")
19
+ end
20
+
21
+ def gitdir
22
+ if File.directory?(".git")
23
+ ".git"
24
+ else
25
+ File.readlines(".git").first.match(/gitdir: (.*)$/)[1]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ # Represents a line from the commit
2
+ module FitCommit
3
+ class Line
4
+ attr_accessor :lineno, :text
5
+ def initialize(lineno, text)
6
+ self.lineno = lineno
7
+ self.text = text
8
+ end
9
+
10
+ def to_s
11
+ text
12
+ end
13
+
14
+ def empty?
15
+ text.empty?
16
+ end
17
+
18
+ def self.from_array(text_array)
19
+ text_array.map.with_index(1) { |text, lineno| new(lineno, text) }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,83 @@
1
+ require "fit-commit/has_errors"
2
+ require "fit-commit/line"
3
+
4
+ module FitCommit
5
+ class Runner
6
+ include FitCommit::HasErrors
7
+
8
+ attr_accessor :message_path, :branch_name, :stdout, :stdin
9
+ def initialize(message_path, branch_name, stdout = $stdout, stdin = $stdin)
10
+ self.message_path = message_path
11
+ self.branch_name = branch_name
12
+ self.stdout = stdout
13
+ self.stdin = stdin
14
+ end
15
+
16
+ def run
17
+ return true if empty_commit?
18
+ run_validators
19
+ return true if [errors, warnings].all?(&:empty?)
20
+ print_results
21
+
22
+ allow_commit = errors.empty?
23
+ unless allow_commit
24
+ stdout.print "\nForce commit? [y/n] "
25
+ return false unless stdin.gets =~ /y/i
26
+ allow_commit = true
27
+ end
28
+
29
+ stdout.print "\n"
30
+ allow_commit
31
+ rescue Interrupt # Ctrl-c
32
+ false
33
+ end
34
+
35
+ private
36
+
37
+ def run_validators
38
+ Dir[File.dirname(__FILE__) + "/validators/*.rb"].each { |file| require file }
39
+ FitCommit::Validators::Base.all.each do |validator_class|
40
+ validator = validator_class.new(lines, branch_name)
41
+ validator.validate
42
+ merge_errors(validator.errors)
43
+ merge_warnings(validator.warnings)
44
+ end
45
+ end
46
+
47
+ def print_results
48
+ unless errors.empty?
49
+ stdout.puts lines
50
+ stdout.print "\n"
51
+ end
52
+
53
+ (errors.keys | warnings.keys).sort.each do |lineno|
54
+ errors[lineno].each do |error|
55
+ stdout.puts "#{lineno}: Error: #{error}"
56
+ end
57
+ warnings[lineno].each do |warning|
58
+ stdout.puts "#{lineno}: Warning: #{warning}"
59
+ end
60
+ end
61
+ end
62
+
63
+ def lines
64
+ @lines ||= FitCommit::Line.from_array(relevant_message_lines)
65
+ end
66
+
67
+ def relevant_message_lines
68
+ message_text.lines.map(&:chomp).reject(&method(:comment?))
69
+ end
70
+
71
+ def message_text
72
+ File.open(message_path, "r").read
73
+ end
74
+
75
+ def comment?(text)
76
+ text =~ /\A#/
77
+ end
78
+
79
+ def empty_commit?
80
+ lines.all?(&:empty?)
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,33 @@
1
+ require "fit-commit/has_errors"
2
+
3
+ module FitCommit
4
+ module Validators
5
+ class Base
6
+ include FitCommit::HasErrors
7
+
8
+ attr_accessor :lines, :branch_name
9
+ def initialize(lines, branch_name)
10
+ self.lines = lines
11
+ self.branch_name = branch_name
12
+ end
13
+
14
+ @all = []
15
+ class << self
16
+ attr_accessor :all
17
+ def inherited(subclass)
18
+ all << subclass
19
+ end
20
+ end
21
+
22
+ def validate
23
+ lines.each do |line|
24
+ validate_line(line.lineno, line.text, branch_name)
25
+ end
26
+ end
27
+
28
+ def validate_line(*)
29
+ fail NotImplementedError, "Implement in subclass"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,14 @@
1
+ require "fit-commit/validators/base"
2
+ require "swearjar"
3
+
4
+ module FitCommit
5
+ module Validators
6
+ class Frathouse < Base
7
+ def validate_line(lineno, text, branch_name)
8
+ if branch_name == "master" && Swearjar.default.profane?(text)
9
+ add_error(lineno, "No frat house commit messages in master.")
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,32 @@
1
+ require "fit-commit/validators/base"
2
+
3
+ module FitCommit
4
+ module Validators
5
+ class LineLength < Base
6
+ FIRST_LINE_MAX_LENGTH = 50
7
+ LINE_MAX_LENGTH = 72
8
+
9
+ def validate_line(lineno, text, _branch_name)
10
+ if lineno == 1 && text.empty?
11
+ add_error(lineno, "First line cannot be blank.")
12
+ elsif lineno == 2 && !text.empty?
13
+ add_error(lineno, "Second line must be blank.")
14
+ elsif line_too_long?(text)
15
+ add_error(lineno, format("Lines should be <= %i chars. (%i)",
16
+ LINE_MAX_LENGTH, text.length))
17
+ elsif lineno == 1 && text.length > FIRST_LINE_MAX_LENGTH
18
+ add_warning(lineno, format("First line should be <= %i chars. (%i)",
19
+ FIRST_LINE_MAX_LENGTH, text.length))
20
+ end
21
+ end
22
+
23
+ def line_too_long?(text)
24
+ text.length > 72 && !contains_url?(text)
25
+ end
26
+
27
+ def contains_url?(text)
28
+ text =~ %r{[a-z]+://}
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,13 @@
1
+ require "fit-commit/validators/base"
2
+
3
+ module FitCommit
4
+ module Validators
5
+ class SummaryPeriod < Base
6
+ def validate_line(lineno, text, branch_name)
7
+ if lineno == 1 && text.end_with?(".")
8
+ add_error(lineno, "Do not end your summary with a period.")
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,78 @@
1
+ require "fit-commit/validators/base"
2
+
3
+ module FitCommit
4
+ module Validators
5
+ class Tense < Base
6
+ VERB_BLACKLIST = %w(
7
+ adds adding added
8
+ allows allowing allowed
9
+ amends amending amended
10
+ bumps bumping bumped
11
+ calculates calculating calculated
12
+ changes changing changed
13
+ cleans cleaning cleaned
14
+ commits committing committed
15
+ corrects correcting corrected
16
+ creates creating created
17
+ darkens darkening darkened
18
+ disables disabling disabled
19
+ displays displaying displayed
20
+ drys drying dryed
21
+ ends ending ended
22
+ enforces enforcing enforced
23
+ enqueues enqueuing enqueued
24
+ extracts extracting extracted
25
+ finishes finishing finished
26
+ fixes fixing fixed
27
+ formats formatting formatted
28
+ guards guarding guarded
29
+ handles handling handled
30
+ hides hiding hid
31
+ increases increasing increased
32
+ ignores ignoring ignored
33
+ implements implementing implemented
34
+ improves improving improved
35
+ keeps keeping kept
36
+ kills killing killed
37
+ makes making made
38
+ merges merging merged
39
+ moves moving moved
40
+ permits permitting permitted
41
+ prevents preventing prevented
42
+ pushes pushing pushed
43
+ rebases rebasing rebased
44
+ refactors refactoring refactored
45
+ removes removing removed
46
+ renames renaming renamed
47
+ reorders reordering reordered
48
+ requires requiring required
49
+ restores restoring restored
50
+ sends sending sent
51
+ sets setting
52
+ separates separating separated
53
+ shows showing showed
54
+ skips skipping skipped
55
+ sorts sorting
56
+ speeds speeding sped
57
+ starts starting started
58
+ supports supporting supported
59
+ takes taking took
60
+ tests testing tested
61
+ truncates truncating truncated
62
+ updates updating updated
63
+ uses using used
64
+ )
65
+
66
+ def validate_line(lineno, text, _branch_name)
67
+ if lineno == 1 && wrong_tense?(text)
68
+ add_error(lineno, "Message must use present imperative tense.")
69
+ end
70
+ end
71
+
72
+ def wrong_tense?(text)
73
+ first_word = text.split.first(2).detect { |w| w =~ /\A\w/ }
74
+ first_word && VERB_BLACKLIST.include?(first_word.downcase)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,14 @@
1
+ require "fit-commit/validators/base"
2
+
3
+ module FitCommit
4
+ module Validators
5
+ class Wip < Base
6
+ def validate_line(lineno, text, branch_name)
7
+ if lineno == 1 && branch_name == "master" &&
8
+ text.split.any? { |word| word == "WIP" }
9
+ add_error(lineno, "Do not commit WIPs to master.")
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module FitCommit
2
+ VERSION = "1.0.1"
3
+ end
data/lib/fit-commit.rb ADDED
@@ -0,0 +1,21 @@
1
+ require "fit-commit/runner"
2
+
3
+ module FitCommit
4
+ def self.run
5
+ runner.run || exit(1)
6
+ end
7
+
8
+ private
9
+
10
+ def self.runner
11
+ FitCommit::Runner.new(message_path, branch_name)
12
+ end
13
+
14
+ def self.message_path
15
+ ENV.fetch("COMMIT_MESSAGE_PATH")
16
+ end
17
+
18
+ def self.branch_name
19
+ `git branch | grep '^\*' | cut -b3-`.strip
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env sh
2
+ #
3
+ # This hook will attempt to setup your environment before running checks.
4
+
5
+ if which rvm >/dev/null 2>/dev/null
6
+ then cmd="rvm default do ruby"
7
+ elif which rbenv >/dev/null 2>/dev/null
8
+ then cmd="rbenv exec ruby"
9
+ else cmd="ruby"
10
+ fi
11
+
12
+ export COMMIT_MESSAGE_PATH=$1
13
+
14
+ ${cmd} -rrubygems -e '
15
+ begin
16
+ require "fit-commit"
17
+ true
18
+ rescue LoadError => e
19
+ $stderr.puts <<-MESSAGE
20
+ fit-commit: WARNING: Skipping checks because: #{e}
21
+ fit-commit: Did you set your Ruby version?
22
+ MESSAGE
23
+ false
24
+ end and FitCommit.run
25
+ ' < /dev/tty
@@ -0,0 +1,81 @@
1
+ require "minitest/autorun"
2
+ require "fit-commit/runner"
3
+
4
+ describe FitCommit::Runner do
5
+ after do
6
+ commit_msg_file.unlink
7
+ end
8
+
9
+ def call_runner
10
+ allow_commit = runner.run
11
+ stdout.rewind
12
+ allow_commit
13
+ end
14
+
15
+ let(:commit_msg_file) do
16
+ Tempfile.new("test-commit-msg").tap do |f|
17
+ f.write(commit_msg)
18
+ f.close
19
+ end
20
+ end
21
+ let(:stdout) { StringIO.new }
22
+ let(:stdin) { StringIO.new }
23
+ let(:branch_name) { "any" }
24
+ let(:runner) do
25
+ FitCommit::Runner.new(commit_msg_file.path, branch_name, stdout, stdin)
26
+ end
27
+
28
+ describe "empty commit msg" do
29
+ let(:commit_msg) { "" }
30
+ it "returns truthy value without printing to stdout" do
31
+ assert call_runner
32
+ assert stdout.read.empty?
33
+ end
34
+ end
35
+
36
+ describe "commit msg consists of all comments" do
37
+ let(:commit_msg) { "\n#hi\n#yo" }
38
+ it "returns truthy value without printing to stdout" do
39
+ assert call_runner
40
+ assert stdout.read.empty?
41
+ end
42
+ end
43
+
44
+ describe "commit msg is present but no errors" do
45
+ let(:commit_msg) { "hello\n\nhi\n#" }
46
+ it "returns truthy value without printing to stdout" do
47
+ assert call_runner
48
+ assert stdout.read.empty?
49
+ end
50
+ end
51
+
52
+ describe "commit msg contains errors" do
53
+ let(:commit_msg) { "foo.\nbar" }
54
+
55
+ def assert_error_output
56
+ stdout_lines = stdout.read.lines.map(&:chomp)
57
+ assert_equal 7, stdout_lines.size
58
+ assert_equal commit_msg, stdout_lines[0..1].join("\n")
59
+ assert_empty stdout_lines[2]
60
+ assert_match(/\A1: Error: /, stdout_lines[3])
61
+ assert_match(/\A2: Error: /, stdout_lines[4])
62
+ assert_empty stdout_lines[5]
63
+ assert_equal "Force commit? [y/n] ", stdout_lines[6]
64
+ end
65
+
66
+ describe "user does not force commit" do
67
+ let(:stdin) { StringIO.new("n") }
68
+ it "prints errors to stdout and returns falsey value" do
69
+ assert !call_runner
70
+ assert_error_output
71
+ end
72
+ end
73
+ describe "user forces commit" do
74
+ let(:stdin) { StringIO.new("y") }
75
+ it "prints errors to stdout and returns truthy value" do
76
+ assert call_runner
77
+ assert_error_output
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,47 @@
1
+ require "minitest/autorun"
2
+ require "fit-commit/validators/frathouse"
3
+
4
+ describe FitCommit::Validators::Frathouse do
5
+ let(:validator) { FitCommit::Validators::Frathouse.new(commit_lines, branch_name) }
6
+ let(:commit_lines) { FitCommit::Line.from_array(commit_msg.split("\n")) }
7
+
8
+ describe "master branch" do
9
+ let(:branch_name) { "master" }
10
+ describe "contains swear word" do
11
+ let(:commit_msg) { "fucking foobar" }
12
+ it "has error" do
13
+ validator.validate
14
+ assert_equal 1, validator.errors[1].size
15
+ assert_empty validator.warnings
16
+ end
17
+ end
18
+ describe "contains swear words on multiple lines" do
19
+ let(:commit_msg) { "damn\n\nIE7 is fucking bullshit!" }
20
+ it "has 1 error per line" do
21
+ validator.validate
22
+ assert_equal 1, validator.errors[1].size
23
+ assert_equal 1, validator.errors[3].size
24
+ assert_empty validator.warnings
25
+ end
26
+ end
27
+ describe "does not contain swear words" do
28
+ let(:commit_msg) { "foo" }
29
+ it "does not have errors/warnings" do
30
+ validator.validate
31
+ assert_empty validator.errors
32
+ assert_empty validator.warnings
33
+ end
34
+ end
35
+ end
36
+ describe "not master branch" do
37
+ let(:branch_name) { "notmaster" }
38
+ describe "contains swear word" do
39
+ let(:commit_msg) { "fucking foo" }
40
+ it "does not have errors/warnings" do
41
+ validator.validate
42
+ assert_empty validator.errors
43
+ assert_empty validator.warnings
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,107 @@
1
+ require "minitest/autorun"
2
+ require "fit-commit/validators/line_length"
3
+
4
+ describe FitCommit::Validators::LineLength do
5
+ let(:validator) { FitCommit::Validators::LineLength.new(commit_lines, branch_name) }
6
+ let(:commit_lines) { FitCommit::Line.from_array(commit_msg.split("\n")) }
7
+
8
+ let(:branch_name) { "any" }
9
+
10
+ describe "first line" do
11
+ describe "first line is empty" do
12
+ let(:commit_msg) { "\n\nbar" }
13
+ it "has error" do
14
+ validator.validate
15
+ assert_equal 1, validator.errors[1].size
16
+ assert_empty validator.warnings
17
+ end
18
+ end
19
+ describe "first line is not empty" do
20
+ let(:commit_msg) { "foo\n\nbar" }
21
+ it "does not have error" do
22
+ validator.validate
23
+ assert_empty validator.errors
24
+ assert_empty validator.warnings
25
+ end
26
+ end
27
+ describe "first line is over warning limit" do
28
+ let(:commit_msg) do
29
+ "x" * (FitCommit::Validators::LineLength::FIRST_LINE_MAX_LENGTH + 1)
30
+ end
31
+ it "has a warning" do
32
+ validator.validate
33
+ assert_empty validator.errors
34
+ assert_equal 1, validator.warnings[1].size
35
+ end
36
+ end
37
+ describe "first line is over error limit" do
38
+ let(:commit_msg) do
39
+ "x" * (FitCommit::Validators::LineLength::LINE_MAX_LENGTH + 1)
40
+ end
41
+ it "has an error and no warning" do
42
+ validator.validate
43
+ assert_equal 1, validator.errors[1].size
44
+ assert_empty validator.warnings
45
+ end
46
+ end
47
+ end
48
+ describe "second line" do
49
+ describe "second line is not empty" do
50
+ let(:commit_msg) { "foo\nbar" }
51
+ it "has error" do
52
+ validator.validate
53
+ assert_equal 1, validator.errors[2].size
54
+ assert_empty validator.warnings
55
+ end
56
+ end
57
+ describe "second line is not empty and too long" do
58
+ let(:commit_msg) do
59
+ "foo\n" + ("x" * (FitCommit::Validators::LineLength::LINE_MAX_LENGTH + 1))
60
+ end
61
+ it "only mentions blank error" do
62
+ validator.validate
63
+ assert_equal 1, validator.errors[2].size
64
+ assert_match(/must be blank/, validator.errors[2][0])
65
+ assert_empty validator.warnings
66
+ end
67
+ end
68
+ describe "second line is empty" do
69
+ let(:commit_msg) { "foo\n\nbar" }
70
+ it "does not have error" do
71
+ validator.validate
72
+ assert_empty validator.errors
73
+ assert_empty validator.warnings
74
+ end
75
+ end
76
+ describe "does not have a second line" do
77
+ let(:commit_msg) { "foo" }
78
+ it "does not have error" do
79
+ validator.validate
80
+ assert_empty validator.errors
81
+ assert_empty validator.warnings
82
+ end
83
+ end
84
+ end
85
+ describe "body text" do
86
+ describe "line is over length limit" do
87
+ let(:commit_msg) do
88
+ "foo\n\n" + ("x" * (FitCommit::Validators::LineLength::LINE_MAX_LENGTH + 1))
89
+ end
90
+ it "has error" do
91
+ validator.validate
92
+ assert_equal 1, validator.errors[3].size
93
+ assert_empty validator.warnings
94
+ end
95
+ end
96
+ describe "line is equal to length limit" do
97
+ let(:commit_msg) do
98
+ "foo\n\n" + ("x" * FitCommit::Validators::LineLength::LINE_MAX_LENGTH)
99
+ end
100
+ it "does not have error" do
101
+ validator.validate
102
+ assert_empty validator.errors
103
+ assert_empty validator.warnings
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,25 @@
1
+ require "minitest/autorun"
2
+ require "fit-commit/validators/summary_period"
3
+
4
+ describe FitCommit::Validators::SummaryPeriod do
5
+ let(:validator) { FitCommit::Validators::SummaryPeriod.new(commit_lines, branch_name) }
6
+ let(:commit_lines) { FitCommit::Line.from_array(commit_msg.split("\n")) }
7
+ let(:branch_name) { "any" }
8
+
9
+ describe "summary ends with period" do
10
+ let(:commit_msg) { "foo bar." }
11
+ it "has error" do
12
+ validator.validate
13
+ assert_equal 1, validator.errors[1].size
14
+ assert_empty validator.warnings
15
+ end
16
+ end
17
+ describe "summary does not end with period" do
18
+ let(:commit_msg) { "foo bar\n\nhi." }
19
+ it "does not have errors/warnings" do
20
+ validator.validate
21
+ assert_empty validator.errors
22
+ assert_empty validator.warnings
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ require "minitest/autorun"
2
+ require "fit-commit/validators/tense"
3
+
4
+ describe FitCommit::Validators::Tense do
5
+ let(:validator) { FitCommit::Validators::Tense.new(commit_lines, branch_name) }
6
+ let(:commit_lines) { FitCommit::Line.from_array(commit_msg.split("\n")) }
7
+
8
+ let(:branch_name) { "anybranch" }
9
+
10
+ describe "uses incorrect tense on first line" do
11
+ let(:commit_msg) { "Changed something\nhi" }
12
+ it "has error" do
13
+ validator.validate
14
+ assert_equal 1, validator.errors[1].size
15
+ assert_empty validator.warnings
16
+ end
17
+ end
18
+
19
+ describe "uses incorrect tense on a line other than first line" do
20
+ let(:commit_msg) { "hi\nChanged something" }
21
+ it "does not have errors/warnings" do
22
+ validator.validate
23
+ assert_empty validator.errors
24
+ assert_empty validator.warnings
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,38 @@
1
+ require "minitest/autorun"
2
+ require "fit-commit/validators/wip"
3
+
4
+ describe FitCommit::Validators::Wip do
5
+ let(:validator) { FitCommit::Validators::Wip.new(commit_lines, branch_name) }
6
+ let(:commit_lines) { FitCommit::Line.from_array(commit_msg.split("\n")) }
7
+
8
+ describe "master branch" do
9
+ let(:branch_name) { "master" }
10
+ describe "contains WIP" do
11
+ let(:commit_msg) { "WIP foo" }
12
+ it "has error" do
13
+ validator.validate
14
+ assert_equal 1, validator.errors[1].size
15
+ assert_empty validator.warnings
16
+ end
17
+ end
18
+ describe "does not contain WIP" do
19
+ let(:commit_msg) { "foo" }
20
+ it "does not have errors/warnings" do
21
+ validator.validate
22
+ assert_empty validator.errors
23
+ assert_empty validator.warnings
24
+ end
25
+ end
26
+ end
27
+ describe "not master branch" do
28
+ let(:branch_name) { "notmaster" }
29
+ describe "contains WIP" do
30
+ let(:commit_msg) { "WIP foo" }
31
+ it "does not have errors/warnings" do
32
+ validator.validate
33
+ assert_empty validator.errors
34
+ assert_empty validator.warnings
35
+ end
36
+ end
37
+ end
38
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fit-commit
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Michael Foley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: swearjar
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.4'
55
+ description: A Git hook to validate your commit messages, based largely on Tim Pope's
56
+ authoritative guide.
57
+ email:
58
+ - foley3@gmail.com
59
+ executables:
60
+ - fit-commit
61
+ extensions: []
62
+ extra_rdoc_files:
63
+ - README.md
64
+ files:
65
+ - ".gitignore"
66
+ - Gemfile
67
+ - Gemfile.lock
68
+ - LICENSE
69
+ - README.md
70
+ - Rakefile
71
+ - TODO.txt
72
+ - bin/fit-commit
73
+ - fit-commit.gemspec
74
+ - lib/fit-commit.rb
75
+ - lib/fit-commit/cli.rb
76
+ - lib/fit-commit/has_errors.rb
77
+ - lib/fit-commit/installer.rb
78
+ - lib/fit-commit/line.rb
79
+ - lib/fit-commit/runner.rb
80
+ - lib/fit-commit/validators/base.rb
81
+ - lib/fit-commit/validators/frathouse.rb
82
+ - lib/fit-commit/validators/line_length.rb
83
+ - lib/fit-commit/validators/summary_period.rb
84
+ - lib/fit-commit/validators/tense.rb
85
+ - lib/fit-commit/validators/wip.rb
86
+ - lib/fit-commit/version.rb
87
+ - templates/hooks/commit-msg
88
+ - test/runner_test.rb
89
+ - test/validators/frathouse_test.rb
90
+ - test/validators/line_length_test.rb
91
+ - test/validators/summary_period_test.rb
92
+ - test/validators/tense_test.rb
93
+ - test/validators/wip_test.rb
94
+ homepage: https://github.com/m1foley/fit-commit
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options:
100
+ - "--main"
101
+ - README.md
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.2.3
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: A Git hook to validate your commit messages
120
+ test_files:
121
+ - test/runner_test.rb
122
+ - test/validators/frathouse_test.rb
123
+ - test/validators/line_length_test.rb
124
+ - test/validators/summary_period_test.rb
125
+ - test/validators/tense_test.rb
126
+ - test/validators/wip_test.rb
127
+ has_rdoc: