git-lint 3.3.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/LICENSE.adoc +134 -214
  4. data/README.adoc +2 -1
  5. data/git-lint.gemspec +6 -4
  6. data/lib/git/lint/analyzer.rb +6 -4
  7. data/lib/git/lint/analyzers/abstract.rb +6 -4
  8. data/lib/git/lint/analyzers/commit_author_capitalization.rb +2 -2
  9. data/lib/git/lint/analyzers/commit_author_email.rb +2 -2
  10. data/lib/git/lint/analyzers/commit_author_name.rb +2 -2
  11. data/lib/git/lint/analyzers/commit_subject_prefix.rb +5 -1
  12. data/lib/git/lint/analyzers/commit_trailer_collaborator_capitalization.rb +5 -2
  13. data/lib/git/lint/analyzers/commit_trailer_collaborator_duplication.rb +2 -2
  14. data/lib/git/lint/analyzers/commit_trailer_collaborator_email.rb +5 -3
  15. data/lib/git/lint/analyzers/commit_trailer_collaborator_key.rb +2 -2
  16. data/lib/git/lint/analyzers/commit_trailer_collaborator_name.rb +5 -3
  17. data/lib/git/lint/cli/actions/analyze/branch.rb +5 -9
  18. data/lib/git/lint/cli/actions/analyze/commit.rb +5 -7
  19. data/lib/git/lint/cli/actions/config.rb +5 -7
  20. data/lib/git/lint/cli/actions/container.rb +25 -0
  21. data/lib/git/lint/cli/actions/hook.rb +5 -9
  22. data/lib/git/lint/cli/actions/import.rb +13 -0
  23. data/lib/git/lint/cli/parser.rb +8 -5
  24. data/lib/git/lint/cli/parsers/core.rb +5 -5
  25. data/lib/git/lint/cli/shell.rb +17 -30
  26. data/lib/git/lint/commits/loader.rb +13 -22
  27. data/lib/git/lint/commits/systems/circle_ci.rb +1 -7
  28. data/lib/git/lint/commits/systems/container.rb +25 -0
  29. data/lib/git/lint/commits/systems/git_hub_action.rb +1 -7
  30. data/lib/git/lint/commits/systems/import.rb +13 -0
  31. data/lib/git/lint/commits/systems/local.rb +1 -7
  32. data/lib/git/lint/commits/systems/netlify_ci.rb +3 -13
  33. data/lib/git/lint/container.rb +5 -24
  34. data/lib/git/lint/import.rb +9 -0
  35. data.tar.gz.sig +0 -0
  36. metadata +51 -19
  37. metadata.gz.sig +0 -0
  38. data/lib/git/lint/commits/container.rb +0 -19
@@ -5,14 +5,16 @@ 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
8
9
  def initialize commit,
9
10
  parser: Parsers::Trailers::Collaborator,
10
- validator: Validators::Email
11
-
12
- super commit
11
+ validator: Validators::Email,
12
+ **dependencies
13
+ super commit, **dependencies
13
14
  @parser = parser
14
15
  @validator = validator
15
16
  end
17
+ # rubocop:enable Metrics/ParameterLists
16
18
 
17
19
  def valid? = affected_commit_trailers.empty?
18
20
 
@@ -5,8 +5,8 @@ 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
9
- super commit
8
+ def initialize commit, parser: Parsers::Trailers::Collaborator, **dependencies
9
+ super commit, **dependencies
10
10
  @parser = parser
11
11
  end
12
12
 
@@ -5,14 +5,16 @@ module Git
5
5
  module Analyzers
6
6
  # Analyzes commit trailer collaborator name construction.
7
7
  class CommitTrailerCollaboratorName < Abstract
8
+ # rubocop:disable Metrics/ParameterLists
8
9
  def initialize commit,
9
10
  parser: Parsers::Trailers::Collaborator,
10
- validator: Validators::Name
11
-
12
- super commit
11
+ validator: Validators::Name,
12
+ **dependencies
13
+ super commit, **dependencies
13
14
  @parser = parser
14
15
  @validator = validator
15
16
  end
17
+ # rubocop:enable Metrics/ParameterLists
16
18
 
17
19
  def valid? = affected_commit_trailers.empty?
18
20
 
@@ -7,9 +7,11 @@ module Git
7
7
  module Analyze
