makit 0.0.147 → 0.0.153

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generated/makit/v1/configuration/project_pb.rb +22 -0
  3. data/lib/generated/makit/v1/configuration/project_service_pb.rb +34 -0
  4. data/lib/generated/makit/v1/configuration/project_service_services_pb.rb +51 -0
  5. data/lib/generated/makit/v1/git/git_repository_model_pb.rb +22 -0
  6. data/lib/generated/makit/v1/git/git_repository_service_pb.rb +29 -0
  7. data/lib/generated/makit/v1/git/git_repository_service_services_pb.rb +39 -0
  8. data/lib/generated/makit/v1/gitlab/pipeline_pb.rb +26 -0
  9. data/lib/generated/makit/v1/gitlab/pipeline_result_pb.rb +29 -0
  10. data/lib/generated/makit/v1/gitlab/pipeline_service_pb.rb +36 -0
  11. data/lib/generated/makit/v1/gitlab/pipeline_service_services_pb.rb +41 -0
  12. data/lib/generated/makit/v1/grpc/service_specification_pb.rb +27 -0
  13. data/lib/generated/makit/v1/grpc/test_specification_pb.rb +29 -0
  14. data/lib/generated/makit/v1/io/filesystem_pb.rb +27 -0
  15. data/lib/generated/makit/v1/io/filesystem_services_pb.rb +47 -0
  16. data/lib/generated/makit/v1/makit.v1_pb.rb +35 -0
  17. data/lib/generated/makit/v1/makit.v1_services_pb.rb +26 -0
  18. data/lib/generated/makit/v1/podman/podman_service_pb.rb +64 -0
  19. data/lib/generated/makit/v1/podman/podman_service_services_pb.rb +52 -0
  20. data/lib/generated/makit/v1/services/repository_manager_model_pb.rb +23 -0
  21. data/lib/generated/makit/v1/services/repository_manager_service_pb.rb +32 -0
  22. data/lib/generated/makit/v1/services/repository_manager_service_services_pb.rb +35 -0
  23. data/lib/generated/makit/v1/spec/message_proto_generator_pb.rb +33 -0
  24. data/lib/generated/makit/v1/spec/message_proto_generator_services_pb.rb +38 -0
  25. data/lib/generated/makit/v1/spec/message_spec_pb.rb +31 -0
  26. data/lib/generated/makit/v1/spec/message_spec_suite_pb.rb +30 -0
  27. data/lib/generated/makit/v1/spec/message_spec_test_pb.rb +34 -0
  28. data/lib/generated/makit/v1/spec/proto_service_pb.rb +53 -0
  29. data/lib/generated/makit/v1/spec/proto_service_services_pb.rb +42 -0
  30. data/lib/generated/makit/v1/spec/spec_manifest_pb.rb +44 -0
  31. data/lib/generated/makit/v1/web/link_pb.rb +20 -0
  32. data/lib/makit/azure/blob_storage.rb +257 -0
  33. data/lib/makit/azure/cli.rb +285 -0
  34. data/lib/makit/configuration/project.rb +137 -291
  35. data/lib/makit/git/repository.rb +24 -190
  36. data/lib/makit/gitlab/pipeline.rb +16 -16
  37. data/lib/makit/gitlab/pipeline_service_impl.rb +43 -43
  38. data/lib/makit/io/filesystem_service_impl.rb +6 -6
  39. data/lib/makit/lint.rb +212 -0
  40. data/lib/makit/logging/configuration.rb +2 -1
  41. data/lib/makit/logging.rb +15 -2
  42. data/lib/makit/podman/podman.rb +20 -20
  43. data/lib/makit/podman/podman_service_impl.rb +41 -41
  44. data/lib/makit/secrets/azure_key_vault.rb +323 -0
  45. data/lib/makit/secrets/azure_secrets.rb +183 -0
  46. data/lib/makit/secrets/local_secrets.rb +72 -0
  47. data/lib/makit/secrets/secrets_manager.rb +105 -0
  48. data/lib/makit/secrets.rb +10 -45
  49. data/lib/makit/tasks/bump.rb +7 -0
  50. data/lib/makit/tasks/info.rb +204 -0
  51. data/lib/makit/tasks/integrate.rb +28 -1
  52. data/lib/makit/tasks/secrets.rb +7 -0
  53. data/lib/makit/tasks/version.rb +6 -0
  54. data/lib/makit/tasks.rb +4 -0
  55. data/lib/makit/v1/configuration/project_service_impl.rb +1 -1
  56. data/lib/makit/version.rb +382 -1
  57. data/lib/makit.rb +21 -18
  58. metadata +46 -5
