makit 0.0.157 → 0.0.158

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 (177) 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/cli/base.rb +17 -17
  9. data/lib/makit/cli/build_commands.rb +500 -500
  10. data/lib/makit/cli/generators/base_generator.rb +74 -74
  11. data/lib/makit/cli/generators/dotnet_generator.rb +50 -50
  12. data/lib/makit/cli/generators/generator_factory.rb +49 -49
  13. data/lib/makit/cli/generators/node_generator.rb +50 -50
  14. data/lib/makit/cli/generators/ruby_generator.rb +77 -77
  15. data/lib/makit/cli/generators/rust_generator.rb +50 -50
  16. data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -167
  17. data/lib/makit/cli/generators/templates/node_templates.rb +161 -161
  18. data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -26
  19. data/lib/makit/cli/generators/templates/ruby/gemspec.rb +41 -41
  20. data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -33
  21. data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -35
  22. data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -63
  23. data/lib/makit/cli/generators/templates/ruby/test.rb +39 -39
  24. data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -29
  25. data/lib/makit/cli/generators/templates/ruby/version.rb +29 -29
  26. data/lib/makit/cli/generators/templates/rust_templates.rb +128 -128
  27. data/lib/makit/cli/main.rb +78 -78
  28. data/lib/makit/cli/pipeline_commands.rb +311 -311
  29. data/lib/makit/cli/project_commands.rb +868 -868
  30. data/lib/makit/cli/repository_commands.rb +661 -661
  31. data/lib/makit/cli/strategy_commands.rb +207 -207
  32. data/lib/makit/cli/utility_commands.rb +521 -521
  33. data/lib/makit/commands/factory.rb +359 -359
  34. data/lib/makit/commands/middleware/base.rb +73 -73
  35. data/lib/makit/commands/middleware/cache.rb +248 -248
  36. data/lib/makit/commands/middleware/command_logger.rb +312 -312
  37. data/lib/makit/commands/middleware/validator.rb +269 -269
  38. data/lib/makit/commands/request.rb +316 -316
  39. data/lib/makit/commands/result.rb +323 -323
  40. data/lib/makit/commands/runner.rb +386 -386
  41. data/lib/makit/commands/strategies/base.rb +171 -171
  42. data/lib/makit/commands/strategies/child_process.rb +162 -162
  43. data/lib/makit/commands/strategies/factory.rb +136 -136
  44. data/lib/makit/commands/strategies/synchronous.rb +139 -139
  45. data/lib/makit/commands.rb +50 -50
  46. data/lib/makit/configuration/dotnet_project.rb +48 -48
  47. data/lib/makit/configuration/gitlab_helper.rb +61 -61
  48. data/lib/makit/configuration/project.rb +292 -292
  49. data/lib/makit/configuration/rakefile_helper.rb +43 -43
  50. data/lib/makit/configuration/step.rb +34 -34
  51. data/lib/makit/configuration/timeout.rb +74 -74
  52. data/lib/makit/configuration.rb +21 -21
  53. data/lib/makit/content/default_gitignore.rb +7 -7
  54. data/lib/makit/content/default_gitignore.txt +225 -225
  55. data/lib/makit/content/default_rakefile.rb +13 -13
  56. data/lib/makit/content/gem_rakefile.rb +16 -16
  57. data/lib/makit/context.rb +1 -1
  58. data/lib/makit/data.rb +49 -49
  59. data/lib/makit/directories.rb +170 -170
  60. data/lib/makit/directory.rb +262 -262
  61. data/lib/makit/docs/files.rb +89 -89
  62. data/lib/makit/docs/rake.rb +102 -102
  63. data/lib/makit/dotnet/cli.rb +69 -69
  64. data/lib/makit/dotnet/project.rb +217 -217
  65. data/lib/makit/dotnet/solution.rb +38 -38
  66. data/lib/makit/dotnet/solution_classlib.rb +239 -239
  67. data/lib/makit/dotnet/solution_console.rb +264 -264
  68. data/lib/makit/dotnet/solution_maui.rb +354 -354
  69. data/lib/makit/dotnet/solution_wasm.rb +275 -275
  70. data/lib/makit/dotnet/solution_wpf.rb +304 -304
  71. data/lib/makit/dotnet.rb +102 -102
  72. data/lib/makit/email.rb +90 -90
  73. data/lib/makit/environment.rb +142 -142
  74. data/lib/makit/examples/runner.rb +370 -370
  75. data/lib/makit/exceptions.rb +45 -45
  76. data/lib/makit/fileinfo.rb +32 -32
  77. data/lib/makit/files.rb +43 -43
  78. data/lib/makit/gems.rb +40 -40
  79. data/lib/makit/git/cli.rb +78 -54
  80. data/lib/makit/git/repository.rb +100 -100
  81. data/lib/makit/git.rb +104 -104
  82. data/lib/makit/gitlab/pipeline.rb +857 -857
  83. data/lib/makit/gitlab/pipeline_service_impl.rb +1535 -1535
  84. data/lib/makit/gitlab_runner.rb +59 -59
  85. data/lib/makit/humanize.rb +218 -218
  86. data/lib/makit/indexer.rb +47 -47
  87. data/lib/makit/io/filesystem.rb +111 -111
  88. data/lib/makit/io/filesystem_service_impl.rb +337 -337
  89. data/lib/makit/lint.rb +212 -212
  90. data/lib/makit/logging/configuration.rb +309 -309
  91. data/lib/makit/logging/format_registry.rb +84 -84
  92. data/lib/makit/logging/formatters/base.rb +39 -39
  93. data/lib/makit/logging/formatters/console_formatter.rb +140 -140
  94. data/lib/makit/logging/formatters/json_formatter.rb +65 -65
  95. data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -71
  96. data/lib/makit/logging/formatters/text_formatter.rb +64 -64
  97. data/lib/makit/logging/log_request.rb +119 -119
  98. data/lib/makit/logging/logger.rb +199 -199
  99. data/lib/makit/logging/sinks/base.rb +91 -91
  100. data/lib/makit/logging/sinks/console.rb +72 -72
  101. data/lib/makit/logging/sinks/file_sink.rb +92 -92
  102. data/lib/makit/logging/sinks/structured.rb +123 -123
  103. data/lib/makit/logging/sinks/unified_file_sink.rb +296 -296
  104. data/lib/makit/logging.rb +578 -578
  105. data/lib/makit/markdown.rb +75 -75
  106. data/lib/makit/mp/basic_object_mp.rb +17 -17
  107. data/lib/makit/mp/command_mp.rb +13 -13
  108. data/lib/makit/mp/command_request.mp.rb +17 -17
  109. data/lib/makit/mp/project_mp.rb +199 -199
  110. data/lib/makit/mp/string_mp.rb +205 -205
  111. data/lib/makit/nuget.rb +74 -74
  112. data/lib/makit/podman/podman.rb +458 -458
  113. data/lib/makit/podman/podman_service_impl.rb +1081 -1081
  114. data/lib/makit/port.rb +32 -32
  115. data/lib/makit/process.rb +377 -377
  116. data/lib/makit/protoc.rb +112 -112
  117. data/lib/makit/rake/cli.rb +196 -196
  118. data/lib/makit/rake/trace_controller.rb +174 -174
  119. data/lib/makit/rake.rb +81 -81
  120. data/lib/makit/ruby/cli.rb +185 -185
  121. data/lib/makit/ruby.rb +25 -25
  122. data/lib/makit/rubygems.rb +137 -0
  123. data/lib/makit/secrets/azure_key_vault.rb +322 -322
  124. data/lib/makit/secrets/azure_secrets.rb +183 -183
  125. data/lib/makit/secrets/local_secrets.rb +72 -72
  126. data/lib/makit/secrets/secrets_manager.rb +105 -105
  127. data/lib/makit/secrets.rb +16 -16
  128. data/lib/makit/serializer.rb +130 -130
  129. data/lib/makit/services/builder.rb +186 -186
  130. data/lib/makit/services/error_handler.rb +226 -226
  131. data/lib/makit/services/repository_manager.rb +367 -367
  132. data/lib/makit/services/validator.rb +112 -112
  133. data/lib/makit/setup/classlib.rb +101 -101
  134. data/lib/makit/setup/gem.rb +268 -268
  135. data/lib/makit/setup/pages.rb +11 -11
  136. data/lib/makit/setup/razorclasslib.rb +101 -101
  137. data/lib/makit/setup/runner.rb +54 -54
  138. data/lib/makit/setup.rb +5 -5
  139. data/lib/makit/show.rb +110 -110
  140. data/lib/makit/storage.rb +126 -126
  141. data/lib/makit/symbols.rb +175 -175
  142. data/lib/makit/task_info.rb +130 -130
  143. data/lib/makit/tasks/at_exit.rb +15 -15
  144. data/lib/makit/tasks/build.rb +22 -22
  145. data/lib/makit/tasks/bump.rb +7 -7
  146. data/lib/makit/tasks/clean.rb +13 -13
  147. data/lib/makit/tasks/configure.rb +10 -10
  148. data/lib/makit/tasks/format.rb +10 -10
  149. data/lib/makit/tasks/hook_manager.rb +443 -443
  150. data/lib/makit/tasks/info.rb +368 -368
  151. data/lib/makit/tasks/init.rb +49 -49
  152. data/lib/makit/tasks/integrate.rb +60 -56
  153. data/lib/makit/tasks/pull_incoming.rb +13 -13
  154. data/lib/makit/tasks/secrets.rb +7 -7
  155. data/lib/makit/tasks/setup.rb +16 -16
  156. data/lib/makit/tasks/sync.rb +14 -17
  157. data/lib/makit/tasks/tag.rb +27 -27
  158. data/lib/makit/tasks/task_monkey_patch.rb +81 -81
  159. data/lib/makit/tasks/test.rb +22 -22
  160. data/lib/makit/tasks/update.rb +18 -18
  161. data/lib/makit/tasks/version.rb +6 -6
  162. data/lib/makit/tasks.rb +24 -24
  163. data/lib/makit/test_cache.rb +239 -239
  164. data/lib/makit/tree.rb +37 -37
  165. data/lib/makit/v1/configuration/project_service_impl.rb +370 -370
  166. data/lib/makit/v1/git/git_repository_service_impl.rb +295 -295
  167. data/lib/makit/v1/makit.v1_pb.rb +35 -35
  168. data/lib/makit/v1/makit.v1_services_pb.rb +27 -27
  169. data/lib/makit/v1/services/repository_manager_service_impl.rb +572 -572
  170. data/lib/makit/version.rb +661 -503
  171. data/lib/makit/version_util.rb +21 -21
  172. data/lib/makit/wix.rb +95 -95
  173. data/lib/makit/yaml.rb +29 -29
  174. data/lib/makit/zip.rb +17 -17
  175. data/lib/makit copy.rb +44 -44
  176. data/lib/makit.rb +115 -114
  177. 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