8
8
  # Handles analyze action for branch.
9
9
  class Branch
10
- def initialize analyzer: Analyzer.new, container: Container
10
+ include Git::Lint::Import[:repository, :kernel, :logger]
11
+
12
+ def initialize analyzer: Analyzer.new, **dependencies
13
+ super(**dependencies)
11
14
  @analyzer = analyzer
12
- @container = container
13
15
  end
14
16
 
15
17
  def call
@@ -21,7 +23,7 @@ module Git
21
23
 
22
24
  private
23
25
 
24
- attr_reader :analyzer, :container
26
+ attr_reader :analyzer
25
27
 
26
28
  def parse
27
29
  analyzer.call do |collector, reporter|
@@ -29,12 +31,6 @@ module Git
29
31
  kernel.abort if collector.errors?
30
32
  end
31
33
  end
32
-
33
- def repository = container[__method__]
34
-
35
- def kernel = container[__method__]
36
-
37
- def logger = container[__method__]
38
34
  end
39
35
  end
40
36
  end
@@ -7,12 +7,14 @@ module Git
7
7
  module Analyze
8
8
  # Handles analyze action for commit(s) by SHA.
9
9
  class Commit
10
+ include Git::Lint::Import[:kernel, :logger]
11
+
10
12
  def initialize analyzer: Analyzer.new,
11
13
  parser: GitPlus::Parsers::Commits::Saved::History.with_show,
12
- container: Container
14
+ **dependencies
15
+ super(**dependencies)
13
16
  @analyzer = analyzer
14
17
  @parser = parser
15
- @container = container
16
18
  end
17
19
 
18
20
  def call sha = nil
@@ -24,7 +26,7 @@ module Git
24
26
 
25
27
  private
26
28
 
27
- attr_reader :analyzer, :parser, :container
29
+ attr_reader :analyzer, :parser
28
30
 
29
31
  def process sha
30
32
  analyzer.call commits: parser.call(*sha) do |collector, reporter|
@@ -32,10 +34,6 @@ module Git
32
34
  kernel.abort if collector.errors?
33
35
  end
34
36
  end
35
-
36
- def kernel = container[__method__]
37
-
38
- def logger = container[__method__]
39
37
  end
40
38
  end
41
39
  end
@@ -6,9 +6,11 @@ module Git
6
6
  module Actions
7
7
  # Handles gem configuration action.
8
8
  class Config
9
- def initialize configuration: Configuration::Loader::CLIENT, container: Container
9
+ include Git::Lint::Import[:kernel, :logger]
10
+
11
+ def initialize configuration: Configuration::Loader::CLIENT, **dependencies
12
+ super(**dependencies)
10
13
  @configuration = configuration
11
- @container = container
12
14
  end
13
15
 
14
16
  def call action
@@ -21,15 +23,11 @@ module Git
21
23
 
22
24
  private
23
25
 
24
- attr_reader :configuration, :container
26
+ attr_reader :configuration
25
27
 
26
28
  def edit = kernel.system("$EDITOR #{configuration.current}")
27
29
 
28
30
  def view = kernel.system("cat #{configuration.current}")
29
-
30
- def kernel = container[__method__]
31
-
32
- def logger = container[__method__]
33
31
  end
34
32
  end
35
33
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/container"
4
+
5
+ module Git
6
+ module Lint
7
+ module CLI
8
+ module Actions
9
+ # Provides a single container with application and action specific dependencies.
10
+ module Container
11
+ extend Dry::Container::Mixin
12
+
13
+ config.registry = ->(container, key, value, _options) { container[key.to_s] = value }
14
+
15
+ merge Git::Lint::Container
16
+
17
+ register(:analyze_branch) { Analyze::Branch.new }
18
+ register(:analyze_commit) { Analyze::Commit.new }
19
+ register(:config) { Config.new }
20
+ register(:hook) { Hook.new }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -6,9 +6,11 @@ module Git
6
6
  module Actions
7
7
  # Handles unsaved Git commit action.
8
8
  class Hook
9
- def initialize analyzer: Analyzer.new, container: Container
9
+ include Git::Lint::Import[:repository, :kernel, :logger]
10
+
11
+ def initialize analyzer: Analyzer.new, **dependencies
12
+ super(**dependencies)
10
13
  @analyzer = analyzer
11
- @container = container
12
14
  end
