fit-commit 3.7.0 → 3.8.3
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 +5 -5
- data/CHANGELOG.md +9 -0
- data/README.md +10 -4
- data/TODO.md +3 -0
- data/fit-commit.gemspec +4 -6
- data/lib/fit_commit/cli.rb +1 -1
- data/lib/fit_commit/configuration_loader.rb +30 -19
- data/lib/fit_commit/message_parser.rb +3 -3
- data/lib/fit_commit/runner.rb +1 -2
- data/lib/fit_commit/validator_loader.rb +3 -2
- data/lib/fit_commit/validators/capitalize_subject.rb +19 -3
- data/lib/fit_commit/validators/line_length.rb +20 -16
- data/lib/fit_commit/validators/tense.rb +1 -0
- data/lib/fit_commit/version.rb +1 -1
- data/templates/config/fit_commit.default.yml +1 -0
- data/test/integration/new_repo_test.rb +3 -3
- data/test/test_helper.rb +1 -1
- data/test/unit/configuration_loader_test.rb +78 -50
- data/test/unit/message_parser_test.rb +2 -6
- data/test/unit/runner_test.rb +2 -5
- data/test/unit/validator_loader_test.rb +28 -37
- data/test/unit/validators/capitalize_subject_test.rb +29 -1
- data/test/unit/validators/line_length_test.rb +16 -0
- metadata +13 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: df282f5ee34b3c0470ecfda368b8e4cdab62f0af1c11c9736bff1e5bfa579889
|
|
4
|
+
data.tar.gz: 93d726e9021c0b916ccea759a0af99aa23f692ae8463ca3d731216c65ba4406a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 97c4c3ff3edbdbc56e9e6b5f5bb73ea8ddf99ffce4dc17744f0a25f01f277c02eea184e435bd8bad4636aec9efd65851d81cb4a63d2960bd079d022ac027bfe4
|
|
7
|
+
data.tar.gz: 352773141ef5ed5d0c16e9d466810bf30de4a999e3d7f748833fcbf8a4bd545f44740597a0a41ec31de3c5fe65d422c95136b68b2232ddcf86c48215c1cddabd
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
### v3.8.0 (2018-08-06)
|
|
4
|
+
- Add CapitalizeSubject config option to warn on WIPlikes
|
|
5
|
+
|
|
6
|
+
### v3.7.0 (2017-01-07)
|
|
7
|
+
- Run via Bundler if available
|
|
8
|
+
|
|
9
|
+
### v3.6.0 (2016-11-18)
|
|
10
|
+
- Disable WIP check by default
|
|
11
|
+
|
|
3
12
|
### v3.5.0 (2016-04-05)
|
|
4
13
|
- All validations are enabled on all branches by default
|
|
5
14
|
|
data/README.md
CHANGED
|
@@ -61,6 +61,7 @@ Validators/SubjectPeriod:
|
|
|
61
61
|
Enabled: true
|
|
62
62
|
Validators/CapitalizeSubject:
|
|
63
63
|
Enabled: true
|
|
64
|
+
WarnOnWiplikes: true
|
|
64
65
|
Validators/Frathouse:
|
|
65
66
|
Enabled: true
|
|
66
67
|
Validators/Wip:
|
|
@@ -73,10 +74,10 @@ The `Enabled` property accepts multiple formats:
|
|
|
73
74
|
# true/false to enable/disable the validation (branch agnostic)
|
|
74
75
|
Validators/Foo:
|
|
75
76
|
Enabled: false
|
|
76
|
-
# Array of String
|
|
77
|
+
# Array of String or Regex matching each branch it's enabled on
|
|
77
78
|
Validators/Bar:
|
|
78
79
|
Enabled:
|
|
79
|
-
-
|
|
80
|
+
- main
|
|
80
81
|
- !ruby/regexp /\Afoo.+bar/
|
|
81
82
|
```
|
|
82
83
|
|
|
@@ -161,10 +162,15 @@ $ git init
|
|
|
161
162
|
Fit Commit can be run outside of a Git hook context with a simple shell script:
|
|
162
163
|
|
|
163
164
|
```sh
|
|
164
|
-
$ GIT_BRANCH_NAME=branch_name
|
|
165
|
+
$ export GIT_BRANCH_NAME=branch_name
|
|
166
|
+
$ export COMMIT_MESSAGE_PATH=path/to/message
|
|
167
|
+
# Using Bundler
|
|
168
|
+
$ bundle exec ruby -e 'require "fit_commit"; FitCommit.run'
|
|
169
|
+
# Not using Bundler
|
|
170
|
+
$ rbenv exec ruby -rrubygems -e 'require "fit_commit"; FitCommit.run'
|
|
165
171
|
```
|
|
166
172
|
|
|
167
|
-
It exits with an error code if any errors are present, which will fail a build if it's part of a CI run.
|
|
173
|
+
It exits with an error code if any errors are present, which will fail a build if it's part of a CI run.
|
|
168
174
|
|
|
169
175
|
### Who decided these rules?
|
|
170
176
|
Fit Commit aims to enforce *community standards*. The two influential guides are:
|
data/TODO.md
ADDED
data/fit-commit.gemspec
CHANGED
|
@@ -12,22 +12,20 @@ Gem::Specification.new do |gem|
|
|
|
12
12
|
gem.description = "A Git hook to validate your commit messages based on community standards."
|
|
13
13
|
gem.files = `git ls-files`.split("\n")
|
|
14
14
|
gem.executables = ["fit-commit"]
|
|
15
|
-
gem.default_executable = "fit-commit"
|
|
16
15
|
gem.test_files = `git ls-files -- test/*`.split("\n")
|
|
17
16
|
gem.require_paths = ["lib"]
|
|
18
17
|
gem.extra_rdoc_files = ["README.md"]
|
|
19
18
|
gem.rdoc_options = ["--main", "README.md"]
|
|
20
19
|
|
|
21
20
|
gem.post_install_message = <<-EOF
|
|
22
|
-
|
|
23
|
-
Install the hook in each git repo you want to scan using:
|
|
21
|
+
Install Fit Commit hooks in each git repo you want to scan using:
|
|
24
22
|
|
|
25
23
|
> fit-commit install
|
|
26
24
|
|
|
27
25
|
Read more: https://github.com/m1foley/fit-commit#readme
|
|
28
26
|
EOF
|
|
29
27
|
|
|
30
|
-
gem.add_dependency("swearjar", "~> 1.
|
|
31
|
-
gem.add_development_dependency("minitest", "~> 5.
|
|
32
|
-
gem.add_development_dependency("rake", "~>
|
|
28
|
+
gem.add_dependency("swearjar", "~> 1.4")
|
|
29
|
+
gem.add_development_dependency("minitest", "~> 5.14")
|
|
30
|
+
gem.add_development_dependency("rake", "~> 13.0")
|
|
33
31
|
end
|
data/lib/fit_commit/cli.rb
CHANGED
|
@@ -2,47 +2,58 @@ require "yaml"
|
|
|
2
2
|
|
|
3
3
|
module FitCommit
|
|
4
4
|
class ConfigurationLoader
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
SYSTEM_FILEPATH = "/etc/fit_commit.yml"
|
|
6
|
+
LOCAL_FILEPATH = ".fit_commit.yml"
|
|
7
|
+
|
|
8
|
+
def initialize(filepaths)
|
|
9
|
+
self.filepaths = filepaths
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.default_configuration
|
|
13
|
+
new(default_filepaths).configuration
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def configuration
|
|
17
|
+
filepaths.each_with_object({}) do |filepath, config|
|
|
7
18
|
config.merge!(read_config(filepath)) do |_key, oldval, newval|
|
|
8
19
|
oldval.merge(newval)
|
|
9
20
|
end
|
|
10
21
|
end
|
|
11
22
|
end
|
|
12
23
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
def self.default_filepaths
|
|
25
|
+
[
|
|
26
|
+
gem_default_filepath,
|
|
27
|
+
SYSTEM_FILEPATH,
|
|
28
|
+
user_filepath,
|
|
29
|
+
config_filepath,
|
|
30
|
+
LOCAL_FILEPATH
|
|
31
|
+
]
|
|
18
32
|
end
|
|
19
33
|
|
|
20
|
-
def
|
|
34
|
+
def self.gem_default_filepath
|
|
21
35
|
File.expand_path("../../../templates/config/fit_commit.default.yml", __FILE__)
|
|
22
36
|
end
|
|
23
37
|
|
|
24
|
-
def
|
|
25
|
-
"/etc/fit_commit.yml"
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def user_filepath
|
|
38
|
+
def self.user_filepath
|
|
29
39
|
File.join(ENV["HOME"], ".fit_commit.yml")
|
|
30
40
|
end
|
|
31
41
|
|
|
32
|
-
def config_filepath
|
|
42
|
+
def self.config_filepath
|
|
33
43
|
File.join(git_top_level, "config", "fit_commit.yml")
|
|
34
44
|
end
|
|
35
45
|
|
|
36
|
-
def
|
|
37
|
-
".fit_commit.yml"
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def git_top_level
|
|
46
|
+
def self.git_top_level
|
|
41
47
|
top_level = `git rev-parse --show-toplevel`.chomp.strip
|
|
42
48
|
fail "Git repo not found! Please submit a bug report." if top_level == ""
|
|
43
49
|
top_level
|
|
44
50
|
end
|
|
45
51
|
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
# sorted by increasing precedence
|
|
55
|
+
attr_accessor :filepaths
|
|
56
|
+
|
|
46
57
|
def read_config(path)
|
|
47
58
|
load_yaml(path).each_with_object({}) do |(key, value), config|
|
|
48
59
|
translated_key = translate_config_key(key)
|
|
@@ -2,6 +2,9 @@ require "fit_commit/line"
|
|
|
2
2
|
|
|
3
3
|
module FitCommit
|
|
4
4
|
class MessageParser
|
|
5
|
+
GIT_VERBOSE_MARKER = "# ------------------------ >8 ------------------------"
|
|
6
|
+
COMMENT_REGEX = /\A#/
|
|
7
|
+
|
|
5
8
|
attr_accessor :message_path
|
|
6
9
|
def initialize(message_path)
|
|
7
10
|
self.message_path = message_path
|
|
@@ -13,9 +16,6 @@ module FitCommit
|
|
|
13
16
|
|
|
14
17
|
private
|
|
15
18
|
|
|
16
|
-
GIT_VERBOSE_MARKER = "# ------------------------ >8 ------------------------"
|
|
17
|
-
COMMENT_REGEX = /\A#/
|
|
18
|
-
|
|
19
19
|
def relevant_lines
|
|
20
20
|
message_text.lines.each_with_object([]) do |line, relevant_lines|
|
|
21
21
|
line.chomp!
|
data/lib/fit_commit/runner.rb
CHANGED
|
@@ -8,6 +8,7 @@ module FitCommit
|
|
|
8
8
|
|
|
9
9
|
EXIT_CODE_ALLOW_COMMIT = 0
|
|
10
10
|
EXIT_CODE_REJECT_COMMIT = 1
|
|
11
|
+
DEFAULT_EDITOR = "vim"
|
|
11
12
|
|
|
12
13
|
attr_accessor :message_path, :branch_name, :stderr, :stdin
|
|
13
14
|
def initialize(message_path, branch_name, stderr = $stderr, stdin = $stdin)
|
|
@@ -105,8 +106,6 @@ module FitCommit
|
|
|
105
106
|
system(editor, message_path)
|
|
106
107
|
end
|
|
107
108
|
|
|
108
|
-
DEFAULT_EDITOR = "vim"
|
|
109
|
-
|
|
110
109
|
def editor
|
|
111
110
|
editor = ENV["EDITOR"]
|
|
112
111
|
editor = DEFAULT_EDITOR unless editor && editor != "none"
|
|
@@ -2,7 +2,6 @@ require "fit_commit/configuration_loader"
|
|
|
2
2
|
|
|
3
3
|
module FitCommit
|
|
4
4
|
class ValidatorLoader
|
|
5
|
-
attr_accessor :branch_name, :configuration
|
|
6
5
|
def initialize(branch_name, configuration = load_configuration)
|
|
7
6
|
self.branch_name = branch_name
|
|
8
7
|
self.configuration = configuration
|
|
@@ -14,8 +13,10 @@ module FitCommit
|
|
|
14
13
|
|
|
15
14
|
private
|
|
16
15
|
|
|
16
|
+
attr_accessor :branch_name, :configuration
|
|
17
|
+
|
|
17
18
|
def load_configuration
|
|
18
|
-
FitCommit::ConfigurationLoader.
|
|
19
|
+
FitCommit::ConfigurationLoader.default_configuration
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def all_validators
|
|
@@ -3,13 +3,29 @@ require "fit_commit/validators/base"
|
|
|
3
3
|
module FitCommit
|
|
4
4
|
module Validators
|
|
5
5
|
class CapitalizeSubject < Base
|
|
6
|
+
MESSAGE = "Begin all subject lines with a capital letter."
|
|
7
|
+
SINGLE_WORD = /\A\w+\z/
|
|
6
8
|
AUTOSQUASH = /\A(fixup|squash)! /
|
|
7
9
|
|
|
8
|
-
def
|
|
9
|
-
if
|
|
10
|
-
|
|
10
|
+
def validate(lines)
|
|
11
|
+
if lines[0].text =~ /\A[[:lower:]]/ && lines[0].text !~ AUTOSQUASH
|
|
12
|
+
if ignore_on_wiplikes? && wiplike?(lines)
|
|
13
|
+
add_warning(1, MESSAGE)
|
|
14
|
+
else
|
|
15
|
+
add_error(1, MESSAGE)
|
|
16
|
+
end
|
|
11
17
|
end
|
|
12
18
|
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def wiplike?(lines)
|
|
23
|
+
lines[0].text =~ SINGLE_WORD && lines[1..-1].all?(&:empty?)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def ignore_on_wiplikes?
|
|
27
|
+
config.fetch("WarnOnWiplikes")
|
|
28
|
+
end
|
|
13
29
|
end
|
|
14
30
|
end
|
|
15
31
|
end
|
|
@@ -3,28 +3,32 @@ require "fit_commit/validators/base"
|
|
|
3
3
|
module FitCommit
|
|
4
4
|
module Validators
|
|
5
5
|
class LineLength < Base
|
|
6
|
+
MERGE_COMMIT = /\AMerge branch '[^']+' into ./
|
|
7
|
+
URL = %r{[a-z]+://}
|
|
8
|
+
|
|
6
9
|
def validate_line(lineno, text)
|
|
7
|
-
if lineno == 1
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
if lineno == 1
|
|
11
|
+
if text.empty?
|
|
12
|
+
add_error(lineno, "Subject line cannot be blank.")
|
|
13
|
+
elsif text !~ MERGE_COMMIT
|
|
14
|
+
if text.length > max_line_length
|
|
15
|
+
add_error(lineno, format("Lines should be <= %i chars. (%i)",
|
|
16
|
+
max_line_length, text.length))
|
|
17
|
+
elsif text.length > subject_warn_length
|
|
18
|
+
add_warning(lineno, format("Subject line should be <= %i chars. (%i)",
|
|
19
|
+
subject_warn_length, text.length))
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
elsif lineno == 2
|
|
23
|
+
unless text.empty?
|
|
24
|
+
add_error(lineno, "Second line must be blank.")
|
|
25
|
+
end
|
|
26
|
+
elsif text.length > max_line_length && !(allow_long_urls? && text =~ URL)
|
|
12
27
|
add_error(lineno, format("Lines should be <= %i chars. (%i)",
|
|
13
28
|
max_line_length, text.length))
|
|
14
|
-
elsif lineno == 1 && text.length > subject_warn_length
|
|
15
|
-
add_warning(lineno, format("Subject line should be <= %i chars. (%i)",
|
|
16
|
-
subject_warn_length, text.length))
|
|
17
29
|
end
|
|
18
30
|
end
|
|
19
31
|
|
|
20
|
-
def line_too_long?(text)
|
|
21
|
-
text.length > max_line_length && !(allow_long_urls? && contains_url?(text))
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def contains_url?(text)
|
|
25
|
-
text =~ %r{[a-z]+://}
|
|
26
|
-
end
|
|
27
|
-
|
|
28
32
|
def max_line_length
|
|
29
33
|
config.fetch("MaxLineLength")
|
|
30
34
|
end
|
data/lib/fit_commit/version.rb
CHANGED
|
@@ -33,7 +33,7 @@ describe "Install and run in a fresh Git repo" do
|
|
|
33
33
|
assert_match(/^#{commit_message}/, results)
|
|
34
34
|
assert_match(/^1: Error: /, results)
|
|
35
35
|
refute_match(/Warning:/, results)
|
|
36
|
-
refute_match(/^\[
|
|
36
|
+
refute_match(/^\[main .+\]/, results)
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
@@ -44,7 +44,7 @@ describe "Install and run in a fresh Git repo" do
|
|
|
44
44
|
refute_match(/^#{commit_message}/, results)
|
|
45
45
|
refute_match(/Error:/, results)
|
|
46
46
|
refute_match(/Warning:/, results)
|
|
47
|
-
assert_match(/^\[
|
|
47
|
+
assert_match(/^\[main .+\] #{commit_message}/, results)
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
@@ -55,7 +55,7 @@ describe "Install and run in a fresh Git repo" do
|
|
|
55
55
|
refute_match(/^#{commit_message}/, results)
|
|
56
56
|
refute_match(/Error/, results)
|
|
57
57
|
assert_match(/^1: Warning: /, results)
|
|
58
|
-
assert_match(/^\[
|
|
58
|
+
assert_match(/^\[main .+\] #{commit_message}/, results)
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
end
|
data/test/test_helper.rb
CHANGED
|
@@ -2,81 +2,109 @@ require "test_helper"
|
|
|
2
2
|
require "fit_commit/configuration_loader"
|
|
3
3
|
|
|
4
4
|
describe FitCommit::ConfigurationLoader do
|
|
5
|
-
subject { FitCommit::ConfigurationLoader.new }
|
|
6
|
-
|
|
7
|
-
after do
|
|
8
|
-
[system_file, user_file].compact.each(&:unlink)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
let(:global_configuration) do
|
|
12
|
-
subject.stub :default_filepath, "/dev/null" do
|
|
13
|
-
subject.stub :system_filepath, (system_file ? system_file.path : "/dev/null") do
|
|
14
|
-
subject.stub :user_filepath, (user_file ? user_file.path : "/dev/null") do
|
|
15
|
-
subject.stub :config_filepath, "/dev/null" do
|
|
16
|
-
subject.stub :local_filepath, "/dev/null" do
|
|
17
|
-
subject.stub :git_top_level, "." do
|
|
18
|
-
subject.global_configuration
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
5
|
describe "no configuration files present" do
|
|
28
|
-
let(:system_file) { nil }
|
|
29
|
-
let(:user_file) { nil }
|
|
30
6
|
it "is empty" do
|
|
31
|
-
|
|
7
|
+
config = FitCommit::ConfigurationLoader.new(["/dev/null"]).configuration
|
|
8
|
+
assert_equal({}, config)
|
|
32
9
|
end
|
|
33
10
|
end
|
|
34
11
|
|
|
35
12
|
describe "just one configuration file present" do
|
|
36
|
-
let(:system_file) { nil }
|
|
37
|
-
let(:user_file) { create_tempfile("user_file", user_file_content) }
|
|
38
|
-
let(:user_file_content) do
|
|
39
|
-
"Foo/Bar:\n Baz: false\nQux/Norf/Blah:\n - !ruby/regexp /\\Afoo/"
|
|
40
|
-
end
|
|
41
|
-
|
|
42
13
|
it "is a configuration equal to that file" do
|
|
43
|
-
|
|
14
|
+
config_content = <<~EOF
|
|
15
|
+
Foo/Bar:
|
|
16
|
+
Baz: false
|
|
17
|
+
Qux/Norf/Blah:
|
|
18
|
+
- !ruby/regexp /\\Afoo/
|
|
19
|
+
EOF
|
|
20
|
+
config_file_path = create_tempfile(config_content).path
|
|
21
|
+
|
|
22
|
+
expected_config = {
|
|
44
23
|
"FitCommit::Foo::Bar" => { "Baz" => false },
|
|
45
24
|
"FitCommit::Qux::Norf::Blah" => [/\Afoo/]
|
|
46
25
|
}
|
|
47
|
-
|
|
26
|
+
|
|
27
|
+
config = FitCommit::ConfigurationLoader.new([config_file_path]).configuration
|
|
28
|
+
assert_equal expected_config, config
|
|
48
29
|
end
|
|
49
30
|
|
|
50
|
-
describe "has a
|
|
51
|
-
let(:user_file_content) do
|
|
52
|
-
"FitCommit:\n Require:\n - foo/bar"
|
|
53
|
-
end
|
|
31
|
+
describe "has a key without a slash" do
|
|
54
32
|
it "doesn't try to namespace the key" do
|
|
55
|
-
|
|
33
|
+
config_content = <<~EOF
|
|
34
|
+
FitCommit:
|
|
35
|
+
Require:
|
|
36
|
+
- foo/bar
|
|
37
|
+
EOF
|
|
38
|
+
config_file_path = create_tempfile(config_content).path
|
|
39
|
+
|
|
40
|
+
expected_config = {
|
|
56
41
|
"FitCommit" => { "Require" => ["foo/bar"] }
|
|
57
42
|
}
|
|
58
|
-
|
|
43
|
+
|
|
44
|
+
config = FitCommit::ConfigurationLoader.new([config_file_path]).configuration
|
|
45
|
+
assert_equal expected_config, config
|
|
59
46
|
end
|
|
60
47
|
end
|
|
61
48
|
end
|
|
62
49
|
|
|
63
50
|
describe "multiple configuration files present" do
|
|
64
|
-
let(:system_file) { create_tempfile("system_file", system_file_content) }
|
|
65
|
-
let(:user_file) { create_tempfile("user_file", user_file_content) }
|
|
66
|
-
let(:system_file_content) do
|
|
67
|
-
"Foo/Bar:\n Baz: false\nQux/Norf/Blah:\n Foobar:\n - !ruby/regexp /\\Afoo/\n Booyah: false"
|
|
68
|
-
end
|
|
69
|
-
let(:user_file_content) do
|
|
70
|
-
"Qux/Norf/Blah:\n Foobar: true\nAbc/Buz:\n - hi"
|
|
71
|
-
end
|
|
72
|
-
|
|
73
51
|
it "is a merged configuration that takes precedence into account" do
|
|
74
|
-
|
|
52
|
+
config1_content = <<~EOF
|
|
53
|
+
Foo/Bar:
|
|
54
|
+
Baz: false
|
|
55
|
+
Qux/Norf/Blah:
|
|
56
|
+
Foobar:
|
|
57
|
+
- !ruby/regexp /\\Afoo/
|
|
58
|
+
Booyah: false
|
|
59
|
+
EOF
|
|
60
|
+
|
|
61
|
+
config2_content = <<~EOF
|
|
62
|
+
Qux/Norf/Blah:
|
|
63
|
+
Foobar: true
|
|
64
|
+
Abc/Buz:
|
|
65
|
+
- hi
|
|
66
|
+
EOF
|
|
67
|
+
|
|
68
|
+
config_file_paths = [
|
|
69
|
+
create_tempfile(config1_content).path,
|
|
70
|
+
create_tempfile(config2_content).path
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
expected_config = {
|
|
75
74
|
"FitCommit::Foo::Bar" => { "Baz" => false },
|
|
76
75
|
"FitCommit::Qux::Norf::Blah" => { "Foobar" => true, "Booyah" => false },
|
|
77
76
|
"FitCommit::Abc::Buz" => ["hi"]
|
|
78
77
|
}
|
|
79
|
-
|
|
78
|
+
|
|
79
|
+
config = FitCommit::ConfigurationLoader.new(config_file_paths).configuration
|
|
80
|
+
assert_equal expected_config, config
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe "default_configuration" do
|
|
85
|
+
it "loads configuration from default filepaths" do
|
|
86
|
+
config_content = <<~EOF
|
|
87
|
+
FitCommit:
|
|
88
|
+
Require:
|
|
89
|
+
- foo/bar
|
|
90
|
+
EOF
|
|
91
|
+
config_file_path = create_tempfile(config_content).path
|
|
92
|
+
|
|
93
|
+
expected_config = {
|
|
94
|
+
"FitCommit" => { "Require" => ["foo/bar"] }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
config = FitCommit::ConfigurationLoader.stub(:default_filepaths, [config_file_path]) do
|
|
98
|
+
FitCommit::ConfigurationLoader.default_configuration
|
|
99
|
+
end
|
|
100
|
+
assert_equal expected_config, config
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
describe "gem_default_filepath" do
|
|
105
|
+
it "returns a valid filepath" do
|
|
106
|
+
gem_default_filepath = FitCommit::ConfigurationLoader.gem_default_filepath
|
|
107
|
+
assert File.exist?(gem_default_filepath)
|
|
80
108
|
end
|
|
81
109
|
end
|
|
82
110
|
end
|
|
@@ -2,12 +2,8 @@ require "test_helper"
|
|
|
2
2
|
require "fit_commit/message_parser"
|
|
3
3
|
|
|
4
4
|
describe FitCommit::MessageParser do
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
let(:commit_msg_file) { create_tempfile("test-commit-msg", commit_msg) }
|
|
10
|
-
let(:lines) { FitCommit::MessageParser.new(commit_msg_file.path).lines }
|
|
5
|
+
let(:commit_msg_file_path) { create_tempfile(commit_msg).path }
|
|
6
|
+
let(:lines) { FitCommit::MessageParser.new(commit_msg_file_path).lines }
|
|
11
7
|
|
|
12
8
|
describe "empty commit msg" do
|
|
13
9
|
let(:commit_msg) { "" }
|
data/test/unit/runner_test.rb
CHANGED
|
@@ -2,15 +2,12 @@ require "test_helper"
|
|
|
2
2
|
require "fit_commit/runner"
|
|
3
3
|
|
|
4
4
|
describe FitCommit::Runner do
|
|
5
|
-
|
|
6
|
-
commit_msg_file.unlink
|
|
7
|
-
end
|
|
8
|
-
let(:commit_msg_file) { create_tempfile("test-commit-msg", commit_msg) }
|
|
5
|
+
let(:commit_msg_file_path) { create_tempfile(commit_msg).path }
|
|
9
6
|
let(:stderr) { StringIO.new }
|
|
10
7
|
let(:stdin) { StringIO.new }
|
|
11
8
|
let(:branch_name) { "any" }
|
|
12
9
|
let(:runner) do
|
|
13
|
-
FitCommit::Runner.new(
|
|
10
|
+
FitCommit::Runner.new(commit_msg_file_path, branch_name, stderr, stdin)
|
|
14
11
|
end
|
|
15
12
|
|
|
16
13
|
def call_runner
|
|
@@ -3,81 +3,71 @@ require "fit_commit/validator_loader"
|
|
|
3
3
|
Dir[File.dirname(__FILE__) + "/validators/*.rb"].each { |file| require file }
|
|
4
4
|
|
|
5
5
|
describe FitCommit::ValidatorLoader do
|
|
6
|
-
|
|
7
|
-
let(:loader) { FitCommit::ValidatorLoader.new(branch_name, configuration) }
|
|
8
|
-
let(:branch_name) { "foo" }
|
|
9
|
-
let(:configuration) do
|
|
6
|
+
def simple_validators(branch_name: "mybranch")
|
|
10
7
|
# Starting with all disabled because every validator needs at least a
|
|
11
8
|
# default entry.
|
|
12
9
|
# The ones specified here are the ones we care about testing.
|
|
13
|
-
all_disabled_configuration.merge(
|
|
10
|
+
configuration = all_disabled_configuration.merge(
|
|
14
11
|
FitCommit::Validators::LineLength.name => { "Enabled" => false },
|
|
15
12
|
FitCommit::Validators::Wip.name => { "Enabled" => true },
|
|
16
13
|
FitCommit::Validators::Frathouse.name => { "Enabled" => ["bar", /\Abaz+/] }
|
|
17
14
|
)
|
|
15
|
+
FitCommit::ValidatorLoader.new(branch_name, configuration).validators
|
|
18
16
|
end
|
|
19
|
-
|
|
17
|
+
|
|
18
|
+
def all_disabled_configuration
|
|
20
19
|
FitCommit::Validators::Base.all.each_with_object({}) do |v, config|
|
|
21
20
|
config[v.name] = { "Enabled" => false }
|
|
22
21
|
end
|
|
23
22
|
end
|
|
24
23
|
|
|
25
24
|
it "loads enabled validators" do
|
|
26
|
-
assert
|
|
25
|
+
assert simple_validators.grep(FitCommit::Validators::Wip).one?
|
|
27
26
|
end
|
|
28
27
|
|
|
29
28
|
it "doesn't load disabled validators" do
|
|
30
|
-
assert
|
|
29
|
+
assert simple_validators.grep(FitCommit::Validators::LineLength).none?
|
|
31
30
|
end
|
|
32
31
|
|
|
33
32
|
describe "non-boolean options for Enabled" do
|
|
34
33
|
describe "branch_name does not match validator" do
|
|
35
34
|
it "doesn't load validator" do
|
|
36
|
-
assert
|
|
35
|
+
assert simple_validators.grep(FitCommit::Validators::Frathouse).none?
|
|
37
36
|
end
|
|
38
37
|
end
|
|
39
38
|
|
|
40
39
|
describe "branch_name matches validator via String" do
|
|
41
|
-
let(:branch_name) { "bar" }
|
|
42
40
|
it "loads validator" do
|
|
43
|
-
assert
|
|
41
|
+
assert simple_validators(branch_name: "bar").
|
|
42
|
+
grep(FitCommit::Validators::Frathouse).one?
|
|
44
43
|
end
|
|
45
44
|
end
|
|
46
45
|
|
|
47
46
|
describe "branch_name matches validator via regex" do
|
|
48
|
-
let(:branch_name) { "bazzz" }
|
|
49
47
|
it "loads validator" do
|
|
50
|
-
assert
|
|
48
|
+
assert simple_validators(branch_name: "bazzz").
|
|
49
|
+
grep(FitCommit::Validators::Frathouse).one?
|
|
51
50
|
end
|
|
52
51
|
end
|
|
53
52
|
end
|
|
54
53
|
|
|
55
54
|
describe "branch_name is blank" do
|
|
56
|
-
let(:branch_name) { "" }
|
|
57
55
|
it "loads enabled validators" do
|
|
58
|
-
assert
|
|
56
|
+
assert simple_validators(branch_name: "").grep(FitCommit::Validators::Wip).one?
|
|
59
57
|
end
|
|
60
58
|
it "doesn't load disabled validators" do
|
|
61
|
-
assert
|
|
59
|
+
assert simple_validators(branch_name: "").grep(FitCommit::Validators::LineLength).none?
|
|
62
60
|
end
|
|
63
61
|
it "doesn't load validators that have non-boolean options for Enabled" do
|
|
64
|
-
assert
|
|
62
|
+
assert simple_validators(branch_name: "").grep(FitCommit::Validators::Frathouse).none?
|
|
65
63
|
end
|
|
66
64
|
end
|
|
67
65
|
|
|
68
66
|
describe "custom validators required" do
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
let(:custom_validator_file) do
|
|
74
|
-
create_tempfile(["my_custom_validator", ".rb"], custom_validator_code)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# Not actually subclassing FitCommit::Validators::Base because
|
|
78
|
-
# that affects the loaded validators for other tests.
|
|
79
|
-
let(:custom_validator_code) do
|
|
80
|
-
<<-EOF
|
|
67
|
+
it "loads enabled custom validator" do
|
|
68
|
+
# Not actually subclassing FitCommit::Validators::Base because
|
|
69
|
+
# that affects the loaded validators for other tests.
|
|
70
|
+
custom_validator_code = <<~EOF
|
|
81
71
|
class MyCustomValidator
|
|
82
72
|
attr_accessor :config
|
|
83
73
|
def initialize(_branch_name, config)
|
|
@@ -88,23 +78,24 @@ describe FitCommit::ValidatorLoader do
|
|
|
88
78
|
end
|
|
89
79
|
end
|
|
90
80
|
EOF
|
|
91
|
-
end
|
|
92
81
|
|
|
93
|
-
|
|
94
|
-
|
|
82
|
+
# rb extension is necessary to `require` it
|
|
83
|
+
custom_validator_file = create_tempfile(
|
|
84
|
+
custom_validator_code, ["custom_validator", ".rb"])
|
|
85
|
+
|
|
86
|
+
configuration = all_disabled_configuration.merge(
|
|
95
87
|
"FitCommit" => { "Require" => [custom_validator_file.path] },
|
|
96
88
|
"MyCustomValidator" => { "Enabled" => true }
|
|
97
89
|
)
|
|
98
|
-
end
|
|
99
90
|
|
|
100
|
-
it "loads enabled custom validator" do
|
|
101
91
|
# stub which will be overridden when the custom validator file is loaded
|
|
102
92
|
MyCustomValidator = Class.new
|
|
103
93
|
|
|
104
|
-
FitCommit::Validators::Base.stub(:all, [MyCustomValidator]) do
|
|
105
|
-
|
|
106
|
-
assert validators.first.is_a?(MyCustomValidator)
|
|
94
|
+
validators = FitCommit::Validators::Base.stub(:all, [MyCustomValidator]) do
|
|
95
|
+
FitCommit::ValidatorLoader.new("mybranch", configuration).validators
|
|
107
96
|
end
|
|
97
|
+
assert_equal 1, validators.size
|
|
98
|
+
assert validators.first.is_a?(MyCustomValidator)
|
|
108
99
|
end
|
|
109
100
|
end
|
|
110
101
|
end
|
|
@@ -9,7 +9,7 @@ describe FitCommit::Validators::CapitalizeSubject do
|
|
|
9
9
|
let(:config) { default_config }
|
|
10
10
|
let(:branch_name) { "any" }
|
|
11
11
|
|
|
12
|
-
describe "subject is
|
|
12
|
+
describe "subject is uncapitalized" do
|
|
13
13
|
let(:commit_msg) { "foo bar" }
|
|
14
14
|
it "has error" do
|
|
15
15
|
validator.validate(commit_lines)
|
|
@@ -17,6 +17,34 @@ describe FitCommit::Validators::CapitalizeSubject do
|
|
|
17
17
|
assert_empty validator.warnings
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
|
+
describe "subject is WIPlike (single uncapitalized word with no body)" do
|
|
21
|
+
let(:commit_msg) { "foo" }
|
|
22
|
+
|
|
23
|
+
describe "WarnOnWiplikes is true" do
|
|
24
|
+
it "has a warning" do
|
|
25
|
+
validator.validate(commit_lines)
|
|
26
|
+
assert_empty validator.errors
|
|
27
|
+
assert_equal 1, validator.warnings[1].size
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe "WarnOnWiplikes is false" do
|
|
32
|
+
let(:config) { default_config.merge("WarnOnWiplikes" => false) }
|
|
33
|
+
it "has an error" do
|
|
34
|
+
validator.validate(commit_lines)
|
|
35
|
+
assert_equal 1, validator.errors[1].size
|
|
36
|
+
assert_empty validator.warnings
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
describe "subject is a single uncapitalized word with a body" do
|
|
41
|
+
let(:commit_msg) { "foo\n\nbaz" }
|
|
42
|
+
it "has error" do
|
|
43
|
+
validator.validate(commit_lines)
|
|
44
|
+
assert_equal 1, validator.errors[1].size
|
|
45
|
+
assert_empty validator.warnings
|
|
46
|
+
end
|
|
47
|
+
end
|
|
20
48
|
describe "subject is fixup commit" do
|
|
21
49
|
let(:commit_msg) { "fixup! foo bar" }
|
|
22
50
|
it "does not have errors/warnings" do
|
|
@@ -42,6 +42,22 @@ describe FitCommit::Validators::LineLength do
|
|
|
42
42
|
assert_empty validator.warnings
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
|
+
describe "first line is over error limit and has an URL" do
|
|
46
|
+
let(:commit_msg) { "foo https://" + ("x" * 70) }
|
|
47
|
+
it "has an error and no warning" do
|
|
48
|
+
validator.validate(commit_lines)
|
|
49
|
+
assert_equal 1, validator.errors[1].size
|
|
50
|
+
assert_empty validator.warnings
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
describe "merge commit is over error limit" do
|
|
54
|
+
let(:commit_msg) { "Merge branch '#{"x" * 30}' into #{"y" * 30}" }
|
|
55
|
+
it "does not have error" do
|
|
56
|
+
validator.validate(commit_lines)
|
|
57
|
+
assert_empty validator.errors
|
|
58
|
+
assert_empty validator.warnings
|
|
59
|
+
end
|
|
60
|
+
end
|
|
45
61
|
describe "SubjectWarnLength modified in config" do
|
|
46
62
|
let(:config) { default_config.merge("SubjectWarnLength" => 5) }
|
|
47
63
|
describe "first line is over modified warning limit" do
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fit-commit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.8.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Foley
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-08-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: swearjar
|
|
@@ -16,42 +16,42 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '1.
|
|
19
|
+
version: '1.4'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '1.
|
|
26
|
+
version: '1.4'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: minitest
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '5.
|
|
33
|
+
version: '5.14'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '5.
|
|
40
|
+
version: '5.14'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rake
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
47
|
+
version: '13.0'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '
|
|
54
|
+
version: '13.0'
|
|
55
55
|
description: A Git hook to validate your commit messages based on community standards.
|
|
56
56
|
email:
|
|
57
57
|
- foley3@gmail.com
|
|
@@ -69,6 +69,7 @@ files:
|
|
|
69
69
|
- LICENSE
|
|
70
70
|
- README.md
|
|
71
71
|
- Rakefile
|
|
72
|
+
- TODO.md
|
|
72
73
|
- bin/fit-commit
|
|
73
74
|
- fit-commit.gemspec
|
|
74
75
|
- lib/fit_commit.rb
|
|
@@ -108,8 +109,7 @@ licenses:
|
|
|
108
109
|
- MIT
|
|
109
110
|
metadata: {}
|
|
110
111
|
post_install_message: |2
|
|
111
|
-
|
|
112
|
-
Install the hook in each git repo you want to scan using:
|
|
112
|
+
Install Fit Commit hooks in each git repo you want to scan using:
|
|
113
113
|
|
|
114
114
|
> fit-commit install
|
|
115
115
|
|
|
@@ -130,9 +130,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
130
130
|
- !ruby/object:Gem::Version
|
|
131
131
|
version: '0'
|
|
132
132
|
requirements: []
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
signing_key:
|
|
133
|
+
rubygems_version: 3.1.4
|
|
134
|
+
signing_key:
|
|
136
135
|
specification_version: 4
|
|
137
136
|
summary: A Git hook to validate your commit messages
|
|
138
137
|
test_files:
|