makit 0.0.98 → 0.0.111

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 (148) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -0
  3. data/exe/makit +5 -0
  4. data/lib/makit/apache.rb +7 -11
  5. data/lib/makit/cli/build_commands.rb +500 -0
  6. data/lib/makit/cli/generators/base_generator.rb +74 -0
  7. data/lib/makit/cli/generators/dotnet_generator.rb +50 -0
  8. data/lib/makit/cli/generators/generator_factory.rb +49 -0
  9. data/lib/makit/cli/generators/node_generator.rb +50 -0
  10. data/lib/makit/cli/generators/ruby_generator.rb +77 -0
  11. data/lib/makit/cli/generators/rust_generator.rb +50 -0
  12. data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -0
  13. data/lib/makit/cli/generators/templates/node_templates.rb +161 -0
  14. data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -0
  15. data/lib/makit/cli/generators/templates/ruby/gemspec.rb +40 -0
  16. data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -0
  17. data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -0
  18. data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -0
  19. data/lib/makit/cli/generators/templates/ruby/test.rb +39 -0
  20. data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -0
  21. data/lib/makit/cli/generators/templates/ruby/version.rb +29 -0
  22. data/lib/makit/cli/generators/templates/rust_templates.rb +128 -0
  23. data/lib/makit/cli/main.rb +48 -19
  24. data/lib/makit/cli/project_commands.rb +868 -0
  25. data/lib/makit/cli/repository_commands.rb +661 -0
  26. data/lib/makit/cli/utility_commands.rb +521 -0
  27. data/lib/makit/command_runner.rb +187 -128
  28. data/lib/makit/commands/compatibility.rb +365 -0
  29. data/lib/makit/commands/factory.rb +359 -0
  30. data/lib/makit/commands/middleware/base.rb +73 -0
  31. data/lib/makit/commands/middleware/cache.rb +248 -0
  32. data/lib/makit/commands/middleware/command_logger.rb +323 -0
  33. data/lib/makit/commands/middleware/unified_logger.rb +243 -0
  34. data/lib/makit/commands/middleware/validator.rb +269 -0
  35. data/lib/makit/commands/request.rb +254 -0
  36. data/lib/makit/commands/result.rb +323 -0
  37. data/lib/makit/commands/runner.rb +317 -0
  38. data/lib/makit/commands/strategies/base.rb +160 -0
  39. data/lib/makit/commands/strategies/synchronous.rb +134 -0
  40. data/lib/makit/commands.rb +24 -3
  41. data/lib/makit/configuration/gitlab_helper.rb +60 -0
  42. data/lib/makit/configuration/project.rb +127 -0
  43. data/lib/makit/configuration/rakefile_helper.rb +43 -0
  44. data/lib/makit/configuration/step.rb +34 -0
  45. data/lib/makit/configuration.rb +14 -0
  46. data/lib/makit/content/default_gitignore.rb +4 -2
  47. data/lib/makit/content/default_rakefile.rb +4 -2
  48. data/lib/makit/content/gem_rakefile.rb +4 -2
  49. data/lib/makit/context.rb +1 -0
  50. data/lib/makit/data.rb +9 -10
  51. data/lib/makit/directories.rb +48 -52
  52. data/lib/makit/directory.rb +38 -52
  53. data/lib/makit/docs/files.rb +5 -10
  54. data/lib/makit/docs/rake.rb +16 -20
  55. data/lib/makit/dotnet/cli.rb +65 -0
  56. data/lib/makit/dotnet/project.rb +153 -0
  57. data/lib/makit/dotnet/solution.rb +38 -0
  58. data/lib/makit/dotnet/solution_classlib.rb +239 -0
  59. data/lib/makit/dotnet/solution_console.rb +264 -0
  60. data/lib/makit/dotnet/solution_maui.rb +354 -0
  61. data/lib/makit/dotnet/solution_wasm.rb +275 -0
  62. data/lib/makit/dotnet/solution_wpf.rb +304 -0
  63. data/lib/makit/dotnet.rb +54 -171
  64. data/lib/makit/email.rb +46 -17
  65. data/lib/makit/environment.rb +22 -19
  66. data/lib/makit/examples/runner.rb +370 -0
  67. data/lib/makit/exceptions.rb +45 -0
  68. data/lib/makit/fileinfo.rb +3 -5
  69. data/lib/makit/files.rb +12 -16
  70. data/lib/makit/gems.rb +40 -39
  71. data/lib/makit/git/cli.rb +54 -0
  72. data/lib/makit/git/repository.rb +90 -0
  73. data/lib/makit/git.rb +44 -91
  74. data/lib/makit/gitlab_runner.rb +0 -1
  75. data/lib/makit/humanize.rb +31 -23
  76. data/lib/makit/indexer.rb +15 -24
  77. data/lib/makit/logging/configuration.rb +305 -0
  78. data/lib/makit/logging/format_registry.rb +84 -0
  79. data/lib/makit/logging/formatters/base.rb +39 -0
  80. data/lib/makit/logging/formatters/console_formatter.rb +127 -0
  81. data/lib/makit/logging/formatters/json_formatter.rb +65 -0
  82. data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -0
  83. data/lib/makit/logging/formatters/text_formatter.rb +64 -0
  84. data/lib/makit/logging/log_request.rb +115 -0
  85. data/lib/makit/logging/logger.rb +159 -0
  86. data/lib/makit/logging/sinks/base.rb +91 -0
  87. data/lib/makit/logging/sinks/console.rb +72 -0
  88. data/lib/makit/logging/sinks/file_sink.rb +92 -0
  89. data/lib/makit/logging/sinks/structured.rb +129 -0
  90. data/lib/makit/logging/sinks/unified_file_sink.rb +303 -0
  91. data/lib/makit/logging.rb +452 -37
  92. data/lib/makit/markdown.rb +18 -18
  93. data/lib/makit/mp/basic_object_mp.rb +5 -4
  94. data/lib/makit/mp/command_mp.rb +5 -5
  95. data/lib/makit/mp/command_request.mp.rb +3 -2
  96. data/lib/makit/mp/project_mp.rb +85 -96
  97. data/lib/makit/mp/string_mp.rb +245 -73
  98. data/lib/makit/nuget.rb +27 -25
  99. data/lib/makit/port.rb +25 -27
  100. data/lib/makit/process.rb +127 -29
  101. data/lib/makit/protoc.rb +27 -24
  102. data/lib/makit/rake/cli.rb +196 -0
  103. data/lib/makit/rake.rb +6 -6
  104. data/lib/makit/ruby/cli.rb +185 -0
  105. data/lib/makit/ruby.rb +25 -0
  106. data/lib/makit/secrets.rb +18 -18
  107. data/lib/makit/serializer.rb +29 -27
  108. data/lib/makit/services/builder.rb +186 -0
  109. data/lib/makit/services/error_handler.rb +226 -0
  110. data/lib/makit/services/repository_manager.rb +229 -0
  111. data/lib/makit/services/validator.rb +112 -0
  112. data/lib/makit/setup/classlib.rb +53 -0
  113. data/lib/makit/setup/gem.rb +250 -0
  114. data/lib/makit/setup/runner.rb +40 -0
  115. data/lib/makit/show.rb +16 -16
  116. data/lib/makit/storage.rb +32 -37
  117. data/lib/makit/symbols.rb +12 -0
  118. data/lib/makit/task_hooks.rb +125 -0
  119. data/lib/makit/task_info.rb +63 -21
  120. data/lib/makit/tasks/at_exit.rb +13 -0
  121. data/lib/makit/tasks/build.rb +18 -0
  122. data/lib/makit/tasks/clean.rb +11 -0
  123. data/lib/makit/tasks/hook_manager.rb +239 -0
  124. data/lib/makit/tasks/init.rb +47 -0
  125. data/lib/makit/tasks/integrate.rb +15 -0
  126. data/lib/makit/tasks/pull_incoming.rb +12 -0
  127. data/lib/makit/tasks/setup.rb +6 -0
  128. data/lib/makit/tasks/sync.rb +11 -0
  129. data/lib/makit/tasks/task_monkey_patch.rb +79 -0
  130. data/lib/makit/tasks.rb +5 -150
  131. data/lib/makit/test_cache.rb +239 -0
  132. data/lib/makit/v1/makit.v1_pb.rb +34 -35
  133. data/lib/makit/v1/makit.v1_services_pb.rb +2 -0
  134. data/lib/makit/version.rb +1 -60
  135. data/lib/makit/wix.rb +23 -23
  136. data/lib/makit/yaml.rb +18 -6
  137. data/lib/makit.rb +2 -261
  138. metadata +109 -145
  139. data/lib/makit/cli/clean.rb +0 -14
  140. data/lib/makit/cli/clone.rb +0 -59
  141. data/lib/makit/cli/init.rb +0 -38
  142. data/lib/makit/cli/make.rb +0 -54
  143. data/lib/makit/cli/new.rb +0 -37
  144. data/lib/makit/cli/nuget_cache.rb +0 -38
  145. data/lib/makit/cli/pull.rb +0 -31
  146. data/lib/makit/cli/setup.rb +0 -71
  147. data/lib/makit/cli/work.rb +0 -21
  148. data/lib/makit/content/default_gitignore.txt +0 -222