13
15
 
14
16
  def call path
@@ -20,13 +22,7 @@ module Git
20
22
 
21
23
  private
22
24
 
23
- attr_reader :analyzer, :container
24
-
25
- def repository = container[__method__]
26
-
27
- def kernel = container[__method__]
28
-
29
- def logger = container[__method__]
25
+ attr_reader :analyzer
30
26
  end
31
27
  end
32
28
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "auto_injector"
4
+
5
+ module Git
6
+ module Lint
7
+ module CLI
8
+ module Actions
9
+ Import = AutoInjector[Container]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -7,26 +7,29 @@ module Git
7
7
  module CLI
8
8
  # Assembles and parses all Command Line Interface (CLI) options.
9
9
  class Parser
10
+ include Import[:configuration]
11
+
10
12
  CLIENT = OptionParser.new nil, 40, " "
11
13
  SECTIONS = [Parsers::Core, Parsers::Analyze].freeze # Order matters.
12
14
 
13
- def initialize sections: SECTIONS, client: CLIENT, container: Container
15
+ def initialize sections: SECTIONS, client: CLIENT, **dependencies
16
+ super(**dependencies)
14
17
  @sections = sections
15
18
  @client = client
16
- @configuration = container[:configuration].dup
19
+ @configuration_duplicate = configuration.dup
17
20
  end
18
21
 
19
22
  def call arguments = []
20
- sections.each { |section| section.call configuration, client: }
23
+ sections.each { |section| section.call configuration_duplicate, client: }
21
24
  client.parse arguments
22
- configuration.freeze
25
+ configuration_duplicate.freeze
23
26
  end
24
27
 
25
28
  def to_s = client.to_s
26
29
 
27
30
  private
28
31
 
29
- attr_reader :sections, :client, :configuration
32
+ attr_reader :sections, :client, :configuration_duplicate
30
33
  end
31
34
  end
32
35
  end
@@ -8,16 +8,18 @@ module Git
8
8
  module Parsers
9
9
  # Handles parsing of Command Line Interface (CLI) core options.
10
10
  class Core
11
+ include Import[:specification]
12
+
11
13
  using ::Refinements::Structs
12
14
 
13
15
  def self.call(...) = new(...).call
14
16
 
15
17
  def initialize configuration = Container[:configuration],
16
18
  client: Parser::CLIENT,
17
- container: Container
19
+ **dependencies
20
+ super(**dependencies)
18
21
  @configuration = configuration
19
22
  @client = client
20
- @container = container
21
23
  end
22
24
 
23
25
  def call arguments = []
@@ -30,7 +32,7 @@ module Git
30
32
 
31
33
  private
32
34
 
33
- attr_reader :configuration, :client, :container
35
+ attr_reader :configuration, :client
34
36
 
35
37
  def collate = private_methods.sort.grep(/add_/).each { |method| __send__ method }
36
38
 
@@ -68,8 +70,6 @@ module Git
68
70
  configuration.merge! action_help: true
69
71
  end
70
72
  end
71
-
72
- def specification = container[__method__]
73
73
  end
74
74
  end
75
75
  end
@@ -5,17 +5,18 @@ module Git
5
5
  module CLI
6
6
  # The main Command Line Interface (CLI) object.
7
7
  class Shell
8
- ACTIONS = {
9
- analyze_branch: Actions::Analyze::Branch.new,
10
- analyze_commit: Actions::Analyze::Commit.new,
11
- config: Actions::Config.new,
12
- hook: Actions::Hook.new
13
- }.freeze
14
-
15
- def initialize parser: Parser.new, actions: ACTIONS, container: Container
8
+ include Actions::Import[
9
+ :analyze_branch,
10
+ :analyze_commit,
11
+ :config,
12
+ :hook,
13
+ :specification,
14
+ :logger
15
+ ]
16
+
17
+ def initialize parser: Parser.new, **dependencies
18
+ super(**dependencies)
16
19
  @parser = parser
17
- @actions = actions
18
- @container = container
19
20
  end
20
21
 
21
22
  def call arguments = []
@@ -26,32 +27,18 @@ module Git
26
27
 
27
28
  private
28
29
 
29
- attr_reader :parser, :actions, :container
30
+ attr_reader :parser
30
31
 
31
32
  def perform configuration
32
33
  case configuration
