dragnet 5.2.1

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 (86) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/release.yml +45 -0
  3. data/.github/workflows/ruby-linters.yml +41 -0
  4. data/.github/workflows/ruby-tests.yml +38 -0
  5. data/.github/workflows/sphinx-doc.yml +79 -0
  6. data/.gitignore +13 -0
  7. data/.reek.yml +15 -0
  8. data/.rspec +3 -0
  9. data/.rubocop.yml +14 -0
  10. data/.ruby-version +1 -0
  11. data/.travis.yml +6 -0
  12. data/CHANGELOG.md +178 -0
  13. data/Gemfile +18 -0
  14. data/README.md +119 -0
  15. data/Rakefile +8 -0
  16. data/bin/console +14 -0
  17. data/bin/setup +8 -0
  18. data/default.reek +7 -0
  19. data/dragnet.gemspec +39 -0
  20. data/exe/dragnet +9 -0
  21. data/lib/dragnet/base_repository.rb +69 -0
  22. data/lib/dragnet/cli/base.rb +72 -0
  23. data/lib/dragnet/cli/logger.rb +72 -0
  24. data/lib/dragnet/cli/master.rb +173 -0
  25. data/lib/dragnet/cli.rb +8 -0
  26. data/lib/dragnet/errors/error.rb +8 -0
  27. data/lib/dragnet/errors/file_not_found_error.rb +11 -0
  28. data/lib/dragnet/errors/incompatible_repository_error.rb +10 -0
  29. data/lib/dragnet/errors/missing_timestamp_attribute_error.rb +11 -0
  30. data/lib/dragnet/errors/no_mtr_files_found_error.rb +11 -0
  31. data/lib/dragnet/errors/not_a_repository_error.rb +11 -0
  32. data/lib/dragnet/errors/repo_path_not_found_error.rb +10 -0
  33. data/lib/dragnet/errors/unable_to_write_report_error.rb +11 -0
  34. data/lib/dragnet/errors/unknown_export_format_error.rb +11 -0
  35. data/lib/dragnet/errors/validation_error.rb +11 -0
  36. data/lib/dragnet/errors/yaml_format_error.rb +9 -0
  37. data/lib/dragnet/errors.rb +9 -0
  38. data/lib/dragnet/explorer.rb +103 -0
  39. data/lib/dragnet/exporter.rb +130 -0
  40. data/lib/dragnet/exporters/exporter.rb +29 -0
  41. data/lib/dragnet/exporters/html_exporter.rb +158 -0
  42. data/lib/dragnet/exporters/id_generator.rb +35 -0
  43. data/lib/dragnet/exporters/json_exporter.rb +34 -0
  44. data/lib/dragnet/exporters/serializers/repo_serializer.rb +40 -0
  45. data/lib/dragnet/exporters/serializers/test_record_serializer.rb +101 -0
  46. data/lib/dragnet/exporters/serializers/verification_result_serializer.rb +34 -0
  47. data/lib/dragnet/exporters/serializers.rb +12 -0
  48. data/lib/dragnet/exporters/templates/template.html.erb +518 -0
  49. data/lib/dragnet/exporters.rb +13 -0
  50. data/lib/dragnet/helpers/repository_helper.rb +27 -0
  51. data/lib/dragnet/multi_repository.rb +48 -0
  52. data/lib/dragnet/repo.rb +31 -0
  53. data/lib/dragnet/repository.rb +77 -0
  54. data/lib/dragnet/test_record.rb +91 -0
  55. data/lib/dragnet/validator.rb +79 -0
  56. data/lib/dragnet/validators/data_validator.rb +75 -0
  57. data/lib/dragnet/validators/entities/repo_validator.rb +31 -0
  58. data/lib/dragnet/validators/entities/test_record_validator.rb +93 -0
  59. data/lib/dragnet/validators/entities.rb +12 -0
  60. data/lib/dragnet/validators/fields/description_validator.rb +24 -0
  61. data/lib/dragnet/validators/fields/field_validator.rb +69 -0
  62. data/lib/dragnet/validators/fields/files_validator.rb +29 -0
  63. data/lib/dragnet/validators/fields/id_validator.rb +36 -0
  64. data/lib/dragnet/validators/fields/meta_data_field_validator.rb +36 -0
  65. data/lib/dragnet/validators/fields/path_validator.rb +22 -0
  66. data/lib/dragnet/validators/fields/repos_validator.rb +62 -0
  67. data/lib/dragnet/validators/fields/result_validator.rb +33 -0
  68. data/lib/dragnet/validators/fields/sha1_validator.rb +42 -0
  69. data/lib/dragnet/validators/fields.rb +17 -0
  70. data/lib/dragnet/validators/files_validator.rb +85 -0
  71. data/lib/dragnet/validators/repos_validator.rb +74 -0
  72. data/lib/dragnet/validators/validator.rb +20 -0
  73. data/lib/dragnet/validators.rb +12 -0
  74. data/lib/dragnet/verification_result.rb +125 -0
  75. data/lib/dragnet/verifier.rb +64 -0
  76. data/lib/dragnet/verifiers/changes_verifier.rb +70 -0
  77. data/lib/dragnet/verifiers/files_verifier.rb +51 -0
  78. data/lib/dragnet/verifiers/repos_verifier.rb +92 -0
  79. data/lib/dragnet/verifiers/repository_verifier.rb +27 -0
  80. data/lib/dragnet/verifiers/result_verifier.rb +32 -0
  81. data/lib/dragnet/verifiers/test_record_verifier.rb +85 -0
  82. data/lib/dragnet/verifiers/verifier.rb +37 -0
  83. data/lib/dragnet/verifiers.rb +8 -0
  84. data/lib/dragnet/version.rb +5 -0
  85. data/lib/dragnet.rb +18 -0
  86. metadata +190 -0
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'errors/incompatible_repository_error'
4
+
5
+ module Dragnet
6
+ # Base class for Dragnet's repository classes.
7
+ class BaseRepository
8
+ attr_reader :path
9
+
10
+ # @param [Pathname] path The path were the repository is located.
11
+ def initialize(path:)
12
+ @path = path
13
+ end
14
+
15
+ # @raise [Dragnet::Errors::IncompatibleRepositoryError] Is always raised
16
+ def git
17
+ incompatible_repository(__method__)
18
+ end
19
+
20
+ # @raise [Dragnet::Errors::IncompatibleRepositoryError] Is always raised
21
+ def branch
22
+ incompatible_repository(__method__)
23
+ end
24
+
25
+ # @raise [Dragnet::Errors::IncompatibleRepositoryError] Is always raised
26
+ def branches
27
+ incompatible_repository(__method__)
28
+ end
29
+
30
+ # @raise [Dragnet::Errors::IncompatibleRepositoryError] Is always raised
31
+ def diff
32
+ incompatible_repository(__method__)
33
+ end
34
+
35
+ # @raise [Dragnet::Errors::IncompatibleRepositoryError] Is always raised
36
+ def head
37
+ incompatible_repository(__method__)
38
+ end
39
+
40
+ # @raise [Dragnet::Errors::IncompatibleRepositoryError] Is always raised
41
+ def remote_uri_path
42
+ incompatible_repository(__method__)
43
+ end
44
+
45
+ # @raise [Dragnet::Errors::IncompatibleRepositoryError] Is always raised
46
+ def repositories
47
+ incompatible_repository(__method__)
48
+ end
49
+
50
+ # @raise [Dragnet::Errors::IncompatibleRepositoryError] Is always raised
51
+ def branches_with(_commit)
52
+ incompatible_repository(__method__)
53
+ end
54
+
55
+ # @raise [Dragnet::Errors::IncompatibleRepositoryError] Is always raised
56
+ def branches_with_head
57
+ incompatible_repository(__method__)
58
+ end
59
+
60
+ private
61
+
62
+ # @param [String] message The message for the raised error.
63
+ # @raise [Dragnet::Errors::IncompatibleRepositoryError] Is always raised
64
+ # with the given message.
65
+ def incompatible_repository(message)
66
+ raise Dragnet::Errors::IncompatibleRepositoryError, message
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext/hash'
5
+ require 'colorize'
6
+ require 'thor'
7
+ require 'yaml'
8
+
9
+ require_relative 'logger'
10
+
11
+ module Dragnet
12
+ module CLI
13
+ # Base class for all CLI classes.
14
+ class Base < Thor
15
+ include Thor::Actions
16
+
17
+ # Exit status codes
18
+ E_CONFIG_LOAD_ERROR = 1
19
+
20
+ attr_reader :configuration, :logger
21
+
22
+ class_option :configuration, aliases: :c, desc: 'Configuration file',
23
+ default: '.dragnet.yaml', required: true
24
+
25
+ class_option :quiet, aliases: :q, default: false, type: :boolean,
26
+ desc: 'Suppresses all terminal output (except for critical errors)'
27
+
28
+ # Tells Thor to return an unsuccessful return code (different from 0) if
29
+ # an error is raised.
30
+ def self.exit_on_failure?
31
+ true
32
+ end
33
+
34
+ # Creates a new instance of the class. Called by Thor when a command is
35
+ # executed. Creates a logger for the class passing Thor's shell to it
36
+ # (Thor's shell handles the output to the console)
37
+ def initialize(*args)
38
+ super
39
+ @logger = Dragnet::CLI::Logger.new(shell)
40
+ end
41
+
42
+ private
43
+
44
+ # @return [String] Returns the name of the configuration file (passed via
45
+ # the -c command line switch).
46
+ def configuration_file
47
+ @configuration_file ||= options[:configuration]
48
+ end
49
+
50
+ # Loads the configuration from the given configuration file. (This is a
51
+ # dumb loader, it basically loads the whole YAML file into a hash, no
52
+ # parsing, validation or checking takes place)
53
+ def load_configuration
54
+ logger.info "Loading configuration file #{configuration_file}..."
55
+ @configuration = YAML.safe_load(File.read(configuration_file)).deep_symbolize_keys
56
+ rescue StandardError => e
57
+ fatal_error("Unable to load the given configuration file: '#{configuration_file}'", e, E_CONFIG_LOAD_ERROR)
58
+ end
59
+
60
+ # Prints the given message alongside the message of the given exception
61
+ # and then terminates the process with the given exit code.
62
+ # @param [String] message The error message.
63
+ # @param [Exception] exception The exception that caused the fatal error.
64
+ # @param [exit_code] exit_code The exit code.
65
+ def fatal_error(message, exception, exit_code)
66
+ puts 'Error: '.colorize(:light_red) + message
67
+ puts " #{exception.message}"
68
+ exit(exit_code)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'colorize'
4
+
5
+ module Dragnet
6
+ module CLI
7
+ # A logger for the CLI. It uses the +say+ method in Thor's +Shell+ class to
8
+ # print the messages to the output, honoring the status of the +quiet+
9
+ # command line switch.
10
+ class Logger
11
+ attr_reader :shell, :log_level
12
+
13
+ LEVELS = { debug: 0, info: 1, warn: 2, error: 3 }.freeze
14
+ DEFAULT_LOG_LEVEL = :info
15
+ PADDING_STRING = ' '
16
+ PADDING_WIDTH = 7
17
+
18
+ # Creates a new instance of the class.
19
+ # @param [Thor::Shell::Basic] shell A reference to Thor's +Shell+ this
20
+ # will be used to send the output to the terminal in which Thor was
21
+ # started.
22
+ # @param [Symbol] log_level The log level for the logger. The higher the
23
+ # level the less output will be printed.
24
+ # @see LEVELS
25
+ def initialize(shell, log_level = DEFAULT_LOG_LEVEL)
26
+ raise ArgumentError, "Unknown logger level: #{log_level}" unless LEVELS.keys.include?(log_level)
27
+
28
+ @log_level = LEVELS[log_level]
29
+ @shell = shell
30
+ end
31
+
32
+ # Prints a message with log level +debug+
33
+ # @param [String] message The message to print
34
+ def debug(message)
35
+ output(:debug, :green, message)
36
+ end
37
+
38
+ # Prints a message with log level +info+
39
+ # @param [String] message The message to print
40
+ def info(message)
41
+ output(:info, :blue, message)
42
+ end
43
+
44
+ # Prints a message with log level +warn+
45
+ # @param [String] message The message to print
46
+ def warn(message)
47
+ output(:warn, :yellow, message)
48
+ end
49
+
50
+ # Prints a message with log level +error+
51
+ # @param [String] message The message to print
52
+ def error(message)
53
+ output(:error, :red, message)
54
+ end
55
+
56
+ private
57
+
58
+ # Prints the given message with the given level and text color (only the
59
+ # name of the level will be colored).
60
+ # @param [Symbol] level The log level
61
+ # @param [Symbol] color The color to use. One of the colors available for
62
+ # the +#colorize+ method.
63
+ # @param [String] message The message to print.
64
+ # @see Colorize::InstanceMethods#colorize
65
+ def output(level, color, message)
66
+ return unless log_level <= LEVELS[level]
67
+
68
+ shell.say "#{level.to_s.capitalize}:".ljust(PADDING_WIDTH, PADDING_STRING).colorize(color) + message
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../explorer'
4
+ require_relative '../exporter'
5
+ require_relative '../multi_repository'
6
+ require_relative '../repository'
7
+ require_relative '../validator'
8
+ require_relative '../verifier'
9
+ require_relative '../version'
10
+ require_relative 'base'
11
+
12
+ module Dragnet
13
+ module CLI
14
+ # Entry point class for the Dragnet CLI. Includes all the commands and
15
+ # sub-commands of the CLI.
16
+ #
17
+ # The class should not contain any logic, everything should be delegated to
18
+ # helper classes as soon as possible. Only exceptions are error handling and
19
+ # message printing.
20
+ class Master < Dragnet::CLI::Base
21
+ E_MISSING_PARAMETER_ERROR = 2
22
+ E_NO_MTR_FILES_FOUND = 3
23
+ E_GIT_ERROR = 4
24
+ E_EXPORT_ERROR = 5
25
+ E_INCOMPATIBLE_REPOSITORY = 6
26
+
27
+ E_ERRORS_DETECTED = 16
28
+ E_FAILED_TESTS = 32
29
+
30
+ map %w[--version -v] => :version
31
+
32
+ desc '--version', 'Prints the current version of the Gem'
33
+ def version
34
+ say "Dragnet #{Dragnet::VERSION}"
35
+ say "Copyright (c) #{Time.now.year} ESR Labs GmbH esrlabs.com"
36
+ end
37
+
38
+ desc 'check [PATH]', 'Executes the verification procedure. '\
39
+ 'Loads the given configuration file and executes the verify procedure on the given path '\
40
+ '(defaults to the value of the "path" key in the configuration file or the current '\
41
+ 'working directory if none of them is given)'
42
+ method_option :export,
43
+ aliases: 'e', type: :string, repeatable: true,
44
+ desc: 'If given, the results of the verification procedure will be exported to'\
45
+ ' the given file. The format of the export will be deducted from the given'\
46
+ " file's name"
47
+ method_option :'multi-repo',
48
+ aliases: '-m', type: :boolean, default: false,
49
+ desc: 'Enables the multi-repo compatibility mode. This prevents Dragnet from assuming'\
50
+ ' that [PATH] refers to a Git repository allowing it to run even if that is not the case.'\
51
+ " Using this option will cause Dragnet to raise an error if it finds a MTR which doesn't"\
52
+ " have a 'repos' attribute"
53
+ def check(path = nil)
54
+ load_configuration
55
+ self.path = path
56
+
57
+ files = explore
58
+ test_records, errors = validate(files)
59
+ verify(test_records)
60
+
61
+ export(test_records, errors) if options[:export]
62
+
63
+ exit_code = 0
64
+ exit_code |= E_ERRORS_DETECTED if errors.any?
65
+ exit_code |= E_FAILED_TESTS unless test_records.all? { |test_record| test_record.verification_result.passed? }
66
+
67
+ exit(exit_code) if exit_code.positive? # doing exit(0) will stop RSpec execution.
68
+ end
69
+
70
+ private
71
+
72
+ # Runs the explorer on the given path.
73
+ # @return [Array<Pathname>] The array of found MTR files.
74
+ def explore
75
+ glob_patterns = configuration[:glob_patterns]
76
+
77
+ begin
78
+ explorer = Dragnet::Explorer.new(path: path, glob_patterns: glob_patterns, logger: logger)
79
+ explorer.files
80
+ rescue ArgumentError => e
81
+ fatal_error('Initialization error. Missing or malformed parameter.', e, E_MISSING_PARAMETER_ERROR)
82
+ rescue Dragnet::Errors::NoMTRFilesFoundError => e
83
+ fatal_error('No MTR Files found.', e, E_NO_MTR_FILES_FOUND)
84
+ end
85
+ end
86
+
87
+ # Executes the validator on the given MTR files.
88
+ # @param [Array<Pathname>] files The files to run the validator on.
89
+ # @return [Array (Array<Dragnet::TestRecord>, Array<Hash>)] An array.
90
+ # - The first element is an array of +TestRecord+s with the MTR data.
91
+ # One for each valid MTR file.
92
+ # - The second element contains the errors occurred during the
93
+ # validation process. Can be an empty array.
94
+ def validate(files)
95
+ validator = Dragnet::Validator.new(files: files, path: path, logger: logger)
96
+ [validator.validate, validator.errors]
97
+ end
98
+
99
+ # Executes the verification on the given MTRs
100
+ # @param [Array<Dragnet::TestRecord>] test_records The array of MTRs on
101
+ # which the verification should be executed.
102
+ def verify(test_records)
103
+ verifier = Dragnet::Verifier.new(test_records: test_records, repository: repository, logger: logger)
104
+ verifier.verify
105
+ rescue ArgumentError => e
106
+ fatal_error("Could not open the specified path: #{path} as a Git Repository", e, E_GIT_ERROR)
107
+ rescue Dragnet::Errors::IncompatibleRepositoryError => e
108
+ incompatible_repository_error(e)
109
+ end
110
+
111
+ # Executes the export process.
112
+ # @param [Array<Dragnet::TestRecord>] test_records The validated and
113
+ # verified test records.
114
+ # @param [Array<Hashes>] errors The array of Hashes with the MTR files
115
+ # that didn't pass the validation process.
116
+ def export(test_records, errors)
117
+ exporter = Dragnet::Exporter.new(
118
+ test_records: test_records, errors: errors, repository: repository, targets: options[:export], logger: logger
119
+ )
120
+
121
+ exporter.export
122
+ rescue Dragnet::Errors::UnknownExportFormatError, Dragnet::Errors::UnableToWriteReportError => e
123
+ fatal_error('Export failed', e, E_EXPORT_ERROR)
124
+ rescue Dragnet::Errors::IncompatibleRepositoryError => e
125
+ incompatible_repository_error(e)
126
+ end
127
+
128
+ # @return [Pathname] The path of the directory where the verification
129
+ # process should be executed.
130
+ def path
131
+ @path || set_fallback_path
132
+ end
133
+
134
+ # @param [Pathname, String] path The path of the directory where the
135
+ # verification process should be executed.
136
+ def path=(path)
137
+ @path = path ? Pathname.new(path) : nil
138
+ end
139
+
140
+ # @raise [ArgumentError] If the given path is not a valid git repository.
141
+ # @return [Dragnet::Repository, Dragnet::MultiRepository] One of the
142
+ # possible Repository objects.
143
+ def repository
144
+ @repository ||= create_repository
145
+ end
146
+
147
+ # Creates the appropriate Repository object in accordance to the status of
148
+ # the +multi-repo+ command line option.
149
+ # @return [Dragnet::MultiRepository] If +multi-repo+ was set to +true+
150
+ # @return [Dragnet::Repository] If +multi_repo+ was set to +false+
151
+ def create_repository
152
+ options[:'multi-repo'] ? Dragnet::MultiRepository.new(path: path) : Dragnet::Repository.new(path: path)
153
+ end
154
+
155
+ # Prints a message and exits with the proper error code when a
156
+ # +Dragnet::Errors::IncompatibleRepositoryError+ is raised.
157
+ # @param [Dragnet::Errors::IncompatibleRepositoryError] error The raised
158
+ # error.
159
+ def incompatible_repository_error(error)
160
+ fatal_error('Incompatible git operation:', error, E_INCOMPATIBLE_REPOSITORY)
161
+ end
162
+
163
+ # Called when no path has been given by the user explicitly. The method
164
+ # uses the configured path or the current working directory as a fallback.
165
+ # @return [Pathname] The constructed fallback path.
166
+ def set_fallback_path
167
+ # The && causes Ruby to return the value of +@path+ AFTER it has been
168
+ # assigned (converted to a Pathname)
169
+ (self.path = configuration[:path] || Dir.pwd) && @path
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'cli/master.rb'
4
+
5
+ module Dragnet
6
+ # Namespace for the Gem's CLI
7
+ module CLI; end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dragnet
4
+ module Errors
5
+ # Base class for all errors raised by the gem.
6
+ class Error < StandardError; end
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'error'
4
+
5
+ module Dragnet
6
+ module Errors
7
+ # An error to be raised when one of the files referenced by a MTR File
8
+ # doesn't exist in the repository.
9
+ class FileNotFoundError < Dragnet::Errors::Error; end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dragnet
4
+ module Errors
5
+ # An error to be raised when an attempt is made to perform an action on a
6
+ # multi-repo set-up which can only be performed on a single-repo set-up.
7
+ # For example, trying to perform a +diff+ operation on the multi-repo root.
8
+ class IncompatibleRepositoryError < Dragnet::Errors::Error; end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'error'
4
+
5
+ module Dragnet
6
+ module Errors
7
+ # An error to be raised when an attempt is made to retrieve the runtime
8
+ # when one or more timestamp attributes are missing.
9
+ class MissingTimestampAttributeError < Dragnet::Errors::Error; end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'error'
4
+
5
+ module Dragnet
6
+ module Errors
7
+ # An error to be raised when the +Explorer+ is unable to locate MTR files
8
+ # with the given glob patterns inside the specified path.
9
+ class NoMTRFilesFoundError < Dragnet::Errors::Error; end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'error'
4
+
5
+ module Dragnet
6
+ module Errors
7
+ # An error to be raised when the path of a repository entry in a MTR with
8
+ # multiple repositories doesn't point to an actual git repository.
9
+ class NotARepositoryError < Dragnet::Errors::Error; end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'error'
4
+
5
+ module Dragnet
6
+ module Errors
7
+ # An error to raise when the +path+ given for a +repos+ entry cannot be found.
8
+ class RepoPathNotFoundError < Dragnet::Errors::Error; end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'error'
4
+
5
+ module Dragnet
6
+ module Errors
7
+ # An error to be raised when Dragnet cannot write to one of the given export
8
+ # files.
9
+ class UnableToWriteReportError < Dragnet::Errors::Error; end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'error'
4
+
5
+ module Dragnet
6
+ module Errors
7
+ # An error to be raised when an export target file is given for which the
8
+ # format is unknown (cannot be deduced from its extension).
9
+ class UnknownExportFormatError < Dragnet::Errors::Error; end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'error'
4
+
5
+ module Dragnet
6
+ module Errors
7
+ # An error to be raised when an attempt is made to create an entity with
8
+ # invalid data.
9
+ class ValidationError < Dragnet::Errors::Error; end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dragnet
4
+ module Errors
5
+ # An error to be raised when there is a formatting problem with a YAML file.
6
+ # For example a missing key. (This error doesn't cover Syntax Errors)
7
+ class YAMLFormatError < Dragnet::Errors::Error; end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'errors/not_a_repository_error'
4
+ require_relative 'errors/repo_path_not_found_error'
5
+
6
+ module Dragnet
7
+ # Namespace to house all the error classes for the gem.
8
+ module Errors; end
9
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'errors/no_mtr_files_found_error'
4
+
5
+ module Dragnet
6
+ # This class searches for Manual Test Record files inside a given path by
7
+ # using the given Glob patterns.
8
+ class Explorer
9
+ attr_reader :path, :glob_patterns, :logger
10
+
11
+ # Creates a new instance of the class.
12
+ # @param [Pathname] path The path that should be explored.
13
+ # @param [String, Array<String>] glob_patterns The glob pattern or glob
14
+ # patterns to use when exploring the specified path.
15
+ # @param [#info] logger A logger object to use for output.
16
+ # @raise [ArgumentError] If +path+ or +glob_patterns+ are +nil+ or if they
17
+ # don't have one of the expected types.
18
+ def initialize(path:, glob_patterns:, logger:)
19
+ validate_path(path)
20
+ validate_patterns(glob_patterns)
21
+
22
+ @path = path
23
+ @glob_patterns = *glob_patterns
24
+ @logger = logger
25
+ end
26
+
27
+ # Performs the search for MTR files and returns an array with the found
28
+ # files.
29
+ # @return [Array<Pathname>] The array of found MTR files.
30
+ # @raise [Dragnet::Errors::NoMTRFilesFoundError] If no MTR files are found.
31
+ def files
32
+ @files ||= find_files
33
+ end
34
+
35
+ private
36
+
37
+ # Raises an +ArgumentError+ with the appropriate message.
38
+ # @param [String] name The name of the missing parameter.
39
+ # @raise [ArgumentError] Is always raised with the appropriate message.
40
+ def missing_parameter(name)
41
+ raise ArgumentError, "Missing required parameter #{name}"
42
+ end
43
+
44
+ # Raises an +ArgumentError+ with the appropriate message.
45
+ # @param [String] name The name of the parameter with an incompatible type.
46
+ # @param [String, Class] expected The expected parameter type.
47
+ # @param [String, Class] given The given parameter type.
48
+ # @raise [ArgumentError] Is always raised with the appropriate message.
49
+ def incompatible_parameter(name, expected, given)
50
+ raise ArgumentError, "Incompatible parameter type #{name}. Expected: #{expected}, given: #{given}"
51
+ end
52
+
53
+ # Validates the given path
54
+ # @param [Object] path The path to validate
55
+ # @raise [ArgumentError] If the given path is nil or is not a +Pathname+.
56
+ def validate_path(path)
57
+ missing_parameter('path') unless path
58
+ return if path.is_a?(Pathname)
59
+
60
+ incompatible_parameter('path', Pathname, path.class)
61
+ end
62
+
63
+ # Validates the given glob patterns
64
+ # @param [String, Array<String>] glob_patterns The glob patterns
65
+ # @raise [ArgumentError] If +glob_patterns+ is +nil+ or it isn't an array
66
+ # of strings.
67
+ def validate_patterns(glob_patterns)
68
+ missing_parameter('glob_patterns') unless glob_patterns
69
+
70
+ return if glob_patterns.is_a?(String)
71
+ return if glob_patterns.is_a?(Array) && glob_patterns.all? { |value| value.is_a?(String) }
72
+
73
+ incompatible_parameter('glob_patterns', 'String or Array<String>', glob_patterns.class)
74
+ end
75
+
76
+ # Logs the MTR files that were found.
77
+ # @param [Array<Pathname>] files The found MTR files.
78
+ # @return [Array<Pathname>] The same array given in +files+.
79
+ def log_found_files(files)
80
+ files.each { |file| logger.info("Found MTR file: #{file}") }
81
+ end
82
+
83
+ # Searches the +path+ for MTR files using the +glob_patterns+
84
+ # @return [Array<Pathname>] The array of found MTR files.
85
+ # @raise [Dragnet::Errors::NoMTRFilesFoundError] If no MTR files are found.
86
+ def find_files
87
+ logger.info 'Searching for Manual Test Records...'
88
+
89
+ files = []
90
+
91
+ glob_patterns.each do |glob_pattern|
92
+ logger.info "Globbing #{path} with #{glob_pattern}..."
93
+
94
+ files += log_found_files(path.glob(glob_pattern))
95
+ end
96
+
97
+ return files if files.any?
98
+
99
+ raise Dragnet::Errors::NoMTRFilesFoundError,
100
+ "No MTR Files found in #{path} with the following glob patterns: #{glob_patterns.join(', ')}"
101
+ end
102
+ end
103
+ end