git-lint 1.0.0
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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/LICENSE.adoc +162 -0
- data/README.adoc +1068 -0
- data/bin/git-lint +9 -0
- data/lib/git/kit/repo.rb +30 -0
- data/lib/git/lint.rb +51 -0
- data/lib/git/lint/analyzers/abstract.rb +108 -0
- data/lib/git/lint/analyzers/commit_author_capitalization.rb +35 -0
- data/lib/git/lint/analyzers/commit_author_email.rb +35 -0
- data/lib/git/lint/analyzers/commit_author_name.rb +40 -0
- data/lib/git/lint/analyzers/commit_body_bullet.rb +43 -0
- data/lib/git/lint/analyzers/commit_body_bullet_capitalization.rb +46 -0
- data/lib/git/lint/analyzers/commit_body_bullet_delimiter.rb +40 -0
- data/lib/git/lint/analyzers/commit_body_issue_tracker_link.rb +45 -0
- data/lib/git/lint/analyzers/commit_body_leading_line.rb +30 -0
- data/lib/git/lint/analyzers/commit_body_line_length.rb +42 -0
- data/lib/git/lint/analyzers/commit_body_paragraph_capitalization.rb +47 -0
- data/lib/git/lint/analyzers/commit_body_phrase.rb +72 -0
- data/lib/git/lint/analyzers/commit_body_presence.rb +36 -0
- data/lib/git/lint/analyzers/commit_body_single_bullet.rb +40 -0
- data/lib/git/lint/analyzers/commit_subject_length.rb +33 -0
- data/lib/git/lint/analyzers/commit_subject_prefix.rb +42 -0
- data/lib/git/lint/analyzers/commit_subject_suffix.rb +39 -0
- data/lib/git/lint/analyzers/commit_trailer_collaborator_capitalization.rb +51 -0
- data/lib/git/lint/analyzers/commit_trailer_collaborator_duplication.rb +56 -0
- data/lib/git/lint/analyzers/commit_trailer_collaborator_email.rb +52 -0
- data/lib/git/lint/analyzers/commit_trailer_collaborator_key.rb +56 -0
- data/lib/git/lint/analyzers/commit_trailer_collaborator_name.rb +57 -0
- data/lib/git/lint/branches/environments/circle_ci.rb +28 -0
- data/lib/git/lint/branches/environments/local.rb +28 -0
- data/lib/git/lint/branches/environments/netlify_ci.rb +34 -0
- data/lib/git/lint/branches/environments/travis_ci.rb +57 -0
- data/lib/git/lint/branches/feature.rb +44 -0
- data/lib/git/lint/cli.rb +122 -0
- data/lib/git/lint/collector.rb +64 -0
- data/lib/git/lint/commits/saved.rb +104 -0
- data/lib/git/lint/commits/unsaved.rb +120 -0
- data/lib/git/lint/errors/base.rb +14 -0
- data/lib/git/lint/errors/severity.rb +13 -0
- data/lib/git/lint/errors/sha.rb +13 -0
- data/lib/git/lint/identity.rb +13 -0
- data/lib/git/lint/kit/filter_list.rb +30 -0
- data/lib/git/lint/parsers/trailers/collaborator.rb +57 -0
- data/lib/git/lint/rake/setup.rb +4 -0
- data/lib/git/lint/rake/tasks.rb +33 -0
- data/lib/git/lint/refinements/strings.rb +25 -0
- data/lib/git/lint/reporters/branch.rb +67 -0
- data/lib/git/lint/reporters/commit.rb +30 -0
- data/lib/git/lint/reporters/line.rb +32 -0
- data/lib/git/lint/reporters/lines/paragraph.rb +49 -0
- data/lib/git/lint/reporters/lines/sentence.rb +31 -0
- data/lib/git/lint/reporters/style.rb +52 -0
- data/lib/git/lint/runner.rb +34 -0
- data/lib/git/lint/validators/capitalization.rb +29 -0
- data/lib/git/lint/validators/email.rb +24 -0
- data/lib/git/lint/validators/name.rb +30 -0
- metadata +363 -0
- metadata.gz.sig +3 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Git
|
4
|
+
module Lint
|
5
|
+
module Analyzers
|
6
|
+
class CommitBodyIssueTrackerLink < Abstract
|
7
|
+
def self.defaults
|
8
|
+
{
|
9
|
+
enabled: true,
|
10
|
+
severity: :error,
|
11
|
+
excludes: [
|
12
|
+
"(f|F)ix(es|ed)?\\s\\#\\d+",
|
13
|
+
"(c|C)lose(s|d)?\\s\\#\\d+",
|
14
|
+
"(r|R)esolve(s|d)?\\s\\#\\d+",
|
15
|
+
"github\\.com\\/.+\\/issues\\/\\d+"
|
16
|
+
]
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def valid?
|
21
|
+
commit.body_lines.none? { |line| invalid_line? line }
|
22
|
+
end
|
23
|
+
|
24
|
+
def issue
|
25
|
+
return {} if valid?
|
26
|
+
|
27
|
+
{
|
28
|
+
hint: "Explain issue instead of using link. Avoid: #{filter_list.to_hint}.",
|
29
|
+
lines: affected_commit_body_lines
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def load_filter_list
|
36
|
+
Kit::FilterList.new settings.fetch :excludes
|
37
|
+
end
|
38
|
+
|
39
|
+
def invalid_line? line
|
40
|
+
line.match?(/.*#{Regexp.union filter_list.to_regexp}.*/)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Git
|
4
|
+
module Lint
|
5
|
+
module Analyzers
|
6
|
+
class CommitBodyLeadingLine < Abstract
|
7
|
+
def self.defaults
|
8
|
+
{
|
9
|
+
enabled: true,
|
10
|
+
severity: :error
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
raw_body = commit.raw_body
|
16
|
+
subject, body = raw_body.split "\n", 2
|
17
|
+
return true if !String(subject).empty? && String(body).strip.empty?
|
18
|
+
|
19
|
+
raw_body.match?(/\A.+\n\n.+/)
|
20
|
+
end
|
21
|
+
|
22
|
+
def issue
|
23
|
+
return {} if valid?
|
24
|
+
|
25
|
+
{hint: "Use blank line between subject and body."}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Git
|
4
|
+
module Lint
|
5
|
+
module Analyzers
|
6
|
+
class CommitBodyLineLength < Abstract
|
7
|
+
def self.defaults
|
8
|
+
{
|
9
|
+
enabled: true,
|
10
|
+
severity: :error,
|
11
|
+
length: 72
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid?
|
16
|
+
commit.body_lines.all? { |line| !invalid_line? line }
|
17
|
+
end
|
18
|
+
|
19
|
+
def issue
|
20
|
+
return {} if valid?
|
21
|
+
|
22
|
+
{
|
23
|
+
hint: "Use #{length} characters or less per line.",
|
24
|
+
lines: affected_commit_body_lines
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def invalid_line? line
|
31
|
+
line.length > length
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def length
|
37
|
+
settings.fetch :length
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Git
|
4
|
+
module Lint
|
5
|
+
module Analyzers
|
6
|
+
class CommitBodyParagraphCapitalization < Abstract
|
7
|
+
def self.defaults
|
8
|
+
{
|
9
|
+
enabled: true,
|
10
|
+
severity: :error
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.invalid? line
|
15
|
+
line.match?(/\A[[:lower:]].+\Z/m)
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid?
|
19
|
+
lowercased_lines.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def issue
|
23
|
+
return {} if valid?
|
24
|
+
|
25
|
+
{
|
26
|
+
hint: "Capitalize first word.",
|
27
|
+
lines: affected_lines
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def lowercased_lines
|
34
|
+
commit.body_paragraphs.select { |line| self.class.invalid? line }
|
35
|
+
end
|
36
|
+
|
37
|
+
def affected_lines
|
38
|
+
klass = self.class
|
39
|
+
|
40
|
+
commit.body_paragraphs.each.with_object([]).with_index do |(line, lines), index|
|
41
|
+
lines << klass.build_issue_line(index, line) if klass.invalid? line
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Git
|
4
|
+
module Lint
|
5
|
+
module Analyzers
|
6
|
+
class CommitBodyPhrase < Abstract
|
7
|
+
# rubocop:disable Metrics/MethodLength
|
8
|
+
def self.defaults
|
9
|
+
{
|
10
|
+
enabled: true,
|
11
|
+
severity: :error,
|
12
|
+
excludes: [
|
13
|
+
"absolutely",
|
14
|
+
"actually",
|
15
|
+
"all intents and purposes",
|
16
|
+
"along the lines",
|
17
|
+
"at this moment in time",
|
18
|
+
"basically",
|
19
|
+
"each and every one",
|
20
|
+
"everyone knows",
|
21
|
+
"fact of the matter",
|
22
|
+
"furthermore",
|
23
|
+
"however",
|
24
|
+
"in due course",
|
25
|
+
"in the end",
|
26
|
+
"last but not least",
|
27
|
+
"matter of fact",
|
28
|
+
"obviously",
|
29
|
+
"of course",
|
30
|
+
"really",
|
31
|
+
"simply",
|
32
|
+
"things being equal",
|
33
|
+
"would like to",
|
34
|
+
/\beasy\b/,
|
35
|
+
/\bjust\b/,
|
36
|
+
/\bquite\b/,
|
37
|
+
/as\sfar\sas\s.+\sconcerned/,
|
38
|
+
/of\sthe\s(fact|opinion)\sthat/
|
39
|
+
]
|
40
|
+
}
|
41
|
+
end
|
42
|
+
# rubocop:enable Metrics/MethodLength
|
43
|
+
|
44
|
+
def valid?
|
45
|
+
commit.body_lines.all? { |line| !invalid_line? line }
|
46
|
+
end
|
47
|
+
|
48
|
+
def issue
|
49
|
+
return {} if valid?
|
50
|
+
|
51
|
+
{
|
52
|
+
hint: %(Avoid: #{filter_list.to_hint}.),
|
53
|
+
lines: affected_commit_body_lines
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
def load_filter_list
|
60
|
+
Kit::FilterList.new settings.fetch(:excludes)
|
61
|
+
end
|
62
|
+
|
63
|
+
def invalid_line? line
|
64
|
+
line.downcase.match? Regexp.new(
|
65
|
+
Regexp.union(filter_list.to_regexp).source,
|
66
|
+
Regexp::IGNORECASE
|
67
|
+
)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Git
|
4
|
+
module Lint
|
5
|
+
module Analyzers
|
6
|
+
class CommitBodyPresence < Abstract
|
7
|
+
using Refinements::Strings
|
8
|
+
|
9
|
+
def self.defaults
|
10
|
+
{
|
11
|
+
enabled: true,
|
12
|
+
severity: :warn,
|
13
|
+
minimum: 1
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid?
|
18
|
+
return true if commit.fixup?
|
19
|
+
|
20
|
+
valid_lines = commit.body_lines.reject { |line| line.match?(/^\s*$/) }
|
21
|
+
valid_lines.size >= minimum
|
22
|
+
end
|
23
|
+
|
24
|
+
def minimum
|
25
|
+
settings.fetch :minimum
|
26
|
+
end
|
27
|
+
|
28
|
+
def issue
|
29
|
+
return {} if valid?
|
30
|
+
|
31
|
+
{hint: %(Use minimum of #{"line".pluralize count: minimum} (non-empty).)}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Git
|
4
|
+
module Lint
|
5
|
+
module Analyzers
|
6
|
+
class CommitBodySingleBullet < Abstract
|
7
|
+
def self.defaults
|
8
|
+
{
|
9
|
+
enabled: true,
|
10
|
+
severity: :error,
|
11
|
+
includes: %w[\\-]
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid?
|
16
|
+
affected_commit_body_lines.size != 1
|
17
|
+
end
|
18
|
+
|
19
|
+
def issue
|
20
|
+
return {} if valid?
|
21
|
+
|
22
|
+
{
|
23
|
+
hint: "Use paragraph instead of single bullet.",
|
24
|
+
lines: affected_commit_body_lines
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def load_filter_list
|
31
|
+
Kit::FilterList.new settings.fetch :includes
|
32
|
+
end
|
33
|
+
|
34
|
+
def invalid_line? line
|
35
|
+
line.match?(/\A#{Regexp.union filter_list.to_regexp}\s+/)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Git
|
4
|
+
module Lint
|
5
|
+
module Analyzers
|
6
|
+
class CommitSubjectLength < Abstract
|
7
|
+
def self.defaults
|
8
|
+
{
|
9
|
+
enabled: true,
|
10
|
+
severity: :error,
|
11
|
+
length: 72
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid?
|
16
|
+
commit.subject.sub(/(fixup!|squash!)\s{1}/, "").size <= length
|
17
|
+
end
|
18
|
+
|
19
|
+
def issue
|
20
|
+
return {} if valid?
|
21
|
+
|
22
|
+
{hint: "Use #{length} characters or less."}
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def length
|
28
|
+
settings.fetch :length
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Git
|
4
|
+
module Lint
|
5
|
+
module Analyzers
|
6
|
+
class CommitSubjectPrefix < Abstract
|
7
|
+
def self.defaults
|
8
|
+
{
|
9
|
+
enabled: true,
|
10
|
+
severity: :error,
|
11
|
+
includes: %w[Fixed Added Updated Removed Refactored]
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid?
|
16
|
+
return true if fixup_or_squash?
|
17
|
+
return true if filter_list.empty?
|
18
|
+
|
19
|
+
commit.subject.match?(/\A#{Regexp.union filter_list.to_regexp}/)
|
20
|
+
end
|
21
|
+
|
22
|
+
def issue
|
23
|
+
return {} if valid?
|
24
|
+
|
25
|
+
{hint: %(Use: #{filter_list.to_hint}.)}
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def load_filter_list
|
31
|
+
Kit::FilterList.new settings.fetch(:includes)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def fixup_or_squash?
|
37
|
+
commit.is_a?(Git::Lint::Commits::Unsaved) && (commit.fixup? || commit.squash?)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Git
|
4
|
+
module Lint
|
5
|
+
module Analyzers
|
6
|
+
class CommitSubjectSuffix < Abstract
|
7
|
+
def self.defaults
|
8
|
+
{
|
9
|
+
enabled: true,
|
10
|
+
severity: :error,
|
11
|
+
excludes: [
|
12
|
+
"\\.",
|
13
|
+
"\\?",
|
14
|
+
"\\!"
|
15
|
+
]
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid?
|
20
|
+
return true if filter_list.empty?
|
21
|
+
|
22
|
+
!commit.subject.match?(/#{Regexp.union filter_list.to_regexp}\Z/)
|
23
|
+
end
|
24
|
+
|
25
|
+
def issue
|
26
|
+
return {} if valid?
|
27
|
+
|
28
|
+
{hint: %(Avoid: #{filter_list.to_hint}.)}
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def load_filter_list
|
34
|
+
Kit::FilterList.new settings.fetch(:excludes)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Git
|
4
|
+
module Lint
|
5
|
+
module Analyzers
|
6
|
+
class CommitTrailerCollaboratorCapitalization < Abstract
|
7
|
+
def self.defaults
|
8
|
+
{
|
9
|
+
enabled: true,
|
10
|
+
severity: :error
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
# rubocop:disable Metrics/ParameterLists
|
15
|
+
def initialize commit:,
|
16
|
+
settings: self.class.defaults,
|
17
|
+
parser: Parsers::Trailers::Collaborator,
|
18
|
+
validator: Validators::Capitalization
|
19
|
+
super commit: commit, settings: settings
|
20
|
+
@parser = parser
|
21
|
+
@validator = validator
|
22
|
+
end
|
23
|
+
# rubocop:enable Metrics/ParameterLists
|
24
|
+
|
25
|
+
def valid?
|
26
|
+
affected_commit_trailer_lines.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
def issue
|
30
|
+
return {} if valid?
|
31
|
+
|
32
|
+
{
|
33
|
+
hint: "Name must be capitalized.",
|
34
|
+
lines: affected_commit_trailer_lines
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def invalid_line? line
|
41
|
+
collaborator = parser.new line
|
42
|
+
collaborator.match? && !validator.new(collaborator.name.strip).valid?
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
attr_reader :parser, :validator
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|