git-lint 9.7.0 → 10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8cab224e2fd996c6b443392e3aa1b2eff4f138aa64b33ff47ee02c3bbf3f8f3b
4
- data.tar.gz: 17b6e916f8bd625cfcdd8050512ae84d25aaefca086590d54b8a8c53c09bb0c7
3
+ metadata.gz: 98f3bcf679d8dac3f4ff32b0d9f569857088fbdcb60d8dd86162fd6ced3e8ffa
4
+ data.tar.gz: 3a553b6561394d438076fee08c548d45534137c23d1b51e2ae9b4a459b4629a9
5
5
  SHA512:
6
- metadata.gz: 1e15c14df6fa4d8c5019126f5ee2949309938a8b5955647952f45bef624efaa60c80bec17d71edf8ce28827bbb96942c9e8d80665bcb4a35f86c3a1ba464c22d
7
- data.tar.gz: e6ddd1ad8b09dda9235dede2fb61ded29fa9a06a7d9ed14b26aa5261924975525d16589e3efcb7ff9b6d026dbadb5e6d31e498863223e619844041648971df5e
6
+ metadata.gz: d522e26a6818717389e52cca02201862cf358175acaad9c2e52f90a5449cb3a9dda4caffdd5f3f5eaca696dd7259ea9536c8543078acc78d2784876c4bfba8a4
7
+ data.tar.gz: a0103d3d4d1c9ba81b3ab6e79cbdf69318e5e51d9bf224b02dde570d224308937d799a1aa869728dbe532cf3aefcea29768f538e8b32f7c2c68862ed73ee67f6
checksums.yaml.gz.sig CHANGED
Binary file
data/README.adoc CHANGED
@@ -194,6 +194,9 @@ commits:
194
194
  includes:
195
195
  - Good
196
196
  subject:
197
+ duplicate:
198
+ enabled: true
199
+ severity: error
197
200
  length:
198
201
  enabled: true
199
202
  severity: error
@@ -624,6 +627,27 @@ Ensures all commit signatures are properly signed for improved security and vali
624
627
 
625
628
  All of the above obtained when using the pretty formats as provided by link:https://git-scm.com/docs/git-log#Documentation/git-log.txt-emGem[Git Log].
626
629
 
630
+ ==== Commit Subject Duplicate
631
+
632
+ [options="header"]
633
+ |===
634
+ | Enabled | Severity
635
+ | true | error
636
+ |===
637
+
638
+ Ensures commit subjects are not duplicated so you can rebase and clean up accordingly. Example:
639
+
640
+ ....
641
+ # Disallowed
642
+ Added documentation
643
+ Added documentation
644
+
645
+ # Allowed
646
+ Added documentation
647
+ ....
648
+
649
+ Automatically ignores _amend!_, _fixup!_, or _squash!_ commit prefixes.
650
+
627
651
  ==== Commit Subject Length
628
652
 
629
653
  [options="header"]
data/git-lint.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "git-lint"
5
- spec.version = "9.7.0"
5
+ spec.version = "10.0.0"
6
6
  spec.authors = ["Brooke Kuhlmann"]
7
7
  spec.email = ["brooke@alchemists.io"]
8
8
  spec.homepage = "https://alchemists.io/projects/git-lint"
@@ -22,20 +22,21 @@ Gem::Specification.new do |spec|
22
22
  spec.signing_key = Gem.default_key_path
23
23
  spec.cert_chain = [Gem.default_cert_path]
24
24
 
25
- spec.required_ruby_version = ">= 3.4"
26
- spec.add_dependency "cogger", "~> 1.0"
27
- spec.add_dependency "containable", "~> 1.1"
28
- spec.add_dependency "core", "~> 2.5"
25
+ spec.required_ruby_version = ">= 4.0"
26
+
27
+ spec.add_dependency "cogger", "~> 2.0"
28
+ spec.add_dependency "containable", "~> 2.0"
29
+ spec.add_dependency "core", "~> 3.0"
29
30
  spec.add_dependency "dry-monads", "~> 1.9"
30
- spec.add_dependency "dry-schema", "~> 1.13"
31
- spec.add_dependency "etcher", "~> 3.0"
32
- spec.add_dependency "gitt", "~> 4.1"
33
- spec.add_dependency "infusible", "~> 4.0"
34
- spec.add_dependency "refinements", "~> 13.6"
35
- spec.add_dependency "runcom", "~> 12.0"
36
- spec.add_dependency "sod", "~> 1.5"
37
- spec.add_dependency "spek", "~> 4.0"
38
- spec.add_dependency "tone", "~> 2.0"
31
+ spec.add_dependency "dry-schema", "~> 1.14"
32
+ spec.add_dependency "etcher", "~> 4.0"
33
+ spec.add_dependency "gitt", "~> 5.0"
34
+ spec.add_dependency "infusible", "~> 5.0"
35
+ spec.add_dependency "refinements", "~> 14.0"
36
+ spec.add_dependency "runcom", "~> 13.0"
37
+ spec.add_dependency "sod", "~> 2.0"
38
+ spec.add_dependency "spek", "~> 5.0"
39
+ spec.add_dependency "tone", "~> 3.0"
39
40
  spec.add_dependency "zeitwerk", "~> 2.7"
