makit 0.0.164 → 0.0.166

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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -41
  3. data/exe/makit +5 -5
  4. data/lib/makit/apache.rb +28 -28
  5. data/lib/makit/auto.rb +48 -48
  6. data/lib/makit/azure/blob_storage.rb +257 -257
  7. data/lib/makit/azure/cli.rb +284 -284
  8. data/lib/makit/azure-pipelines.rb +139 -0
  9. data/lib/makit/cli/base.rb +17 -17
  10. data/lib/makit/cli/build_commands.rb +500 -500
  11. data/lib/makit/cli/generators/base_generator.rb +74 -74
  12. data/lib/makit/cli/generators/dotnet_generator.rb +50 -50
  13. data/lib/makit/cli/generators/generator_factory.rb +49 -49
  14. data/lib/makit/cli/generators/node_generator.rb +50 -50
  15. data/lib/makit/cli/generators/ruby_generator.rb +77 -77
  16. data/lib/makit/cli/generators/rust_generator.rb +50 -50
  17. data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -167
  18. data/lib/makit/cli/generators/templates/node_templates.rb +161 -161
  19. data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -26
  20. data/lib/makit/cli/generators/templates/ruby/gemspec.rb +41 -41
  21. data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -33
  22. data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -35
  23. data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -63
  24. data/lib/makit/cli/generators/templates/ruby/test.rb +39 -39
  25. data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -29
  26. data/lib/makit/cli/generators/templates/ruby/version.rb +29 -29
  27. data/lib/makit/cli/generators/templates/rust_templates.rb +128 -128
  28. data/lib/makit/cli/main.rb +78 -78
  29. data/lib/makit/cli/pipeline_commands.rb +311 -311
  30. data/lib/makit/cli/project_commands.rb +868 -868
  31. data/lib/makit/cli/repository_commands.rb +661 -661
  32. data/lib/makit/cli/strategy_commands.rb +207 -207
  33. data/lib/makit/cli/utility_commands.rb +521 -521
  34. data/lib/makit/commands/factory.rb +359 -359
  35. data/lib/makit/commands/middleware/base.rb +73 -73
  36. data/lib/makit/commands/middleware/cache.rb +248 -248
  37. data/lib/makit/commands/middleware/command_logger.rb +312 -312
  38. data/lib/makit/commands/middleware/validator.rb +269 -269
  39. data/lib/makit/commands/request.rb +316 -316
  40. data/lib/makit/commands/result.rb +323 -323
  41. data/lib/makit/commands/runner.rb +386 -386
  42. data/lib/makit/commands/strategies/base.rb +171 -171
  43. data/lib/makit/commands/strategies/child_process.rb +162 -162
  44. data/lib/makit/commands/strategies/factory.rb +136 -136
  45. data/lib/makit/commands/strategies/synchronous.rb +139 -139
  46. data/lib/makit/commands.rb +50 -50
  47. data/lib/makit/configuration/dotnet_project.rb +48 -48
  48. data/lib/makit/configuration/gitlab_helper.rb +61 -61
  49. data/lib/makit/configuration/project.rb +292 -292
  50. data/lib/makit/configuration/rakefile_helper.rb +43 -43
  51. data/lib/makit/configuration/step.rb +34 -34
  52. data/lib/makit/configuration/timeout.rb +74 -74
  53. data/lib/makit/configuration.rb +21 -21
  54. data/lib/makit/content/default_gitignore.rb +7 -7
  55. data/lib/makit/content/default_gitignore.txt +225 -225
  56. data/lib/makit/content/default_rakefile.rb +13 -13
  57. data/lib/makit/content/gem_rakefile.rb +16 -16
  58. data/lib/makit/context.rb +1 -1
  59. data/lib/makit/data.rb +49 -49
  60. data/lib/makit/directories.rb +170 -170
  61. data/lib/makit/directory.rb +262 -262
  62. data/lib/makit/docs/files.rb +89 -89
  63. data/lib/makit/docs/rake.rb +102 -102
  64. data/lib/makit/dotnet/cli.rb +224 -224
  65. data/lib/makit/dotnet/project.rb +217 -217
  66. data/lib/makit/dotnet/solution.rb +38 -38
  67. data/lib/makit/dotnet/solution_classlib.rb +239 -239
  68. data/lib/makit/dotnet/solution_console.rb +264 -264
  69. data/lib/makit/dotnet/solution_maui.rb +354 -354
  70. data/lib/makit/dotnet/solution_wasm.rb +275 -275
  71. data/lib/makit/dotnet/solution_wpf.rb +304 -304
  72. data/lib/makit/dotnet.rb +110 -110
  73. data/lib/makit/email.rb +90 -90
  74. data/lib/makit/environment.rb +142 -142
  75. data/lib/makit/examples/runner.rb +370 -370
  76. data/lib/makit/exceptions.rb +45 -45
  77. data/lib/makit/fileinfo.rb +32 -32
  78. data/lib/makit/files.rb +43 -43
  79. data/lib/makit/gems.rb +49 -49
  80. data/lib/makit/git/cli.rb +103 -103
  81. data/lib/makit/git/repository.rb +100 -100
  82. data/lib/makit/git.rb +104 -104
  83. data/lib/makit/gitlab/pipeline.rb +857 -857
  84. data/lib/makit/gitlab/pipeline_service_impl.rb +1535 -1535
  85. data/lib/makit/gitlab_runner.rb +59 -59
  86. data/lib/makit/humanize.rb +218 -218
  87. data/lib/makit/indexer.rb +47 -47
  88. data/lib/makit/io/filesystem.rb +111 -111
  89. data/lib/makit/io/filesystem_service_impl.rb +337 -337
  90. data/lib/makit/lint.rb +212 -212
  91. data/lib/makit/logging/configuration.rb +309 -309
  92. data/lib/makit/logging/format_registry.rb +84 -84
  93. data/lib/makit/logging/formatters/base.rb +39 -39
  94. data/lib/makit/logging/formatters/console_formatter.rb +140 -140
  95. data/lib/makit/logging/formatters/json_formatter.rb +65 -65
  96. data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -71
  97. data/lib/makit/logging/formatters/text_formatter.rb +64 -64
  98. data/lib/makit/logging/log_request.rb +119 -119
  99. data/lib/makit/logging/logger.rb +199 -199
  100. data/lib/makit/logging/sinks/base.rb +91 -91
  101. data/lib/makit/logging/sinks/console.rb +72 -72
  102. data/lib/makit/logging/sinks/file_sink.rb +92 -92
  103. data/lib/makit/logging/sinks/structured.rb +123 -123
  104. data/lib/makit/logging/sinks/unified_file_sink.rb +296 -296
  105. data/lib/makit/logging.rb +578 -578
  106. data/lib/makit/markdown.rb +75 -75
  107. data/lib/makit/mp/basic_object_mp.rb +17 -17
  108. data/lib/makit/mp/command_mp.rb +13 -13
  109. data/lib/makit/mp/command_request.mp.rb +17 -17
  110. data/lib/makit/mp/project_mp.rb +199 -199
  111. data/lib/makit/mp/string_mp.rb +205 -205
  112. data/lib/makit/nuget.rb +454 -454
  113. data/lib/makit/podman/podman.rb +458 -458
  114. data/lib/makit/podman/podman_service_impl.rb +1081 -1081
  115. data/lib/makit/port.rb +32 -32
  116. data/lib/makit/process.rb +377 -377
  117. data/lib/makit/protoc.rb +112 -112
  118. data/lib/makit/rake/cli.rb +196 -196
  119. data/lib/makit/rake/trace_controller.rb +174 -174
  120. data/lib/makit/rake.rb +81 -81
  121. data/lib/makit/ruby/cli.rb +185 -185
  122. data/lib/makit/ruby.rb +25 -25
  123. data/lib/makit/rubygems.rb +137 -137
  124. data/lib/makit/secrets/azure_key_vault.rb +322 -322
  125. data/lib/makit/secrets/azure_secrets.rb +221 -183
  126. data/lib/makit/secrets/local_secrets.rb +72 -72
  127. data/lib/makit/secrets/secrets_manager.rb +105 -105
  128. data/lib/makit/secrets.rb +96 -16
  129. data/lib/makit/serializer.rb +130 -130
  130. data/lib/makit/services/builder.rb +186 -186
  131. data/lib/makit/services/error_handler.rb +226 -226
  132. data/lib/makit/services/repository_manager.rb +367 -367
  133. data/lib/makit/services/validator.rb +112 -112
  134. data/lib/makit/setup/classlib.rb +101 -101
  135. data/lib/makit/setup/gem.rb +268 -268
  136. data/lib/makit/setup/pages.rb +11 -11
  137. data/lib/makit/setup/razorclasslib.rb +101 -101
  138. data/lib/makit/setup/runner.rb +54 -54
  139. data/lib/makit/setup.rb +5 -5
  140. data/lib/makit/show.rb +110 -110
  141. data/lib/makit/storage.rb +126 -126
  142. data/lib/makit/symbols.rb +175 -175
  143. data/lib/makit/task_info.rb +130 -130
  144. data/lib/makit/tasks/at_exit.rb +15 -15
  145. data/lib/makit/tasks/build.rb +22 -22
  146. data/lib/makit/tasks/bump.rb +7 -7
  147. data/lib/makit/tasks/clean.rb +13 -13
  148. data/lib/makit/tasks/configure.rb +10 -10
  149. data/lib/makit/tasks/format.rb +10 -10
  150. data/lib/makit/tasks/hook_manager.rb +443 -443
  151. data/lib/makit/tasks/info.rb +368 -368
  152. data/lib/makit/tasks/init.rb +49 -49
  153. data/lib/makit/tasks/integrate.rb +60 -60
  154. data/lib/makit/tasks/pull_incoming.rb +13 -13
  155. data/lib/makit/tasks/secrets.rb +7 -7
  156. data/lib/makit/tasks/setup.rb +16 -16
  157. data/lib/makit/tasks/sync.rb +14 -14
  158. data/lib/makit/tasks/tag.rb +27 -27
  159. data/lib/makit/tasks/task_monkey_patch.rb +81 -81
  160. data/lib/makit/tasks/test.rb +22 -22
  161. data/lib/makit/tasks/update.rb +21 -21
  162. data/lib/makit/tasks/version.rb +6 -6
  163. data/lib/makit/tasks.rb +24 -24
  164. data/lib/makit/test_cache.rb +239 -239
  165. data/lib/makit/tree.rb +37 -37
  166. data/lib/makit/v1/configuration/project_service_impl.rb +370 -370
  167. data/lib/makit/v1/git/git_repository_service_impl.rb +295 -295
  168. data/lib/makit/v1/makit.v1_pb.rb +35 -35
  169. data/lib/makit/v1/makit.v1_services_pb.rb +27 -27
  170. data/lib/makit/v1/services/repository_manager_service_impl.rb +572 -572
  171. data/lib/makit/version.rb +661 -661
  172. data/lib/makit/version_util.rb +21 -21
  173. data/lib/makit/wix.rb +95 -95
  174. data/lib/makit/yaml.rb +29 -29
  175. data/lib/makit/zip.rb +17 -17
  176. data/lib/makit copy.rb +44 -44
  177. data/lib/makit.rb +120 -119
  178. metadata +3 -2
