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.
- checksums.yaml +4 -4
- data/README.md +41 -41
- data/exe/makit +5 -5
- data/lib/makit/apache.rb +28 -28
- data/lib/makit/auto.rb +48 -48
- data/lib/makit/azure/blob_storage.rb +257 -257
- data/lib/makit/azure/cli.rb +284 -284
- data/lib/makit/cli/base.rb +17 -17
- data/lib/makit/cli/build_commands.rb +500 -500
- data/lib/makit/cli/generators/base_generator.rb +74 -74
- data/lib/makit/cli/generators/dotnet_generator.rb +50 -50
- data/lib/makit/cli/generators/generator_factory.rb +49 -49
- data/lib/makit/cli/generators/node_generator.rb +50 -50
- data/lib/makit/cli/generators/ruby_generator.rb +77 -77
- data/lib/makit/cli/generators/rust_generator.rb +50 -50
- data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -167
- data/lib/makit/cli/generators/templates/node_templates.rb +161 -161
- data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -26
- data/lib/makit/cli/generators/templates/ruby/gemspec.rb +41 -41
- data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -33
- data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -35
- data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -63
- data/lib/makit/cli/generators/templates/ruby/test.rb +39 -39
- data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -29
- data/lib/makit/cli/generators/templates/ruby/version.rb +29 -29
- data/lib/makit/cli/generators/templates/rust_templates.rb +128 -128
- data/lib/makit/cli/main.rb +78 -78
- data/lib/makit/cli/pipeline_commands.rb +311 -311
- data/lib/makit/cli/project_commands.rb +868 -868
- data/lib/makit/cli/repository_commands.rb +661 -661
- data/lib/makit/cli/strategy_commands.rb +207 -207
- data/lib/makit/cli/utility_commands.rb +521 -521
- data/lib/makit/commands/factory.rb +359 -359
- data/lib/makit/commands/middleware/base.rb +73 -73
- data/lib/makit/commands/middleware/cache.rb +248 -248
- data/lib/makit/commands/middleware/command_logger.rb +312 -312
- data/lib/makit/commands/middleware/validator.rb +269 -269
- data/lib/makit/commands/request.rb +316 -316
- data/lib/makit/commands/result.rb +323 -323
- data/lib/makit/commands/runner.rb +386 -386
- data/lib/makit/commands/strategies/base.rb +171 -171
- data/lib/makit/commands/strategies/child_process.rb +162 -162
- data/lib/makit/commands/strategies/factory.rb +136 -136
- data/lib/makit/commands/strategies/synchronous.rb +139 -139
- data/lib/makit/commands.rb +50 -50
- data/lib/makit/configuration/dotnet_project.rb +48 -48
- data/lib/makit/configuration/gitlab_helper.rb +61 -61
- data/lib/makit/configuration/project.rb +292 -292
- data/lib/makit/configuration/rakefile_helper.rb +43 -43
- data/lib/makit/configuration/step.rb +34 -34
- data/lib/makit/configuration/timeout.rb +74 -74
- data/lib/makit/configuration.rb +21 -21
- data/lib/makit/content/default_gitignore.rb +7 -7
- data/lib/makit/content/default_gitignore.txt +225 -225
- data/lib/makit/content/default_rakefile.rb +13 -13
- data/lib/makit/content/gem_rakefile.rb +16 -16
- data/lib/makit/context.rb +1 -1
- data/lib/makit/data.rb +49 -49
- data/lib/makit/directories.rb +170 -170
- data/lib/makit/directory.rb +262 -262
- data/lib/makit/docs/files.rb +89 -89
- data/lib/makit/docs/rake.rb +102 -102
- data/lib/makit/dotnet/cli.rb +69 -69
- data/lib/makit/dotnet/project.rb +217 -217
- data/lib/makit/dotnet/solution.rb +38 -38
- data/lib/makit/dotnet/solution_classlib.rb +239 -239
- data/lib/makit/dotnet/solution_console.rb +264 -264
- data/lib/makit/dotnet/solution_maui.rb +354 -354
- data/lib/makit/dotnet/solution_wasm.rb +275 -275
- data/lib/makit/dotnet/solution_wpf.rb +304 -304
- data/lib/makit/dotnet.rb +102 -102
- data/lib/makit/email.rb +90 -90
- data/lib/makit/environment.rb +142 -142
- data/lib/makit/examples/runner.rb +370 -370
- data/lib/makit/exceptions.rb +45 -45
- data/lib/makit/fileinfo.rb +32 -32
- data/lib/makit/files.rb +43 -43
- data/lib/makit/gems.rb +40 -40
- data/lib/makit/git/cli.rb +78 -54
- data/lib/makit/git/repository.rb +100 -100
- data/lib/makit/git.rb +104 -104
- data/lib/makit/gitlab/pipeline.rb +857 -857
- data/lib/makit/gitlab/pipeline_service_impl.rb +1535 -1535
- data/lib/makit/gitlab_runner.rb +59 -59
- data/lib/makit/humanize.rb +218 -218
- data/lib/makit/indexer.rb +47 -47
- data/lib/makit/io/filesystem.rb +111 -111
- data/lib/makit/io/filesystem_service_impl.rb +337 -337
- data/lib/makit/lint.rb +212 -212
- data/lib/makit/logging/configuration.rb +309 -309
- data/lib/makit/logging/format_registry.rb +84 -84
- data/lib/makit/logging/formatters/base.rb +39 -39
- data/lib/makit/logging/formatters/console_formatter.rb +140 -140
- data/lib/makit/logging/formatters/json_formatter.rb +65 -65
- data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -71
- data/lib/makit/logging/formatters/text_formatter.rb +64 -64
- data/lib/makit/logging/log_request.rb +119 -119
- data/lib/makit/logging/logger.rb +199 -199
- data/lib/makit/logging/sinks/base.rb +91 -91
- data/lib/makit/logging/sinks/console.rb +72 -72
- data/lib/makit/logging/sinks/file_sink.rb +92 -92
- data/lib/makit/logging/sinks/structured.rb +123 -123
- data/lib/makit/logging/sinks/unified_file_sink.rb +296 -296
- data/lib/makit/logging.rb +578 -578
- data/lib/makit/markdown.rb +75 -75
- data/lib/makit/mp/basic_object_mp.rb +17 -17
- data/lib/makit/mp/command_mp.rb +13 -13
- data/lib/makit/mp/command_request.mp.rb +17 -17
- data/lib/makit/mp/project_mp.rb +199 -199
- data/lib/makit/mp/string_mp.rb +205 -205
- data/lib/makit/nuget.rb +74 -74
- data/lib/makit/podman/podman.rb +458 -458
- data/lib/makit/podman/podman_service_impl.rb +1081 -1081
- data/lib/makit/port.rb +32 -32
- data/lib/makit/process.rb +377 -377
- data/lib/makit/protoc.rb +112 -112
- data/lib/makit/rake/cli.rb +196 -196
- data/lib/makit/rake/trace_controller.rb +174 -174
- data/lib/makit/rake.rb +81 -81
- data/lib/makit/ruby/cli.rb +185 -185
- data/lib/makit/ruby.rb +25 -25
- data/lib/makit/rubygems.rb +137 -0
- data/lib/makit/secrets/azure_key_vault.rb +322 -322
- data/lib/makit/secrets/azure_secrets.rb +183 -183
- data/lib/makit/secrets/local_secrets.rb +72 -72
- data/lib/makit/secrets/secrets_manager.rb +105 -105
- data/lib/makit/secrets.rb +16 -16
- data/lib/makit/serializer.rb +130 -130
- data/lib/makit/services/builder.rb +186 -186
- data/lib/makit/services/error_handler.rb +226 -226
- data/lib/makit/services/repository_manager.rb +367 -367
- data/lib/makit/services/validator.rb +112 -112
- data/lib/makit/setup/classlib.rb +101 -101
- data/lib/makit/setup/gem.rb +268 -268
- data/lib/makit/setup/pages.rb +11 -11
- data/lib/makit/setup/razorclasslib.rb +101 -101
- data/lib/makit/setup/runner.rb +54 -54
- data/lib/makit/setup.rb +5 -5
- data/lib/makit/show.rb +110 -110
- data/lib/makit/storage.rb +126 -126
- data/lib/makit/symbols.rb +175 -175
- data/lib/makit/task_info.rb +130 -130
- data/lib/makit/tasks/at_exit.rb +15 -15
- data/lib/makit/tasks/build.rb +22 -22
- data/lib/makit/tasks/bump.rb +7 -7
- data/lib/makit/tasks/clean.rb +13 -13
- data/lib/makit/tasks/configure.rb +10 -10
- data/lib/makit/tasks/format.rb +10 -10
- data/lib/makit/tasks/hook_manager.rb +443 -443
- data/lib/makit/tasks/info.rb +368 -368
- data/lib/makit/tasks/init.rb +49 -49
- data/lib/makit/tasks/integrate.rb +60 -56
- data/lib/makit/tasks/pull_incoming.rb +13 -13
- data/lib/makit/tasks/secrets.rb +7 -7
- data/lib/makit/tasks/setup.rb +16 -16
- data/lib/makit/tasks/sync.rb +14 -17
- data/lib/makit/tasks/tag.rb +27 -27
- data/lib/makit/tasks/task_monkey_patch.rb +81 -81
- data/lib/makit/tasks/test.rb +22 -22
- data/lib/makit/tasks/update.rb +18 -18
- data/lib/makit/tasks/version.rb +6 -6
- data/lib/makit/tasks.rb +24 -24
- data/lib/makit/test_cache.rb +239 -239
- data/lib/makit/tree.rb +37 -37
- data/lib/makit/v1/configuration/project_service_impl.rb +370 -370
- data/lib/makit/v1/git/git_repository_service_impl.rb +295 -295
- data/lib/makit/v1/makit.v1_pb.rb +35 -35
- data/lib/makit/v1/makit.v1_services_pb.rb +27 -27
- data/lib/makit/v1/services/repository_manager_service_impl.rb +572 -572
- data/lib/makit/version.rb +661 -503
- data/lib/makit/version_util.rb +21 -21
- data/lib/makit/wix.rb +95 -95
- data/lib/makit/yaml.rb +29 -29
- data/lib/makit/zip.rb +17 -17
- data/lib/makit copy.rb +44 -44
- data/lib/makit.rb +115 -114
- metadata +3 -2
|
@@ -1,311 +1,311 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "clamp"
|
|
4
|
-
require "colorize"
|
|
5
|
-
require_relative "../gitlab/pipeline"
|
|
6
|
-
require_relative "../humanize"
|
|
7
|
-
|
|
8
|
-
module Makit
|
|
9
|
-
module Cli
|
|
10
|
-
# Command to run GitLab CI pipelines
|
|
11
|
-
class PipelineRunCommand < Clamp::Command
|
|
12
|
-
self.description = <<~DESC
|
|
13
|
-
Execute a GitLab CI pipeline using Podman containers.
|
|
14
|
-
|
|
15
|
-
By default, looks for .gitlab-ci.yml in the current directory.
|
|
16
|
-
Each job in the pipeline will be executed in a separate Podman container.
|
|
17
|
-
DESC
|
|
18
|
-
|
|
19
|
-
option ["-f", "--file"], "FILE", "Pipeline file to execute", default: ".gitlab-ci.yml"
|
|
20
|
-
option ["-v", "--variables"], "VARS", "Variables to pass to the pipeline (format: KEY=value,KEY2=value2)"
|
|
21
|
-
option ["-w", "--working-directory"], "DIR", "Working directory for execution", default: Dir.pwd
|
|
22
|
-
option ["-p", "--podman-executable"], "EXECUTABLE", "Podman executable path", default: "podman"
|
|
23
|
-
option ["-d", "--dry-run"], :flag, "Simulate execution without actually running"
|
|
24
|
-
option ["--verbose"], :flag, "Show detailed output"
|
|
25
|
-
option ["--no-color"], :flag, "Disable colored output"
|
|
26
|
-
|
|
27
|
-
def execute
|
|
28
|
-
# Disable color if requested
|
|
29
|
-
String.disable_colorization = true if no_color?
|
|
30
|
-
|
|
31
|
-
# Check if pipeline file exists
|
|
32
|
-
unless File.exist?(file)
|
|
33
|
-
error "Pipeline file '#{file}' not found"
|
|
34
|
-
exit(1)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Parse variables
|
|
38
|
-
variables = parse_variables
|
|
39
|
-
|
|
40
|
-
# Load and parse pipeline
|
|
41
|
-
puts "Loading pipeline from #{file}..." if verbose?
|
|
42
|
-
begin
|
|
43
|
-
pipeline_content = File.read(file)
|
|
44
|
-
pipeline = Makit::Gitlab::Pipeline.parse_yaml(pipeline_content)
|
|
45
|
-
rescue StandardError => e
|
|
46
|
-
error "Failed to parse pipeline file: #{e.message}"
|
|
47
|
-
exit(1)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Validate pipeline
|
|
51
|
-
validation_result = pipeline.validate
|
|
52
|
-
unless validation_result[:is_valid]
|
|
53
|
-
error "Pipeline validation failed:"
|
|
54
|
-
validation_result[:errors].each { |err| error " - #{err}" }
|
|
55
|
-
exit(1)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Show warnings if any
|
|
59
|
-
if validation_result[:warnings].any?
|
|
60
|
-
warning "Pipeline warnings:"
|
|
61
|
-
validation_result[:warnings].each { |warn| warning " - #{warn}" }
|
|
62
|
-
puts
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
# Show pipeline info
|
|
66
|
-
show_pipeline_info(pipeline)
|
|
67
|
-
|
|
68
|
-
# Execute pipeline
|
|
69
|
-
puts "\nExecuting pipeline..." unless dry_run?
|
|
70
|
-
puts "Dry run mode - no actual execution will occur" if dry_run?
|
|
71
|
-
|
|
72
|
-
start_time = Time.now
|
|
73
|
-
result = pipeline.execute_pipeline(
|
|
74
|
-
variables: variables,
|
|
75
|
-
working_directory: working_directory,
|
|
76
|
-
podman_executable: podman_executable,
|
|
77
|
-
dry_run: dry_run?
|
|
78
|
-
)
|
|
79
|
-
end_time = Time.now
|
|
80
|
-
|
|
81
|
-
# Display results
|
|
82
|
-
display_execution_result(result, start_time, end_time)
|
|
83
|
-
|
|
84
|
-
# Exit with appropriate code
|
|
85
|
-
success = if result.is_a?(Hash)
|
|
86
|
-
result[:success]
|
|
87
|
-
else
|
|
88
|
-
result.success
|
|
89
|
-
end
|
|
90
|
-
exit(success ? 0 : 1)
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
private
|
|
94
|
-
|
|
95
|
-
def parse_variables
|
|
96
|
-
return {} unless variables
|
|
97
|
-
|
|
98
|
-
vars = {}
|
|
99
|
-
variables.split(",").each do |var|
|
|
100
|
-
key, value = var.split("=", 2)
|
|
101
|
-
if key && value
|
|
102
|
-
vars[key.strip] = value.strip
|
|
103
|
-
else
|
|
104
|
-
error "Invalid variable format: #{var}. Use KEY=value format."
|
|
105
|
-
exit(1)
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
vars
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def show_pipeline_info(pipeline)
|
|
112
|
-
puts "Pipeline Information:"
|
|
113
|
-
puts " Image: #{pipeline.pipeline_data.image}" unless pipeline.pipeline_data.image.empty?
|
|
114
|
-
puts " Stages: #{pipeline.pipeline_data.stages.map(&:name).join(', ')}"
|
|
115
|
-
puts " Jobs: #{pipeline.pipeline_data.jobs.keys.join(', ')}"
|
|
116
|
-
puts " Variables: #{pipeline.pipeline_data.variables.keys.join(', ')}" unless pipeline.pipeline_data.variables.empty?
|
|
117
|
-
puts
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def display_execution_result(result, start_time, end_time)
|
|
121
|
-
puts "\n" + "="*60
|
|
122
|
-
puts "PIPELINE EXECUTION RESULT".center(60)
|
|
123
|
-
puts "="*60
|
|
124
|
-
|
|
125
|
-
# Extract result data based on mode
|
|
126
|
-
if result.is_a?(Hash)
|
|
127
|
-
# Fallback mode
|
|
128
|
-
execution_result = result[:result]
|
|
129
|
-
success = result[:success]
|
|
130
|
-
errors = result[:errors] || []
|
|
131
|
-
warnings = result[:warnings] || []
|
|
132
|
-
else
|
|
133
|
-
# gRPC mode
|
|
134
|
-
execution_result = result.result
|
|
135
|
-
success = result.success
|
|
136
|
-
errors = result.errors || []
|
|
137
|
-
warnings = result.warnings || []
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
# Overall status
|
|
141
|
-
status_color = success ? :green : :red
|
|
142
|
-
status_icon = success ? "✓" : "✗"
|
|
143
|
-
puts "#{status_icon} Status: #{success ? 'SUCCESS' : 'FAILED'}".colorize(status_color)
|
|
144
|
-
|
|
145
|
-
# Access execution result fields safely
|
|
146
|
-
execution_id = if execution_result.respond_to?(:execution_id)
|
|
147
|
-
execution_result.execution_id
|
|
148
|
-
else
|
|
149
|
-
execution_result[:execution_id]
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
started_at = if execution_result.respond_to?(:started_at)
|
|
153
|
-
execution_result.started_at
|
|
154
|
-
else
|
|
155
|
-
execution_result[:started_at]
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
finished_at = if execution_result.respond_to?(:finished_at)
|
|
159
|
-
execution_result.finished_at
|
|
160
|
-
else
|
|
161
|
-
execution_result[:finished_at]
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
puts " Execution ID: #{execution_id}"
|
|
165
|
-
puts " Started: #{started_at}"
|
|
166
|
-
puts " Finished: #{finished_at}" if finished_at
|
|
167
|
-
puts " Duration: #{Makit::Humanize.get_humanized_duration(end_time - start_time)}"
|
|
168
|
-
|
|
169
|
-
# Podman info
|
|
170
|
-
podman_version = if execution_result.respond_to?(:podman_version)
|
|
171
|
-
execution_result.podman_version
|
|
172
|
-
else
|
|
173
|
-
execution_result[:podman_version]
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
execution_host = if execution_result.respond_to?(:execution_host)
|
|
177
|
-
execution_result.execution_host
|
|
178
|
-
else
|
|
179
|
-
execution_result[:execution_host]
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
puts " Podman Version: #{podman_version}" if podman_version
|
|
183
|
-
puts " Host: #{execution_host}" if execution_host
|
|
184
|
-
|
|
185
|
-
# Job results
|
|
186
|
-
job_results = if execution_result.respond_to?(:job_results)
|
|
187
|
-
execution_result.job_results
|
|
188
|
-
else
|
|
189
|
-
execution_result[:job_results]
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
if job_results && job_results.any?
|
|
193
|
-
puts "\nJob Results:"
|
|
194
|
-
job_results.each do |job_result|
|
|
195
|
-
display_job_result(job_result)
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
# Errors
|
|
200
|
-
if errors.any?
|
|
201
|
-
puts "\nErrors:".colorize(:red)
|
|
202
|
-
errors.each { |err| puts " ✗ #{err}".colorize(:red) }
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
# Warnings
|
|
206
|
-
if warnings.any?
|
|
207
|
-
puts "\nWarnings:".colorize(:yellow)
|
|
208
|
-
warnings.each { |warn| puts " ⚠ #{warn}".colorize(:yellow) }
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
# Logs
|
|
212
|
-
logs = if execution_result.respond_to?(:logs)
|
|
213
|
-
execution_result.logs
|
|
214
|
-
else
|
|
215
|
-
execution_result[:logs]
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
if logs && logs.any? && verbose?
|
|
219
|
-
puts "\nExecution Logs:"
|
|
220
|
-
logs.each { |log| puts " #{log}" }
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
puts "="*60
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
def display_job_result(job_result)
|
|
227
|
-
# Extract job data based on mode
|
|
228
|
-
if job_result.is_a?(Hash)
|
|
229
|
-
job_name = job_result[:job_name]
|
|
230
|
-
status = job_result[:status]
|
|
231
|
-
exit_code = job_result[:exit_code]
|
|
232
|
-
started_at = job_result[:started_at]
|
|
233
|
-
finished_at = job_result[:finished_at]
|
|
234
|
-
logs = job_result[:logs] || []
|
|
235
|
-
errors = job_result[:errors] || []
|
|
236
|
-
stdout = job_result[:stdout] || ""
|
|
237
|
-
stderr = job_result[:stderr] || ""
|
|
238
|
-
else
|
|
239
|
-
job_name = job_result.job_name
|
|
240
|
-
status = job_result.status
|
|
241
|
-
exit_code = job_result.exit_code
|
|
242
|
-
started_at = job_result.started_at
|
|
243
|
-
finished_at = job_result.finished_at
|
|
244
|
-
logs = job_result.logs || []
|
|
245
|
-
errors = job_result.errors || []
|
|
246
|
-
stdout = job_result.respond_to?(:stdout) ? job_result.stdout : ""
|
|
247
|
-
stderr = job_result.respond_to?(:stderr) ? job_result.stderr : ""
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
# Job status
|
|
251
|
-
status_color = (status == :success || status.to_s.include?('SUCCESS')) ? :green : :red
|
|
252
|
-
status_icon = (status == :success || status.to_s.include?('SUCCESS')) ? "✓" : "✗"
|
|
253
|
-
|
|
254
|
-
puts " #{status_icon} #{job_name}: #{status.to_s.upcase}".colorize(status_color)
|
|
255
|
-
puts " Exit Code: #{exit_code}" if exit_code
|
|
256
|
-
puts " Started: #{started_at}"
|
|
257
|
-
puts " Finished: #{finished_at}" if finished_at
|
|
258
|
-
|
|
259
|
-
# Job errors
|
|
260
|
-
if errors.any?
|
|
261
|
-
puts " Errors:".colorize(:red)
|
|
262
|
-
errors.each { |err| puts " ✗ #{err}".colorize(:red) }
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
# Job logs (if verbose)
|
|
266
|
-
if logs.any? && verbose?
|
|
267
|
-
puts " Logs:"
|
|
268
|
-
logs.each { |log| puts " #{log}" }
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
# Job stdout (if verbose and not empty)
|
|
272
|
-
if stdout && !stdout.empty? && verbose?
|
|
273
|
-
puts " Stdout:".colorize(:green)
|
|
274
|
-
stdout.split("\n").each { |line| puts " #{line}".colorize(:green) }
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
# Job stderr (if verbose and not empty)
|
|
278
|
-
if stderr && !stderr.empty? && verbose?
|
|
279
|
-
puts " Stderr:".colorize(:red)
|
|
280
|
-
stderr.split("\n").each { |line| puts " #{line}".colorize(:red) }
|
|
281
|
-
end
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
def error(message)
|
|
285
|
-
puts "Error: #{message}".colorize(:red)
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
def warning(message)
|
|
289
|
-
puts "Warning: #{message}".colorize(:yellow)
|
|
290
|
-
end
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
# Pipeline command group for GitLab CI pipeline operations
|
|
294
|
-
class PipelineCommand < Clamp::Command
|
|
295
|
-
self.description = <<~DESC
|
|
296
|
-
GitLab CI Pipeline operations.
|
|
297
|
-
|
|
298
|
-
Available commands:
|
|
299
|
-
run - Execute a GitLab CI pipeline using Podman
|
|
300
|
-
|
|
301
|
-
Examples:
|
|
302
|
-
makit pipeline run # Run .gitlab-ci.yml in current directory
|
|
303
|
-
makit pipeline run --file custom-ci.yml # Run custom pipeline file
|
|
304
|
-
makit pipeline run --dry-run # Simulate execution without running
|
|
305
|
-
makit pipeline run --variables KEY=value # Pass variables to pipeline
|
|
306
|
-
DESC
|
|
307
|
-
|
|
308
|
-
subcommand "run", "Execute a GitLab CI pipeline", PipelineRunCommand
|
|
309
|
-
end
|
|
310
|
-
end
|
|
311
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "clamp"
|
|
4
|
+
require "colorize"
|
|
5
|
+
require_relative "../gitlab/pipeline"
|
|
6
|
+
require_relative "../humanize"
|
|
7
|
+
|
|
8
|
+
module Makit
|
|
9
|
+
module Cli
|
|
10
|
+
# Command to run GitLab CI pipelines
|
|
11
|
+
class PipelineRunCommand < Clamp::Command
|
|
12
|
+
self.description = <<~DESC
|
|
13
|
+
Execute a GitLab CI pipeline using Podman containers.
|
|
14
|
+
|
|
15
|
+
By default, looks for .gitlab-ci.yml in the current directory.
|
|
16
|
+
Each job in the pipeline will be executed in a separate Podman container.
|
|
17
|
+
DESC
|
|
18
|
+
|
|
19
|
+
option ["-f", "--file"], "FILE", "Pipeline file to execute", default: ".gitlab-ci.yml"
|
|
20
|
+
option ["-v", "--variables"], "VARS", "Variables to pass to the pipeline (format: KEY=value,KEY2=value2)"
|
|
21
|
+
option ["-w", "--working-directory"], "DIR", "Working directory for execution", default: Dir.pwd
|
|
22
|
+
option ["-p", "--podman-executable"], "EXECUTABLE", "Podman executable path", default: "podman"
|
|
23
|
+
option ["-d", "--dry-run"], :flag, "Simulate execution without actually running"
|
|
24
|
+
option ["--verbose"], :flag, "Show detailed output"
|
|
25
|
+
option ["--no-color"], :flag, "Disable colored output"
|
|
26
|
+
|
|
27
|
+
def execute
|
|
28
|
+
# Disable color if requested
|
|
29
|
+
String.disable_colorization = true if no_color?
|
|
30
|
+
|
|
31
|
+
# Check if pipeline file exists
|
|
32
|
+
unless File.exist?(file)
|
|
33
|
+
error "Pipeline file '#{file}' not found"
|
|
34
|
+
exit(1)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Parse variables
|
|
38
|
+
variables = parse_variables
|
|
39
|
+
|
|
40
|
+
# Load and parse pipeline
|
|
41
|
+
puts "Loading pipeline from #{file}..." if verbose?
|
|
42
|
+
begin
|
|
43
|
+
pipeline_content = File.read(file)
|
|
44
|
+
pipeline = Makit::Gitlab::Pipeline.parse_yaml(pipeline_content)
|
|
45
|
+
rescue StandardError => e
|
|
46
|
+
error "Failed to parse pipeline file: #{e.message}"
|
|
47
|
+
exit(1)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Validate pipeline
|
|
51
|
+
validation_result = pipeline.validate
|
|
52
|
+
unless validation_result[:is_valid]
|
|
53
|
+
error "Pipeline validation failed:"
|
|
54
|
+
validation_result[:errors].each { |err| error " - #{err}" }
|
|
55
|
+
exit(1)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Show warnings if any
|
|
59
|
+
if validation_result[:warnings].any?
|
|
60
|
+
warning "Pipeline warnings:"
|
|
61
|
+
validation_result[:warnings].each { |warn| warning " - #{warn}" }
|
|
62
|
+
puts
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Show pipeline info
|
|
66
|
+
show_pipeline_info(pipeline)
|
|
67
|
+
|
|
68
|
+
# Execute pipeline
|
|
69
|
+
puts "\nExecuting pipeline..." unless dry_run?
|
|
70
|
+
puts "Dry run mode - no actual execution will occur" if dry_run?
|
|
71
|
+
|
|
72
|
+
start_time = Time.now
|
|
73
|
+
result = pipeline.execute_pipeline(
|
|
74
|
+
variables: variables,
|
|
75
|
+
working_directory: working_directory,
|
|
76
|
+
podman_executable: podman_executable,
|
|
77
|
+
dry_run: dry_run?
|
|
78
|
+
)
|
|
79
|
+
end_time = Time.now
|
|
80
|
+
|
|
81
|
+
# Display results
|
|
82
|
+
display_execution_result(result, start_time, end_time)
|
|
83
|
+
|
|
84
|
+
# Exit with appropriate code
|
|
85
|
+
success = if result.is_a?(Hash)
|
|
86
|
+
result[:success]
|
|
87
|
+
else
|
|
88
|
+
result.success
|
|
89
|
+
end
|
|
90
|
+
exit(success ? 0 : 1)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def parse_variables
|
|
96
|
+
return {} unless variables
|
|
97
|
+
|
|
98
|
+
vars = {}
|
|
99
|
+
variables.split(",").each do |var|
|
|
100
|
+
key, value = var.split("=", 2)
|
|
101
|
+
if key && value
|
|
102
|
+
vars[key.strip] = value.strip
|
|
103
|
+
else
|
|
104
|
+
error "Invalid variable format: #{var}. Use KEY=value format."
|
|
105
|
+
exit(1)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
vars
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def show_pipeline_info(pipeline)
|
|
112
|
+
puts "Pipeline Information:"
|
|
113
|
+
puts " Image: #{pipeline.pipeline_data.image}" unless pipeline.pipeline_data.image.empty?
|
|
114
|
+
puts " Stages: #{pipeline.pipeline_data.stages.map(&:name).join(', ')}"
|
|
115
|
+
puts " Jobs: #{pipeline.pipeline_data.jobs.keys.join(', ')}"
|
|
116
|
+
puts " Variables: #{pipeline.pipeline_data.variables.keys.join(', ')}" unless pipeline.pipeline_data.variables.empty?
|
|
117
|
+
puts
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def display_execution_result(result, start_time, end_time)
|
|
121
|
+
puts "\n" + "="*60
|
|
122
|
+
puts "PIPELINE EXECUTION RESULT".center(60)
|
|
123
|
+
puts "="*60
|
|
124
|
+
|
|
125
|
+
# Extract result data based on mode
|
|
126
|
+
if result.is_a?(Hash)
|
|
127
|
+
# Fallback mode
|
|
128
|
+
execution_result = result[:result]
|
|
129
|
+
success = result[:success]
|
|
130
|
+
errors = result[:errors] || []
|
|
131
|
+
warnings = result[:warnings] || []
|
|
132
|
+
else
|
|
133
|
+
# gRPC mode
|
|
134
|
+
execution_result = result.result
|
|
135
|
+
success = result.success
|
|
136
|
+
errors = result.errors || []
|
|
137
|
+
warnings = result.warnings || []
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Overall status
|
|
141
|
+
status_color = success ? :green : :red
|
|
142
|
+
status_icon = success ? "✓" : "✗"
|
|
143
|
+
puts "#{status_icon} Status: #{success ? 'SUCCESS' : 'FAILED'}".colorize(status_color)
|
|
144
|
+
|
|
145
|
+
# Access execution result fields safely
|
|
146
|
+
execution_id = if execution_result.respond_to?(:execution_id)
|
|
147
|
+
execution_result.execution_id
|
|
148
|
+
else
|
|
149
|
+
execution_result[:execution_id]
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
started_at = if execution_result.respond_to?(:started_at)
|
|
153
|
+
execution_result.started_at
|
|
154
|
+
else
|
|
155
|
+
execution_result[:started_at]
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
finished_at = if execution_result.respond_to?(:finished_at)
|
|
159
|
+
execution_result.finished_at
|
|
160
|
+
else
|
|
161
|
+
execution_result[:finished_at]
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
puts " Execution ID: #{execution_id}"
|
|
165
|
+
puts " Started: #{started_at}"
|
|
166
|
+
puts " Finished: #{finished_at}" if finished_at
|
|
167
|
+
puts " Duration: #{Makit::Humanize.get_humanized_duration(end_time - start_time)}"
|
|
168
|
+
|
|
169
|
+
# Podman info
|
|
170
|
+
podman_version = if execution_result.respond_to?(:podman_version)
|
|
171
|
+
execution_result.podman_version
|
|
172
|
+
else
|
|
173
|
+
execution_result[:podman_version]
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
execution_host = if execution_result.respond_to?(:execution_host)
|
|
177
|
+
execution_result.execution_host
|
|
178
|
+
else
|
|
179
|
+
execution_result[:execution_host]
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
puts " Podman Version: #{podman_version}" if podman_version
|
|
183
|
+
puts " Host: #{execution_host}" if execution_host
|
|
184
|
+
|
|
185
|
+
# Job results
|
|
186
|
+
job_results = if execution_result.respond_to?(:job_results)
|
|
187
|
+
execution_result.job_results
|
|
188
|
+
else
|
|
189
|
+
execution_result[:job_results]
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
if job_results && job_results.any?
|
|
193
|
+
puts "\nJob Results:"
|
|
194
|
+
job_results.each do |job_result|
|
|
195
|
+
display_job_result(job_result)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Errors
|
|
200
|
+
if errors.any?
|
|
201
|
+
puts "\nErrors:".colorize(:red)
|
|
202
|
+
errors.each { |err| puts " ✗ #{err}".colorize(:red) }
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Warnings
|
|
206
|
+
if warnings.any?
|
|
207
|
+
puts "\nWarnings:".colorize(:yellow)
|
|
208
|
+
warnings.each { |warn| puts " ⚠ #{warn}".colorize(:yellow) }
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Logs
|
|
212
|
+
logs = if execution_result.respond_to?(:logs)
|
|
213
|
+
execution_result.logs
|
|
214
|
+
else
|
|
215
|
+
execution_result[:logs]
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
if logs && logs.any? && verbose?
|
|
219
|
+
puts "\nExecution Logs:"
|
|
220
|
+
logs.each { |log| puts " #{log}" }
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
puts "="*60
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def display_job_result(job_result)
|
|
227
|
+
# Extract job data based on mode
|
|
228
|
+
if job_result.is_a?(Hash)
|
|
229
|
+
job_name = job_result[:job_name]
|
|
230
|
+
status = job_result[:status]
|
|
231
|
+
exit_code = job_result[:exit_code]
|
|
232
|
+
started_at = job_result[:started_at]
|
|
233
|
+
finished_at = job_result[:finished_at]
|
|
234
|
+
logs = job_result[:logs] || []
|
|
235
|
+
errors = job_result[:errors] || []
|
|
236
|
+
stdout = job_result[:stdout] || ""
|
|
237
|
+
stderr = job_result[:stderr] || ""
|
|
238
|
+
else
|
|
239
|
+
job_name = job_result.job_name
|
|
240
|
+
status = job_result.status
|
|
241
|
+
exit_code = job_result.exit_code
|
|
242
|
+
started_at = job_result.started_at
|
|
243
|
+
finished_at = job_result.finished_at
|
|
244
|
+
logs = job_result.logs || []
|
|
245
|
+
errors = job_result.errors || []
|
|
246
|
+
stdout = job_result.respond_to?(:stdout) ? job_result.stdout : ""
|
|
247
|
+
stderr = job_result.respond_to?(:stderr) ? job_result.stderr : ""
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Job status
|
|
251
|
+
status_color = (status == :success || status.to_s.include?('SUCCESS')) ? :green : :red
|
|
252
|
+
status_icon = (status == :success || status.to_s.include?('SUCCESS')) ? "✓" : "✗"
|
|
253
|
+
|
|
254
|
+
puts " #{status_icon} #{job_name}: #{status.to_s.upcase}".colorize(status_color)
|
|
255
|
+
puts " Exit Code: #{exit_code}" if exit_code
|
|
256
|
+
puts " Started: #{started_at}"
|
|
257
|
+
puts " Finished: #{finished_at}" if finished_at
|
|
258
|
+
|
|
259
|
+
# Job errors
|
|
260
|
+
if errors.any?
|
|
261
|
+
puts " Errors:".colorize(:red)
|
|
262
|
+
errors.each { |err| puts " ✗ #{err}".colorize(:red) }
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Job logs (if verbose)
|
|
266
|
+
if logs.any? && verbose?
|
|
267
|
+
puts " Logs:"
|
|
268
|
+
logs.each { |log| puts " #{log}" }
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Job stdout (if verbose and not empty)
|
|
272
|
+
if stdout && !stdout.empty? && verbose?
|
|
273
|
+
puts " Stdout:".colorize(:green)
|
|
274
|
+
stdout.split("\n").each { |line| puts " #{line}".colorize(:green) }
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Job stderr (if verbose and not empty)
|
|
278
|
+
if stderr && !stderr.empty? && verbose?
|
|
279
|
+
puts " Stderr:".colorize(:red)
|
|
280
|
+
stderr.split("\n").each { |line| puts " #{line}".colorize(:red) }
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def error(message)
|
|
285
|
+
puts "Error: #{message}".colorize(:red)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def warning(message)
|
|
289
|
+
puts "Warning: #{message}".colorize(:yellow)
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Pipeline command group for GitLab CI pipeline operations
|
|
294
|
+
class PipelineCommand < Clamp::Command
|
|
295
|
+
self.description = <<~DESC
|
|
296
|
+
GitLab CI Pipeline operations.
|
|
297
|
+
|
|
298
|
+
Available commands:
|
|
299
|
+
run - Execute a GitLab CI pipeline using Podman
|
|
300
|
+
|
|
301
|
+
Examples:
|
|
302
|
+
makit pipeline run # Run .gitlab-ci.yml in current directory
|
|
303
|
+
makit pipeline run --file custom-ci.yml # Run custom pipeline file
|
|
304
|
+
makit pipeline run --dry-run # Simulate execution without running
|
|
305
|
+
makit pipeline run --variables KEY=value # Pass variables to pipeline
|
|
306
|
+
DESC
|
|
307
|
+
|
|
308
|
+
subcommand "run", "Execute a GitLab CI pipeline", PipelineRunCommand
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
end
|