40
41
 
41
42
  spec.bindir = "exe"
@@ -1,94 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "core"
4
+
3
5
  module Git
4
6
  module Lint
5
7
  # Runs all analyzers.
6
8
  class Analyzer
7
- include Dependencies[:settings]
9
+ include Dependencies[:collector]
8
10
 
9
- ANALYZERS = [
10
- Analyzers::CommitAuthorCapitalization,
11
- Analyzers::CommitAuthorEmail,
12
- Analyzers::CommitAuthorName,
13
- Analyzers::CommitBodyBulletCapitalization,
14
- Analyzers::CommitBodyBulletDelimiter,
15
- Analyzers::CommitBodyBulletOnly,
16
- Analyzers::CommitBodyLeadingLine,
17
- Analyzers::CommitBodyLineLength,
18
- Analyzers::CommitBodyParagraphCapitalization,
19
- Analyzers::CommitBodyPhrase,
20
- Analyzers::CommitBodyPresence,
21
- Analyzers::CommitBodyTrackerShorthand,
22
- Analyzers::CommitBodyWordRepeat,
23
- Analyzers::CommitSignature,
24
- Analyzers::CommitSubjectLength,
25
- Analyzers::CommitSubjectPrefix,
26
- Analyzers::CommitSubjectSuffix,
27
- Analyzers::CommitSubjectWordRepeat,
28
- Analyzers::CommitTrailerCollaboratorCapitalization,
29
- Analyzers::CommitTrailerCollaboratorEmail,
30
- Analyzers::CommitTrailerCollaboratorKey,
31
- Analyzers::CommitTrailerCollaboratorName,
32
- Analyzers::CommitTrailerDuplicate,
33
- Analyzers::CommitTrailerFormatKey,
34
- Analyzers::CommitTrailerFormatValue,
35
- Analyzers::CommitTrailerIssueKey,
36
- Analyzers::CommitTrailerIssueValue,
37
- Analyzers::CommitTrailerMilestoneKey,
38
- Analyzers::CommitTrailerMilestoneValue,
39
- Analyzers::CommitTrailerOrder,
40
- Analyzers::CommitTrailerReviewerKey,
41
- Analyzers::CommitTrailerReviewerValue,
42
- Analyzers::CommitTrailerSignerCapitalization,
43
- Analyzers::CommitTrailerSignerEmail,
44
- Analyzers::CommitTrailerSignerKey,
45
- Analyzers::CommitTrailerSignerName,
46
- Analyzers::CommitTrailerTrackerKey,
47
- Analyzers::CommitTrailerTrackerValue
48
- ].freeze
11
+ DELEGATES = [Analyzers::Commits::Sole, Analyzers::Commits::Many].freeze
49
12
 
50
- # rubocop:disable Metrics/ParameterLists
51
- def initialize(
52
- analyzers: ANALYZERS,
53
- collector: Collector.new,
54
- reporter: Reporters::Branch,
55
- **
56
- )
13
+ def initialize(reporter: Reporters::Branch, delegates: DELEGATES, **)
57
14
  super(**)
58
- @analyzers = analyzers
59
- @collector = collector
60
15
  @reporter = reporter
16
+ @delegates = delegates
61
17
  end
62
- # rubocop:enable Metrics/ParameterLists
63
18
 
64
- def call commits: Commits::Loader.new.call
19
+ def call commits = Core::EMPTY_ARRAY
65
20
  process commits
66
- a_reporter = reporter.new(collector:)
67
- block_given? ? yield(collector, a_reporter) : [collector, a_reporter]
21
+ reporter.new total: collector.total
68
22
  end
69
23
 
70
24
  private
71
25
 
72
- attr_reader :analyzers, :collector, :reporter
26
+ attr_reader :reporter, :delegates
73
27
 
74
28
  def process commits
75
29
  collector.clear
76
- commits.value_or([]).map { |commit| analyze commit }
77
- end
78
-
79
- def analyze(commit) = enabled.map { |id| collector.add load_analyzer(commit, id) }
80
-
81
- # :reek:FeatureEnvy
82
- def enabled
83
- settings.to_h
84
- .select { |key, value| key.end_with?("enabled") && value == true }
85
- .keys
86
- .map { |key| key.to_s.sub("commits_", "commit_").delete_suffix! "_enabled" }
87
- end
88
-
89
- def load_analyzer commit, id
90
- analyzers.find { |analyzer| analyzer.id == id }
91
- .then { |analyzer| analyzer.new commit }
30
+ delegates.each { |delegate| delegate.new.call commits }
92
31
  end