33
- in action_analyze: true, analyze_sha: nil then analyze_branch
34
- in action_analyze: true, analyze_sha: String => sha then analyze_commit sha
35
- in action_config: Symbol => action then config action
36
- in action_hook: Pathname => path then hook path
34
+ in action_analyze: true, analyze_sha: nil then analyze_branch.call
35
+ in action_analyze: true, analyze_sha: String => sha then analyze_commit.call sha
36
+ in action_config: Symbol => action then config.call action
37
+ in action_hook: Pathname => path then hook.call path
37
38
  in action_version: true then logger.info { specification.labeled_version }
38
- else usage
39
+ else logger.any { parser.to_s }
39
40
  end
40
41
  end
41
-
42
- def analyze_branch = actions.fetch(__method__).call
43
-
44
- def analyze_commit(sha) = actions.fetch(__method__).call(sha)
45
-
46
- def config(action) = actions.fetch(__method__).call(action)
47
-
48
- def hook(path) = actions.fetch(__method__).call(path)
49
-
50
- def usage = logger.unknown { parser.to_s }
51
-
52
- def specification = container[__method__]
53
-
54
- def logger = container[__method__]
55
42
  end
56
43
  end
57
44
  end
@@ -7,19 +7,16 @@ module Git
7
7
  module Commits
8
8
  # Automatically detects and loads system.
9
9
  class Loader
10
- using ::Refinements::Strings
11
-
12
- SYSTEMS = {
13
- circle_ci: Systems::CircleCI.new,
14
- git_hub_action: Systems::GitHubAction.new,
15
- netlify_ci: Systems::NetlifyCI.new,
16
- local: Systems::Local.new
17
- }.freeze
10
+ include Systems::Import[
11
+ :circle_ci,
12
+ :git_hub_action,
13
+ :netlify_ci,
14
+ :local,
15
+ :repository,
16
+ :environment
17
+ ]
18
18
 
19
- def initialize systems: SYSTEMS, container: Container
20
- @systems = systems
21
- @container = container
22
- end
19
+ using ::Refinements::Strings
23
20
 
24
21
  def call
25
22
  message = "Invalid repository. Are you within a Git repository?"
@@ -30,21 +27,15 @@ module Git
30
27
 
31
28
  private
32
29
 
33
- attr_reader :systems, :container
34
-
35
30
  def load_system
36
- if key? "CIRCLECI" then systems.fetch :circle_ci
37
- elsif key? "GITHUB_ACTIONS" then systems.fetch :git_hub_action
38
- elsif key? "NETLIFY" then systems.fetch :netlify_ci
39
- else systems.fetch :local
31
+ if key? "CIRCLECI" then circle_ci
32
+ elsif key? "GITHUB_ACTIONS" then git_hub_action
33
+ elsif key? "NETLIFY" then netlify_ci
34
+ else local
40
35
  end
41
36
  end
42
37
 
43
38
  def key?(key) = environment.fetch(key, "false").to_bool
44
-
45
- def repository = container[__method__]
46
-
47
- def environment = container[__method__]
48
39
  end
49
40
  end
50
41
  end
@@ -6,19 +6,13 @@ module Git
6
6
  module Systems
7
7
  # Provides Circle CI build environment feature branch information.
8
8
  class CircleCI
9
- def initialize container: Container
10
- @container = container
11
- end
9
+ include Git::Lint::Import[:repository]
12
10
 
13
11
  def call = repository.commits("origin/#{repository.branch_default}..#{name}")
14
12
 
15
13
  private
16
14
 
17
- attr_reader :container
18
-
19
15
  def name = "origin/#{repository.branch_name}"
20
-
21
- def repository = container[__method__]
22
16
  end
23
17
  end
24
18
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/container"
4
+
5
+ module Git
6
+ module Lint
7
+ module Commits
8
+ module Systems
9
+ # Provides a single container with application and system specific dependencies.
10
+ module Container
11
+ extend Dry::Container::Mixin
12
+
13
+ config.registry = ->(container, key, value, _options) { container[key.to_s] = value }
14
+
15
+ merge Git::Lint::Container
16
+
17
+ register(:circle_ci) { CircleCI.new }
18
+ register(:git_hub_action) { GitHubAction.new }
19
+ register(:netlify_ci) { NetlifyCI.new }
20
+ register(:local) { Local.new }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -6,19 +6,13 @@ module Git
6
6
  module Systems
