git-lint 4.6.0 → 5.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.adoc +235 -30
  4. data/git-lint.gemspec +9 -8
  5. data/lib/git/lint/analyzer.rb +14 -3
  6. data/lib/git/lint/analyzers/abstract.rb +8 -5
  7. data/lib/git/lint/analyzers/commit_author_capitalization.rb +2 -9
  8. data/lib/git/lint/analyzers/commit_author_email.rb +2 -9
  9. data/lib/git/lint/analyzers/commit_author_name.rb +2 -7
  10. data/lib/git/lint/analyzers/commit_body_leading_line.rb +3 -3
  11. data/lib/git/lint/analyzers/commit_body_paragraph_capitalization.rb +9 -6
  12. data/lib/git/lint/analyzers/commit_signature.rb +22 -0
  13. data/lib/git/lint/analyzers/commit_trailer_collaborator_capitalization.rb +9 -17
  14. data/lib/git/lint/analyzers/commit_trailer_collaborator_email.rb +9 -13
  15. data/lib/git/lint/analyzers/commit_trailer_collaborator_key.rb +5 -15
  16. data/lib/git/lint/analyzers/commit_trailer_collaborator_name.rb +9 -15
  17. data/lib/git/lint/analyzers/commit_trailer_duplicate.rb +25 -0
  18. data/lib/git/lint/analyzers/commit_trailer_format_key.rb +33 -0
  19. data/lib/git/lint/analyzers/commit_trailer_format_value.rb +33 -0
  20. data/lib/git/lint/analyzers/commit_trailer_issue_key.rb +33 -0
  21. data/lib/git/lint/analyzers/commit_trailer_issue_value.rb +33 -0
  22. data/lib/git/lint/analyzers/commit_trailer_signer_capitalization.rb +35 -0
  23. data/lib/git/lint/analyzers/commit_trailer_signer_email.rb +39 -0
  24. data/lib/git/lint/analyzers/commit_trailer_signer_key.rb +33 -0
  25. data/lib/git/lint/analyzers/commit_trailer_signer_name.rb +39 -0
  26. data/lib/git/lint/analyzers/commit_trailer_tracker_key.rb +33 -0
  27. data/lib/git/lint/analyzers/commit_trailer_tracker_value.rb +33 -0
  28. data/lib/git/lint/cli/actions/analyze/branch.rb +1 -1
  29. data/lib/git/lint/cli/actions/analyze/commit.rb +8 -11
  30. data/lib/git/lint/cli/actions/hook.rb +4 -2
  31. data/lib/git/lint/commits/loader.rb +2 -2
  32. data/lib/git/lint/commits/systems/circle_ci.rb +5 -3
  33. data/lib/git/lint/commits/systems/git_hub_action.rb +5 -3
  34. data/lib/git/lint/commits/systems/local.rb +5 -3
  35. data/lib/git/lint/commits/systems/netlify_ci.rb +7 -7
  36. data/lib/git/lint/configuration/defaults.yml +58 -15
  37. data/lib/git/lint/container.rb +25 -4
  38. data/lib/git/lint/rake/{tasks.rb → register.rb} +6 -8
  39. data/lib/git/lint/reporters/commit.rb +1 -1
  40. data/lib/git/lint/validators/capitalization.rb +4 -7
  41. data/lib/git/lint/validators/email.rb +3 -4
  42. data/lib/git/lint/validators/name.rb +12 -9
  43. data/lib/git/lint.rb +0 -1
  44. data.tar.gz.sig +0 -0
  45. metadata +44 -21
  46. metadata.gz.sig +0 -0
  47. data/lib/git/lint/analyzers/commit_trailer_collaborator_duplication.rb +0 -46
  48. data/lib/git/lint/parsers/trailers/collaborator.rb +0 -50
  49. data/lib/git/lint/rake/setup.rb +0 -4
@@ -5,16 +5,12 @@ module Git
5
5
  module Analyzers
6
6
  # Analyzes commit trailer collaborator email address format.
7
7
  class CommitTrailerCollaboratorEmail < Abstract
8
- # rubocop:disable Metrics/ParameterLists
9
- def initialize commit,
10
- parser: Parsers::Trailers::Collaborator,
11
- validator: Validators::Email,
12
- **dependencies
13
- super commit, **dependencies
14
- @parser = parser
15
- @validator = validator
16
- end
17
- # rubocop:enable Metrics/ParameterLists
8
+ include Import[
9
+ pattern: "trailers.collaborator",
10
+ parser: "parsers.person",
11
+ sanitizer: "sanitizers.email",
12
+ validator: "validators.email"
13
+ ]
18
14
 