@@ -12,7 +12,7 @@ module Makit
12
12
  class PipelineServiceImpl
13
13
  # Check if gRPC service is available
14
14
  def self.grpc_available?
15
- defined?(Gitlab::Pipeline::PipelineService)
15
+ defined?(Makit::V1::Gitlab::Ci::PipelineService)
16
16
  end
17
17
 
18
18
  # Parse GitLab CI YAML content into Pipeline message
@@ -28,7 +28,7 @@ module Makit
28
28
  errors, warnings = validate_pipeline_data(yaml_data)
29
29
 
30
30
  if grpc_available?
31
- Gitlab::Pipeline::ParseYamlResponse.new(
31
+ Makit::V1::Gitlab::Ci::ParseYamlResponse.new(
32
32
  pipeline: pipeline,
33
33
  errors: errors,
34
34
  warnings: warnings,
@@ -45,8 +45,8 @@ module Makit
45
45
  end
46
46
  rescue Psych::SyntaxError => e
47
47
  if grpc_available?
48
- Gitlab::Pipeline::ParseYamlResponse.new(
49
- pipeline: Gitlab::Pipeline::Pipeline.new,
48
+ Makit::V1::Gitlab::Ci::ParseYamlResponse.new(
49
+ pipeline: Makit::V1::Gitlab::Ci::Pipeline.new,
50
50
  errors: ["YAML syntax error: #{e.message}"],
51
51
  warnings: [],
52
52
  success: false
@@ -61,8 +61,8 @@ module Makit
61
61
  end
62
62
  rescue StandardError => e
63
63
  if grpc_available?
64
- Gitlab::Pipeline::ParseYamlResponse.new(
65
- pipeline: Gitlab::Pipeline::Pipeline.new,
64
+ Makit::V1::Gitlab::Ci::ParseYamlResponse.new(
65
+ pipeline: Makit::V1::Gitlab::Ci::Pipeline.new,
66
66
  errors: ["Parse error: #{e.message}"],
67
67
  warnings: [],
68
68
  success: false
@@ -85,7 +85,7 @@ module Makit
85
85
  yaml_content = convert_pipeline_to_yaml(request.pipeline, request.pretty_format, request.indent_size)
86
86
 
87
87
  if grpc_available?
88
- Gitlab::Pipeline::ToYamlResponse.new(
88
+ Makit::V1::Gitlab::Ci::ToYamlResponse.new(
89
89
  yaml_content: yaml_content,
90
90
  errors: [],
91
91
  success: true
@@ -99,7 +99,7 @@ module Makit
99
99
  end
100
100
  rescue StandardError => e
101
101
  if grpc_available?
102
- Gitlab::Pipeline::ToYamlResponse.new(
102
+ Makit::V1::Gitlab::Ci::ToYamlResponse.new(
103
103
  yaml_content: "",
104
104
  errors: ["YAML generation error: #{e.message}"],
105
105
  success: false
@@ -147,7 +147,7 @@ module Makit
147
147
  end
148
148
 
149
149
  if grpc_available?
150
- Gitlab::Pipeline::ValidatePipelineResponse.new(
150
+ Makit::V1::Gitlab::Ci::ValidatePipelineResponse.new(
151
151
  is_valid: errors.empty?,
152
152
  errors: errors,
153
153
  warnings: warnings,
@@ -214,7 +214,7 @@ module Makit
214
214
  end
215
215
 
216
216
  if grpc_available?
217
- Gitlab::Pipeline::MergePipelinesResponse.new(
217
+ Makit::V1::Gitlab::Ci::MergePipelinesResponse.new(
218
218
  merged_pipeline: merged,
219
219
  conflicts: conflicts,
220
220
  warnings: warnings
@@ -237,7 +237,7 @@ module Makit
237
237
  total_variables = pipeline.variables.length + pipeline.jobs.values.sum { |job| job.variables.length }
238
238
 
239
239
  if grpc_available?
240
- Gitlab::Pipeline::GetPipelineStatsResponse.new(
240
+ Makit::V1::Gitlab::Ci::GetPipelineStatsResponse.new(
241
241
  total_jobs: pipeline.jobs.length,
242
242
  total_stages: pipeline.stages.length,
243
243
  total_artifacts: total_artifacts,
@@ -321,9 +321,9 @@ module Makit
321
321
  result.logs.push("Podman version: #{podman_version}")
322
322
 
323
323
  if grpc_available?
324
- Gitlab::Pipeline::ExecutePipelineResponse.new(
324
+ Makit::V1::Gitlab::Ci::ExecutePipelineResponse.new(
325
325
  result: result,
326
- success: result.status == Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_SUCCESS,
326
+ success: result.status == Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_SUCCESS,
327
327
  errors: result.errors,
328
328
  warnings: result.warnings
329
329
  )
@@ -338,13 +338,13 @@ module Makit
338
338
 
339
339
  rescue StandardError => e
340
340
  error_result = create_execution_result(SecureRandom.uuid, Time.now)
341
- error_result.status = grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
341
+ error_result.status = grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
342
342
  error_result.errors.push("Pipeline execution failed: #{e.message}")
343
343
  error_result.logs.push("Error: #{e.message}")
344
344
  error_result.logs.push("Backtrace: #{e.backtrace.join("\n")}")
345
345
 
346
346
  if grpc_available?
347
- Gitlab::Pipeline::ExecutePipelineResponse.new(
347
+ Makit::V1::Gitlab::Ci::ExecutePipelineResponse.new(
348
348
  result: error_result,
349
349
  success: false,
350
350
  errors: error_result.errors,
@@ -398,7 +398,7 @@ module Makit
398
398
  removed_stages = (pipeline1_stages - pipeline2_stages).to_a
399
399
 
400
400
  if grpc_available?
401
- Gitlab::Pipeline::ComparePipelinesResponse.new(
401
+ Makit::V1::Gitlab::Ci::ComparePipelinesResponse.new(
402
402
  are_identical: differences.empty? && added_jobs.empty? && removed_jobs.empty? && added_stages.empty? && removed_stages.empty?,
403
403
  differences: differences,
404
404
  added_jobs: added_jobs,
@@ -474,9 +474,9 @@ module Makit
474
474
  # Create execution result object
475
475
  def create_execution_result(execution_id, start_time)
476
476
  if grpc_available?
477
- Gitlab::Pipeline::PipelineExecutionResult.new(
477
+ Makit::V1::Gitlab::Ci::PipelineExecutionResult.new(
478
478
  execution_id: execution_id,
479
- status: Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_RUNNING,
479
+ status: Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_RUNNING,
480
480
  started_at: start_time.iso8601,
481
481
  job_results: [],
482
482
  logs: [],
@@ -591,12 +591,12 @@ module Makit
591
591
  # Create error response
592
592
  def create_error_response(message)
593
593
  error_result = create_execution_result(SecureRandom.uuid, Time.now)
594
- error_result.status = grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
594
+ error_result.status = grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
595
595
  error_result.errors.push(message)
596
596
  error_result.logs.push("Error: #{message}")
597
597
 
598
598
  if grpc_available?
599
- Gitlab::Pipeline::ExecutePipelineResponse.new(
599
+ Makit::V1::Gitlab::Ci::ExecutePipelineResponse.new(
600
600
  result: error_result,
601
601
  success: false,
602
602
  errors: error_result.errors,
@@ -615,9 +615,9 @@ module Makit
615
615
  # Execute a single stage
616
616
  def execute_stage(stage, pipeline, working_dir, request, execution_id, podman_executable)
617
617
  stage_result = if grpc_available?
618
- Gitlab::Pipeline::StageExecutionResult.new(
618
+ Makit::V1::Gitlab::Ci::StageExecutionResult.new(
619
619
  stage_name: stage.name,
620
- status: Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_RUNNING,
620
+ status: Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_RUNNING,
621
621
  started_at: Time.now.iso8601,
622
622
  job_results: []
623
623
  )
@@ -692,9 +692,9 @@ module Makit
692
692
  # Execute a single job
693
693
  def execute_job(job_name, job, pipeline, working_dir, request, execution_id, podman_executable)
694
694
  job_result = if grpc_available?
695
- Gitlab::Pipeline::JobExecutionResult.new(
695
+ Makit::V1::Gitlab::Ci::JobExecutionResult.new(
696
696
  job_name: job_name,
697
- status: Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_RUNNING,
697
+ status: Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_RUNNING,
698
698
  started_at: Time.now.iso8601,
699
699
  logs: [],
700
700
  errors: []
@@ -798,7 +798,7 @@ module Makit
798
798
  if dry_run
799
799
  job_result.logs.push("DRY RUN: Would execute job: #{job_name}")
800
800
  job_result.logs.push("DRY RUN: Skipping actual execution")
801
- job_result.status = grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success
801
+ job_result.status = grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success
802
802
  job_result.exit_code = 0
803
803
  job_result.finished_at = Time.now.iso8601
804
804
  return job_result
@@ -852,11 +852,11 @@ module Makit
852
852
  job_result.finished_at = Time.now.iso8601
853
853
 
854
854
  if result.success
855
- job_result.status = grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success
855
+ job_result.status = grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success
856
856
  job_result.stdout = result.stdout if result.stdout
857
857
  job_result.stderr = result.stderr if result.stderr
858
858
  else
859
- job_result.status = grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
859
+ job_result.status = grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
860
860
  job_result.errors.push("Job failed with exit code #{result.exit_code}")
861
861
  job_result.stdout = result.stdout if result.stdout
862
862
  job_result.stderr = result.stderr if result.stderr
@@ -867,11 +867,11 @@ module Makit
867
867
  job_result.finished_at = Time.now.iso8601
868
868
 
869
869
  if result[:success]
870
- job_result.status = grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success
870
+ job_result.status = grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success
871
871
  job_result.stdout = result[:stdout] if result[:stdout]
872
872
  job_result.stderr = result[:stderr] if result[:stderr]
873
873
  else
874
- job_result.status = grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
874
+ job_result.status = grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
875
875
  job_result.errors.push("Job failed with exit code #{result[:exit_code]}")
876
876
  job_result.stdout = result[:stdout] if result[:stdout]
877
877
  job_result.stderr = result[:stderr] if result[:stderr]
@@ -879,7 +879,7 @@ module Makit
879
879
  end
880
880
 
881
881
  rescue StandardError => e
882
- job_result.status = grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
882
+ job_result.status = grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
883
883
  job_result.errors.push("Job execution error: #{e.message}")
884
884
  job_result.logs.push("Error: #{e.message}")
885
885
  job_result.finished_at = Time.now.iso8601
@@ -968,45 +968,45 @@ module Makit
968
968
 
969
969
  # Determine pipeline status from job results
970
970
  def determine_pipeline_status(job_results)
971
- return grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success if job_results.empty?
971
+ return grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success if job_results.empty?
972
972
 
973
973
  failed_jobs = job_results.select do |job|
974
974
  if grpc_available?
975
- job.status == Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_FAILED
975
+ job.status == Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_FAILED
976
976
  else
977
977
  job.status == :failed
978
978
  end
979
979
  end
980
980
 
981
981
  if failed_jobs.any?
982
- grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
982
+ grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
983
983
  else
984
- grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success
984
+ grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success
985
985
  end
986
986
  end
987
987
 
988
988
  # Determine stage status from job results
989
989
  def determine_stage_status(job_results)
990
- return grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success if job_results.empty?
990
+ return grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success if job_results.empty?
991
991
 
992
992
  failed_jobs = job_results.select do |job|
993
993
  if grpc_available?
994
- job.status == Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_FAILED
994
+ job.status == Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_FAILED
995
995
  else
996
996
  job.status == :failed
997
997
  end
998
998
  end
999
999
 
1000
1000
  if failed_jobs.any?
1001
- grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
1001
+ grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_FAILED : :failed
1002
1002
  else
1003
- grpc_available? ? Gitlab::Pipeline::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success
1003
+ grpc_available? ? Makit::V1::Gitlab::Ci::PipelineStatus::PIPELINE_STATUS_SUCCESS : :success
1004
1004
  end
1005
1005
  end
1006
1006
 
1007
1007
  def create_empty_pipeline
1008
1008
  if grpc_available?
1009
- Gitlab::Pipeline::Pipeline.new
1009
+ Makit::V1::Gitlab::Ci::Pipeline.new
1010
1010
  else
1011
1011
  create_empty_pipeline_fallback
1012
1012
  end
@@ -1072,7 +1072,7 @@ module Makit
1072
1072
  end
1073
1073
 
1074
1074
  def convert_yaml_to_pipeline_grpc(yaml_data)
1075
- pipeline = Gitlab::Pipeline::Pipeline.new
1075
+ pipeline = Makit::V1::Gitlab::Ci::Pipeline.new
1076
1076
 
1077
1077
  pipeline.image = yaml_data["image"] || ""
1078
1078
  pipeline.timeout = yaml_data["timeout"] || 0
@@ -1086,7 +1086,7 @@ module Makit
1086
1086
 
1087
1087
  # Convert cache
1088
1088
  if yaml_data["cache"]
1089
- cache = Gitlab::Pipeline::Cache.new
1089
+ cache = Makit::V1::Gitlab::Ci::Cache.new
1090
1090
  cache.key = yaml_data["cache"]["key"] || ""
1091
1091
  cache.policy = yaml_data["cache"]["policy"] || ""
1092
1092
  cache.expire_in = yaml_data["cache"]["expire_in"] || 0
@@ -1103,7 +1103,7 @@ module Makit
1103
1103
  # Convert stages
1104
1104
  if yaml_data["stages"]
1105
1105
  yaml_data["stages"].each do |stage_name|
1106
- stage = Gitlab::Pipeline::Stage.new
1106
+ stage = Makit::V1::Gitlab::Ci::Stage.new
1107
1107
  stage.name = stage_name
1108
1108
  pipeline.stages << stage
1109
1109
  end
@@ -1176,7 +1176,7 @@ module Makit
1176
1176
  end
1177
1177
 
1178
1178
  def convert_yaml_to_job_grpc(yaml_data)
1179
- job = Gitlab::Pipeline::Job.new
1179
+ job = Makit::V1::Gitlab::Ci::Job.new
1180
1180
 
1181
1181
  job.stage = yaml_data["stage"] || ""
1182
1182
  job.image = yaml_data["image"] || ""
@@ -14,7 +14,7 @@ module Makit
14
14
 
15
15
  # Check if gRPC service is available
16
16
  def self.grpc_available?
17
- defined?(Makit::Io::FileSystemService)
17
+ defined?(Makit::V1::Io::FileSystemService)
18
18
  end
19
19
 
20
20
  # Get a single file's content and/or metadata
@@ -48,7 +48,7 @@ module Makit
48
48
  end
49
49
 
50
50
  if self.class.grpc_available?
51
- Makit::Io::FileResponse.new(file: Makit::Io::File.new(file_data))
51
+ Makit::V1::Io::FileResponse.new(file: Makit::V1::Io::File.new(file_data))
52
52
  else
53
53
  { file: file_data }
54
54
  end
@@ -83,7 +83,7 @@ module Makit
83
83
  end
84
84
 
85
85
  if self.class.grpc_available?
86
- Makit::Io::FileResponse.new(file: Makit::Io::File.new(file_data))
86
+ Makit::V1::Io::FileResponse.new(file: Makit::V1::Io::File.new(file_data))
87
87
  else
88
88
  { file: file_data }
89
89
  end
@@ -159,7 +159,7 @@ module Makit
159
159
  end
160
160
 
161
161
  if self.class.grpc_available?
162
- Makit::Io::FileList.new(files: files.map { |f| Makit::Io::File.new(f) })
162
+ Makit::V1::Io::FileList.new(files: files.map { |f| Makit::V1::Io::File.new(f) })
163
163
  else
164
164
  { files: files }
165
165
  end
@@ -231,7 +231,7 @@ module Makit
231
231
  result = results.first
232
232
 
233
233
  if self.class.grpc_available?
234
- Makit::Io::FileResponse.new(file: Makit::Io::File.new(result))
234
+ Makit::V1::Io::FileResponse.new(file: Makit::V1::Io::File.new(result))
235
235
  else
236
236
  { file: result }
237
237
  end
@@ -264,7 +264,7 @@ module Makit
264
264
  end
265
265
 
266
266
  if self.class.grpc_available?
267
- chunks.map { |c| Makit::Io::FileChunk.new(c) }
267
+ chunks.map { |c| Makit::V1::Io::FileChunk.new(c) }
268
268
  else
269
269
  chunks
270
270
  end
data/lib/makit/lint.rb ADDED
@@ -0,0 +1,212 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "yaml"
5
+
6
+ # This module provides classes for the Makit gem.
7
+ module Makit
8
+ # Lint utilities for validating JSON and YAML files
9
+ #
10
+ # This class provides methods for linting JSON and YAML files,
11
+ # helping to catch syntax errors and validation issues early.
12
+ class Lint
13
+ # Default directories to exclude from linting
14
+ DEFAULT_EXCLUDE_PATTERNS = [
15
+ "artifacts/",
16
+ "bin/",
17
+ "obj/",
18
+ ".nuget/",
19
+ ".git/",
20
+ ".specify/"
21
+ ].freeze
22
+
23
+ # Lint JSON files based on a glob pattern or filename
24
+ #
25
+ # @param pattern [String] Glob pattern (e.g., "**/*.json") or specific filename
26
+ # @param exclude_patterns [Array<String>] Optional array of path prefixes to exclude
27
+ # @return [Hash] Hash with :valid (boolean), :errors (array), :file_count (integer)
28
+ def self.lint_json(pattern, exclude_patterns: DEFAULT_EXCLUDE_PATTERNS)
29
+ # Determine if pattern is a glob or specific file
30
+ if File.file?(pattern)
31
+ json_files = [pattern]
32
+ else
33
+ json_files = Dir.glob(pattern)
34
+ .reject { |f| exclude_patterns.any? { |exclude| f.start_with?(exclude) } }
35
+ .select { |f| File.file?(f) }
36
+ end
37
+
38
+ if json_files.empty?
39
+ return {
40
+ valid: true,
41
+ errors: [],
42
+ file_count: 0,
43
+ message: "No JSON files found to validate"
44
+ }
45
+ end
46
+
47
+ errors = []
48
+ json_files.each do |file|
49
+ begin
50
+ content = File.read(file)
51
+ # Remove BOM if present (UTF-8 BOM: EF BB BF)
52
+ content = content.force_encoding("UTF-8").sub(/\A\xEF\xBB\xBF/, "")
53
+ JSON.parse(content)
54
+ rescue JSON::ParserError => e
55
+ errors << { file: file, error: e.message }
56
+ end
57
+ end
58
+
59
+ {
60
+ valid: errors.empty?,
61
+ errors: errors,
62
+ file_count: json_files.length
63
+ }
64
+ end
65
+
66
+ # Lint JSON files and print results
67
+ #
68
+ # @param pattern [String] Glob pattern or filename
69
+ # @param exclude_patterns [Array<String>] Optional array of path prefixes to exclude
70
+ # @param verbose [Boolean] Whether to print progress dots
71
+ # @raise [RuntimeError] If validation fails
72
+ def self.lint_json!(pattern, exclude_patterns: DEFAULT_EXCLUDE_PATTERNS, verbose: true)
73
+ result = lint_json(pattern, exclude_patterns: exclude_patterns)
74
+
75
+ if result[:file_count] == 0
76
+ puts result[:message] if verbose
77
+ return result
78
+ end
79
+
80
+ if verbose
81
+ puts "Validating #{result[:file_count]} JSON file(s)..."
82
+ end
83
+
84
+ # Re-run to show progress dots
85
+ if verbose && result[:file_count] > 0
86
+ json_files = File.file?(pattern) ? [pattern] : Dir.glob(pattern)
87
+ .reject { |f| exclude_patterns.any? { |exclude| f.start_with?(exclude) } }
88
+ .select { |f| File.file?(f) }
89
+
90
+ json_files.each do |file|
91
+ begin
92
+ content = File.read(file)
93
+ content = content.force_encoding("UTF-8").sub(/\A\xEF\xBB\xBF/, "")
94
+ JSON.parse(content)
95
+ print "."
96
+ rescue JSON::ParserError
97
+ print "F"
98
+ end
99
+ end
100
+ puts "\n"
101
+ end
102
+
103
+ if result[:valid]
104
+ puts "✓ All JSON files are valid" if verbose
105
+ else
106
+ puts "\n✗ Found #{result[:errors].length} invalid JSON file(s):" if verbose
107
+ result[:errors].each do |err|
108
+ puts " - #{err[:file]}: #{err[:error]}" if verbose
109
+ end
110
+ raise "JSON validation failed"
111
+ end
112
+
113
+ result
114
+ end
115
+
116
+ # Lint YAML files based on a glob pattern or filename
117
+ #
118
+ # @param pattern [String] Glob pattern (e.g., "**/*.yml") or specific filename
119
+ # @param exclude_patterns [Array<String>] Optional array of path prefixes to exclude
120
+ # @return [Hash] Hash with :valid (boolean), :errors (array), :file_count (integer)
121
+ def self.lint_yaml(pattern, exclude_patterns: DEFAULT_EXCLUDE_PATTERNS)
122
+ # Determine if pattern is a glob or specific file
123
+ if File.file?(pattern)
124
+ yaml_files = [pattern]
125
+ else
126
+ yaml_files = Dir.glob(pattern)
127
+ .reject { |f| exclude_patterns.any? { |exclude| f.start_with?(exclude) } }
128
+ .select { |f| File.file?(f) }
129
+ end
130
+
131
+ if yaml_files.empty?
132
+ return {
133
+ valid: true,
134
+ errors: [],
135
+ file_count: 0,
136
+ message: "No YAML files found to validate"
137
+ }
138
+ end
139
+
140
+ errors = []
141
+ yaml_files.each do |file|
142
+ begin
143
+ content = File.read(file)
144
+ # Remove BOM if present (UTF-8 BOM: EF BB BF)
145
+ content = content.force_encoding("UTF-8").sub(/\A\xEF\xBB\xBF/, "")
146
+ YAML.load(content, permitted_classes: [Symbol, Date, Time], aliases: true)
147
+ rescue Psych::SyntaxError => e
148
+ errors << { file: file, error: e.message }
149
+ rescue => e
150
+ errors << { file: file, error: e.message }
151
+ end
152
+ end
153
+
154
+ {
155
+ valid: errors.empty?,
156
+ errors: errors,
157
+ file_count: yaml_files.length
158
+ }
159
+ end
160
+
161
+ # Lint YAML files and print results
162
+ #
163
+ # @param pattern [String] Glob pattern or filename
164
+ # @param exclude_patterns [Array<String>] Optional array of path prefixes to exclude
165
+ # @param verbose [Boolean] Whether to print progress dots
166
+ # @raise [RuntimeError] If validation fails
167
+ def self.lint_yaml!(pattern, exclude_patterns: DEFAULT_EXCLUDE_PATTERNS, verbose: true)
168
+ result = lint_yaml(pattern, exclude_patterns: exclude_patterns)
169
+
170
+ if result[:file_count] == 0
171
+ puts result[:message] if verbose
172
+ return result
173
+ end
174
+
175
+ if verbose
176
+ puts "Validating #{result[:file_count]} YAML file(s)..."
177
+ end
178
+
179
+ # Re-run to show progress dots
180
+ if verbose && result[:file_count] > 0
181
+ yaml_files = File.file?(pattern) ? [pattern] : Dir.glob(pattern)
182
+ .reject { |f| exclude_patterns.any? { |exclude| f.start_with?(exclude) } }
183
+ .select { |f| File.file?(f) }
184
+
185
+ yaml_files.each do |file|
186
+ begin
187
+ content = File.read(file)
188
+ content = content.force_encoding("UTF-8").sub(/\A\xEF\xBB\xBF/, "")
189
+ YAML.load(content, permitted_classes: [Symbol, Date, Time], aliases: true)
190
+ print "."
191
+ rescue
192
+ print "F"
193
+ end
194
+ end
195
+ puts "\n"
196
+ end
197
+
198
+ if result[:valid]
199
+ puts "✓ All YAML files are valid" if verbose
200
+ else
201
+ puts "\n✗ Found #{result[:errors].length} invalid YAML file(s):" if verbose
202
+ result[:errors].each do |err|
203
+ puts " - #{err[:file]}: #{err[:error]}" if verbose
204
+ end
205
+ raise "YAML validation failed"
206
+ end
207
+
208
+ result
209
+ end
210
+ end
211
+ end
212
+
@@ -88,10 +88,11 @@ module Makit
88
88
  #
89
89
  # @return [Configuration] default configuration
90
90
  def self.default_config
91
+ require_relative "../logging" unless defined?(Makit::Logging)
91
92
  new(
92
93
  configurations: [
93
94
  { file: $stdout, format: :console },
94
- { file: "artifacts/makit.log", format: :json, append: true },
95
+ { file: Makit::Logging.log_file_path("makit.log"), format: :json, append: true },
95
96
  ],
96
97
  )
97
98
  end
data/lib/makit/logging.rb CHANGED
@@ -87,6 +87,19 @@ module Makit
87
87
  :normal
88
88
  end
89
89
 
90
+ # Get the log file path in the user's temp directory
91
+ #
92
+ # For log files that would normally be in the project's artifacts/ directory,
93
+ # this method returns the path in the user's temp directory (~/.makit/log/)
94
+ # instead. This prevents log files from cluttering project directories.
95
+ #
96
+ # @param filename [String] The log filename (e.g., "makit.log", "debug.log")
97
+ # @return [String] Full path to the log file in the temp directory
98
+ def self.log_file_path(filename)
99
+ require_relative "directories" unless defined?(Makit::Directories)
100
+ File.join(Makit::Directories::LOG, filename)
101
+ end
102
+
90
103
  # Get the current verbosity level from the default logger
91
104
  #
92
105
  # @return [Symbol] current verbosity level (:quiet, :normal, :verbose, :debug)
@@ -415,14 +428,14 @@ module Makit
415
428
  },
416
429
  # Main log file in JSON format
417
430
  {
418
- file: "artifacts/makit.log",
431
+ file: log_file_path("makit.log"),
419
432
  format: :json,
420
433
  append: true,
421
434
  include_metadata: true,
422
435
  },
423
436
  # Debug log file in text format
424
437
  {
425
- file: "artifacts/debug.log",
438
+ file: log_file_path("debug.log"),
426
439
  format: :text,
427
440
  append: true,
428
441
  min_level: :debug,