makit 0.0.99 → 0.0.112
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 -0
- data/exe/makit +5 -0
- data/lib/makit/apache.rb +28 -32
- data/lib/makit/cli/build_commands.rb +500 -0
- data/lib/makit/cli/generators/base_generator.rb +74 -0
- data/lib/makit/cli/generators/dotnet_generator.rb +50 -0
- data/lib/makit/cli/generators/generator_factory.rb +49 -0
- data/lib/makit/cli/generators/node_generator.rb +50 -0
- data/lib/makit/cli/generators/ruby_generator.rb +77 -0
- data/lib/makit/cli/generators/rust_generator.rb +50 -0
- data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -0
- data/lib/makit/cli/generators/templates/node_templates.rb +161 -0
- data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -0
- data/lib/makit/cli/generators/templates/ruby/gemspec.rb +40 -0
- data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -0
- data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -0
- data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -0
- data/lib/makit/cli/generators/templates/ruby/test.rb +39 -0
- data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -0
- data/lib/makit/cli/generators/templates/ruby/version.rb +29 -0
- data/lib/makit/cli/generators/templates/rust_templates.rb +128 -0
- data/lib/makit/cli/main.rb +62 -33
- data/lib/makit/cli/project_commands.rb +868 -0
- data/lib/makit/cli/repository_commands.rb +661 -0
- data/lib/makit/cli/utility_commands.rb +521 -0
- data/lib/makit/commands/factory.rb +359 -0
- data/lib/makit/commands/middleware/base.rb +73 -0
- data/lib/makit/commands/middleware/cache.rb +248 -0
- data/lib/makit/commands/middleware/command_logger.rb +320 -0
- data/lib/makit/commands/middleware/unified_logger.rb +243 -0
- data/lib/makit/commands/middleware/validator.rb +269 -0
- data/lib/makit/commands/request.rb +254 -0
- data/lib/makit/commands/result.rb +323 -0
- data/lib/makit/commands/runner.rb +337 -0
- data/lib/makit/commands/strategies/base.rb +160 -0
- data/lib/makit/commands/strategies/synchronous.rb +134 -0
- data/lib/makit/commands.rb +51 -21
- data/lib/makit/configuration/gitlab_helper.rb +60 -0
- data/lib/makit/configuration/project.rb +127 -0
- data/lib/makit/configuration/rakefile_helper.rb +43 -0
- data/lib/makit/configuration/step.rb +34 -0
- data/lib/makit/configuration.rb +14 -0
- data/lib/makit/content/default_gitignore.rb +7 -5
- data/lib/makit/content/default_rakefile.rb +13 -11
- data/lib/makit/content/gem_rakefile.rb +16 -14
- data/lib/makit/context.rb +1 -0
- data/lib/makit/data.rb +49 -50
- data/lib/makit/directories.rb +141 -145
- data/lib/makit/directory.rb +262 -276
- data/lib/makit/docs/files.rb +89 -94
- data/lib/makit/docs/rake.rb +102 -106
- data/lib/makit/dotnet/cli.rb +65 -0
- data/lib/makit/dotnet/project.rb +153 -0
- data/lib/makit/dotnet/solution.rb +38 -0
- data/lib/makit/dotnet/solution_classlib.rb +239 -0
- data/lib/makit/dotnet/solution_console.rb +264 -0
- data/lib/makit/dotnet/solution_maui.rb +354 -0
- data/lib/makit/dotnet/solution_wasm.rb +275 -0
- data/lib/makit/dotnet/solution_wpf.rb +304 -0
- data/lib/makit/dotnet.rb +102 -219
- data/lib/makit/email.rb +90 -61
- data/lib/makit/environment.rb +142 -139
- data/lib/makit/examples/runner.rb +370 -0
- data/lib/makit/exceptions.rb +45 -0
- data/lib/makit/fileinfo.rb +24 -26
- data/lib/makit/files.rb +43 -47
- data/lib/makit/gems.rb +29 -28
- data/lib/makit/git/cli.rb +54 -0
- data/lib/makit/git/repository.rb +90 -0
- data/lib/makit/git.rb +98 -145
- data/lib/makit/gitlab_runner.rb +59 -60
- data/lib/makit/humanize.rb +137 -129
- data/lib/makit/indexer.rb +47 -56
- data/lib/makit/logging/configuration.rb +305 -0
- data/lib/makit/logging/format_registry.rb +84 -0
- data/lib/makit/logging/formatters/base.rb +39 -0
- data/lib/makit/logging/formatters/console_formatter.rb +140 -0
- data/lib/makit/logging/formatters/json_formatter.rb +65 -0
- data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -0
- data/lib/makit/logging/formatters/text_formatter.rb +64 -0
- data/lib/makit/logging/log_request.rb +115 -0
- data/lib/makit/logging/logger.rb +163 -0
- data/lib/makit/logging/sinks/base.rb +91 -0
- data/lib/makit/logging/sinks/console.rb +72 -0
- data/lib/makit/logging/sinks/file_sink.rb +92 -0
- data/lib/makit/logging/sinks/structured.rb +129 -0
- data/lib/makit/logging/sinks/unified_file_sink.rb +303 -0
- data/lib/makit/logging.rb +530 -106
- data/lib/makit/markdown.rb +75 -75
- data/lib/makit/mp/basic_object_mp.rb +17 -16
- data/lib/makit/mp/command_mp.rb +13 -13
- data/lib/makit/mp/command_request.mp.rb +17 -16
- data/lib/makit/mp/project_mp.rb +199 -210
- data/lib/makit/mp/string_mp.rb +193 -176
- data/lib/makit/nuget.rb +74 -72
- data/lib/makit/port.rb +32 -34
- data/lib/makit/process.rb +163 -65
- data/lib/makit/protoc.rb +107 -104
- data/lib/makit/rake/cli.rb +196 -0
- data/lib/makit/rake.rb +25 -25
- data/lib/makit/ruby/cli.rb +185 -0
- data/lib/makit/ruby.rb +25 -0
- data/lib/makit/secrets.rb +51 -51
- data/lib/makit/serializer.rb +130 -115
- data/lib/makit/services/builder.rb +186 -0
- data/lib/makit/services/error_handler.rb +226 -0
- data/lib/makit/services/repository_manager.rb +229 -0
- data/lib/makit/services/validator.rb +112 -0
- data/lib/makit/setup/classlib.rb +53 -0
- data/lib/makit/setup/gem.rb +263 -0
- data/lib/makit/setup/runner.rb +45 -0
- data/lib/makit/setup.rb +5 -0
- data/lib/makit/show.rb +110 -110
- data/lib/makit/storage.rb +126 -131
- data/lib/makit/symbols.rb +170 -149
- data/lib/makit/task_info.rb +128 -86
- data/lib/makit/tasks/at_exit.rb +13 -0
- data/lib/makit/tasks/build.rb +19 -0
- data/lib/makit/tasks/clean.rb +11 -0
- data/lib/makit/tasks/hook_manager.rb +393 -0
- data/lib/makit/tasks/init.rb +47 -0
- data/lib/makit/tasks/integrate.rb +17 -0
- data/lib/makit/tasks/pull_incoming.rb +11 -0
- data/lib/makit/tasks/setup.rb +6 -0
- data/lib/makit/tasks/sync.rb +12 -0
- data/lib/makit/tasks/tag.rb +15 -0
- data/lib/makit/tasks/task_monkey_patch.rb +79 -0
- data/lib/makit/tasks.rb +15 -150
- data/lib/makit/test_cache.rb +239 -0
- data/lib/makit/tree.rb +37 -37
- data/lib/makit/v1/makit.v1_pb.rb +3 -4
- data/lib/makit/v1/makit.v1_services_pb.rb +27 -25
- data/lib/makit/version.rb +5 -61
- data/lib/makit/version_util.rb +21 -0
- data/lib/makit/wix.rb +95 -95
- data/lib/makit/yaml.rb +29 -17
- data/lib/makit/zip.rb +17 -17
- data/lib/makit copy.rb +44 -0
- data/lib/makit.rb +40 -267
- metadata +117 -110
- data/lib/makit/cli/clean.rb +0 -14
- data/lib/makit/cli/clone.rb +0 -59
- data/lib/makit/cli/init.rb +0 -38
- data/lib/makit/cli/make.rb +0 -54
- data/lib/makit/cli/new.rb +0 -37
- data/lib/makit/cli/nuget_cache.rb +0 -38
- data/lib/makit/cli/pull.rb +0 -31
- data/lib/makit/cli/setup.rb +0 -71
- data/lib/makit/cli/work.rb +0 -21
- data/lib/makit/command_runner.rb +0 -404
- data/lib/makit/content/default_gitignore.txt +0 -222
@@ -0,0 +1,186 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "validator"
|
4
|
+
require_relative "repository_manager"
|
5
|
+
|
6
|
+
module Makit
|
7
|
+
module Services
|
8
|
+
# Service class responsible for build operations and make processes
|
9
|
+
# Handles the complex build workflow including repository setup and execution
|
10
|
+
class Builder
|
11
|
+
class << self
|
12
|
+
# Build a repository at a specific commit
|
13
|
+
#
|
14
|
+
# @param url [String] the git repository URL
|
15
|
+
# @param commit [String] the commit hash or "latest" for the most recent commit
|
16
|
+
# @param force [Boolean] whether to force rebuild even if cached result exists
|
17
|
+
# @return [Makit::V1::MakeResult] the build result with all command outputs
|
18
|
+
def make_repository(url, commit, force: false)
|
19
|
+
Validator.validate_url_parameter(url)
|
20
|
+
Validator.validate_commit_parameter(commit)
|
21
|
+
|
22
|
+
log_filename = get_log_filename(url, commit)
|
23
|
+
|
24
|
+
return load_existing_result(log_filename) if should_load_existing_result?(log_filename, force, commit)
|
25
|
+
|
26
|
+
execute_make_process(url, commit, log_filename)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Ensure .gitignore exists in the current directory
|
30
|
+
def ensure_gitignore
|
31
|
+
return if File.exist?(".gitignore")
|
32
|
+
|
33
|
+
Makit::LOGGER.info("added .gitignore file")
|
34
|
+
File.open(".gitignore", "w") do |file|
|
35
|
+
file.puts Makit::Content::GITIGNORE
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Get the log filename for storing build results
|
42
|
+
def get_log_filename(url, commit)
|
43
|
+
File.join(
|
44
|
+
Directories.get_log_directory(url),
|
45
|
+
commit,
|
46
|
+
"#{Makit::RUNTIME_IDENTIFIER}.#{Makit::DEVICE}.json"
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Check if we should load an existing cached result
|
51
|
+
def should_load_existing_result?(log_filename, force, commit)
|
52
|
+
File.exist?(log_filename) && !force && commit != Validator::COMMIT_LATEST
|
53
|
+
end
|
54
|
+
|
55
|
+
# Load existing build result from cache
|
56
|
+
def load_existing_result(log_filename)
|
57
|
+
Makit::V1::MakeResult.decode_json(File.read(log_filename))
|
58
|
+
rescue StandardError
|
59
|
+
FileUtils.rm(log_filename)
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# Execute the complete make process
|
64
|
+
def execute_make_process(url, commit, log_filename)
|
65
|
+
commands = []
|
66
|
+
begin
|
67
|
+
commands = setup_repository_for_build(url, commit, log_filename)
|
68
|
+
make_result = build_make_result(url, commit, commands)
|
69
|
+
save_make_result(make_result, log_filename)
|
70
|
+
make_result
|
71
|
+
rescue StandardError => e
|
72
|
+
handle_make_error(e, url, commit, commands)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Set up repository for build process
|
77
|
+
def setup_repository_for_build(url, commit, log_filename)
|
78
|
+
commands = initialize_repository_commands(url)
|
79
|
+
|
80
|
+
clone_dir = RepositoryManager.validate_clone_directory(url)
|
81
|
+
resolved_commit = resolve_commit_reference(commit, clone_dir, commands, log_filename, url)
|
82
|
+
prepare_make_directory(url, resolved_commit, clone_dir, commands)
|
83
|
+
|
84
|
+
commands
|
85
|
+
end
|
86
|
+
|
87
|
+
# Initialize repository commands (clone or pull)
|
88
|
+
def initialize_repository_commands(url)
|
89
|
+
RepositoryManager.clone_or_pull_repository(url).flatten
|
90
|
+
end
|
91
|
+
|
92
|
+
# Resolve commit reference (handle "latest" commit)
|
93
|
+
def resolve_commit_reference(commit, clone_dir, commands, log_filename, url)
|
94
|
+
return commit unless commit == Validator::COMMIT_LATEST
|
95
|
+
|
96
|
+
latest_commit = RepositoryManager.get_latest_commit(clone_dir, commands)
|
97
|
+
# Update log filename with resolved commit hash
|
98
|
+
log_filename.replace(
|
99
|
+
File.join(
|
100
|
+
Directories.get_log_directory(url),
|
101
|
+
latest_commit,
|
102
|
+
"#{Makit::RUNTIME_IDENTIFIER}.#{Makit::DEVICE}.json"
|
103
|
+
)
|
104
|
+
)
|
105
|
+
latest_commit
|
106
|
+
end
|
107
|
+
|
108
|
+
# Prepare make directory with repository clone
|
109
|
+
def prepare_make_directory(url, commit, clone_dir, commands)
|
110
|
+
make_dir = Directories.get_make_commit_directory(url, commit)
|
111
|
+
FileUtils.rm_rf(make_dir)
|
112
|
+
|
113
|
+
clone_command = Makit::Commands::Runner.default.execute("git clone #{clone_dir} #{make_dir}")
|
114
|
+
commands << clone_command
|
115
|
+
|
116
|
+
return if Dir.exist?(make_dir)
|
117
|
+
|
118
|
+
raise Makit::CloneError, "failed to clone repository: #{url} to #{make_dir}"
|
119
|
+
end
|
120
|
+
|
121
|
+
# Build the make result by executing all build steps
|
122
|
+
def build_make_result(url, commit, commands)
|
123
|
+
Dir.chdir(Directories.get_make_commit_directory(url, commit)) do
|
124
|
+
execute_git_commands(commit, commands)
|
125
|
+
execute_build_commands(commands)
|
126
|
+
|
127
|
+
make_result = create_make_result_object(url, commit)
|
128
|
+
commands.flatten.each { |command| make_result.commands << command }
|
129
|
+
make_result
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Execute git-specific commands for the build
|
134
|
+
def execute_git_commands(commit, commands)
|
135
|
+
commands << Makit::Commands::Runner.default.execute("git reset --hard #{commit}")
|
136
|
+
commands << Makit::Commands::Runner.default.execute("git log -n 1")
|
137
|
+
end
|
138
|
+
|
139
|
+
# Execute build commands (bundle, rake, etc.)
|
140
|
+
def execute_build_commands(commands)
|
141
|
+
commands << Makit::Commands::Runner.default.execute("bundle install") if File.exist?("Gemfile")
|
142
|
+
|
143
|
+
return unless File.exist?("Rakefile") || File.exist?("rakefile.rb")
|
144
|
+
|
145
|
+
commands << Makit::Commands::Runner.default.execute("rake default")
|
146
|
+
end
|
147
|
+
|
148
|
+
# Create the make result object
|
149
|
+
def create_make_result_object(url, commit)
|
150
|
+
Makit::V1::MakeResult.new(
|
151
|
+
repository: url,
|
152
|
+
commit: commit,
|
153
|
+
branch: "?",
|
154
|
+
tag: "?",
|
155
|
+
device: Makit::DEVICE,
|
156
|
+
runtime_identifier: Makit::RUNTIME_IDENTIFIER,
|
157
|
+
)
|
158
|
+
end
|
159
|
+
|
160
|
+
# Save make result to file
|
161
|
+
def save_make_result(make_result, log_filename)
|
162
|
+
FileUtils.mkdir_p(File.dirname(log_filename))
|
163
|
+
File.write(log_filename, make_result.to_json)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Handle make process errors
|
167
|
+
def handle_make_error(error, url, commit, commands)
|
168
|
+
message_parts = [
|
169
|
+
"error raised attempting to make repository: #{url} commit: #{commit}",
|
170
|
+
"",
|
171
|
+
error.message,
|
172
|
+
error.backtrace.join("\\n"),
|
173
|
+
"",
|
174
|
+
"commands:",
|
175
|
+
]
|
176
|
+
|
177
|
+
commands.flatten.each do |command|
|
178
|
+
message_parts << Makit::Humanize.get_command_details(command)
|
179
|
+
end
|
180
|
+
|
181
|
+
raise Makit::BuildError, message_parts.join("\\n")
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Makit
|
4
|
+
module Services
|
5
|
+
# Service class responsible for handling and formatting errors
|
6
|
+
# Provides user-friendly error messages and recovery suggestions
|
7
|
+
class ErrorHandler
|
8
|
+
# Error message templates with suggestions
|
9
|
+
ERROR_MESSAGES = {
|
10
|
+
invalid_url: {
|
11
|
+
message: "The repository URL '%<url>s' is not valid.",
|
12
|
+
suggestions: [
|
13
|
+
"Use HTTPS format: https://github.com/user/repo.git",
|
14
|
+
"Use SSH format: git@github.com:user/repo.git",
|
15
|
+
"Use simple format: user/repo",
|
16
|
+
"Ensure the URL points to a git repository",
|
17
|
+
],
|
18
|
+
},
|
19
|
+
invalid_directory: {
|
20
|
+
message: "The directory path '%<directory>s' is not valid.",
|
21
|
+
suggestions: [
|
22
|
+
"Use absolute paths like /path/to/directory",
|
23
|
+
"Use relative paths like ./relative/path",
|
24
|
+
"Ensure the path doesn't contain null characters",
|
25
|
+
"Keep directory paths under 255 characters",
|
26
|
+
],
|
27
|
+
},
|
28
|
+
invalid_commit: {
|
29
|
+
message: "The commit '%<commit>s' is not valid.",
|
30
|
+
suggestions: [
|
31
|
+
"Use 'latest' for the most recent commit",
|
32
|
+
"Use a full 40-character commit hash",
|
33
|
+
"Use a short 7+ character commit hash",
|
34
|
+
"Verify the commit exists in the repository",
|
35
|
+
],
|
36
|
+
},
|
37
|
+
directory_not_found: {
|
38
|
+
message: "The directory '%<directory>s' does not exist or is not accessible.",
|
39
|
+
suggestions: [
|
40
|
+
"Check that the directory path is correct",
|
41
|
+
"Verify you have read permissions for the directory",
|
42
|
+
"Create the directory first if it doesn't exist",
|
43
|
+
"Use 'makit init' to create a new project directory",
|
44
|
+
],
|
45
|
+
},
|
46
|
+
git_command_failed: {
|
47
|
+
message: "Git command failed: %<command>s",
|
48
|
+
suggestions: [
|
49
|
+
"Check that git is installed and available in PATH",
|
50
|
+
"Verify you have network connectivity for remote operations",
|
51
|
+
"Ensure you have proper permissions for the repository",
|
52
|
+
"Check that the remote repository URL is accessible",
|
53
|
+
],
|
54
|
+
},
|
55
|
+
clone_failed: {
|
56
|
+
message: "Failed to clone repository '%<url>s'.",
|
57
|
+
suggestions: [
|
58
|
+
"Check that the repository URL is correct and accessible",
|
59
|
+
"Verify your network connectivity",
|
60
|
+
"Ensure you have proper authentication (SSH keys, tokens)",
|
61
|
+
"Check that you have write permissions to the destination directory",
|
62
|
+
],
|
63
|
+
},
|
64
|
+
pull_failed: {
|
65
|
+
message: "Failed to pull changes from repository.",
|
66
|
+
suggestions: [
|
67
|
+
"Check that you have network connectivity",
|
68
|
+
"Verify the remote repository is accessible",
|
69
|
+
"Ensure your local repository is in a clean state",
|
70
|
+
"Try 'git status' to check for conflicts",
|
71
|
+
],
|
72
|
+
},
|
73
|
+
build_failed: {
|
74
|
+
message: "Build process failed for repository '%<url>s' at commit '%<commit>s'.",
|
75
|
+
suggestions: [
|
76
|
+
"Check the build logs for specific error messages",
|
77
|
+
"Verify all dependencies are installed",
|
78
|
+
"Ensure the commit hash is valid and exists",
|
79
|
+
"Try building manually to isolate the issue",
|
80
|
+
],
|
81
|
+
},
|
82
|
+
}.freeze
|
83
|
+
|
84
|
+
class << self
|
85
|
+
# Format an error with user-friendly message and suggestions
|
86
|
+
#
|
87
|
+
# @param error_type [Symbol] the type of error from ERROR_MESSAGES
|
88
|
+
# @param details [Hash] details to interpolate into the message
|
89
|
+
# @param original_error [Exception] the original exception (optional)
|
90
|
+
# @return [String] formatted error message with suggestions
|
91
|
+
def format_error(error_type, details = {}, original_error = nil)
|
92
|
+
error_config = ERROR_MESSAGES[error_type]
|
93
|
+
return "Unknown error type: #{error_type}" unless error_config
|
94
|
+
|
95
|
+
message = error_config[:message] % details
|
96
|
+
suggestions = error_config[:suggestions]
|
97
|
+
|
98
|
+
formatted_message = ["❌ Error: #{message}"]
|
99
|
+
|
100
|
+
if suggestions && !suggestions.empty?
|
101
|
+
formatted_message << ""
|
102
|
+
formatted_message << "💡 Suggestions:"
|
103
|
+
suggestions.each_with_index do |suggestion, index|
|
104
|
+
formatted_message << " #{index + 1}. #{suggestion}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
if original_error && !original_error.message.empty?
|
109
|
+
formatted_message << ""
|
110
|
+
formatted_message << "🔍 Technical details:"
|
111
|
+
formatted_message << " #{original_error.class}: #{original_error.message}"
|
112
|
+
end
|
113
|
+
|
114
|
+
formatted_message.join("\n")
|
115
|
+
end
|
116
|
+
|
117
|
+
# Handle ArgumentError exceptions with user-friendly formatting
|
118
|
+
#
|
119
|
+
# @param error [ArgumentError] the argument error to format
|
120
|
+
# @param context [Hash] additional context about where the error occurred
|
121
|
+
# @return [String] formatted error message
|
122
|
+
def handle_argument_error(error, context = {})
|
123
|
+
case error.message
|
124
|
+
when /URL parameter cannot be nil|URL parameter cannot be empty|Invalid URL format/
|
125
|
+
format_error(:invalid_url, { url: context[:url] || "unknown" }, error)
|
126
|
+
when /directory parameter cannot be nil|directory parameter cannot be empty|directory path/
|
127
|
+
format_error(:invalid_directory, { directory: context[:directory] || "unknown" }, error)
|
128
|
+
when /commit parameter cannot be nil|commit parameter cannot be empty|Invalid commit format/
|
129
|
+
format_error(:invalid_commit, { commit: context[:commit] || "unknown" }, error)
|
130
|
+
else
|
131
|
+
"❌ Error: #{error.message}\n💡 Please check your input parameters and try again."
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Handle Makit-specific exceptions with user-friendly formatting
|
136
|
+
#
|
137
|
+
# @param error [Makit::Error] the Makit error to format
|
138
|
+
# @param context [Hash] additional context about where the error occurred
|
139
|
+
# @return [String] formatted error message
|
140
|
+
def handle_makit_error(error, context = {})
|
141
|
+
case error
|
142
|
+
when Makit::DirectoryError
|
143
|
+
format_error(:directory_not_found, { directory: context[:directory] || "unknown" }, error)
|
144
|
+
when Makit::CloneError
|
145
|
+
format_error(:clone_failed, { url: context[:url] || "unknown" }, error)
|
146
|
+
when Makit::PullError
|
147
|
+
format_error(:pull_failed, {}, error)
|
148
|
+
when Makit::BuildError
|
149
|
+
format_error(:build_failed, { url: context[:url] || "unknown", commit: context[:commit] || "unknown" },
|
150
|
+
error)
|
151
|
+
when Makit::GitError
|
152
|
+
format_error(:git_command_failed, { command: context[:command] || "unknown" }, error)
|
153
|
+
else
|
154
|
+
"❌ Error: #{error.message}\n💡 Please refer to the documentation or run with --verbose for more details."
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Log error with context for debugging
|
159
|
+
#
|
160
|
+
# @param error [Exception] the error to log
|
161
|
+
# @param context [Hash] additional context information
|
162
|
+
def log_error(error, context = {})
|
163
|
+
return unless defined?(Makit::LOGGER) && Makit::LOGGER
|
164
|
+
|
165
|
+
Makit::LOGGER.error "Error occurred: #{error.class} - #{error.message}"
|
166
|
+
Makit::LOGGER.error "Context: #{context.inspect}" unless context.empty?
|
167
|
+
Makit::LOGGER.debug "Backtrace: #{error.backtrace&.join("\n")}" if error.backtrace
|
168
|
+
end
|
169
|
+
|
170
|
+
# Wrap a block with comprehensive error handling
|
171
|
+
#
|
172
|
+
# @param context [Hash] context information for error messages
|
173
|
+
# @yield block to execute with error handling
|
174
|
+
# @return [Object] the result of the block
|
175
|
+
def with_error_handling(context = {})
|
176
|
+
yield
|
177
|
+
rescue ArgumentError => e
|
178
|
+
log_error(e, context)
|
179
|
+
formatted_message = handle_argument_error(e, context)
|
180
|
+
raise Makit::ValidationError, formatted_message
|
181
|
+
rescue Makit::Error => e
|
182
|
+
log_error(e, context)
|
183
|
+
formatted_message = handle_makit_error(e, context)
|
184
|
+
raise e.class, formatted_message
|
185
|
+
rescue StandardError => e
|
186
|
+
log_error(e, context)
|
187
|
+
formatted_message = "❌ An unexpected error occurred: #{e.message}\n💡 Please check the logs or run with --verbose for more details."
|
188
|
+
raise Makit::Error, formatted_message
|
189
|
+
end
|
190
|
+
|
191
|
+
# Validate input and provide helpful error messages
|
192
|
+
#
|
193
|
+
# @param validations [Array<Hash>] array of validation rules
|
194
|
+
# @example
|
195
|
+
# validate_inputs([
|
196
|
+
# { value: url, validator: :url, name: 'repository URL' },
|
197
|
+
# { value: commit, validator: :commit, name: 'commit hash' }
|
198
|
+
# ])
|
199
|
+
def validate_inputs(validations)
|
200
|
+
validations.each do |validation|
|
201
|
+
value = validation[:value]
|
202
|
+
validator = validation[:validator]
|
203
|
+
name = validation[:name] || "parameter"
|
204
|
+
|
205
|
+
case validator
|
206
|
+
when :url
|
207
|
+
Validator.validate_url_parameter(value)
|
208
|
+
when :directory
|
209
|
+
Validator.validate_directory_parameter(value)
|
210
|
+
when :commit
|
211
|
+
Validator.validate_commit_parameter(value)
|
212
|
+
when :required_string
|
213
|
+
Validator.validate_required_string(value, name)
|
214
|
+
when :boolean
|
215
|
+
Validator.validate_boolean_parameter(value, name)
|
216
|
+
end
|
217
|
+
rescue ArgumentError => e
|
218
|
+
context = { validator => value }
|
219
|
+
formatted_message = handle_argument_error(e, context)
|
220
|
+
raise Makit::ValidationError, formatted_message
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "validator"
|
4
|
+
|
5
|
+
module Makit
|
6
|
+
module Services
|
7
|
+
# Service class responsible for git repository management operations
|
8
|
+
# Handles cloning, pulling, logging, and working directory setup
|
9
|
+
class RepositoryManager
|
10
|
+
class << self
|
11
|
+
# Initialize a new git repository in the specified directory
|
12
|
+
#
|
13
|
+
# @param directory [String] the directory path to initialize
|
14
|
+
# @return [Makit::V1::Command] the git init command result
|
15
|
+
# @raise [Makit::DirectoryError] if the directory cannot be created
|
16
|
+
# @raise [Makit::GitError] if git initialization fails
|
17
|
+
def initialize_repository(directory)
|
18
|
+
Validator.validate_directory_parameter(directory)
|
19
|
+
FileUtils.mkdir_p(directory)
|
20
|
+
|
21
|
+
raise Makit::DirectoryError, "directory does not exist: #{directory}" unless Dir.exist?(directory)
|
22
|
+
|
23
|
+
Dir.chdir(directory) do
|
24
|
+
File.write(".gitignore", Makit::Content::GITIGNORE) unless File.exist?(".gitignore")
|
25
|
+
init_command = Makit::Commands::Runner.default.execute("git init")
|
26
|
+
|
27
|
+
if init_command.exit_code != 0
|
28
|
+
raise Makit::GitError, "failed to initialize local repository: #{directory}\\n#{Makit::Humanize.get_command_summary(init_command)}"
|
29
|
+
end
|
30
|
+
|
31
|
+
init_command
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Clone a git repository to a local directory
|
36
|
+
#
|
37
|
+
# @param git_repository [String] the git repository URL
|
38
|
+
# @return [Array<Makit::V1::Command>] array of command results
|
39
|
+
def clone_repository(git_repository)
|
40
|
+
Validator.validate_url_parameter(git_repository)
|
41
|
+
commands = []
|
42
|
+
|
43
|
+
clone_dir = Directories.get_clone_directory(git_repository)
|
44
|
+
commands << Makit::Commands::Runner.default.execute("git clone #{git_repository} #{clone_dir}") unless Dir.exist?(clone_dir)
|
45
|
+
|
46
|
+
commands
|
47
|
+
end
|
48
|
+
|
49
|
+
# Pull the latest changes from the remote repository
|
50
|
+
#
|
51
|
+
# @param git_repository [String] the git repository URL
|
52
|
+
# @return [Makit::V1::Command] the git pull command result
|
53
|
+
def pull_repository(git_repository)
|
54
|
+
Validator.validate_url_parameter(git_repository)
|
55
|
+
clone_dir = Directories.get_clone_directory(git_repository)
|
56
|
+
|
57
|
+
Validator.validate_directory_exists(clone_dir, "clone directory")
|
58
|
+
|
59
|
+
Dir.chdir(clone_dir) do
|
60
|
+
execute_git_pull(clone_dir)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Clone repository if it doesn't exist, otherwise pull latest changes
|
65
|
+
#
|
66
|
+
# @param git_repository [String] the git repository URL
|
67
|
+
# @return [Array<Makit::V1::Command>] array of command results
|
68
|
+
def clone_or_pull_repository(git_repository)
|
69
|
+
commands = []
|
70
|
+
clone_dir = Directories.get_clone_directory(git_repository)
|
71
|
+
|
72
|
+
commands << if Dir.exist?(clone_dir)
|
73
|
+
pull_repository(git_repository)
|
74
|
+
else
|
75
|
+
clone_repository(git_repository)
|
76
|
+
end
|
77
|
+
commands
|
78
|
+
end
|
79
|
+
|
80
|
+
# Get git log information for a repository
|
81
|
+
#
|
82
|
+
# @param git_repository [String] the git repository URL
|
83
|
+
# @param limit [Integer] maximum number of commits to retrieve
|
84
|
+
# @param skip [Integer] number of commits to skip
|
85
|
+
# @return [Array<Makit::V1::GitLogEntry>] array of log entries
|
86
|
+
def get_repository_log(git_repository, limit, skip)
|
87
|
+
Validator.validate_url_parameter(git_repository)
|
88
|
+
Validator.validate_pagination_parameters(limit, skip)
|
89
|
+
|
90
|
+
clone_dir = Directories.get_clone_directory(git_repository)
|
91
|
+
Validator.validate_directory_exists(clone_dir, "clone directory")
|
92
|
+
|
93
|
+
Dir.chdir(clone_dir) do
|
94
|
+
log_command = Makit::Commands::Runner.default.execute("git log -n #{limit} --skip #{skip} --date=iso")
|
95
|
+
parse_git_log_output(log_command)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Set up a work directory for a repository
|
100
|
+
#
|
101
|
+
# @param repository [String] the git repository URL
|
102
|
+
# @return [nil] always returns nil
|
103
|
+
def setup_work_directory(repository)
|
104
|
+
Validator.validate_url_parameter(repository)
|
105
|
+
clone_or_pull_repository(repository)
|
106
|
+
create_work_directory(repository)
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
|
110
|
+
# Get the latest commit hash from a repository
|
111
|
+
#
|
112
|
+
# @param clone_dir [String] the local clone directory
|
113
|
+
# @param commands [Array] array to append command results to
|
114
|
+
# @return [String] the latest commit hash
|
115
|
+
def get_latest_commit(clone_dir, commands)
|
116
|
+
Dir.chdir(clone_dir) do
|
117
|
+
git_log = Makit::Commands::Runner.default.execute("git log -n 1 --date=iso")
|
118
|
+
commands << git_log
|
119
|
+
|
120
|
+
commit = git_log.output.match(/^commit ([0-9a-f]{#{Validator::COMMIT_HASH_LENGTH}})$/i)&.captures&.first
|
121
|
+
|
122
|
+
if commit.nil? || commit.empty? || !commit.match?(/\\A[0-9a-f]{#{Validator::COMMIT_HASH_LENGTH}}\\z/i)
|
123
|
+
raise Makit::InvalidCommitError, "invalid commit: #{commit}"
|
124
|
+
end
|
125
|
+
|
126
|
+
commit
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Validate that a clone directory exists for the given repository
|
131
|
+
#
|
132
|
+
# @param url [String] the git repository URL
|
133
|
+
# @return [String] the clone directory path
|
134
|
+
def validate_clone_directory(url)
|
135
|
+
clone_dir = Directories.get_clone_directory(url)
|
136
|
+
Validator.validate_directory_exists(clone_dir, "clone directory")
|
137
|
+
clone_dir
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
# Execute git pull command with proper error handling
|
143
|
+
def execute_git_pull(clone_dir)
|
144
|
+
request = Makit::V1::CommandRequest.new(
|
145
|
+
name: "git",
|
146
|
+
arguments: ["pull"],
|
147
|
+
directory: clone_dir,
|
148
|
+
)
|
149
|
+
pull_command = Makit::Commands::Runner.default.execute(request)
|
150
|
+
|
151
|
+
raise Makit::PullError, Makit::Humanize.get_command_details(pull_command) if pull_command.exit_code != 0
|
152
|
+
|
153
|
+
pull_command
|
154
|
+
end
|
155
|
+
|
156
|
+
# Create work directory for development
|
157
|
+
def create_work_directory(repository)
|
158
|
+
work_dir = Makit::Directories.get_work_directory(repository)
|
159
|
+
clone_dir = Makit::Directories.get_clone_directory(repository)
|
160
|
+
|
161
|
+
unless Dir.exist?(work_dir)
|
162
|
+
FileUtils.mkdir_p(File.dirname(work_dir))
|
163
|
+
Makit::Commands::Runner.default.execute("git clone #{clone_dir} #{work_dir}")
|
164
|
+
end
|
165
|
+
|
166
|
+
Dir.chdir(work_dir) do
|
167
|
+
File.write(".gitignore", Makit::Content::GITIGNORE) unless File.exist?(".gitignore")
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Parse git log output into structured log entries
|
172
|
+
def parse_git_log_output(log_command)
|
173
|
+
entries = []
|
174
|
+
return entries if log_command.exit_code != 0
|
175
|
+
|
176
|
+
lines = log_command.output.split("\\n")
|
177
|
+
current_entry = nil
|
178
|
+
|
179
|
+
lines.each do |line|
|
180
|
+
current_entry = process_git_log_line(line, current_entry, entries)
|
181
|
+
end
|
182
|
+
|
183
|
+
entries
|
184
|
+
end
|
185
|
+
|
186
|
+
# Process a single line from git log output
|
187
|
+
def process_git_log_line(line, current_entry, entries)
|
188
|
+
case line
|
189
|
+
when /^commit/
|
190
|
+
create_new_log_entry(line, entries)
|
191
|
+
when /^Author:/
|
192
|
+
current_entry ? update_entry_author(line, current_entry) : current_entry
|
193
|
+
when /^Date:/
|
194
|
+
current_entry ? update_entry_date(line, current_entry) : current_entry
|
195
|
+
when /^ /
|
196
|
+
current_entry ? update_entry_message(line, current_entry) : current_entry
|
197
|
+
else
|
198
|
+
current_entry
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Create new git log entry from commit line
|
203
|
+
def create_new_log_entry(line, entries)
|
204
|
+
current_entry = GitLogEntry.new(line.split[1])
|
205
|
+
entries << current_entry
|
206
|
+
current_entry
|
207
|
+
end
|
208
|
+
|
209
|
+
# Update log entry with author information
|
210
|
+
def update_entry_author(line, current_entry)
|
211
|
+
current_entry.author = line.split[1..].join(" ")
|
212
|
+
current_entry
|
213
|
+
end
|
214
|
+
|
215
|
+
# Update log entry with date information
|
216
|
+
def update_entry_date(line, current_entry)
|
217
|
+
current_entry.date = line.split[1..].join(" ")
|
218
|
+
current_entry
|
219
|
+
end
|
220
|
+
|
221
|
+
# Update log entry with commit message
|
222
|
+
def update_entry_message(line, current_entry)
|
223
|
+
current_entry.message += line[4..]
|
224
|
+
current_entry
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|