19
15
  def valid? = affected_commit_trailers.empty?
20
16
 
@@ -29,9 +25,9 @@ module Git
29
25
 
30
26
  protected
31
27
 
32
- def invalid_line? line
33
- collaborator = parser.new line
34
- collaborator.match? && !validator.new(collaborator.email).valid?
28
+ def invalid_line? trailer
29
+ email = sanitizer.call parser.call(trailer.value).email
30
+ trailer.key.match?(pattern) && !validator.call(email)
35
31
  end
36
32
 
37
33
  private
@@ -5,10 +5,7 @@ module Git
5
5
  module Analyzers
6
6
  # Analyzes commit trailer collaborator key usage.
7
7
  class CommitTrailerCollaboratorKey < Abstract
8
- def initialize commit, parser: Parsers::Trailers::Collaborator, **dependencies
9
- super commit, **dependencies
10
- @parser = parser
11
- end
8
+ include Import[pattern: "trailers.collaborator"]
12
9
 
13
10
  def valid? = affected_commit_trailers.empty?
14
11
 
@@ -25,18 +22,11 @@ module Git
25
22
 
26
23
  def load_filter_list = Kit::FilterList.new(settings.includes)
27
24
 
28
- def invalid_line? line
29
- collaborator = parser.new line
30
- key = collaborator.key
31
-
32
- collaborator.match? && !key.empty? && !key.match?(
33
- /\A#{Regexp.union filter_list.to_regexp}\Z/
34
- )
25
+ def invalid_line? trailer
26
+ trailer.key.then do |key|
27
+ key.match?(pattern) && !key.match?(/\A#{Regexp.union filter_list.to_regexp}\Z/)
28
+ end
35
29
  end
36
-
37
- private
38
-
39
- attr_reader :parser
40
30
  end
41
31
  end
42
32
  end
@@ -5,16 +5,11 @@ module Git
5
5
  module Analyzers
6
6
  # Analyzes commit trailer collaborator name construction.
7
7
  class CommitTrailerCollaboratorName < Abstract
8
- # rubocop:disable Metrics/ParameterLists
9
- def initialize commit,
10
- parser: Parsers::Trailers::Collaborator,
11
- validator: Validators::Name,
12
- **dependencies
13
- super commit, **dependencies
14
- @parser = parser
15
- @validator = validator
16
- end
17
- # rubocop:enable Metrics/ParameterLists
8
+ include Import[
9
+ pattern: "trailers.collaborator",
10
+ parser: "parsers.person",
11
+ validator: "validators.name"
12
+ ]
18
13
 
19
14
  def valid? = affected_commit_trailers.empty?
20
15
 
@@ -29,15 +24,14 @@ module Git
29
24
 
30
25
  protected
31
26
 
32
- def invalid_line? line
33
- collaborator = parser.new line
34
- collaborator.match? && !validator.new(collaborator.name.strip, minimum:).valid?
27
+ def invalid_line? trailer
28
+ parser.call(trailer.value).then do |person|
29
+ trailer.key.match?(pattern) && !validator.call(person.name, minimum:)
30
+ end
35
31
  end
36
32
 
37
33
  private
38
34
 
39
- attr_reader :parser, :validator
40
-
41
35
  def minimum = settings.minimum
42
36
  end
43
37
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ module Lint
5
+ module Analyzers
6
+ # Analyzes commit trailer duplicate.
7
+ class CommitTrailerDuplicate < Abstract
8
+ def valid? = affected_commit_trailers.empty?
9
+
10
+ def issue
11
+ return {} if valid?
12
+
13
+ {
14
+ hint: "Avoid duplicates.",
15
+ lines: affected_commit_trailers
16
+ }
17
+ end
18
+
19
+ protected
20
+
21
+ def invalid_line?(trailer) = commit.trailers.tally[trailer] != 1
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ module Lint
5
+ module Analyzers
6
+ # Analyzes commit trailer format key usage.
7
+ class CommitTrailerFormatKey < Abstract
8
+ include Import[pattern: "trailers.format"]
9
+
10
+ def valid? = affected_commit_trailers.empty?
11
+
12
+ def issue
13
+ return {} if valid?
14
+
15
+ {
16
+ hint: "Use format: #{filter_list.to_hint}.",
17
+ lines: affected_commit_trailers
18
+ }
19
+ end
20
+
21
+ protected
22
+
23
+ def load_filter_list = Kit::FilterList.new(settings.includes)
24
+
25
+ def invalid_line? trailer
26
+ trailer.key.then do |key|
27
+ key.match?(pattern) && !key.match?(/\A#{Regexp.union filter_list.to_regexp}\Z/)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ module Lint
5
+ module Analyzers
6
+ # Analyzes commit trailer format value.
7
+ class CommitTrailerFormatValue < Abstract
8
+ include Import[pattern: "trailers.format"]
9
+
10
+ def valid? = affected_commit_trailers.empty?
11
+
12
+ def issue
13
+ return {} if valid?
14
+
15
+ {
16
+ hint: "Use format: #{filter_list.to_hint}.",
17
+ lines: affected_commit_trailers
18
+ }
19
+ end
20
+
21
+ protected
22
+
23
+ def load_filter_list = Kit::FilterList.new(settings.includes)
24
+
25
+ def invalid_line? trailer
26
+ trailer.key.match?(pattern) && !trailer.value.match?(value_pattern)
27
+ end
28
+
29
+ def value_pattern = /\A#{Regexp.union filter_list.to_regexp}\Z/
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ module Lint
5
+ module Analyzers
6
+ # Analyzes commit trailer issue key usage.
7
+ class CommitTrailerIssueKey < Abstract
8
+ include Import[pattern: "trailers.issue"]
9
+
10
+ def valid? = affected_commit_trailers.empty?
11
+
12
+ def issue
13
+ return {} if valid?
14
+
15
+ {
16
+ hint: "Use format: #{filter_list.to_hint}.",
17
+ lines: affected_commit_trailers
18
+ }
19
+ end
20
+
21
+ protected
22
+
23
+ def load_filter_list = Kit::FilterList.new(settings.includes)
24
+
25
+ def invalid_line? trailer
26
+ trailer.key.then do |key|
27
+ key.match?(pattern) && !key.match?(/\A#{Regexp.union filter_list.to_regexp}\Z/)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ module Lint
5
+ module Analyzers
6
+ # Analyzes commit trailer issue value.
7
+ class CommitTrailerIssueValue < Abstract
8
+ include Import[pattern: "trailers.issue"]
9
+
10
+ def valid? = affected_commit_trailers.empty?
11
+
12
+ def issue
13
+ return {} if valid?
14
+
15
+ {
16
+ hint: "Use format: #{filter_list.to_hint}.",
17
+ lines: affected_commit_trailers
18
+ }
19
+ end
20
+
21
+ protected
22
+
23
+ def load_filter_list = Kit::FilterList.new(settings.includes)
24
+
25
+ def invalid_line? trailer
26
+ trailer.key.match?(pattern) && !trailer.value.match?(value_pattern)
27
+ end
28
+
29
+ def value_pattern = /\A#{Regexp.union filter_list.to_regexp}\Z/
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ module Lint
5
+ module Analyzers
6
+ # Analyzes commit trailer signer name capitalization.
7
+ class CommitTrailerSignerCapitalization < Abstract
8
+ include Import[
9
+ pattern: "trailers.signer",
10
+ parser: "parsers.person",
11
+ validator: "validators.capitalization"
12
+ ]
13
+
14
+ def valid? = affected_commit_trailers.empty?
15
+
16
+ def issue
17
+ return {} if valid?
18
+
19
+ {
20
+ hint: "Name must be capitalized.",
21
+ lines: affected_commit_trailers
22
+ }
23
+ end
24
+
25
+ protected
26
+
27
+ def invalid_line? trailer
28
+ parser.call(trailer.value).then do |person|
29
+ trailer.key.match?(pattern) && !validator.call(person.name)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ module Lint
5
+ module Analyzers
6
+ # Analyzes commit trailer signer email address format.
7
+ class CommitTrailerSignerEmail < Abstract
8
+ include Import[
9
+ pattern: "trailers.signer",
10
+ parser: "parsers.person",
11
+ sanitizer: "sanitizers.email",
12
+ validator: "validators.email"
13
+ ]
14
+
15
+ def valid? = affected_commit_trailers.empty?
16
+
17
+ def issue
18
+ return {} if valid?
19
+
20
+ {
21
+ hint: %(Email must follow name and use format: "<name@server.domain>".),
22
+ lines: affected_commit_trailers
23
+ }
24
+ end
25
+
26
+ protected
27
+
28
+ def invalid_line? trailer
29
+ email = sanitizer.call parser.call(trailer.value).email
30
+ trailer.key.match?(pattern) && !validator.call(email)
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader :parser, :validator
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ module Lint
5
+ module Analyzers
6
+ # Analyzes commit trailer signer key usage.
7
+ class CommitTrailerSignerKey < Abstract
8
+ include Import[pattern: "trailers.signer"]
9
+
10
+ def valid? = affected_commit_trailers.empty?
11
+
12
+ def issue
13
+ return {} if valid?
14
+
15
+ {
16
+ hint: "Use format: #{filter_list.to_hint}.",
17
+ lines: affected_commit_trailers
18
+ }
19
+ end
20
+
21
+ protected
22
+
23
+ def load_filter_list = Kit::FilterList.new(settings.includes)
24
+
25
+ def invalid_line? trailer
26
+ trailer.key.then do |key|
27
+ key.match?(pattern) && !key.match?(/\A#{Regexp.union filter_list.to_regexp}\Z/)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ module Lint
5
+ module Analyzers
6
+ # Analyzes commit trailer signer name construction.
7
+ class CommitTrailerSignerName < Abstract
8
+ include Import[
9
+ pattern: "trailers.signer",
10
+ parser: "parsers.person",
11
+ validator: "validators.name"
12
+ ]
13
+
14
+ def valid? = affected_commit_trailers.empty?
15
+
16
+ def issue
17
+ return {} if valid?
18
+
19
+ {
20
+ hint: "Name must follow key and consist of #{minimum} parts (minimum).",
21
+ lines: affected_commit_trailers
22
+ }
23
+ end
24
+
25
+ protected
26
+
27
+ def invalid_line? trailer
28
+ parser.call(trailer.value).then do |person|
29
+ trailer.key.match?(pattern) && !validator.call(person.name, minimum:)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def minimum = settings.minimum
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ module Lint
5
+ module Analyzers
6
+ # Analyzes commit trailer tracker key usage.
7
+ class CommitTrailerTrackerKey < Abstract
8
+ include Import[pattern: "trailers.tracker"]
9
+
10
+ def valid? = affected_commit_trailers.empty?
11
+
12
+ def issue
13
+ return {} if valid?
14
+
15
+ {
16
+ hint: "Use format: #{filter_list.to_hint}.",
17
+ lines: affected_commit_trailers
18
+ }
19
+ end
20
+
21
+ protected
22
+
23
+ def load_filter_list = Kit::FilterList.new(settings.includes)
24
+
25
+ def invalid_line? trailer
26
+ trailer.key.then do |key|
27
+ key.match?(pattern) && !key.match?(/\A#{Regexp.union filter_list.to_regexp}\Z/)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ module Lint
5
+ module Analyzers
6
+ # Analyzes commit trailer tracker value.
7
+ class CommitTrailerTrackerValue < Abstract
8
+ include Import[pattern: "trailers.tracker"]
9
+
10
+ def valid? = affected_commit_trailers.empty?
11
+
12
+ def issue
13
+ return {} if valid?
14
+
15
+ {
16
+ hint: "Use format: #{filter_list.to_hint}.",
17
+ lines: affected_commit_trailers
18
+ }
19
+ end
20
+
21
+ protected
22
+
23
+ def load_filter_list = Kit::FilterList.new(settings.includes)
24
+
25
+ def invalid_line? trailer
26
+ trailer.key.match?(pattern) && !trailer.value.match?(value_pattern)
27
+ end
28
+
29
+ def value_pattern = /\A#{Regexp.union filter_list.to_regexp}\Z/
30
+ end
31
+ end
32
+ end
33
+ end
@@ -7,7 +7,7 @@ module Git
7
7
  module Analyze
8
8
  # Handles analyze action for branch.
9
9
  class Branch
10
- include Git::Lint::Import[:repository, :kernel, :logger]
10
+ include Git::Lint::Import[:kernel, :logger]
11
11
 
12
12
  def initialize analyzer: Analyzer.new, **dependencies
13
13
  super(**dependencies)
@@ -5,20 +5,17 @@ module Git
5
5
  module CLI
6
6
  module Actions
7
7
  module Analyze
8
- # Handles analyze action for commit(s) by SHA.
8
+ # Handles analyze action for single commit SHA
9
9
  class Commit
10
- include Git::Lint::Import[:kernel, :logger]
10
+ include Git::Lint::Import[:git, :kernel, :logger]
11
11
 
12
- def initialize analyzer: Analyzer.new,
13
- parser: GitPlus::Parsers::Commits::Saved::History.with_show,
14
- **dependencies
12
+ def initialize analyzer: Analyzer.new, **dependencies
15
13
  super(**dependencies)
16
14
  @analyzer = analyzer
17
- @parser = parser
18
15
  end
19
16
 
20
- def call sha = nil
21
- process sha
17
+ def call *arguments
18
+ process arguments.unshift "-1"
22
19
  rescue Errors::Base => error
23
20
  logger.error { error.message }
24
21
  kernel.abort
@@ -26,10 +23,10 @@ module Git
26
23
 
27
24
  private
28
25
 
29
- attr_reader :analyzer, :parser
26
+ attr_reader :analyzer
30
27
 
31
- def process sha
32
- analyzer.call commits: parser.call(*sha) do |collector, reporter|
28
+ def process arguments
29
+ analyzer.call commits: git.commits(*arguments) do |collector, reporter|
33
30
  kernel.puts reporter
34
31
  kernel.abort if collector.errors?
35
32
  end
@@ -6,7 +6,7 @@ module Git
6
6
  module Actions
7
7
  # Handles unsaved Git commit action.
8
8
  class Hook
9
- include Git::Lint::Import[:repository, :kernel, :logger]
9
+ include Git::Lint::Import[:git, :kernel, :logger]
10
10
 
11
11
  def initialize analyzer: Analyzer.new, **dependencies
12
12
  super(**dependencies)
@@ -14,7 +14,7 @@ module Git
14
14
  end
15
15
 
16
16
  def call path
17
- analyzer.call commits: [repository.unsaved(path)] do |collector, reporter|
17
+ analyzer.call commits: commits(path) do |collector, reporter|
18
18
  kernel.puts reporter
19
19
  kernel.abort if collector.errors?
20
20
  end
@@ -23,6 +23,8 @@ module Git
23
23
  private
24
24
 
25
25
  attr_reader :analyzer
26
+
27
+ def commits(path) = git.uncommitted(path).fmap { |commit| [commit] }
26
28
  end
27
29
  end
28
30
  end
@@ -9,10 +9,10 @@ module Git
9
9
  class Loader
10
10
  include Systems::Import[
11
11
  :circle_ci,
12
+ :git,
12
13
  :git_hub_action,
13
14
  :netlify_ci,
14
15
  :local,
15
- :repository,
16
16
  :environment
17
17
  ]
18
18
 
@@ -20,7 +20,7 @@ module Git
20
20
 
21
21
  def call
22
22
  message = "Invalid repository. Are you within a Git repository?"
23
- fail Errors::Base, message unless repository.exist?
23
+ fail Errors::Base, message unless git.exist?
24
24
 
25
25
  load_system.call
26
26
  end
@@ -6,13 +6,15 @@ module Git
6
6
  module Systems
7
7
  # Provides Circle CI build environment feature branch information.
8
8
  class CircleCI
9
- include Git::Lint::Import[:repository]
9
+ include Git::Lint::Import[:git]
10
10
 
11
- def call = repository.commits("origin/#{repository.branch_default}..#{name}")
11
+ def call = git.commits("origin/#{branch_default}..#{branch_name}")
12
12
 
13
13
  private
14
14
 
15
- def name = "origin/#{repository.branch_name}"
15
+ def branch_default = git.branch_default.value_or nil
16
+
17
+ def branch_name = "origin/#{git.branch_name.value_or nil}"
16
18
  end
17
19
  end
18
20
  end
@@ -6,13 +6,15 @@ module Git
6
6
  module Systems
7
7
  # Provides GitHub Action build environment feature branch information.
8
8
  class GitHubAction
9
- include Git::Lint::Import[:repository]
9
+ include Git::Lint::Import[:git]
10
10
 
11
- def call = repository.commits("origin/#{repository.branch_default}..#{name}")
11
+ def call = git.commits("origin/#{branch_default}..#{branch_name}")
12
12
 
13
13
  private
14
14
 
15
- def name = "origin/#{repository.branch_name}"
15
+ def branch_default = git.branch_default.value_or nil
16
+
17
+ def branch_name = "origin/#{git.branch_name.value_or nil}"
16
18
  end
17
19
  end
18
20
  end
@@ -6,13 +6,15 @@ module Git
6
6
  module Systems
7
7
  # Provides local build environment feature branch information.
8
8
  class Local
9
- include Git::Lint::Import[:repository]
9
+ include Git::Lint::Import[:git]
10
10
 
11
- def call = repository.commits("#{repository.branch_default}..#{name}")
11
+ def call = git.commits("#{branch_default}..#{branch_name}")
12
12
 
13
13
  private
14
14
 
15
- def name = repository.branch_name
15
+ def branch_default = git.branch_default.value_or nil
16
+
17
+ def branch_name = git.branch_name.value_or nil
16
18
  end
17
19
  end
18
20
  end