@@ -0,0 +1,160 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+ require "timeout"
5
+
6
+ module Makit
7
+ module Commands
8
+ module Strategies
9
+ # Base class for command execution strategies.
10
+ #
11
+ # Execution strategies define how commands are actually executed -
12
+ # synchronously, asynchronously, in parallel, etc. This provides
13
+ # flexibility in execution patterns while maintaining a consistent
14
+ # interface.
15
+ #
16
+ # @example Creating custom strategy
17
+ # class CustomStrategy < Base
18
+ # def execute(request)
19
+ # # Custom execution logic
20
+ # result = Result.new(command: request.to_shell_command)
21
+ # # ... perform execution ...
22
+ # result.finish!(exit_code: 0, stdout: "success")
23
+ # end
24
+ # end
25
+ class Base
26
+ # Execute a command request.
27
+ #
28
+ # This method must be implemented by subclasses to provide the actual
29
+ # command execution logic. The implementation should create a Result
30
+ # object and populate it with execution details.
31
+ #
32
+ # @param request [Request] the command request to execute
33
+ # @return [Result] the execution result
34
+ # @raise [NotImplementedError] if not overridden by subclass
35
+ def execute(request)
36
+ raise NotImplementedError, "#{self.class.name} must implement #execute"
37
+ end
38
+
39
+ # Execute multiple requests (default: sequential execution).
40
+ #
41
+ # Override this method in subclasses to provide optimized batch execution
42
+ # such as parallel execution.
43
+ #
44
+ # @param requests [Array<Request>] requests to execute
45
+ # @return [Array<Result>] execution results in same order
46
+ def execute_batch(requests)
47
+ requests.map { |request| execute(request) }
48
+ end
49
+
50
+ # Check if this strategy can handle the given request.
51
+ #
52
+ # Override this method to provide conditional strategy selection
53
+ # based on request properties.
54
+ #
55
+ # @param request [Request] the command request
56
+ # @return [Boolean] true if strategy can handle the request
57
+ def supports?(_request)
58
+ true
59
+ end
60
+
61
+ # Get strategy name for logging and debugging.
62
+ #
63
+ # @return [String] strategy name
64
+ def name
65
+ self.class.name.split("::").last
66
+ end
67
+
68
+ # Get strategy configuration.
69
+ #
70
+ # @return [Hash] strategy configuration
71
+ def config
72
+ {}
73
+ end
74
+
75
+ protected
76
+
77
+ # Execute command using Open3 for cross-platform compatibility.
78
+ #
79
+ # This is a helper method that subclasses can use for actual
80
+ # system command execution.
81
+ #
82
+ # @param request [Request] the command request
83
+ # @return [Result] execution result
84
+ def execute_with_open3(request)
85
+ result = Result.new(
86
+ command: request.to_shell_command,
87
+ started_at: Time.now,
88
+ )
89
+
90
+ begin
91
+ # Change to specified directory if provided
92
+ Dir.chdir(request.directory) do
93
+ # Execute command with timeout using Timeout module
94
+ stdout, stderr, status = if request.timeout&.positive?
95
+ Timeout.timeout(request.timeout) do
96
+ Open3.capture3(
97
+ request.environment,
98
+ request.command,
99
+ *request.arguments
100
+ )
101
+ end
102
+ else
103
+ Open3.capture3(
104
+ request.environment,
105
+ request.command,
106
+ *request.arguments
107
+ )
108
+ end
109
+
110
+ result.finish!(
111
+ exit_code: status.exitstatus,
112
+ stdout: stdout,
113
+ stderr: stderr,
114
+ )
115
+ end
116
+ rescue Timeout::Error => e
117
+ result.finish!(
118
+ exit_code: 124, # timeout exit code
119
+ stderr: "Command timed out after #{request.timeout} seconds",
120
+ ).add_metadata(:timeout, true)
121
+ .add_metadata(:error, e.message)
122
+ rescue StandardError => e
123
+ result.finish!(
124
+ exit_code: 1,
125
+ stderr: e.message,
126
+ ).add_metadata(:error_class, e.class.name)
127
+ .add_metadata(:error, e.message)
128
+ end
129
+
130
+ result
131
+ end
132
+
133
+ # Validate that the command exists and is executable.
134
+ #
135
+ # @param command [String] command to validate
136
+ # @return [Boolean] true if command is available
137
+ def command_available?(command)
138
+ system("which #{command} > /dev/null 2>&1") ||
139
+ system("where #{command} > nul 2>&1") # Windows
140
+ end
141
+
142
+ # Get the full path to a command.
143
+ #
144
+ # @param command [String] command name
145
+ # @return [String, nil] full path to command or nil if not found
146
+ def which(command)
147
+ # Try Unix-style which first
148
+ path = `which #{command} 2>/dev/null`.strip
149
+ return path unless path.empty?
150
+
151
+ # Try Windows-style where
152
+ path = `where #{command} 2>nul`.strip
153
+ return path unless path.empty?
154
+
155
+ nil
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "../result"
5
+
6
+ module Makit
7
+ module Commands
8
+ module Strategies
9
+ # Synchronous command execution strategy.
10
+ #
11
+ # This strategy executes commands one at a time, blocking until each
12
+ # command completes. This is the simplest and most reliable execution
13
+ # pattern, suitable for most use cases.
14
+ #
15
+ # @example Using synchronous execution
16
+ # strategy = Synchronous.new
17
+ # request = Request.new(command: "echo", arguments: ["hello"])
18
+ # result = strategy.execute(request)
19
+ # puts result.stdout # "hello"
20
+ class Synchronous < Base
21
+ # Initialize synchronous execution strategy.
22
+ #
23
+ # @param options [Hash] strategy configuration
24
+ # @option options [Boolean] :validate_commands (true) whether to validate commands exist
25
+ # @option options [Integer] :max_output_size (1048576) maximum output size in bytes
26
+ def initialize(**options)
27
+ @validate_commands = options.fetch(:validate_commands, true)
28
+ @max_output_size = options.fetch(:max_output_size, 1024 * 1024) # 1MB default
29
+ end
30
+
31
+ # Execute a single command request synchronously.
32
+ #
33
+ # @param request [Request] the command request to execute
34
+ # @return [Result] execution result
35
+ def execute(request)
36
+ # Skip command validation for basic commands like echo on Windows
37
+ # This is a simplified approach for demonstration purposes
38
+ if @validate_commands && !basic_command?(request.command) && !command_available?(request.command)
39
+ return Result.failure(
40
+ command: request.to_shell_command,
41
+ error: "Command not found: #{request.command}",
42
+ )
43
+ end
44
+
45
+ # Execute using Open3 for cross-platform support
46
+ result = execute_with_open3(request)
47
+
48
+ # Truncate output if too large
49
+ if result.stdout.bytesize > @max_output_size
50
+ original_size = result.stdout.bytesize
51
+ truncated_stdout = result.stdout.byteslice(0, @max_output_size)
52
+ result.instance_variable_set(:@stdout, "#{truncated_stdout}\n[OUTPUT TRUNCATED]")
53
+ result.add_metadata(:output_truncated, true)
54
+ result.add_metadata(:original_stdout_size, original_size)
55
+ end
56
+
57
+ if result.stderr.bytesize > @max_output_size
58
+ original_size = result.stderr.bytesize
59
+ truncated_stderr = result.stderr.byteslice(0, @max_output_size)
60
+ result.instance_variable_set(:@stderr, "#{truncated_stderr}\n[ERROR OUTPUT TRUNCATED]")
61
+ result.add_metadata(:stderr_truncated, true)
62
+ result.add_metadata(:original_stderr_size, original_size)
63
+ end
64
+
65
+ # Add strategy metadata
66
+ result.add_metadata(:execution_strategy, "synchronous")
67
+ result.add_metadata(:validated_command, @validate_commands)
68
+
69
+ result
70
+ end
71
+
72
+ # Execute multiple requests sequentially.
73
+ #
74
+ # @param requests [Array<Request>] requests to execute
75
+ # @return [Array<Result>] execution results in same order
76
+ def execute_batch(requests)
77
+ results = []
78
+
79
+ requests.each_with_index do |request, index|
80
+ result = execute(request)
81
+ result.add_metadata(:batch_index, index)
82
+ result.add_metadata(:batch_size, requests.size)
83
+ results << result
84
+
85
+ # Stop on first failure if configured
86
+ break if result.failure? && fail_fast?
87
+ end
88
+
89
+ results
90
+ end
91
+
92
+ # Check if strategy supports the given request.
93
+ #
94
+ # Synchronous strategy supports all requests.
95
+ #
96
+ # @param request [Request] the command request
97
+ # @return [Boolean] always true
98
+ def supports?(_request)
99
+ true
100
+ end
101
+
102
+ # Get strategy configuration.
103
+ #
104
+ # @return [Hash] strategy configuration
105
+ def config
106
+ {
107
+ name: "synchronous",
108
+ validate_commands: @validate_commands,
109
+ max_output_size: @max_output_size,
110
+ fail_fast: fail_fast?,
111
+ }
112
+ end
113
+
114
+ private
115
+
116
+ # Check if command is a basic system command that should always be available.
117
+ #
118
+ # @param command [String] command name
119
+ # @return [Boolean] true if it's a basic command
120
+ def basic_command?(command)
121
+ %w[echo ruby bundle rake git].include?(command)
122
+ end
123
+
124
+ # Check if execution should stop on first failure.
125
+ #
126
+ # @return [Boolean] whether to fail fast
127
+ def fail_fast?
128
+ # Could be configurable in the future
129
+ false
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -8,14 +8,35 @@ require "logger"
8
8
 