93
32
  end
94
33
  end
@@ -22,7 +22,9 @@ module Git
22
22
  Kit::FilterList.new settings.commits_body_bullet_delimiter_includes
23
23
  end
24
24
 
25
- def invalid_line?(line) = line.match?(/\A\s*#{pattern}(?!(#{pattern}|\s)).+\Z/)
25
+ def invalid_line? line
26
+ line.match?(/\A\s*#{pattern}(?!(#{pattern}|\s))(?!.+#{pattern}$).+\Z/)
27
+ end
26
28
 
27
29
  def pattern = Regexp.union filter_list
28
30
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "core"
4
+
5
+ module Git
6
+ module Lint
7
+ module Analyzers
8
+ module Commits
9
+ # Runs all analyzers for a single commit only.
10
+ class Many
11
+ include Dependencies[:settings, :collector]
12
+
13
+ ANALYZERS = [Analyzers::Commits::Subjects::Duplicate].freeze
14
+
15
+ def initialize(analyzers: ANALYZERS, **)
16
+ super(**)
17
+ @analyzers = analyzers
18
+ end
19
+
20
+ def call commits = Core::EMPTY_ARRAY
21
+ analyzers.select { |analyzer| settings.public_send :"#{analyzer.id}_enabled" }
22
+ .each { |analyzer| collector.add analyzer.new(commits) }
23
+
24
+ collector
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :analyzers
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "core"
4
+
5
+ module Git
6
+ module Lint
7
+ module Analyzers
8
+ module Commits
9
+ # Runs all analyzers for a single commit only.
10
+ class Sole
11
+ include Dependencies[:settings, :collector]
12
+
13
+ ANALYZERS = [
14
+ Analyzers::CommitAuthorCapitalization,
15
+ Analyzers::CommitAuthorEmail,
16
+ Analyzers::CommitAuthorName,
17
+ Analyzers::CommitBodyBulletCapitalization,
18
+ Analyzers::CommitBodyBulletDelimiter,
19
+ Analyzers::CommitBodyBulletOnly,
20
+ Analyzers::CommitBodyLeadingLine,
21
+ Analyzers::CommitBodyLineLength,
22
+ Analyzers::CommitBodyParagraphCapitalization,
23
+ Analyzers::CommitBodyPhrase,
24
+ Analyzers::CommitBodyPresence,
25
+ Analyzers::CommitBodyTrackerShorthand,
26
+ Analyzers::CommitBodyWordRepeat,
27
+ Analyzers::CommitSignature,
28
+ Analyzers::CommitSubjectLength,
29
+ Analyzers::CommitSubjectPrefix,
30
+ Analyzers::CommitSubjectSuffix,
31
+ Analyzers::CommitSubjectWordRepeat,
32
+ Analyzers::CommitTrailerCollaboratorCapitalization,
33
+ Analyzers::CommitTrailerCollaboratorEmail,
34
+ Analyzers::CommitTrailerCollaboratorKey,
35
+ Analyzers::CommitTrailerCollaboratorName,
36
+ Analyzers::CommitTrailerDuplicate,
37
+ Analyzers::CommitTrailerFormatKey,
38
+ Analyzers::CommitTrailerFormatValue,
39
+ Analyzers::CommitTrailerIssueKey,
40
+ Analyzers::CommitTrailerIssueValue,
41
+ Analyzers::CommitTrailerMilestoneKey,
42
+ Analyzers::CommitTrailerMilestoneValue,
43
+ Analyzers::CommitTrailerOrder,
44
+ Analyzers::CommitTrailerReviewerKey,
45
+ Analyzers::CommitTrailerReviewerValue,
46
+ Analyzers::CommitTrailerSignerCapitalization,
47
+ Analyzers::CommitTrailerSignerEmail,
48
+ Analyzers::CommitTrailerSignerKey,
49
+ Analyzers::CommitTrailerSignerName,
50
+ Analyzers::CommitTrailerTrackerKey,
51
+ Analyzers::CommitTrailerTrackerValue
52
+ ].freeze
53
+
54
+ def initialize(analyzers: ANALYZERS, **)
55
+ super(**)
56
+ @analyzers = analyzers
57
+ end
58
+
59
+ def call commits = Core::EMPTY_ARRAY
60
+ commits.each { |commit| select commit }
61
+ collector
62
+ end
63
+
64
+ private
65
+
66
+ attr_reader :analyzers
67
+
68
+ def select commit
69
+ settings.to_h
70
+ .select { |key, value| key.end_with?("enabled") && value == true }
71
+ .each_key do |key|
72
+ id = key.to_s.sub("commits_", "commit_").delete_suffix! "_enabled"
73
+ add commit, id
74
+ end
75
+ end
76
+
77
+ def add commit, id
78
+ analyzers.find { |analyzer| analyzer.id == id }
79
+ .then { |analyzer| collector.add analyzer.new(commit) if analyzer }
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/array"
4
+
5
+ module Git
6
+ module Lint
7
+ module Analyzers
8
+ module Commits
9
+ module Subjects
10
+ # Analyzes and detects duplicate subjects.
11
+ class Duplicate < Abstract
12
+ using Refinements::Array
13
+
14
+ def self.id = "commits_subject_duplicate"
15
+
16
+ def self.label = "Commit Subject Duplicate"
17
+
18
+ def initialize(commits, **)
19
+ super(nil, **)
20
+ @commits = commits
21
+ end
22
+
23
+ def valid? = normals.map(&:subject).tally.all? { |_subject, total| total == 1 }
24
+
25
+ def issue
26
+ return {} if valid?
27
+
28
+ {
29
+ hint: "Use unique subjects.",
30
+ references: normals.map { |commit| "#{commit.sha} #{commit.subject}" }
31
+ }
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :commits
37
+
38
+ def normals = commits.reject(&:directive?)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -15,26 +15,27 @@ module Git
15
15
 
16
16
  on %w[-b --branch]
17
17
 
18
- def initialize(analyzer: Analyzer.new, **)
18
+ def initialize(analyzer: Analyzer.new, loader: Git::Lint::Commits::Loader.new, **)
19
19
  super(**)
20
20
  @analyzer = analyzer
21
+ @loader = loader
21
22
  end
22
23
 
23
24
  def call(*)
24
- parse
25
+ report
25
26
  rescue Errors::Base => error
26
- logger.error { error.message }
27
- kernel.abort
27
+ logger.abort error.message
28
28
  end
29
29
 
30
30
  private
31
31
 
32
- attr_reader :analyzer
32
+ attr_reader :analyzer, :loader
33
33
 
34
- def parse
35
- analyzer.call do |collector, reporter|
34
+ def report
35
+ loader.call.bind do |commits|
36
+ reporter = analyzer.call commits
36
37
  io.puts reporter
37
- kernel.abort if collector.errors?
38
+ kernel.abort if reporter.errors?
38
39
  end
39
40
  end
40
41
  end
@@ -21,21 +21,25 @@ module Git
21
21
  end
22
22
 
23
23
  def call *arguments
24
- process arguments.unshift "-1"
24
+ collect arguments.unshift("-1")
25
25
  rescue Errors::Base => error
26
- logger.error { error.message }
27
- kernel.abort
26
+ logger.abort error.message
28
27
  end
29
28
 
30
29
  private
31
30
 
32
31
  attr_reader :analyzer
33
32
 
34
- def process arguments
35
- analyzer.call commits: git.commits(*arguments) do |collector, reporter|
36
- io.puts reporter
37
- kernel.abort if collector.errors?
38
- end
33
+ def collect arguments
34
+ git.commits(*arguments).either -> commits { report commits },
35
+ -> message { logger.abort message.chomp }
36
+ end
37
+
38
+ def report commits
39
+ reporter = analyzer.call commits
40
+
41
+ io.puts reporter
42
+ kernel.abort if reporter.errors?
39
43
  end
40
44
  end
41
45
  end
@@ -21,17 +21,17 @@ module Git
21
21
  end
22
22
 
23
23
  def call path
24
- analyzer.call commits: commits(path) do |collector, reporter|
25
- io.puts reporter
26
- kernel.abort if collector.errors?
27
- end
24
+ reporter = analyzer.call read(path)
25
+
26
+ io.puts reporter
27
+ kernel.abort if reporter.errors?
28
28
  end
29
29
 
30
30
  private
31
31
 
32
32
  attr_reader :analyzer
33
33
 
34
- def commits(path) = git.uncommitted(path).fmap { |commit| [commit] }
34
+ def read(path) = git.uncommitted(path).bind { |commit| [commit] }
35
35
  end
36
36
  end
37
37
  end
@@ -4,7 +4,8 @@ module Git
4
4
  module Lint
5
5
  # Collects and categorizes, by severity, all issues (if any).
6
6
  class Collector
7
- def initialize
7
+ def initialize model: Models::Total
8
+ @model = model
8
9
  @collection = Hash.new { |default, missing_id| default[missing_id] = [] }
9
10
  end
10
11
 
@@ -13,31 +14,28 @@ module Git
13
14
  analyzer
14
15
  end
15
16
 
17
+ def total
18
+ values = collection.values.flatten
19
+
20
+ model[
21
+ items: collection.keys.compact.size,
22
+ issues: values.count(&:invalid?),
23
+ warnings: values.count(&:warning?),
24
+ errors: values.count(&:error?)
25
+ ]
26
+ end
27
+
16
28
  def retrieve(id) = collection[id]
17
29
 
18
30
  def clear = collection.clear && self
19
31
 
20
32
  def empty? = collection.empty?
21
33
 
22
- def warnings? = collection.values.flatten.any?(&:warning?)
23
-
24
- def errors? = collection.values.flatten.any?(&:error?)
25
-
26
- def issues? = collection.values.flatten.any?(&:invalid?)
27
-
28
- def total_warnings = collection.values.flatten.count(&:warning?)
29
-
30
- def total_errors = collection.values.flatten.count(&:error?)
31
-
32
- def total_issues = collection.values.flatten.count(&:invalid?)
33
-
34
- def total_commits = collection.keys.size
35
-
36
34
  def to_h = collection
37
35
 
38
36
  private
39
37
 
40
- attr_reader :collection
38
+ attr_reader :model, :collection
41
39
  end
42
40
  end
43
41
  end
@@ -46,6 +46,8 @@ module Git
46
46
  required(:commits_signature_enabled).filled :bool
47
47
  required(:commits_signature_severity).filled :string
48
48
  required(:commits_signature_includes).array :string
49
+ required(:commits_subject_duplicate_enabled).filled :bool
50
+ required(:commits_subject_duplicate_severity).filled :string
49
51
  required(:commits_subject_length_enabled).filled :bool
50
52
  required(:commits_subject_length_severity).filled :string
51
53
  required(:commits_subject_length_maximum).filled :integer
@@ -91,6 +91,9 @@ commits:
91
91
  includes:
92
92
  - Good
93
93
  subject:
94
+ duplicate:
95
+ enabled: true
96
+ severity: error
94
97
  length:
95
98
  enabled: true
96
99
  severity: error
@@ -41,6 +41,8 @@ module Git
41
41
  :commits_signature_enabled,
42
42
  :commits_signature_severity,
43
43
  :commits_signature_includes,
44
+ :commits_subject_duplicate_enabled,
45
+ :commits_subject_duplicate_severity,
44
46
  :commits_subject_length_enabled,
45
47
  :commits_subject_length_severity,
46
48
  :commits_subject_length_maximum,
@@ -75,6 +75,7 @@ module Git
75
75
  register(:settings) { Etcher.call(self[:registry]).dup }
76
76
  register(:defaults_path) { Pathname(__dir__).join("configuration/defaults.yml") }
77
77
  register(:specification) { Spek::Loader.call "#{__dir__}/../../../git-lint.gemspec" }
78
+ register(:collector) { Collector.new }
78
79
  register(:color) { Tone.new }
79
80
  register :environment, ENV
80
81
  register(:git) { Gitt::Repository.new }
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ module Lint
5
+ module Models
6
+ # Models totals for reporting purposes.
7
+ Total = Data.define :items, :issues, :warnings, :errors do
8
+ def initialize items: 0, issues: 0, warnings: 0, errors: 0
9
+ super
10
+ end
11
+
12
+ def empty? = items.zero?
13
+
14
+ def issues? = issues.positive?
15
+
16
+ def warnings? = warnings.positive?
17
+
18
+ def errors? = errors.positive?
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,17 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "forwardable"
4
+
3
5
  module Git
4
6
  module Lint
5
7
  module Reporters
6
8
  # Reports issues related to a single branch.
7
9
  class Branch
8
- include Dependencies[:color]
10
+ extend Forwardable
11
+
12
+ include Dependencies[:collector, :color]
9
13
 
10
14
  using Refinements::String
11
15
 
12
- def initialize(collector: Collector.new, **)
16
+ DELEGATES = {individual: Individual, group: Group}.freeze
17
+
18
+ delegate %i[empty? issues? warnings? errors?] => :total
19
+
20
+ def initialize(total: Models::Total.new, delegates: DELEGATES, **)
13
21
  super(**)
14
- @collector = collector
22
+ @total = total
23
+ @delegates = delegates
15
24
  end
16
25
 
17
26
  def to_s
@@ -23,27 +32,35 @@ module Git
23
32
 
24
33
  private
25
34
 
26
- attr_reader :collector
35
+ attr_reader :total, :delegates
27
36
 
28
37
  def branch_report
29
- return "" unless collector.issues?
38
+ return "" unless total.issues?
30
39
 
31
40
  "\n\n#{commit_report}".chomp
32
41
  end
33
42
 
34
43
  def commit_report
35
- collector.to_h.reduce "" do |details, (commit, analyzers)|
36
- details + Commit.new(commit:, analyzers:)
44
+ collector.to_h.reduce "" do |details, (reference, analyzers)|
45
+ if reference
46
+ details + individual.new(reference, analyzers:)
47
+ else
48
+ details + group_by(analyzers)
49
+ end
37
50
  end
38
51
  end
39
52
 
53
+ def group_by analyzers
54
+ analyzers.reduce(+"") { |text, analyzer| text << group.new(analyzer) }
55
+ end
56
+
40
57
  def commit_total
41
- total = collector.total_commits
42
- %(#{total} #{"commit".pluralize "s", total} inspected)
58
+ commits = total.items
59
+ %(#{commits} #{"commit".pluralize "s", commits} inspected)
43
60
  end
44
61
 
45
62
  def issue_totals
46
- if collector.issues?
63
+ if total.issues?
47
64
  "#{issue_total} detected (#{warning_total}, #{error_total})"
48
65
  else
49
66
  color["0 issues", :green] + " detected"
@@ -51,22 +68,26 @@ module Git
51
68
  end
52
69
 
53
70
  def issue_total
54
- style = collector.errors? ? :red : :yellow
55
- total = collector.total_issues
56
- color["#{total} issue".pluralize("s", total), style]
71
+ style = total.errors? ? :red : :yellow
72
+ issues = total.issues
73
+ color["#{issues} issue".pluralize("s", issues), style]
57
74
  end
58
75
 
59
76
  def warning_total
60
- style = collector.warnings? ? :yellow : :green
61
- total = collector.total_warnings
62
- color["#{total} warning".pluralize("s", total), style]
77
+ style = total.warnings? ? :yellow : :green
78
+ warnings = total.warnings
79
+ color["#{warnings} warning".pluralize("s", warnings), style]
63
80
  end
64
81
 
65
82
  def error_total
66
- style = collector.errors? ? :red : :green
67
- total = collector.total_errors
68
- color["#{total} error".pluralize("s", total), style]
83
+ style = total.errors? ? :red : :green
84
+ errors = total.errors
85
+ color["#{errors} error".pluralize("s", errors), style]
69
86
  end
87
+
88
+ def individual = delegates.fetch __method__
89
+
90
+ def group = delegates.fetch __method__
70
91
  end
71
92
  end
72
93
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "core"
4
+
5
+ module Git
6
+ module Lint
7
+ module Reporters
8
+ # Reports issue for a group of references.
9
+ class Group
10
+ include Dependencies[:color]
11
+
12
+ def initialize(analyzer, **)
13
+ super(**)
14
+ @analyzer = analyzer
15
+ @issue = analyzer.issue
16
+ end
17
+
18
+ def to_s
19
+ return Core::EMPTY_STRING if issue.empty?
20
+
21
+ color[message, style]
22
+ end
23
+
24
+ alias to_str to_s
25
+
26
+ private
27
+
28
+ attr_reader :analyzer, :issue
29
+
30
+ def message
31
+ "#{analyzer.class.label}#{severity_suffix}. #{issue.fetch :hint}\n" \
32
+ "#{affected_references}"
33
+ end
34
+
35
+ def severity_suffix
36
+ case analyzer.severity
37
+ when "warn" then " Warning"
38
+ when "error" then " Error"
39
+ else ""
40
+ end
41
+ end
42
+
43
+ def style
44
+ case analyzer.severity
45
+ when "warn" then :yellow
46
+ when "error" then :red
47
+ else :white
48
+ end
49
+ end
50
+
51
+ def affected_references
52
+ issue.fetch(:references, Core::EMPTY_ARRAY)
53
+ .map { |sha| " #{sha}" }
54
+ .join "\n"
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -3,25 +3,25 @@
3
3
  module Git
4
4
  module Lint
5
5
  module Reporters
6
- # Reports issues related to a single commit.
7
- class Commit
8
- def initialize commit:, analyzers: []
9
- @commit = commit
6
+ # Reports issues related to a single reference.
7
+ class Individual
8
+ def initialize reference, analyzers: []
9
+ @reference = reference
10
10
  @analyzers = analyzers.select(&:invalid?)
11
11
  end
12
12
 
13
13
  def to_s
14
14
  return "" if analyzers.empty?
15
15
 
16
- "#{commit.sha} (#{commit.author_name}, #{commit.authored_relative_at}): " \
17
- "#{commit.subject}\n#{report}\n"
16
+ "#{reference.sha} (#{reference.author_name}, #{reference.authored_relative_at}): " \
17
+ "#{reference.subject}\n#{report}\n"
18
18
  end
19
19
 
20
20
  alias to_str to_s
21
21
 
22
22
  private
23
23
 
24
- attr_reader :commit, :analyzers
24
+ attr_reader :reference, :analyzers
25
25
 
26
26
  def report = analyzers.reduce("") { |report, analyzer| report + Style.new(analyzer) }
27
27
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git-lint
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.7.0
4
+ version: 10.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brooke Kuhlmann
@@ -41,42 +41,42 @@ dependencies:
41
41
  requirements:
42
42
  - - "~>"
43
43
  - !ruby/object:Gem::Version
44
- version: '1.0'
44
+ version: '2.0'
45
45
  type: :runtime
46
46
  prerelease: false
47
47
  version_requirements: !ruby/object:Gem::Requirement
48
48
  requirements:
49
49
  - - "~>"
50
50
  - !ruby/object:Gem::Version
51
- version: '1.0'
51
+ version: '2.0'
52
52
  - !ruby/object:Gem::Dependency
53
53
  name: containable
54
54
  requirement: !ruby/object:Gem::Requirement
55
55
  requirements:
56
56
  - - "~>"
57
57
  - !ruby/object:Gem::Version
58
- version: '1.1'
58
+ version: '2.0'
59
59
  type: :runtime
60
60
  prerelease: false
61
61
  version_requirements: !ruby/object:Gem::Requirement
62
62
  requirements:
63
63
  - - "~>"
64
64
  - !ruby/object:Gem::Version
65
- version: '1.1'
65
+ version: '2.0'
66
66
  - !ruby/object:Gem::Dependency
67
67
  name: core
68
68
  requirement: !ruby/object:Gem::Requirement
69
69
  requirements:
70
70
  - - "~>"
71
71
  - !ruby/object:Gem::Version
72
- version: '2.5'
72
+ version: '3.0'
73
73
  type: :runtime
74
74
  prerelease: false
75
75
  version_requirements: !ruby/object:Gem::Requirement
76
76
  requirements:
77
77
  - - "~>"
78
78
  - !ruby/object:Gem::Version
79
- version: '2.5'
79
+ version: '3.0'
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: dry-monads
82
82
  requirement: !ruby/object:Gem::Requirement
@@ -97,126 +97,126 @@ dependencies:
97
97
  requirements:
98
98
  - - "~>"
99
99
  - !ruby/object:Gem::Version
100
- version: '1.13'
100
+ version: '1.14'
101
101
  type: :runtime
102
102
  prerelease: false
103
103
  version_requirements: !ruby/object:Gem::Requirement
104
104
  requirements:
105
105
  - - "~>"
106
106
  - !ruby/object:Gem::Version
107
- version: '1.13'
107
+ version: '1.14'
108
108
  - !ruby/object:Gem::Dependency
109
109
  name: etcher
110
110
  requirement: !ruby/object:Gem::Requirement
111
111
  requirements:
112
112
  - - "~>"
113
113
  - !ruby/object:Gem::Version
114
- version: '3.0'
114
+ version: '4.0'
115
115
  type: :runtime
116
116
  prerelease: false
117
117
  version_requirements: !ruby/object:Gem::Requirement
118
118
  requirements:
119
119
  - - "~>"
120
120
  - !ruby/object:Gem::Version
121
- version: '3.0'
121
+ version: '4.0'
122
122
  - !ruby/object:Gem::Dependency
123
123
  name: gitt
124
124
  requirement: !ruby/object:Gem::Requirement
125
125
  requirements:
126
126
  - - "~>"
127
127
  - !ruby/object:Gem::Version
128
- version: '4.1'
128
+ version: '5.0'
129
129
  type: :runtime
130
130
  prerelease: false
131
131
  version_requirements: !ruby/object:Gem::Requirement
132
132
  requirements:
133
133
  - - "~>"
134
134
  - !ruby/object:Gem::Version
135
- version: '4.1'
135
+ version: '5.0'
136
136
  - !ruby/object:Gem::Dependency
137
137
  name: infusible
138
138
  requirement: !ruby/object:Gem::Requirement
139
139
  requirements:
140
140
  - - "~>"
141
141
  - !ruby/object:Gem::Version
142
- version: '4.0'
142
+ version: '5.0'
143
143
  type: :runtime
144
144
  prerelease: false
145
145
  version_requirements: !ruby/object:Gem::Requirement
146
146
  requirements:
147
147
  - - "~>"
148
148
  - !ruby/object:Gem::Version
149
- version: '4.0'
149
+ version: '5.0'
150
150
  - !ruby/object:Gem::Dependency
151
151
  name: refinements
152
152
  requirement: !ruby/object:Gem::Requirement
153
153
  requirements:
154
154
  - - "~>"
155
155
  - !ruby/object:Gem::Version
156
- version: '13.6'
156
+ version: '14.0'
157
157
  type: :runtime
158
158
  prerelease: false
159
159
  version_requirements: !ruby/object:Gem::Requirement
160
160
  requirements:
161
161
  - - "~>"
162
162
  - !ruby/object:Gem::Version
163
- version: '13.6'
163
+ version: '14.0'
164
164
  - !ruby/object:Gem::Dependency
165
165
  name: runcom
166
166
  requirement: !ruby/object:Gem::Requirement
167
167
  requirements:
168
168
  - - "~>"
169
169
  - !ruby/object:Gem::Version
170
- version: '12.0'
170
+ version: '13.0'
171
171
  type: :runtime
172
172
  prerelease: false
173
173
  version_requirements: !ruby/object:Gem::Requirement
174
174
  requirements:
175
175
  - - "~>"
176
176
  - !ruby/object:Gem::Version
177
- version: '12.0'
177
+ version: '13.0'
178
178
  - !ruby/object:Gem::Dependency
179
179
  name: sod
180
180
  requirement: !ruby/object:Gem::Requirement
181
181
  requirements:
182
182
  - - "~>"
183
183
  - !ruby/object:Gem::Version
184
- version: '1.5'
184
+ version: '2.0'
185
185
  type: :runtime
186
186
  prerelease: false
187
187
  version_requirements: !ruby/object:Gem::Requirement
188
188
  requirements:
189
189
  - - "~>"
190
190
  - !ruby/object:Gem::Version
191
- version: '1.5'
191
+ version: '2.0'
192
192
  - !ruby/object:Gem::Dependency
193
193
  name: spek
194
194
  requirement: !ruby/object:Gem::Requirement
195
195
  requirements:
196
196
  - - "~>"
197
197
  - !ruby/object:Gem::Version
198
- version: '4.0'
198
+ version: '5.0'
199
199
  type: :runtime
200
200
  prerelease: false
201
201
  version_requirements: !ruby/object:Gem::Requirement
202
202
  requirements:
203
203
  - - "~>"
204
204
  - !ruby/object:Gem::Version
205
- version: '4.0'
205
+ version: '5.0'
206
206
  - !ruby/object:Gem::Dependency
207
207
  name: tone
208
208
  requirement: !ruby/object:Gem::Requirement
209
209
  requirements:
210
210
  - - "~>"
211
211
  - !ruby/object:Gem::Version
212
- version: '2.0'
212
+ version: '3.0'
213
213
  type: :runtime
214
214
  prerelease: false
215
215
  version_requirements: !ruby/object:Gem::Requirement
216
216
  requirements:
217
217
  - - "~>"
218
218
  - !ruby/object:Gem::Version
219
- version: '2.0'
219
+ version: '3.0'
220
220
  - !ruby/object:Gem::Dependency
221
221
  name: zeitwerk
222
222
  requirement: !ruby/object:Gem::Requirement
@@ -285,6 +285,9 @@ files:
285
285
  - lib/git/lint/analyzers/commit_trailer_signer_name.rb
286
286
  - lib/git/lint/analyzers/commit_trailer_tracker_key.rb
287
287
  - lib/git/lint/analyzers/commit_trailer_tracker_value.rb
288
+ - lib/git/lint/analyzers/commits/many.rb
289
+ - lib/git/lint/analyzers/commits/sole.rb
290
+ - lib/git/lint/analyzers/commits/subjects/duplicate.rb
288
291
  - lib/git/lint/cli/actions/analyze/branch.rb
289
292
  - lib/git/lint/cli/actions/analyze/commit.rb
290
293
  - lib/git/lint/cli/actions/hook.rb
@@ -305,9 +308,11 @@ files:
305
308
  - lib/git/lint/errors/severity.rb
306
309
  - lib/git/lint/errors/sha.rb
307
310
  - lib/git/lint/kit/filter_list.rb
311
+ - lib/git/lint/models/total.rb
308
312
  - lib/git/lint/rake/register.rb
309
313
  - lib/git/lint/reporters/branch.rb
310
- - lib/git/lint/reporters/commit.rb
314
+ - lib/git/lint/reporters/group.rb
315
+ - lib/git/lint/reporters/individual.rb
311
316
  - lib/git/lint/reporters/line.rb
312
317
  - lib/git/lint/reporters/lines/paragraph.rb
313
318
  - lib/git/lint/reporters/lines/sentence.rb
@@ -334,14 +339,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
334
339
  requirements:
335
340
  - - ">="
336
341
  - !ruby/object:Gem::Version
337
- version: '3.4'
342
+ version: '4.0'
338
343
  required_rubygems_version: !ruby/object:Gem::Requirement
339
344
  requirements:
340
345
  - - ">="
341
346
  - !ruby/object:Gem::Version
342
347
  version: '0'
343
348
  requirements: []
344
- rubygems_version: 3.7.2
349
+ rubygems_version: 4.0.3
345
350
  specification_version: 4
346
351
  summary: A command line interface for linting Git commits.
347
352
  test_files: []
metadata.gz.sig CHANGED
Binary file