@@ -1,309 +1,309 @@
1
- # frozen_string_literal: true
2
-
3
- module Makit
4
- module Logging
5
- # Configuration management for unified logging
6
- #
7
- # Provides schema validation, default configurations, and helper methods
8
- # for setting up the unified file sink with various output configurations.
9
- #
10
- # @example Basic configuration
11
- # config = Configuration.new(
12
- # configurations: [
13
- # { file: $stdout, format: :console },
14
- # { file: "logs/app.log", format: :json }
15
- # ]
16
- # )
17
- #
18
- # @example YAML configuration
19
- # config = Configuration.from_yaml("config/logging.yml")
20
- #
21
- # @example Environment-based configuration
22
- # config = Configuration.for_environment(:production)
23
- class Configuration
24
- # @return [Array<Hash>] list of output configurations
25
- attr_reader :configurations
26
-
27
- # Initialize configuration
28
- #
29
- # @param configurations [Array<Hash>] list of output configurations
30
- def initialize(configurations: [])
31
- @configurations = configurations
32
- end
33
-
34
- # Create configuration from YAML file
35
- #
36
- # @param yaml_file [String] path to YAML configuration file
37
- # @return [Configuration] new configuration instance
38
- def self.from_yaml(yaml_file)
39
- require "yaml"
40
- data = YAML.load_file(yaml_file)
41
- configurations = data["logging"]["sinks"] || []
42
-
43
- # Convert string keys to symbols
44
- configurations = configurations.map do |config|
45
- config.transform_keys(&:to_sym)
46
- end
47
-
48
- new(configurations: configurations)
49
- end
50
-
51
- # Create configuration from JSON file
52
- #
53
- # @param json_file [String] path to JSON configuration file
54
- # @return [Configuration] new configuration instance
55
- def self.from_json(json_file)
56
- require "json"
57
- data = JSON.parse(File.read(json_file))
58
- configurations = data["logging"]["sinks"] || []
59
-
60
- # Convert string keys to symbols
61
- configurations = configurations.map do |config|
62
- config.transform_keys(&:to_sym)
63
- end
64
-
65
- new(configurations: configurations)
66
- end
67
-
68
- # Create environment-specific configuration
69
- #
70
- # @param environment [Symbol] environment name (:development, :production, :test)
71
- # @return [Configuration] new configuration instance
72
- def self.for_environment(environment)
73
- case environment
74
- when :development
75
- development_config
76
- when :production
77
- production_config
78
- when :test
79
- test_config
80
- when :ci
81
- ci_config
82
- else
83
- default_config
84
- end
85
- end
86
-
87
- # Get default configuration
88
- #
89
- # @return [Configuration] default configuration
90
- def self.default_config
91
- require_relative "../logging" unless defined?(Makit::Logging)
92
- new(
93
- configurations: [
94
- { file: $stdout, format: :console },
95
- { file: Makit::Logging.log_file_path("makit.log"), format: :json, append: true },
96
- ],
97
- )
98
- end
99
-
100
- # Get development configuration
101
- #
102
- # @return [Configuration] development configuration
103
- def self.development_config
104
- new(
105
- configurations: [
106
- {
107
- file: $stdout,
108
- format: :console,
109
- show_timestamp: true,
110
- show_level: true,
111
- },
112
- {
113
- file: "logs/development.log",
114
- format: :text,
115
- append: true,
116
- include_context: true,
117
- },
118
- {
119
- file: "logs/debug.log",
120
- format: :json,
121
- append: true,
122
- min_level: :debug,
123
- },
124
- ],
125
- )
126
- end
127
-
128
- # Get production configuration
129
- #
130
- # @return [Configuration] production configuration
131
- def self.production_config
132
- new(
133
- configurations: [
134
- {
135
- file: "logs/application.log",
136
- format: :json,
137
- append: true,
138
- include_metadata: true,
139
- rotation: { max_size: "100MB", max_files: 10 },
140
- },
141
- {
142
- file: "logs/errors.log",
143
- format: :json,
144
- append: true,
145
- min_level: :error,
146
- include_metadata: true,
147
- },
148
- ],
149
- )
150
- end
151
-
152
- # Get test configuration
153
- #
154
- # @return [Configuration] test configuration
155
- def self.test_config
156
- new(
157
- configurations: [
158
- {
159
- file: "logs/test.log",
160
- format: :text,
161
- append: false,
162
- include_context: true,
163
- },
164
- ],
165
- )
166
- end
167
-
168
- # Get CI/CD configuration
169
- #
170
- # @return [Configuration] CI configuration
171
- def self.ci_config
172
- new(
173
- configurations: [
174
- {
175
- file: $stdout,
176
- format: :console,
177
- show_level: true,
178
- },
179
- {
180
- file: "artifacts/build.log",
181
- format: :json,
182
- append: true,
183
- include_metadata: true,
184
- },
185
- ],
186
- )
187
- end
188
-
189
- # Validate configuration
190
- #
191
- # @return [Boolean] true if valid
192
- # @raise [ArgumentError] if configuration is invalid
193
- def validate!
194
- raise ArgumentError, "configurations must be an array" unless @configurations.is_a?(Array)
195
- raise ArgumentError, "at least one configuration is required" if @configurations.empty?
196
-
197
- @configurations.each_with_index do |config, index|
198
- validate_single_configuration(config, index)
199
- end
200
-
201
- true
202
- end
203
-
204
- # Check if configuration is valid
205
- #
206
- # @return [Boolean] true if valid
207
- def valid?
208
- validate!
209
- true
210
- rescue ArgumentError
211
- false
212
- end
213
-
214
- # Get configuration as hash
215
- #
216
- # @return [Hash] configuration as hash
217
- def to_hash
218
- {
219
- logging: {
220
- sinks: @configurations,
221
- },
222
- }
223
- end
224
-
225
- # Save configuration to YAML file
226
- #
227
- # @param yaml_file [String] path to YAML file
228
- # @return [void]
229
- def save_yaml(yaml_file)
230
- require "yaml"
231
- FileUtils.mkdir_p(File.dirname(yaml_file))
232
- File.write(yaml_file, to_hash.to_yaml)
233
- end
234
-
235
- # Save configuration to JSON file
236
- #
237
- # @param json_file [String] path to JSON file
238
- # @return [void]
239
- def save_json(json_file)
240
- require "json"
241
- FileUtils.mkdir_p(File.dirname(json_file))
242
- File.write(json_file, JSON.pretty_generate(to_hash))
243
- end
244
-
245
- private
246
-
247
- # Validate a single configuration
248
- #
249
- # @param config [Hash] configuration to validate
250
- # @param index [Integer] configuration index for error messages
251
- # @raise [ArgumentError] if configuration is invalid
252
- def validate_single_configuration(config, index)
253
- raise ArgumentError, "configuration #{index} must be a hash" unless config.is_a?(Hash)
254
-
255
- required_keys = %i[file format]
256
- missing_keys = required_keys - config.keys
257
- unless missing_keys.empty?
258
- raise ArgumentError,
259
- "configuration #{index} missing required keys: #{missing_keys.join(", ")}"
260
- end
261
-
262
- # Validate file
263
- file = config[:file]
264
- unless file.is_a?(String) || file.is_a?(IO) || file.respond_to?(:write)
265
- raise ArgumentError, "configuration #{index} file must be a String path, IO object, or writable object"
266
- end
267
-
268
- # Validate format
269
- format = config[:format]
270
- unless format.is_a?(Symbol) || format.is_a?(String)
271
- raise ArgumentError, "configuration #{index} format must be a Symbol or String"
272
- end
273
-
274
- # Validate log levels if specified
275
- if config[:min_level] && !valid_log_level?(config[:min_level])
276
- raise ArgumentError, "configuration #{index} min_level must be a valid log level"
277
- end
278
-
279
- if config[:max_level] && !valid_log_level?(config[:max_level])
280
- raise ArgumentError, "configuration #{index} max_level must be a valid log level"
281
- end
282
-
283
- # Validate rotation if specified
284
- return unless config[:rotation] && !valid_rotation_config?(config[:rotation])
285
-
286
- raise ArgumentError, "configuration #{index} rotation must be a valid rotation configuration"
287
- end
288
-
289
- # Check if log level is valid
290
- #
291
- # @param level [Symbol] log level to check
292
- # @return [Boolean] true if valid
293
- def valid_log_level?(level)
294
- %i[debug info warn error fatal success].include?(level)
295
- end
296
-
297
- # Check if rotation configuration is valid
298
- #
299
- # @param rotation [Hash] rotation configuration
300
- # @return [Boolean] true if valid
301
- def valid_rotation_config?(rotation)
302
- return false unless rotation.is_a?(Hash)
303
-
304
- valid_keys = %i[max_size max_files compress pattern]
305
- rotation.keys.all? { |key| valid_keys.include?(key) }
306
- end
307
- end
308
- end
309
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Makit
4
+ module Logging
5
+ # Configuration management for unified logging
6
+ #
7
+ # Provides schema validation, default configurations, and helper methods
8
+ # for setting up the unified file sink with various output configurations.
9
+ #
10
+ # @example Basic configuration
11
+ # config = Configuration.new(
12
+ # configurations: [
13
+ # { file: $stdout, format: :console },
14
+ # { file: "logs/app.log", format: :json }
15
+ # ]
16
+ # )
17
+ #
18
+ # @example YAML configuration
19
+ # config = Configuration.from_yaml("config/logging.yml")
20
+ #
21
+ # @example Environment-based configuration
22
+ # config = Configuration.for_environment(:production)
23
+ class Configuration
24
+ # @return [Array<Hash>] list of output configurations
25
+ attr_reader :configurations
26
+
27
+ # Initialize configuration
28
+ #
29
+ # @param configurations [Array<Hash>] list of output configurations
30
+ def initialize(configurations: [])
31
+ @configurations = configurations
32
+ end
33
+
34
+ # Create configuration from YAML file
35
+ #
36
+ # @param yaml_file [String] path to YAML configuration file
37
+ # @return [Configuration] new configuration instance
38
+ def self.from_yaml(yaml_file)
39
+ require "yaml"
40
+ data = YAML.load_file(yaml_file)
41
+ configurations = data["logging"]["sinks"] || []
42
+
43
+ # Convert string keys to symbols
44
+ configurations = configurations.map do |config|
45
+ config.transform_keys(&:to_sym)
46
+ end
47
+
48
+ new(configurations: configurations)
49
+ end
50
+
51
+ # Create configuration from JSON file
52
+ #
53
+ # @param json_file [String] path to JSON configuration file
54
+ # @return [Configuration] new configuration instance
55
+ def self.from_json(json_file)
56
+ require "json"
57
+ data = JSON.parse(File.read(json_file))
58
+ configurations = data["logging"]["sinks"] || []
59
+
60
+ # Convert string keys to symbols
61
+ configurations = configurations.map do |config|
62
+ config.transform_keys(&:to_sym)
63
+ end
64
+
65
+ new(configurations: configurations)
66
+ end
67
+
68
+ # Create environment-specific configuration
69
+ #
70
+ # @param environment [Symbol] environment name (:development, :production, :test)
71
+ # @return [Configuration] new configuration instance
72
+ def self.for_environment(environment)
73
+ case environment
74
+ when :development
75
+ development_config
76
+ when :production
77
+ production_config
78
+ when :test
79
+ test_config
80
+ when :ci
81
+ ci_config
82
+ else
83
+ default_config
84
+ end
85
+ end
86
+
87
+ # Get default configuration
88
+ #
89
+ # @return [Configuration] default configuration
90
+ def self.default_config
91
+ require_relative "../logging" unless defined?(Makit::Logging)
92
+ new(
93
+ configurations: [
94
+ { file: $stdout, format: :console },
95
+ { file: Makit::Logging.log_file_path("makit.log"), format: :json, append: true },
96
+ ],
97
+ )
98
+ end
99
+
100
+ # Get development configuration
101
+ #
102
+ # @return [Configuration] development configuration
103
+ def self.development_config
104
+ new(
105
+ configurations: [
106
+ {
107
+ file: $stdout,
108
+ format: :console,
109
+ show_timestamp: true,
110
+ show_level: true,
111
+ },
112
+ {
113
+ file: "logs/development.log",
114
+ format: :text,
115
+ append: true,
116
+ include_context: true,
117
+ },
118
+ {
119
+ file: "logs/debug.log",
120
+ format: :json,
121
+ append: true,
122
+ min_level: :debug,
123
+ },
124
+ ],
125
+ )
126
+ end
127
+
128
+ # Get production configuration
129
+ #
130
+ # @return [Configuration] production configuration
131
+ def self.production_config
132
+ new(
133
+ configurations: [
134
+ {
135
+ file: "logs/application.log",
136
+ format: :json,
137
+ append: true,
138
+ include_metadata: true,
139
+ rotation: { max_size: "100MB", max_files: 10 },
140
+ },
141
+ {
142
+ file: "logs/errors.log",
143
+ format: :json,
144
+ append: true,
145
+ min_level: :error,
146
+ include_metadata: true,
147
+ },
148
+ ],
149
+ )
150
+ end
151
+
152
+ # Get test configuration
153
+ #
154
+ # @return [Configuration] test configuration
155
+ def self.test_config
156
+ new(
157
+ configurations: [
158
+ {
159
+ file: "logs/test.log",
160
+ format: :text,
161
+ append: false,
162
+ include_context: true,
163
+ },
164
+ ],
165
+ )
166
+ end
167
+
168
+ # Get CI/CD configuration
169
+ #
170
+ # @return [Configuration] CI configuration
171
+ def self.ci_config
172
+ new(
173
+ configurations: [
174
+ {
175
+ file: $stdout,
176
+ format: :console,
177
+ show_level: true,
178
+ },
179
+ {
180
+ file: "artifacts/build.log",
181
+ format: :json,
182
+ append: true,
183
+ include_metadata: true,
184
+ },
185
+ ],
186
+ )
187
+ end
188
+
189
+ # Validate configuration
190
+ #
191
+ # @return [Boolean] true if valid
192
+ # @raise [ArgumentError] if configuration is invalid
193
+ def validate!
194
+ raise ArgumentError, "configurations must be an array" unless @configurations.is_a?(Array)
195
+ raise ArgumentError, "at least one configuration is required" if @configurations.empty?
196
+
197
+ @configurations.each_with_index do |config, index|
198
+ validate_single_configuration(config, index)
199
+ end
200
+
201
+ true
202
+ end
203
+
204
+ # Check if configuration is valid
205
+ #
206
+ # @return [Boolean] true if valid
207
+ def valid?
208
+ validate!
209
+ true
210
+ rescue ArgumentError
211
+ false
212
+ end
213
+
214
+ # Get configuration as hash
215
+ #
216
+ # @return [Hash] configuration as hash
217
+ def to_hash
218
+ {
219
+ logging: {
220
+ sinks: @configurations,
221
+ },
222
+ }
223
+ end
224
+
225
+ # Save configuration to YAML file
226
+ #
227
+ # @param yaml_file [String] path to YAML file
228
+ # @return [void]
229
+ def save_yaml(yaml_file)
230
+ require "yaml"
231
+ FileUtils.mkdir_p(File.dirname(yaml_file))
232
+ File.write(yaml_file, to_hash.to_yaml)
233
+ end
234
+
235
+ # Save configuration to JSON file
236
+ #
237
+ # @param json_file [String] path to JSON file
238
+ # @return [void]
239
+ def save_json(json_file)
240
+ require "json"
241
+ FileUtils.mkdir_p(File.dirname(json_file))
242
+ File.write(json_file, JSON.pretty_generate(to_hash))
243
+ end
244
+
245
+ private
246
+
247
+ # Validate a single configuration
248
+ #
249
+ # @param config [Hash] configuration to validate
250
+ # @param index [Integer] configuration index for error messages
251
+ # @raise [ArgumentError] if configuration is invalid
252
+ def validate_single_configuration(config, index)
253
+ raise ArgumentError, "configuration #{index} must be a hash" unless config.is_a?(Hash)
254
+
255
+ required_keys = %i[file format]
256
+ missing_keys = required_keys - config.keys
257
+ unless missing_keys.empty?
258
+ raise ArgumentError,
259
+ "configuration #{index} missing required keys: #{missing_keys.join(", ")}"
260
+ end
261
+
262
+ # Validate file
263
+ file = config[:file]
264
+ unless file.is_a?(String) || file.is_a?(IO) || file.respond_to?(:write)
265
+ raise ArgumentError, "configuration #{index} file must be a String path, IO object, or writable object"
266
+ end
267
+
268
+ # Validate format
269
+ format = config[:format]
270
+ unless format.is_a?(Symbol) || format.is_a?(String)
271
+ raise ArgumentError, "configuration #{index} format must be a Symbol or String"
272
+ end
273
+
274
+ # Validate log levels if specified
275
+ if config[:min_level] && !valid_log_level?(config[:min_level])
276
+ raise ArgumentError, "configuration #{index} min_level must be a valid log level"
277
+ end
278
+
279
+ if config[:max_level] && !valid_log_level?(config[:max_level])
280
+ raise ArgumentError, "configuration #{index} max_level must be a valid log level"
281
+ end
282
+
283
+ # Validate rotation if specified
284
+ return unless config[:rotation] && !valid_rotation_config?(config[:rotation])
285
+
286
+ raise ArgumentError, "configuration #{index} rotation must be a valid rotation configuration"
287
+ end
288
+
289
+ # Check if log level is valid
290
+ #
291
+ # @param level [Symbol] log level to check
292
+ # @return [Boolean] true if valid
293
+ def valid_log_level?(level)
294
+ %i[debug info warn error fatal success].include?(level)
295
+ end
296
+
297
+ # Check if rotation configuration is valid
298
+ #
299
+ # @param rotation [Hash] rotation configuration
300
+ # @return [Boolean] true if valid
301
+ def valid_rotation_config?(rotation)
302
+ return false unless rotation.is_a?(Hash)
303
+
304
+ valid_keys = %i[max_size max_files compress pattern]
305
+ rotation.keys.all? { |key| valid_keys.include?(key) }
306
+ end
307
+ end
308
+ end
309
+ end