9
9
  # This module provides classes for the Makit gem.
10
10
  module Makit
11
+ # Commands module provides a modern, flexible command execution framework
12
+ # with middleware support, validation, caching, and structured logging.
13
+ module Commands
14
+ # Custom exception for security-related command validation failures
15
+ class SecurityError < StandardError; end
16
+
17
+ # Custom exception for command execution failures
18
+ class ExecutionError < StandardError
19
+ attr_reader :exit_code, :stderr
20
+
21
+ def initialize(message, exit_code: nil, stderr: nil)
22
+ @exit_code = exit_code
23
+ @stderr = stderr
24
+ super(message)
25
+ end
26
+ end
27
+ end
28
+
11
29
  # This class provide methods running commands.
12
30
  #
13
- class Commands < Array
14
-
31
+ class LegacyCommands < Array
15
32
  # Generate the commands based on the current directory.
16
33
  def auto_generate
17
34
  self << Makit::V1::CommandRequest.new(name: "bundle", arguments: ["install"]) if File.exist?("Gemfile")
18
- self << Makit::V1::CommandRequest.new(name: "bundle", arguments: ["exec", "rake"]) if File.exist?("Rakefile")
35
+ self << Makit::V1::CommandRequest.new(name: "bundle", arguments: %w[exec rake]) if File.exist?("Rakefile")
19
36
  end
