git-lint 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|