7
7
  # Provides GitHub Action build environment feature branch information.
8
8
  class GitHubAction
9
- def initialize container: Container
10
- @container = container
11
- end
9
+ include Git::Lint::Import[:repository]
12
10
 
13
11
  def call = repository.commits("origin/#{repository.branch_default}..#{name}")
14
12
 
15
13
  private
16
14
 
17
- attr_reader :container
18
-
19
15
  def name = "origin/#{repository.branch_name}"
20
-
21
- def repository = container[__method__]
22
16
  end
23
17
  end
24
18
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "auto_injector"
4
+
5
+ module Git
6
+ module Lint
7
+ module Commits
8
+ module Systems
9
+ Import = AutoInjector[Container]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -6,19 +6,13 @@ module Git
6
6
  module Systems
7
7
  # Provides local build environment feature branch information.
8
8
  class Local
9
- def initialize container: Container
10
- @container = container
11
- end
9
+ include Git::Lint::Import[:repository]
12
10
 
13
11
  def call = repository.commits("#{repository.branch_default}..#{name}")
14
12
 
15
13
  private
16
14
 
17
- attr_reader :container
18
-
19
15
  def name = repository.branch_name
20
-
21
- def repository = container[__method__]
22
16
  end
23
17
  end
24
18
  end
@@ -8,27 +8,17 @@ module Git
8
8
  module Systems
9
9
  # Provides Netlify CI build environment feature branch information.
10
10
  class NetlifyCI
11
- def initialize container: Container
12
- @container = container
13
- end
11
+ include Git::Lint::Import[:repository, :executor, :environment]
14
12
 
15
13
  def call
16
- shell.capture3 "git remote add -f origin #{environment["REPOSITORY_URL"]}"
17
- shell.capture3 "git fetch origin #{name}:#{name}"
14
+ executor.capture3 "git remote add -f origin #{environment["REPOSITORY_URL"]}"
15
+ executor.capture3 "git fetch origin #{name}:#{name}"
18
16
  repository.commits "origin/#{repository.branch_default}..origin/#{name}"
19
17
  end
20
18
 
21
19
  private
22
20
 
23
- attr_reader :container
24
-
25
21
  def name = environment["HEAD"]
26
-
27
- def repository = container[__method__]
28
-
29
- def shell = container[__method__]
30
-
31
- def environment = container[__method__]
32
22
  end
33
23
  end
34
24
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "cogger"
3
4
  require "dry-container"
4
5
  require "git_plus"
5
- require "logger"
6
- require "pastel"
6
+ require "open3"
7
7
  require "spek"
8
8
 
9
9
  module Git
@@ -13,31 +13,12 @@ module Git
13
13
  extend Dry::Container::Mixin
14
14
 
15
15
  register(:configuration) { Configuration::Loader.call }
16
+ register(:environment) { ENV }
16
17
  register(:repository) { GitPlus::Repository.new }
17
18
  register(:specification) { Spek::Loader.call "#{__dir__}/../../../git-lint.gemspec" }
18
- register(:colorizer) { Pastel.new enabled: $stdout.tty? }
19
19
  register(:kernel) { Kernel }
20
-
21
- register :log_colors do
22
- {
23
- "DEBUG" => self[:colorizer].white.detach,
24
- "INFO" => self[:colorizer].green.detach,
25
- "WARN" => self[:colorizer].yellow.detach,
26
- "ERROR" => self[:colorizer].red.detach,
27
- "FATAL" => self[:colorizer].white.bold.on_red.detach,
28
- "ANY" => self[:colorizer].white.bold.detach
29
- }
30
- end
31
-
32
- register :logger do
33
- Logger.new $stdout,
34
- level: Logger.const_get(ENV.fetch("LOG_LEVEL", "INFO")),
35
- formatter: (
36
- lambda do |severity, _at, _name, message|
37
- self[:log_colors][severity].call "#{message}\n"
38
- end
39
- )
40
- end
20
+ register(:executor) { Open3 }
21
+ register(:logger) { Cogger::Client.new }
41
22
  end
42
23
  end
43
24
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "auto_injector"
4
+
5
+ module Git
6
+ module Lint
7
+ Import = AutoInjector[Container]
8
+ end
9
+ end
data.tar.gz.sig CHANGED
Binary file