20
37
  end
21
38
  end
39
+
40
+ # Load command system components (load existing components only)
41
+ require_relative "commands/result"
42
+ require_relative "commands/middleware/validator"
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module Makit
6
+ module Configuration
7
+ # Helper for GitLab CI YAML conversion
8
+ class GitLabHelper
9
+ def self.to_yaml(project, path)
10
+ yaml_content = generate_yaml(project)
11
+ File.write(path, yaml_content)
12
+ end
13
+
14
+ def self.from_yaml(path)
15
+ content = File.read(path)
16
+ data = YAML.safe_load(content, symbolize_names: true, permitted_classes: [Symbol])
17
+
18
+ project = Project.new(name: data[:name] || "Unknown", version: data[:version] || "1.0.0")
19
+
20
+ # Extract steps from GitLab CI jobs
21
+ data.each do |key, value|
22
+ next unless value.is_a?(Hash) && value[:script]
23
+
24
+ step_name = key.to_s.gsub(/_job$/, "")
25
+ step = Step.new(
26
+ name: step_name,
27
+ description: value[:description] || "GitLab CI job: #{step_name}",
28
+ commands: value[:script],
29
+ )
30
+ project.add_step(step)
31
+ end
32
+
33
+ project
34
+ end
35
+
36
+ private
37
+
38
+ def self.generate_yaml(project)
39
+ yaml = {
40
+ stages: project.steps.map(&:name),
41
+ variables: {
42
+ project_name: project.name,
43
+ project_version: project.version,
44
+ },
45
+ }
46
+
47
+ project.steps.each do |step|
48
+ job_name = "#{step.name}_job"
49
+ yaml[job_name.to_sym] = {
50
+ stage: step.name,
51
+ script: step.commands,
52
+ description: step.description,
53
+ }
54
+ end
55
+
56
+ yaml.to_yaml
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Makit
6
+ module Configuration
7
+ # Project configuration management
8
+ class Project
9
+ attr_accessor :git_remote_url, :name, :version, :project_type, :steps
10
+
11
+ def initialize(name, version = nil, project_type = nil)
12
+ # Support both keyword arguments and positional arguments for compatibility
13
+ if name.is_a?(Hash)
14
+ # Keyword arguments: Project.new(name: "test", version: "1.0.0")
15
+ @name = name[:name]
16
+ @version = name[:version]
17
+ @project_type = name[:project_type]
18
+ else
19
+ # Positional arguments: Project.new("test", "1.0.0", "nuget")
20
+ @name = name
21
+ @version = version
22
+ @project_type = project_type
23
+ end
24
+
25
+ @steps = []
26
+ end
27
+
28
+ def add_step(step)
29
+ raise ArgumentError, "Step must be a Makit::Configuration::Step instance" unless step.is_a?(Step)
30
+ @steps << step
31
+ end
32
+
33
+ def to_json(*args)
34
+ {
35
+ name: @name,
36
+ version: @version,
37
+ project_type: @project_type,
38
+ steps: @steps.map(&:to_h),
39
+ }.to_json(*args)
40
+ end
41
+
42
+ def to_json_pretty
43
+ JSON.pretty_generate({
44
+ name: @name,
45
+ version: @version,
46
+ project_type: @project_type,
47
+ steps: @steps.map(&:to_h),
48
+ })
49
+ end
50
+
51
+ def self.from_json(path)
52
+ content = File.read(path)
53
+ data = JSON.parse(content, symbolize_names: true)
54
+
55
+ project = new(data[:name], data[:version], data[:project_type])
56
+ data[:steps].each do |step_data|
57
+ step = Step.new(
58
+ name: step_data[:name],
59
+ description: step_data[:description],
60
+ commands: step_data[:commands],
61
+ )
62
+ project.add_step(step)
63
+ end
64
+
65
+ project
66
+ end
67
+
68
+ # Class method for deserializing from JSON string (used by serializer)
69
+ def self.decode_json(json_string)
70
+ data = JSON.parse(json_string, symbolize_names: true)
71
+
72
+ project = new(data[:name], data[:version], data[:project_type])
73
+ data[:steps].each do |step_data|
74
+ step = Step.new(
75
+ name: step_data[:name],
76
+ description: step_data[:description],
77
+ commands: step_data[:commands],
78
+ )
79
+ project.add_step(step)
80
+ end
81
+
82
+ project
83
+ end
84
+
85
+ def to_gitlab_ci(path)
86
+ GitLabHelper.to_yaml(self, path)
87
+ end
88
+
89
+ def to_rakefile
90
+ RakefileHelper.generate(self)
91
+ end
92
+
93
+ # Save the project to a specific path as pretty JSON
94
+ def save_as(path)
95
+ File.write(path, to_json_pretty)
96
+ end
97
+
98
+ def save
99
+ save_as(".makit.json")
100
+ end
101
+
102
+ # Display the project configuration in YAML format
103
+ def show
104
+ require "yaml"
105
+
106
+ project_data = {
107
+ name: @name,
108
+ version: @version,
109
+ project_type: @project_type,
110
+ git_remote_url: @git_remote_url,
111
+ steps: @steps.map(&:to_h),
112
+ }
113
+
114
+ puts YAML.dump(project_data)
115
+ end
116
+
117
+ # Load a project from the default .makit.json file
118
+ def self.default
119
+ if File.exist?(".makit.json")
120
+ from_json(".makit.json")
121
+ else
122
+ new(name: "", version: "0.0.0", project_type: "")
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Makit
4
+ module Configuration
5
+ # Helper for Rakefile generation
6
+ class RakefileHelper
7
+ def self.generate(project)
8
+ rakefile_content = []
9
+
10
+ # Add header comment
11
+ rakefile_content << "# Generated Rakefile for #{project.name} v#{project.version}"
12
+ rakefile_content << "# Generated by Makit::Configuration::RakefileHelper"
13
+ rakefile_content << ""
14
+
15
+ # Add default task
16
+ if project.steps.any?
17
+ default_tasks = project.steps.map(&:name).join(",")
18
+ rakefile_content << "desc 'Run all project steps'"
19
+ rakefile_content << "task :default => [:#{default_tasks}]"
20
+ rakefile_content << ""
21
+ end
22
+
23
+ # Add individual step tasks
24
+ project.steps.each do |step|
25
+ rakefile_content << "desc '#{step.description}'"
26
+ rakefile_content << "task :#{step.name} do"
27
+ step.commands.each do |command|
28
+ rakefile_content << " sh '#{command}'"
29
+ end
30
+ rakefile_content << "end"
31
+ rakefile_content << ""
32
+ end
33
+
34
+ rakefile_content.join("\n")
35
+ end
36
+
37
+ def self.write(project, path)
38
+ content = generate(project)
39
+ File.write(path, content)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Makit
4
+ module Configuration
5
+ # Individual step in a project configuration
6
+ class Step
7
+ attr_accessor :name, :description, :commands
8
+
9
+ def initialize(name:, description:, commands:)
10
+ @name = name
11
+ @description = description
12
+ @commands = commands.is_a?(Array) ? commands : [commands]
13
+
14
+ validate_commands
15
+ end
16
+
17
+ def to_h
18
+ {
19
+ name: @name,
20
+ description: @description,
21
+ commands: @commands,
22
+ }
23
+ end
24
+
25
+ private
26
+
27
+ def validate_commands
28
+ unless @commands.is_a?(Array) && @commands.all? { |cmd| cmd.is_a?(String) }
29
+ raise ArgumentError, "Commands must be an array of strings"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Load all configuration classes
4
+ require_relative "configuration/project"
5
+ require_relative "configuration/step"
6
+ require_relative "configuration/gitlab_helper"
7
+ require_relative "configuration/rakefile_helper"
8
+
9
+ # Main configuration module that loads all configuration classes
10
+ module Makit
11
+ module Configuration
12
+ # All configuration classes are now loaded above
13
+ end
14
+ end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Makit
2
4
  module Content
3
5
  GITIGNORE = File.read(File.join(__dir__, "default_gitignore.txt"))
4
- end # module Content
5
- end # module Makit
6
+ end
7
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Makit
2
4
  module Content
3
5
  RAKEFILE = <<~HEREDOC
@@ -7,5 +9,5 @@ module Makit
7
9
  end
8
10
 
9
11
  HEREDOC
10
- end # module Content
11
- end # module Makit
12
+ end
13
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Makit
2
4
  module Content
3
5
  GEM_RAKEFILE = <<~HEREDOC
@@ -10,5 +12,5 @@ module Makit
10
12
  end
11
13
 
12
14
  HEREDOC
13
- end # module Content
14
- end # module Makit
15
+ end
16
+ end
@@ -0,0 +1 @@
1
+ # frozen_string_literal: true