makit 0.0.140 → 0.0.141
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/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 +40 -40
- 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 +69 -69
- 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 +203 -203
- 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 +388 -385
- data/lib/makit/commands/strategies/base.rb +171 -171
- data/lib/makit/commands/strategies/child_process.rb +165 -165
- 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 +12 -12
- data/lib/makit/configuration/gitlab_helper.rb +58 -58
- data/lib/makit/configuration/project.rb +168 -168
- 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 +15 -15
- 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 +140 -140
- 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 +24 -24
- data/lib/makit/files.rb +43 -43
- data/lib/makit/gems.rb +40 -40
- data/lib/makit/git/cli.rb +54 -54
- data/lib/makit/git/repository.rb +90 -90
- data/lib/makit/git.rb +98 -98
- data/lib/makit/gitlab_runner.rb +59 -59
- data/lib/makit/humanize.rb +137 -137
- data/lib/makit/indexer.rb +47 -47
- data/lib/makit/logging/configuration.rb +308 -308
- 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 +565 -565
- 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 +199 -191
- data/lib/makit/nuget.rb +74 -74
- data/lib/makit/port.rb +32 -32
- data/lib/makit/process.rb +163 -163
- data/lib/makit/protoc.rb +107 -107
- data/lib/makit/rake/cli.rb +196 -196
- data/lib/makit/rake/trace_controller.rb +173 -173
- data/lib/makit/rake.rb +80 -80
- data/lib/makit/ruby/cli.rb +185 -185
- data/lib/makit/ruby.rb +25 -25
- data/lib/makit/secrets.rb +51 -51
- 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 +231 -231
- 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/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 +170 -170
- 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/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/init.rb +49 -49
- data/lib/makit/tasks/integrate.rb +29 -29
- data/lib/makit/tasks/pull_incoming.rb +13 -13
- data/lib/makit/tasks/setup.rb +13 -13
- data/lib/makit/tasks/sync.rb +17 -17
- data/lib/makit/tasks/tag.rb +16 -16
- 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.rb +20 -20
- data/lib/makit/test_cache.rb +239 -239
- data/lib/makit/tree.rb +37 -37
- data/lib/makit/v1/makit.v1_pb.rb +35 -35
- data/lib/makit/v1/makit.v1_services_pb.rb +27 -27
- data/lib/makit/version.rb +99 -99
- 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 +42 -42
- metadata +2 -2
@@ -1,868 +1,868 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "clamp"
|
4
|
-
require "fileutils"
|
5
|
-
require "erb"
|
6
|
-
|
7
|
-
module Makit
|
8
|
-
module Cli
|
9
|
-
# Consolidated project management commands
|
10
|
-
# Combines: new, init, setup, work functionality
|
11
|
-
class ProjectCommand < Clamp::Command
|
12
|
-
self.description = <<~DESC
|
13
|
-
Manage project creation, initialization, and workspace setup.
|
14
|
-
|
15
|
-
Available operations:
|
16
|
-
new - Create new project from template
|
17
|
-
init - Initialize existing directory as project
|
18
|
-
setup - Setup project dependencies and configuration#{" "}
|
19
|
-
work - Open project in IDE or navigate to directory
|
20
|
-
DESC
|
21
|
-
end
|
22
|
-
|
23
|
-
# Create new project from template
|
24
|
-
class NewProjectCommand < Clamp::Command
|
25
|
-
self.description = <<~DESC
|
26
|
-
Create a new project from available templates.
|
27
|
-
|
28
|
-
Examples:
|
29
|
-
makit project new my-app --type ruby
|
30
|
-
makit project new WebApp --type dotnet --framework net8.0
|
31
|
-
makit project new api-service --type node
|
32
|
-
DESC
|
33
|
-
|
34
|
-
parameter "PROJECT_NAME", "Name of the new project", attribute_name: :project_name, required: true
|
35
|
-
option ["--type", "-t"], "TYPE", "Project type (ruby, dotnet, node, rust)", default: "ruby"
|
36
|
-
option ["--framework"], "FRAMEWORK", "Target framework (for .NET projects)", default: "net8.0"
|
37
|
-
option ["--template"], "TEMPLATE", "Specific template to use"
|
38
|
-
option ["--directory", "-d"], "DIR", "Parent directory for new project", default: Dir.pwd
|
39
|
-
option ["--dry-run"], :flag, "Show what would be created without actually creating"
|
40
|
-
option ["--verbose"], :flag, "Show verbose output"
|
41
|
-
|
42
|
-
def execute
|
43
|
-
validate_project_name
|
44
|
-
validate_project_type
|
45
|
-
|
46
|
-
project_dir = File.join(directory, project_name)
|
47
|
-
|
48
|
-
if Dir.exist?(project_dir)
|
49
|
-
puts "Error: Project directory already exists: #{project_dir}"
|
50
|
-
exit 1
|
51
|
-
end
|
52
|
-
|
53
|
-
puts "Creating #{type} project: #{project_name}"
|
54
|
-
puts "Location: #{project_dir}"
|
55
|
-
puts "Template: #{selected_template}" if verbose?
|
56
|
-
|
57
|
-
return if dry_run?
|
58
|
-
|
59
|
-
create_project_structure(project_dir)
|
60
|
-
puts "✅ Successfully created #{type} project: #{project_name}"
|
61
|
-
puts "📁 Project location: #{project_dir}"
|
62
|
-
puts "\nNext steps:"
|
63
|
-
puts " cd #{project_name}"
|
64
|
-
puts " makit project setup # Setup dependencies"
|
65
|
-
puts " makit project work # Open in IDE"
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
def validate_project_name
|
71
|
-
if project_name.nil? || project_name.strip.empty?
|
72
|
-
puts "Error: Project name cannot be empty"
|
73
|
-
exit 1
|
74
|
-
end
|
75
|
-
|
76
|
-
# Check for valid project name characters
|
77
|
-
return if project_name.match?(/\A[a-zA-Z0-9][a-zA-Z0-9._-]*\z/)
|
78
|
-
|
79
|
-
puts "Error: Project name must start with letter/number and contain only letters, numbers, dots, hyphens, and underscores"
|
80
|
-
exit 1
|
81
|
-
end
|
82
|
-
|
83
|
-
def validate_project_type
|
84
|
-
valid_types = %w[ruby dotnet node rust]
|
85
|
-
return if valid_types.include?(type)
|
86
|
-
|
87
|
-
puts "Error: Invalid project type '#{type}'. Valid types: #{valid_types.join(", ")}"
|
88
|
-
exit 1
|
89
|
-
end
|
90
|
-
|
91
|
-
def selected_template
|
92
|
-
return template if template
|
93
|
-
|
94
|
-
case type
|
95
|
-
when "ruby" then "ruby-gem"
|
96
|
-
when "dotnet" then "dotnet-console"
|
97
|
-
when "node" then "node-express"
|
98
|
-
when "rust" then "rust-binary"
|
99
|
-
else "basic"
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def create_project_structure(project_dir)
|
104
|
-
FileUtils.mkdir_p(project_dir)
|
105
|
-
|
106
|
-
case type
|
107
|
-
when "ruby"
|
108
|
-
create_ruby_project(project_dir)
|
109
|
-
when "dotnet"
|
110
|
-
create_dotnet_project(project_dir)
|
111
|
-
when "node"
|
112
|
-
create_node_project(project_dir)
|
113
|
-
when "rust"
|
114
|
-
create_rust_project(project_dir)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def create_ruby_project(project_dir)
|
119
|
-
# Create basic Ruby gem structure
|
120
|
-
FileUtils.mkdir_p(File.join(project_dir, "lib", project_name.tr("-", "_")))
|
121
|
-
FileUtils.mkdir_p(File.join(project_dir, "test"))
|
122
|
-
FileUtils.mkdir_p(File.join(project_dir, "bin"))
|
123
|
-
|
124
|
-
# Create main library file
|
125
|
-
lib_file = File.join(project_dir, "lib", "#{project_name.tr("-", "_")}.rb")
|
126
|
-
write_template_file(lib_file, ruby_main_template)
|
127
|
-
|
128
|
-
# Create version file
|
129
|
-
version_file = File.join(project_dir, "lib", project_name.tr("-", "_"), "version.rb")
|
130
|
-
write_template_file(version_file, ruby_version_template)
|
131
|
-
|
132
|
-
# Create gemspec
|
133
|
-
gemspec_file = File.join(project_dir, "#{project_name}.gemspec")
|
134
|
-
write_template_file(gemspec_file, ruby_gemspec_template)
|
135
|
-
|
136
|
-
# Create Gemfile
|
137
|
-
gemfile = File.join(project_dir, "Gemfile")
|
138
|
-
write_template_file(gemfile, ruby_gemfile_template)
|
139
|
-
|
140
|
-
# Create Rakefile
|
141
|
-
rakefile = File.join(project_dir, "Rakefile")
|
142
|
-
write_template_file(rakefile, ruby_rakefile_template)
|
143
|
-
|
144
|
-
# Create test file
|
145
|
-
test_file = File.join(project_dir, "test", "test_#{project_name.tr("-", "_")}.rb")
|
146
|
-
write_template_file(test_file, ruby_test_template)
|
147
|
-
|
148
|
-
# Create README
|
149
|
-
readme_file = File.join(project_dir, "README.md")
|
150
|
-
write_template_file(readme_file, readme_template)
|
151
|
-
|
152
|
-
puts " ✅ Created Ruby gem structure" if verbose?
|
153
|
-
end
|
154
|
-
|
155
|
-
def create_dotnet_project(project_dir)
|
156
|
-
# Create .NET console application structure
|
157
|
-
FileUtils.mkdir_p(File.join(project_dir, "src"))
|
158
|
-
|
159
|
-
# Create project file
|
160
|
-
csproj_file = File.join(project_dir, "src", "#{project_name}.csproj")
|
161
|
-
write_template_file(csproj_file, dotnet_csproj_template)
|
162
|
-
|
163
|
-
# Create Program.cs
|
164
|
-
program_file = File.join(project_dir, "src", "Program.cs")
|
165
|
-
write_template_file(program_file, dotnet_program_template)
|
166
|
-
|
167
|
-
# Create solution file
|
168
|
-
sln_file = File.join(project_dir, "#{project_name}.sln")
|
169
|
-
write_template_file(sln_file, dotnet_solution_template)
|
170
|
-
|
171
|
-
# Create README
|
172
|
-
readme_file = File.join(project_dir, "README.md")
|
173
|
-
write_template_file(readme_file, readme_template)
|
174
|
-
|
175
|
-
puts " ✅ Created .NET #{framework} project structure" if verbose?
|
176
|
-
end
|
177
|
-
|
178
|
-
def create_node_project(project_dir)
|
179
|
-
# Create Node.js project structure
|
180
|
-
FileUtils.mkdir_p(File.join(project_dir, "src"))
|
181
|
-
FileUtils.mkdir_p(File.join(project_dir, "test"))
|
182
|
-
|
183
|
-
# Create package.json
|
184
|
-
package_file = File.join(project_dir, "package.json")
|
185
|
-
write_template_file(package_file, node_package_template)
|
186
|
-
|
187
|
-
# Create main application file
|
188
|
-
main_file = File.join(project_dir, "src", "index.js")
|
189
|
-
write_template_file(main_file, node_main_template)
|
190
|
-
|
191
|
-
# Create test file
|
192
|
-
test_file = File.join(project_dir, "test", "index.test.js")
|
193
|
-
write_template_file(test_file, node_test_template)
|
194
|
-
|
195
|
-
# Create README
|
196
|
-
readme_file = File.join(project_dir, "README.md")
|
197
|
-
write_template_file(readme_file, readme_template)
|
198
|
-
|
199
|
-
puts " ✅ Created Node.js project structure" if verbose?
|
200
|
-
end
|
201
|
-
|
202
|
-
def create_rust_project(project_dir)
|
203
|
-
# Create Rust project structure
|
204
|
-
FileUtils.mkdir_p(File.join(project_dir, "src"))
|
205
|
-
|
206
|
-
# Create Cargo.toml
|
207
|
-
cargo_file = File.join(project_dir, "Cargo.toml")
|
208
|
-
write_template_file(cargo_file, rust_cargo_template)
|
209
|
-
|
210
|
-
# Create main.rs
|
211
|
-
main_file = File.join(project_dir, "src", "main.rs")
|
212
|
-
write_template_file(main_file, rust_main_template)
|
213
|
-
|
214
|
-
# Create README
|
215
|
-
readme_file = File.join(project_dir, "README.md")
|
216
|
-
write_template_file(readme_file, readme_template)
|
217
|
-
|
218
|
-
puts " ✅ Created Rust project structure" if verbose?
|
219
|
-
end
|
220
|
-
|
221
|
-
def write_template_file(file_path, template_content)
|
222
|
-
FileUtils.mkdir_p(File.dirname(file_path))
|
223
|
-
processed_content = ERB.new(template_content).result(binding)
|
224
|
-
File.write(file_path, processed_content)
|
225
|
-
puts " Created: #{file_path}" if verbose?
|
226
|
-
end
|
227
|
-
|
228
|
-
# Template methods
|
229
|
-
def ruby_main_template
|
230
|
-
<<~RUBY
|
231
|
-
# frozen_string_literal: true
|
232
|
-
|
233
|
-
require_relative "<%= project_name.tr("-", "_") %>/version"
|
234
|
-
|
235
|
-
module <%= project_name.split(/[-_]/).map(&:capitalize).join %>
|
236
|
-
class Error < StandardError; end
|
237
|
-
#{" "}
|
238
|
-
def self.hello
|
239
|
-
"Hello from <%= project_name %>!"
|
240
|
-
end
|
241
|
-
end
|
242
|
-
RUBY
|
243
|
-
end
|
244
|
-
|
245
|
-
def ruby_version_template
|
246
|
-
<<~RUBY
|
247
|
-
# frozen_string_literal: true
|
248
|
-
|
249
|
-
module <%= project_name.split(/[-_]/).map(&:capitalize).join %>
|
250
|
-
VERSION = "0.1.0"
|
251
|
-
end
|
252
|
-
RUBY
|
253
|
-
end
|
254
|
-
|
255
|
-
def ruby_gemspec_template
|
256
|
-
<<~RUBY
|
257
|
-
# frozen_string_literal: true
|
258
|
-
|
259
|
-
require_relative "lib/<%= project_name.tr("-", "_") %>/version"
|
260
|
-
|
261
|
-
Gem::Specification.new do |spec|
|
262
|
-
spec.name = "<%= project_name %>"
|
263
|
-
spec.version = <%= project_name.split(/[-_]/).map(&:capitalize).join %>::VERSION
|
264
|
-
spec.authors = ["Your Name"]
|
265
|
-
spec.email = ["your.email@example.com"]
|
266
|
-
|
267
|
-
spec.summary = "A new Ruby gem"
|
268
|
-
spec.description = "A longer description of your new gem"
|
269
|
-
spec.homepage = "https://github.com/yourusername/<%= project_name %>"
|
270
|
-
spec.license = "MIT"
|
271
|
-
|
272
|
-
spec.required_ruby_version = ">= 3.0.0"
|
273
|
-
|
274
|
-
spec.files = Dir.glob("lib/**/*") + ["README.md"]
|
275
|
-
spec.require_paths = ["lib"]
|
276
|
-
|
277
|
-
spec.add_development_dependency "minitest", "~> 5.0"
|
278
|
-
spec.add_development_dependency "rake", "~> 13.0"
|
279
|
-
end
|
280
|
-
RUBY
|
281
|
-
end
|
282
|
-
|
283
|
-
def ruby_gemfile_template
|
284
|
-
<<~RUBY
|
285
|
-
# frozen_string_literal: true
|
286
|
-
|
287
|
-
source "https://rubygems.org"
|
288
|
-
|
289
|
-
gemspec
|
290
|
-
RUBY
|
291
|
-
end
|
292
|
-
|
293
|
-
def ruby_rakefile_template
|
294
|
-
<<~RUBY
|
295
|
-
# frozen_string_literal: true
|
296
|
-
|
297
|
-
require "bundler/gem_tasks"
|
298
|
-
require "rake/testtask"
|
299
|
-
|
300
|
-
Rake::TestTask.new(:test) do |t|
|
301
|
-
t.libs << "test"
|
302
|
-
t.libs << "lib"
|
303
|
-
t.test_files = FileList["test/**/test_*.rb"]
|
304
|
-
end
|
305
|
-
|
306
|
-
task default: :test
|
307
|
-
RUBY
|
308
|
-
end
|
309
|
-
|
310
|
-
def ruby_test_template
|
311
|
-
<<~RUBY
|
312
|
-
# frozen_string_literal: true
|
313
|
-
|
314
|
-
require "test_helper"
|
315
|
-
require "<%= project_name.tr("-", "_") %>"
|
316
|
-
|
317
|
-
class Test<%= project_name.split(/[-_]/).map(&:capitalize).join %> < Minitest::Test
|
318
|
-
def test_version
|
319
|
-
refute_nil <%= project_name.split(/[-_]/).map(&:capitalize).join %>::VERSION
|
320
|
-
end
|
321
|
-
|
322
|
-
def test_hello
|
323
|
-
assert_equal "Hello from <%= project_name %>!", <%= project_name.split(/[-_]/).map(&:capitalize).join %>.hello
|
324
|
-
end
|
325
|
-
end
|
326
|
-
RUBY
|
327
|
-
end
|
328
|
-
|
329
|
-
def dotnet_csproj_template
|
330
|
-
<<~XML
|
331
|
-
<Project Sdk="Microsoft.NET.Sdk">
|
332
|
-
|
333
|
-
<PropertyGroup>
|
334
|
-
<OutputType>Exe</OutputType>
|
335
|
-
<TargetFramework><%= framework %></TargetFramework>
|
336
|
-
<ImplicitUsings>enable</ImplicitUsings>
|
337
|
-
<Nullable>enable</Nullable>
|
338
|
-
</PropertyGroup>
|
339
|
-
|
340
|
-
</Project>
|
341
|
-
XML
|
342
|
-
end
|
343
|
-
|
344
|
-
def dotnet_program_template
|
345
|
-
<<~CSHARP
|
346
|
-
namespace <%= project_name.split(/[-_]/).map(&:capitalize).join %>;
|
347
|
-
|
348
|
-
class Program
|
349
|
-
{
|
350
|
-
static void Main(string[] args)
|
351
|
-
{
|
352
|
-
Console.WriteLine("Hello from <%= project_name %>!");
|
353
|
-
}
|
354
|
-
}
|
355
|
-
CSHARP
|
356
|
-
end
|
357
|
-
|
358
|
-
def dotnet_solution_template
|
359
|
-
<<~TEXT
|
360
|
-
Microsoft Visual Studio Solution File, Format Version 12.00
|
361
|
-
# Visual Studio Version 17
|
362
|
-
VisualStudioVersion = 17.0.31903.59
|
363
|
-
MinimumVisualStudioVersion = 10.0.40219.1
|
364
|
-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "<%= project_name %>", "src\\<%= project_name %>.csproj", "{<%= SecureRandom.uuid.upcase %>}"
|
365
|
-
EndProject
|
366
|
-
Global
|
367
|
-
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
368
|
-
Debug|Any CPU = Debug|Any CPU
|
369
|
-
Release|Any CPU = Release|Any CPU
|
370
|
-
EndGlobalSection
|
371
|
-
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
372
|
-
{<%= SecureRandom.uuid.upcase %>}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
373
|
-
{<%= SecureRandom.uuid.upcase %>}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
374
|
-
{<%= SecureRandom.uuid.upcase %>}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
375
|
-
{<%= SecureRandom.uuid.upcase %>}.Release|Any CPU.Build.0 = Release|Any CPU
|
376
|
-
EndGlobalSection
|
377
|
-
EndGlobal
|
378
|
-
TEXT
|
379
|
-
end
|
380
|
-
|
381
|
-
def node_package_template
|
382
|
-
<<~JSON
|
383
|
-
{
|
384
|
-
"name": "<%= project_name %>",
|
385
|
-
"version": "1.0.0",
|
386
|
-
"description": "A new Node.js project",
|
387
|
-
"main": "src/index.js",
|
388
|
-
"scripts": {
|
389
|
-
"start": "node src/index.js",
|
390
|
-
"test": "jest",
|
391
|
-
"dev": "nodemon src/index.js"
|
392
|
-
},
|
393
|
-
"keywords": [],
|
394
|
-
"author": "Your Name",
|
395
|
-
"license": "MIT",
|
396
|
-
"dependencies": {
|
397
|
-
"express": "^4.18.0"
|
398
|
-
},
|
399
|
-
"devDependencies": {
|
400
|
-
"jest": "^29.0.0",
|
401
|
-
"nodemon": "^2.0.0"
|
402
|
-
}
|
403
|
-
}
|
404
|
-
JSON
|
405
|
-
end
|
406
|
-
|
407
|
-
def node_main_template
|
408
|
-
<<~JAVASCRIPT
|
409
|
-
const express = require('express');
|
410
|
-
const app = express();
|
411
|
-
const port = process.env.PORT || 3000;
|
412
|
-
|
413
|
-
app.get('/', (req, res) => {
|
414
|
-
res.json({ message: 'Hello from <%= project_name %>!' });
|
415
|
-
});
|
416
|
-
|
417
|
-
app.listen(port, () => {
|
418
|
-
console.log(`<%= project_name %> listening on port ${port}`);
|
419
|
-
});
|
420
|
-
|
421
|
-
module.exports = app;
|
422
|
-
JAVASCRIPT
|
423
|
-
end
|
424
|
-
|
425
|
-
def node_test_template
|
426
|
-
<<~JAVASCRIPT
|
427
|
-
const request = require('supertest');
|
428
|
-
const app = require('../src/index');
|
429
|
-
|
430
|
-
describe('GET /', () => {
|
431
|
-
it('should return hello message', async () => {
|
432
|
-
const res = await request(app)
|
433
|
-
.get('/')
|
434
|
-
.expect('Content-Type', /json/)
|
435
|
-
.expect(200);
|
436
|
-
#{" "}
|
437
|
-
expect(res.body.message).toBe('Hello from <%= project_name %>!');
|
438
|
-
});
|
439
|
-
});
|
440
|
-
JAVASCRIPT
|
441
|
-
end
|
442
|
-
|
443
|
-
def rust_cargo_template
|
444
|
-
<<~TOML
|
445
|
-
[package]
|
446
|
-
name = "<%= project_name %>"
|
447
|
-
version = "0.1.0"
|
448
|
-
edition = "2021"
|
449
|
-
authors = ["Your Name <your.email@example.com>"]
|
450
|
-
description = "A new Rust project"
|
451
|
-
license = "MIT"
|
452
|
-
|
453
|
-
[dependencies]
|
454
|
-
TOML
|
455
|
-
end
|
456
|
-
|
457
|
-
def rust_main_template
|
458
|
-
<<~RUST
|
459
|
-
fn main() {
|
460
|
-
println!("Hello from <%= project_name %>!");
|
461
|
-
}
|
462
|
-
|
463
|
-
#[cfg(test)]
|
464
|
-
mod tests {
|
465
|
-
use super::*;
|
466
|
-
|
467
|
-
#[test]
|
468
|
-
fn it_works() {
|
469
|
-
assert_eq!(2 + 2, 4);
|
470
|
-
}
|
471
|
-
}
|
472
|
-
RUST
|
473
|
-
end
|
474
|
-
|
475
|
-
def readme_template
|
476
|
-
<<~MARKDOWN
|
477
|
-
# <%= project_name.split(/[-_]/).map(&:capitalize).join(" ") %>
|
478
|
-
|
479
|
-
A new <%= type %> project created with Makit.
|
480
|
-
|
481
|
-
## Getting Started
|
482
|
-
|
483
|
-
<% case type %>
|
484
|
-
<% when "ruby" %>
|
485
|
-
```bash
|
486
|
-
# Install dependencies
|
487
|
-
bundle install
|
488
|
-
|
489
|
-
# Run tests
|
490
|
-
rake test
|
491
|
-
|
492
|
-
# Build gem
|
493
|
-
rake build
|
494
|
-
```
|
495
|
-
<% when "dotnet" %>
|
496
|
-
```bash
|
497
|
-
# Build project
|
498
|
-
dotnet build
|
499
|
-
|
500
|
-
# Run project
|
501
|
-
dotnet run --project src/<%= project_name %>.csproj
|
502
|
-
|
503
|
-
# Test project
|
504
|
-
dotnet test
|
505
|
-
```
|
506
|
-
<% when "node" %>
|
507
|
-
```bash
|
508
|
-
# Install dependencies
|
509
|
-
npm install
|
510
|
-
|
511
|
-
# Start development server
|
512
|
-
npm run dev
|
513
|
-
|
514
|
-
# Run tests
|
515
|
-
npm test
|
516
|
-
```
|
517
|
-
<% when "rust" %>
|
518
|
-
```bash
|
519
|
-
# Build project
|
520
|
-
cargo build
|
521
|
-
|
522
|
-
# Run project
|
523
|
-
cargo run
|
524
|
-
|
525
|
-
# Test project
|
526
|
-
cargo test
|
527
|
-
```
|
528
|
-
<% end %>
|
529
|
-
|
530
|
-
## Contributing
|
531
|
-
|
532
|
-
1. Fork the repository
|
533
|
-
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
534
|
-
3. Commit your changes (`git commit -am 'Add amazing feature'`)
|
535
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
536
|
-
5. Create a Pull Request
|
537
|
-
|
538
|
-
## License
|
539
|
-
|
540
|
-
This project is licensed under the MIT License - see the LICENSE file for details.
|
541
|
-
MARKDOWN
|
542
|
-
end
|
543
|
-
end
|
544
|
-
|
545
|
-
# Initialize existing directory as project
|
546
|
-
class InitProjectCommand < Clamp::Command
|
547
|
-
self.description = <<~DESC
|
548
|
-
Initialize an existing directory as a Makit-managed project.
|
549
|
-
|
550
|
-
Examples:
|
551
|
-
makit project init
|
552
|
-
makit project init --type ruby
|
553
|
-
makit project init /path/to/existing/project
|
554
|
-
DESC
|
555
|
-
|
556
|
-
parameter "PATH", "Path to initialize (default: current directory)", attribute_name: :path, default: Dir.pwd
|
557
|
-
option ["--type", "-t"], "TYPE", "Project type (ruby, dotnet, node, rust)", default: "auto"
|
558
|
-
option ["--force"], :flag, "Force initialization even if project files exist"
|
559
|
-
|
560
|
-
def execute
|
561
|
-
init_path = File.expand_path(path)
|
562
|
-
|
563
|
-
unless Dir.exist?(init_path)
|
564
|
-
puts "Error: Directory does not exist: #{init_path}"
|
565
|
-
exit 1
|
566
|
-
end
|
567
|
-
|
568
|
-
detected_type = detect_project_type(init_path)
|
569
|
-
actual_type = type == "auto" ? detected_type : type
|
570
|
-
|
571
|
-
if actual_type == "unknown"
|
572
|
-
puts "Error: Could not detect project type. Please specify --type explicitly."
|
573
|
-
exit 1
|
574
|
-
end
|
575
|
-
|
576
|
-
puts "Initializing #{actual_type} project in: #{init_path}"
|
577
|
-
|
578
|
-
if has_project_files?(init_path, actual_type) && !force?
|
579
|
-
puts "Error: Project files already exist. Use --force to overwrite."
|
580
|
-
exit 1
|
581
|
-
end
|
582
|
-
|
583
|
-
initialize_project(init_path, actual_type)
|
584
|
-
puts "✅ Successfully initialized #{actual_type} project"
|
585
|
-
end
|
586
|
-
|
587
|
-
private
|
588
|
-
|
589
|
-
def detect_project_type(dir)
|
590
|
-
return "ruby" if File.exist?(File.join(dir, "Gemfile")) || File.exist?(File.join(dir, ".gemspec"))
|
591
|
-
return "dotnet" if Dir.glob(File.join(dir, "*.csproj")).any? || Dir.glob(File.join(dir, "*.sln")).any?
|
592
|
-
return "node" if File.exist?(File.join(dir, "package.json"))
|
593
|
-
return "rust" if File.exist?(File.join(dir, "Cargo.toml"))
|
594
|
-
|
595
|
-
"unknown"
|
596
|
-
end
|
597
|
-
|
598
|
-
def has_project_files?(dir, project_type)
|
599
|
-
case project_type
|
600
|
-
when "ruby"
|
601
|
-
File.exist?(File.join(dir, "Rakefile"))
|
602
|
-
when "dotnet"
|
603
|
-
Dir.glob(File.join(dir, "*.csproj")).any?
|
604
|
-
when "node"
|
605
|
-
File.exist?(File.join(dir, "package.json"))
|
606
|
-
when "rust"
|
607
|
-
File.exist?(File.join(dir, "Cargo.toml"))
|
608
|
-
else
|
609
|
-
false
|
610
|
-
end
|
611
|
-
end
|
612
|
-
|
613
|
-
def initialize_project(dir, project_type)
|
614
|
-
case project_type
|
615
|
-
when "ruby"
|
616
|
-
initialize_ruby_project(dir)
|
617
|
-
when "dotnet"
|
618
|
-
initialize_dotnet_project(dir)
|
619
|
-
when "node"
|
620
|
-
initialize_node_project(dir)
|
621
|
-
when "rust"
|
622
|
-
initialize_rust_project(dir)
|
623
|
-
end
|
624
|
-
end
|
625
|
-
|
626
|
-
def initialize_ruby_project(dir)
|
627
|
-
File.write(File.join(dir, "Rakefile"), basic_ruby_rakefile) unless File.exist?(File.join(dir, "Rakefile"))
|
628
|
-
|
629
|
-
return if Dir.exist?(File.join(dir, "test"))
|
630
|
-
|
631
|
-
FileUtils.mkdir_p(File.join(dir, "test"))
|
632
|
-
end
|
633
|
-
|
634
|
-
def initialize_dotnet_project(_dir)
|
635
|
-
# Add any .NET-specific initialization if needed
|
636
|
-
puts " ✅ .NET project initialized"
|
637
|
-
end
|
638
|
-
|
639
|
-
def initialize_node_project(_dir)
|
640
|
-
# Add any Node.js-specific initialization if needed
|
641
|
-
puts " ✅ Node.js project initialized"
|
642
|
-
end
|
643
|
-
|
644
|
-
def initialize_rust_project(_dir)
|
645
|
-
# Add any Rust-specific initialization if needed
|
646
|
-
puts " ✅ Rust project initialized"
|
647
|
-
end
|
648
|
-
|
649
|
-
def basic_ruby_rakefile
|
650
|
-
<<~RUBY
|
651
|
-
# frozen_string_literal: true
|
652
|
-
|
653
|
-
require "rake/testtask"
|
654
|
-
|
655
|
-
Rake::TestTask.new(:test) do |t|
|
656
|
-
t.libs << "test"
|
657
|
-
t.libs << "lib"
|
658
|
-
t.test_files = FileList["test/**/test_*.rb"]
|
659
|
-
end
|
660
|
-
|
661
|
-
task default: :test
|
662
|
-
RUBY
|
663
|
-
end
|
664
|
-
end
|
665
|
-
|
666
|
-
# Setup project dependencies and configuration
|
667
|
-
class SetupProjectCommand < Clamp::Command
|
668
|
-
self.description = <<~DESC
|
669
|
-
Setup project dependencies and development environment.
|
670
|
-
|
671
|
-
Examples:
|
672
|
-
makit project setup
|
673
|
-
makit project setup --skip-deps
|
674
|
-
makit project setup /path/to/project
|
675
|
-
DESC
|
676
|
-
|
677
|
-
parameter "PATH", "Path to project (default: current directory)", attribute_name: :path, default: Dir.pwd
|
678
|
-
option ["--skip-deps"], :flag, "Skip dependency installation"
|
679
|
-
option ["--verbose"], :flag, "Show verbose output"
|
680
|
-
|
681
|
-
def execute
|
682
|
-
project_path = File.expand_path(path)
|
683
|
-
|
684
|
-
unless Dir.exist?(project_path)
|
685
|
-
puts "Error: Directory does not exist: #{project_path}"
|
686
|
-
exit 1
|
687
|
-
end
|
688
|
-
|
689
|
-
project_type = detect_project_type(project_path)
|
690
|
-
|
691
|
-
if project_type == "unknown"
|
692
|
-
puts "Error: Could not detect project type in: #{project_path}"
|
693
|
-
exit 1
|
694
|
-
end
|
695
|
-
|
696
|
-
puts "Setting up #{project_type} project dependencies..."
|
697
|
-
|
698
|
-
Dir.chdir(project_path) do
|
699
|
-
setup_project(project_type)
|
700
|
-
end
|
701
|
-
|
702
|
-
puts "✅ Project setup completed successfully"
|
703
|
-
end
|
704
|
-
|
705
|
-
private
|
706
|
-
|
707
|
-
def detect_project_type(dir)
|
708
|
-
return "ruby" if File.exist?(File.join(dir, "Gemfile"))
|
709
|
-
return "dotnet" if Dir.glob(File.join(dir, "*.csproj")).any? || Dir.glob(File.join(dir, "*.sln")).any?
|
710
|
-
return "node" if File.exist?(File.join(dir, "package.json"))
|
711
|
-
return "rust" if File.exist?(File.join(dir, "Cargo.toml"))
|
712
|
-
|
713
|
-
"unknown"
|
714
|
-
end
|
715
|
-
|
716
|
-
def setup_project(project_type)
|
717
|
-
case project_type
|
718
|
-
when "ruby"
|
719
|
-
setup_ruby_project
|
720
|
-
when "dotnet"
|
721
|
-
setup_dotnet_project
|
722
|
-
when "node"
|
723
|
-
setup_node_project
|
724
|
-
when "rust"
|
725
|
-
setup_rust_project
|
726
|
-
end
|
727
|
-
end
|
728
|
-
|
729
|
-
def setup_ruby_project
|
730
|
-
unless skip_deps?
|
731
|
-
puts " Installing Ruby dependencies..."
|
732
|
-
system("bundle install") || puts("Warning: bundle install failed")
|
733
|
-
end
|
734
|
-
|
735
|
-
puts " ✅ Ruby project setup complete"
|
736
|
-
end
|
737
|
-
|
738
|
-
def setup_dotnet_project
|
739
|
-
unless skip_deps?
|
740
|
-
puts " Restoring .NET dependencies..."
|
741
|
-
system("dotnet restore") || puts("Warning: dotnet restore failed")
|
742
|
-
end
|
743
|
-
|
744
|
-
puts " ✅ .NET project setup complete"
|
745
|
-
end
|
746
|
-
|
747
|
-
def setup_node_project
|
748
|
-
unless skip_deps?
|
749
|
-
puts " Installing Node.js dependencies..."
|
750
|
-
if File.exist?("package-lock.json")
|
751
|
-
system("npm ci") || puts("Warning: npm ci failed")
|
752
|
-
else
|
753
|
-
system("npm install") || puts("Warning: npm install failed")
|
754
|
-
end
|
755
|
-
end
|
756
|
-
|
757
|
-
puts " ✅ Node.js project setup complete"
|
758
|
-
end
|
759
|
-
|
760
|
-
def setup_rust_project
|
761
|
-
unless skip_deps?
|
762
|
-
puts " Building Rust project..."
|
763
|
-
system("cargo build") || puts("Warning: cargo build failed")
|
764
|
-
end
|
765
|
-
|
766
|
-
puts " ✅ Rust project setup complete"
|
767
|
-
end
|
768
|
-
end
|
769
|
-
|
770
|
-
# Open project in IDE or navigate to directory
|
771
|
-
class WorkProjectCommand < Clamp::Command
|
772
|
-
self.description = <<~DESC
|
773
|
-
Open project in your preferred IDE or navigate to project directory.
|
774
|
-
|
775
|
-
Examples:
|
776
|
-
makit project work
|
777
|
-
makit project work /path/to/project
|
778
|
-
makit project work --editor code
|
779
|
-
DESC
|
780
|
-
|
781
|
-
parameter "PATH", "Path to project (default: current directory)", attribute_name: :path, default: Dir.pwd
|
782
|
-
option ["--editor"], "EDITOR", "Preferred editor (code, subl, atom, vim)", default: "auto"
|
783
|
-
option ["--list-editors"], :flag, "List available editors"
|
784
|
-
|
785
|
-
def execute
|
786
|
-
if list_editors?
|
787
|
-
show_available_editors
|
788
|
-
return
|
789
|
-
end
|
790
|
-
|
791
|
-
project_path = File.expand_path(path)
|
792
|
-
|
793
|
-
unless Dir.exist?(project_path)
|
794
|
-
puts "Error: Directory does not exist: #{project_path}"
|
795
|
-
exit 1
|
796
|
-
end
|
797
|
-
|
798
|
-
editor_cmd = determine_editor
|
799
|
-
|
800
|
-
if editor_cmd
|
801
|
-
puts "Opening project in #{editor_cmd}..."
|
802
|
-
launch_editor(editor_cmd, project_path)
|
803
|
-
else
|
804
|
-
puts "No suitable editor found. Available editors:"
|
805
|
-
show_available_editors
|
806
|
-
puts "\nNavigating to project directory: #{project_path}"
|
807
|
-
puts "Run: cd #{project_path}"
|
808
|
-
end
|
809
|
-
end
|
810
|
-
|
811
|
-
private
|
812
|
-
|
813
|
-
def show_available_editors
|
814
|
-
editors = {
|
815
|
-
"code" => "Visual Studio Code",
|
816
|
-
"subl" => "Sublime Text",
|
817
|
-
"atom" => "Atom",
|
818
|
-
"vim" => "Vim",
|
819
|
-
"nvim" => "Neovim",
|
820
|
-
"emacs" => "Emacs",
|
821
|
-
}
|
822
|
-
|
823
|
-
puts "Available editors:"
|
824
|
-
editors.each do |cmd, name|
|
825
|
-
available = system("which #{cmd} > /dev/null 2>&1")
|
826
|
-
status = available ? "✅" : "❌"
|
827
|
-
puts " #{status} #{name} (#{cmd})"
|
828
|
-
end
|
829
|
-
end
|
830
|
-
|
831
|
-
def determine_editor
|
832
|
-
return editor if editor != "auto" && editor_available?(editor)
|
833
|
-
|
834
|
-
# Try to detect available editors in preference order
|
835
|
-
preferred_editors = %w[code subl atom vim nvim]
|
836
|
-
preferred_editors.find { |ed| editor_available?(ed) }
|
837
|
-
end
|
838
|
-
|
839
|
-
def editor_available?(editor_name)
|
840
|
-
system("which #{editor_name} > /dev/null 2>&1")
|
841
|
-
end
|
842
|
-
|
843
|
-
def launch_editor(editor_cmd, project_path)
|
844
|
-
case editor_cmd
|
845
|
-
when "code"
|
846
|
-
system("code '#{project_path}'")
|
847
|
-
when "subl"
|
848
|
-
system("subl '#{project_path}'")
|
849
|
-
when "atom"
|
850
|
-
system("atom '#{project_path}'")
|
851
|
-
when "vim", "nvim"
|
852
|
-
system("#{editor_cmd} '#{project_path}'")
|
853
|
-
when "emacs"
|
854
|
-
system("emacs '#{project_path}' &")
|
855
|
-
else
|
856
|
-
puts "Unknown editor: #{editor_cmd}"
|
857
|
-
exit 1
|
858
|
-
end
|
859
|
-
end
|
860
|
-
end
|
861
|
-
|
862
|
-
# Add subcommand declarations after all classes are defined
|
863
|
-
ProjectCommand.subcommand "new", "Create new project from template", NewProjectCommand
|
864
|
-
ProjectCommand.subcommand "init", "Initialize existing directory as project", InitProjectCommand
|
865
|
-
ProjectCommand.subcommand "setup", "Setup project dependencies", SetupProjectCommand
|
866
|
-
ProjectCommand.subcommand "work", "Open project in IDE", WorkProjectCommand
|
867
|
-
end
|
868
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "clamp"
|
4
|
+
require "fileutils"
|
5
|
+
require "erb"
|
6
|
+
|
7
|
+
module Makit
|
8
|
+
module Cli
|
9
|
+
# Consolidated project management commands
|
10
|
+
# Combines: new, init, setup, work functionality
|
11
|
+
class ProjectCommand < Clamp::Command
|
12
|
+
self.description = <<~DESC
|
13
|
+
Manage project creation, initialization, and workspace setup.
|
14
|
+
|
15
|
+
Available operations:
|
16
|
+
new - Create new project from template
|
17
|
+
init - Initialize existing directory as project
|
18
|
+
setup - Setup project dependencies and configuration#{" "}
|
19
|
+
work - Open project in IDE or navigate to directory
|
20
|
+
DESC
|
21
|
+
end
|
22
|
+
|
23
|
+
# Create new project from template
|
24
|
+
class NewProjectCommand < Clamp::Command
|
25
|
+
self.description = <<~DESC
|
26
|
+
Create a new project from available templates.
|
27
|
+
|
28
|
+
Examples:
|
29
|
+
makit project new my-app --type ruby
|
30
|
+
makit project new WebApp --type dotnet --framework net8.0
|
31
|
+
makit project new api-service --type node
|
32
|
+
DESC
|
33
|
+
|
34
|
+
parameter "PROJECT_NAME", "Name of the new project", attribute_name: :project_name, required: true
|
35
|
+
option ["--type", "-t"], "TYPE", "Project type (ruby, dotnet, node, rust)", default: "ruby"
|
36
|
+
option ["--framework"], "FRAMEWORK", "Target framework (for .NET projects)", default: "net8.0"
|
37
|
+
option ["--template"], "TEMPLATE", "Specific template to use"
|
38
|
+
option ["--directory", "-d"], "DIR", "Parent directory for new project", default: Dir.pwd
|
39
|
+
option ["--dry-run"], :flag, "Show what would be created without actually creating"
|
40
|
+
option ["--verbose"], :flag, "Show verbose output"
|
41
|
+
|
42
|
+
def execute
|
43
|
+
validate_project_name
|
44
|
+
validate_project_type
|
45
|
+
|
46
|
+
project_dir = File.join(directory, project_name)
|
47
|
+
|
48
|
+
if Dir.exist?(project_dir)
|
49
|
+
puts "Error: Project directory already exists: #{project_dir}"
|
50
|
+
exit 1
|
51
|
+
end
|
52
|
+
|
53
|
+
puts "Creating #{type} project: #{project_name}"
|
54
|
+
puts "Location: #{project_dir}"
|
55
|
+
puts "Template: #{selected_template}" if verbose?
|
56
|
+
|
57
|
+
return if dry_run?
|
58
|
+
|
59
|
+
create_project_structure(project_dir)
|
60
|
+
puts "✅ Successfully created #{type} project: #{project_name}"
|
61
|
+
puts "📁 Project location: #{project_dir}"
|
62
|
+
puts "\nNext steps:"
|
63
|
+
puts " cd #{project_name}"
|
64
|
+
puts " makit project setup # Setup dependencies"
|
65
|
+
puts " makit project work # Open in IDE"
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def validate_project_name
|
71
|
+
if project_name.nil? || project_name.strip.empty?
|
72
|
+
puts "Error: Project name cannot be empty"
|
73
|
+
exit 1
|
74
|
+
end
|
75
|
+
|
76
|
+
# Check for valid project name characters
|
77
|
+
return if project_name.match?(/\A[a-zA-Z0-9][a-zA-Z0-9._-]*\z/)
|
78
|
+
|
79
|
+
puts "Error: Project name must start with letter/number and contain only letters, numbers, dots, hyphens, and underscores"
|
80
|
+
exit 1
|
81
|
+
end
|
82
|
+
|
83
|
+
def validate_project_type
|
84
|
+
valid_types = %w[ruby dotnet node rust]
|
85
|
+
return if valid_types.include?(type)
|
86
|
+
|
87
|
+
puts "Error: Invalid project type '#{type}'. Valid types: #{valid_types.join(", ")}"
|
88
|
+
exit 1
|
89
|
+
end
|
90
|
+
|
91
|
+
def selected_template
|
92
|
+
return template if template
|
93
|
+
|
94
|
+
case type
|
95
|
+
when "ruby" then "ruby-gem"
|
96
|
+
when "dotnet" then "dotnet-console"
|
97
|
+
when "node" then "node-express"
|
98
|
+
when "rust" then "rust-binary"
|
99
|
+
else "basic"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def create_project_structure(project_dir)
|
104
|
+
FileUtils.mkdir_p(project_dir)
|
105
|
+
|
106
|
+
case type
|
107
|
+
when "ruby"
|
108
|
+
create_ruby_project(project_dir)
|
109
|
+
when "dotnet"
|
110
|
+
create_dotnet_project(project_dir)
|
111
|
+
when "node"
|
112
|
+
create_node_project(project_dir)
|
113
|
+
when "rust"
|
114
|
+
create_rust_project(project_dir)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def create_ruby_project(project_dir)
|
119
|
+
# Create basic Ruby gem structure
|
120
|
+
FileUtils.mkdir_p(File.join(project_dir, "lib", project_name.tr("-", "_")))
|
121
|
+
FileUtils.mkdir_p(File.join(project_dir, "test"))
|
122
|
+
FileUtils.mkdir_p(File.join(project_dir, "bin"))
|
123
|
+
|
124
|
+
# Create main library file
|
125
|
+
lib_file = File.join(project_dir, "lib", "#{project_name.tr("-", "_")}.rb")
|
126
|
+
write_template_file(lib_file, ruby_main_template)
|
127
|
+
|
128
|
+
# Create version file
|
129
|
+
version_file = File.join(project_dir, "lib", project_name.tr("-", "_"), "version.rb")
|
130
|
+
write_template_file(version_file, ruby_version_template)
|
131
|
+
|
132
|
+
# Create gemspec
|
133
|
+
gemspec_file = File.join(project_dir, "#{project_name}.gemspec")
|
134
|
+
write_template_file(gemspec_file, ruby_gemspec_template)
|
135
|
+
|
136
|
+
# Create Gemfile
|
137
|
+
gemfile = File.join(project_dir, "Gemfile")
|
138
|
+
write_template_file(gemfile, ruby_gemfile_template)
|
139
|
+
|
140
|
+
# Create Rakefile
|
141
|
+
rakefile = File.join(project_dir, "Rakefile")
|
142
|
+
write_template_file(rakefile, ruby_rakefile_template)
|
143
|
+
|
144
|
+
# Create test file
|
145
|
+
test_file = File.join(project_dir, "test", "test_#{project_name.tr("-", "_")}.rb")
|
146
|
+
write_template_file(test_file, ruby_test_template)
|
147
|
+
|
148
|
+
# Create README
|
149
|
+
readme_file = File.join(project_dir, "README.md")
|
150
|
+
write_template_file(readme_file, readme_template)
|
151
|
+
|
152
|
+
puts " ✅ Created Ruby gem structure" if verbose?
|
153
|
+
end
|
154
|
+
|
155
|
+
def create_dotnet_project(project_dir)
|
156
|
+
# Create .NET console application structure
|
157
|
+
FileUtils.mkdir_p(File.join(project_dir, "src"))
|
158
|
+
|
159
|
+
# Create project file
|
160
|
+
csproj_file = File.join(project_dir, "src", "#{project_name}.csproj")
|
161
|
+
write_template_file(csproj_file, dotnet_csproj_template)
|
162
|
+
|
163
|
+
# Create Program.cs
|
164
|
+
program_file = File.join(project_dir, "src", "Program.cs")
|
165
|
+
write_template_file(program_file, dotnet_program_template)
|
166
|
+
|
167
|
+
# Create solution file
|
168
|
+
sln_file = File.join(project_dir, "#{project_name}.sln")
|
169
|
+
write_template_file(sln_file, dotnet_solution_template)
|
170
|
+
|
171
|
+
# Create README
|
172
|
+
readme_file = File.join(project_dir, "README.md")
|
173
|
+
write_template_file(readme_file, readme_template)
|
174
|
+
|
175
|
+
puts " ✅ Created .NET #{framework} project structure" if verbose?
|
176
|
+
end
|
177
|
+
|
178
|
+
def create_node_project(project_dir)
|
179
|
+
# Create Node.js project structure
|
180
|
+
FileUtils.mkdir_p(File.join(project_dir, "src"))
|
181
|
+
FileUtils.mkdir_p(File.join(project_dir, "test"))
|
182
|
+
|
183
|
+
# Create package.json
|
184
|
+
package_file = File.join(project_dir, "package.json")
|
185
|
+
write_template_file(package_file, node_package_template)
|
186
|
+
|
187
|
+
# Create main application file
|
188
|
+
main_file = File.join(project_dir, "src", "index.js")
|
189
|
+
write_template_file(main_file, node_main_template)
|
190
|
+
|
191
|
+
# Create test file
|
192
|
+
test_file = File.join(project_dir, "test", "index.test.js")
|
193
|
+
write_template_file(test_file, node_test_template)
|
194
|
+
|
195
|
+
# Create README
|
196
|
+
readme_file = File.join(project_dir, "README.md")
|
197
|
+
write_template_file(readme_file, readme_template)
|
198
|
+
|
199
|
+
puts " ✅ Created Node.js project structure" if verbose?
|
200
|
+
end
|
201
|
+
|
202
|
+
def create_rust_project(project_dir)
|
203
|
+
# Create Rust project structure
|
204
|
+
FileUtils.mkdir_p(File.join(project_dir, "src"))
|
205
|
+
|
206
|
+
# Create Cargo.toml
|
207
|
+
cargo_file = File.join(project_dir, "Cargo.toml")
|
208
|
+
write_template_file(cargo_file, rust_cargo_template)
|
209
|
+
|
210
|
+
# Create main.rs
|
211
|
+
main_file = File.join(project_dir, "src", "main.rs")
|
212
|
+
write_template_file(main_file, rust_main_template)
|
213
|
+
|
214
|
+
# Create README
|
215
|
+
readme_file = File.join(project_dir, "README.md")
|
216
|
+
write_template_file(readme_file, readme_template)
|
217
|
+
|
218
|
+
puts " ✅ Created Rust project structure" if verbose?
|
219
|
+
end
|
220
|
+
|
221
|
+
def write_template_file(file_path, template_content)
|
222
|
+
FileUtils.mkdir_p(File.dirname(file_path))
|
223
|
+
processed_content = ERB.new(template_content).result(binding)
|
224
|
+
File.write(file_path, processed_content)
|
225
|
+
puts " Created: #{file_path}" if verbose?
|
226
|
+
end
|
227
|
+
|
228
|
+
# Template methods
|
229
|
+
def ruby_main_template
|
230
|
+
<<~RUBY
|
231
|
+
# frozen_string_literal: true
|
232
|
+
|
233
|
+
require_relative "<%= project_name.tr("-", "_") %>/version"
|
234
|
+
|
235
|
+
module <%= project_name.split(/[-_]/).map(&:capitalize).join %>
|
236
|
+
class Error < StandardError; end
|
237
|
+
#{" "}
|
238
|
+
def self.hello
|
239
|
+
"Hello from <%= project_name %>!"
|
240
|
+
end
|
241
|
+
end
|
242
|
+
RUBY
|
243
|
+
end
|
244
|
+
|
245
|
+
def ruby_version_template
|
246
|
+
<<~RUBY
|
247
|
+
# frozen_string_literal: true
|
248
|
+
|
249
|
+
module <%= project_name.split(/[-_]/).map(&:capitalize).join %>
|
250
|
+
VERSION = "0.1.0"
|
251
|
+
end
|
252
|
+
RUBY
|
253
|
+
end
|
254
|
+
|
255
|
+
def ruby_gemspec_template
|
256
|
+
<<~RUBY
|
257
|
+
# frozen_string_literal: true
|
258
|
+
|
259
|
+
require_relative "lib/<%= project_name.tr("-", "_") %>/version"
|
260
|
+
|
261
|
+
Gem::Specification.new do |spec|
|
262
|
+
spec.name = "<%= project_name %>"
|
263
|
+
spec.version = <%= project_name.split(/[-_]/).map(&:capitalize).join %>::VERSION
|
264
|
+
spec.authors = ["Your Name"]
|
265
|
+
spec.email = ["your.email@example.com"]
|
266
|
+
|
267
|
+
spec.summary = "A new Ruby gem"
|
268
|
+
spec.description = "A longer description of your new gem"
|
269
|
+
spec.homepage = "https://github.com/yourusername/<%= project_name %>"
|
270
|
+
spec.license = "MIT"
|
271
|
+
|
272
|
+
spec.required_ruby_version = ">= 3.0.0"
|
273
|
+
|
274
|
+
spec.files = Dir.glob("lib/**/*") + ["README.md"]
|
275
|
+
spec.require_paths = ["lib"]
|
276
|
+
|
277
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
278
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
279
|
+
end
|
280
|
+
RUBY
|
281
|
+
end
|
282
|
+
|
283
|
+
def ruby_gemfile_template
|
284
|
+
<<~RUBY
|
285
|
+
# frozen_string_literal: true
|
286
|
+
|
287
|
+
source "https://rubygems.org"
|
288
|
+
|
289
|
+
gemspec
|
290
|
+
RUBY
|
291
|
+
end
|
292
|
+
|
293
|
+
def ruby_rakefile_template
|
294
|
+
<<~RUBY
|
295
|
+
# frozen_string_literal: true
|
296
|
+
|
297
|
+
require "bundler/gem_tasks"
|
298
|
+
require "rake/testtask"
|
299
|
+
|
300
|
+
Rake::TestTask.new(:test) do |t|
|
301
|
+
t.libs << "test"
|
302
|
+
t.libs << "lib"
|
303
|
+
t.test_files = FileList["test/**/test_*.rb"]
|
304
|
+
end
|
305
|
+
|
306
|
+
task default: :test
|
307
|
+
RUBY
|
308
|
+
end
|
309
|
+
|
310
|
+
def ruby_test_template
|
311
|
+
<<~RUBY
|
312
|
+
# frozen_string_literal: true
|
313
|
+
|
314
|
+
require "test_helper"
|
315
|
+
require "<%= project_name.tr("-", "_") %>"
|
316
|
+
|
317
|
+
class Test<%= project_name.split(/[-_]/).map(&:capitalize).join %> < Minitest::Test
|
318
|
+
def test_version
|
319
|
+
refute_nil <%= project_name.split(/[-_]/).map(&:capitalize).join %>::VERSION
|
320
|
+
end
|
321
|
+
|
322
|
+
def test_hello
|
323
|
+
assert_equal "Hello from <%= project_name %>!", <%= project_name.split(/[-_]/).map(&:capitalize).join %>.hello
|
324
|
+
end
|
325
|
+
end
|
326
|
+
RUBY
|
327
|
+
end
|
328
|
+
|
329
|
+
def dotnet_csproj_template
|
330
|
+
<<~XML
|
331
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
332
|
+
|
333
|
+
<PropertyGroup>
|
334
|
+
<OutputType>Exe</OutputType>
|
335
|
+
<TargetFramework><%= framework %></TargetFramework>
|
336
|
+
<ImplicitUsings>enable</ImplicitUsings>
|
337
|
+
<Nullable>enable</Nullable>
|
338
|
+
</PropertyGroup>
|
339
|
+
|
340
|
+
</Project>
|
341
|
+
XML
|
342
|
+
end
|
343
|
+
|
344
|
+
def dotnet_program_template
|
345
|
+
<<~CSHARP
|
346
|
+
namespace <%= project_name.split(/[-_]/).map(&:capitalize).join %>;
|
347
|
+
|
348
|
+
class Program
|
349
|
+
{
|
350
|
+
static void Main(string[] args)
|
351
|
+
{
|
352
|
+
Console.WriteLine("Hello from <%= project_name %>!");
|
353
|
+
}
|
354
|
+
}
|
355
|
+
CSHARP
|
356
|
+
end
|
357
|
+
|
358
|
+
def dotnet_solution_template
|
359
|
+
<<~TEXT
|
360
|
+
Microsoft Visual Studio Solution File, Format Version 12.00
|
361
|
+
# Visual Studio Version 17
|
362
|
+
VisualStudioVersion = 17.0.31903.59
|
363
|
+
MinimumVisualStudioVersion = 10.0.40219.1
|
364
|
+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "<%= project_name %>", "src\\<%= project_name %>.csproj", "{<%= SecureRandom.uuid.upcase %>}"
|
365
|
+
EndProject
|
366
|
+
Global
|
367
|
+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
368
|
+
Debug|Any CPU = Debug|Any CPU
|
369
|
+
Release|Any CPU = Release|Any CPU
|
370
|
+
EndGlobalSection
|
371
|
+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
372
|
+
{<%= SecureRandom.uuid.upcase %>}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
373
|
+
{<%= SecureRandom.uuid.upcase %>}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
374
|
+
{<%= SecureRandom.uuid.upcase %>}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
375
|
+
{<%= SecureRandom.uuid.upcase %>}.Release|Any CPU.Build.0 = Release|Any CPU
|
376
|
+
EndGlobalSection
|
377
|
+
EndGlobal
|
378
|
+
TEXT
|
379
|
+
end
|
380
|
+
|
381
|
+
def node_package_template
|
382
|
+
<<~JSON
|
383
|
+
{
|
384
|
+
"name": "<%= project_name %>",
|
385
|
+
"version": "1.0.0",
|
386
|
+
"description": "A new Node.js project",
|
387
|
+
"main": "src/index.js",
|
388
|
+
"scripts": {
|
389
|
+
"start": "node src/index.js",
|
390
|
+
"test": "jest",
|
391
|
+
"dev": "nodemon src/index.js"
|
392
|
+
},
|
393
|
+
"keywords": [],
|
394
|
+
"author": "Your Name",
|
395
|
+
"license": "MIT",
|
396
|
+
"dependencies": {
|
397
|
+
"express": "^4.18.0"
|
398
|
+
},
|
399
|
+
"devDependencies": {
|
400
|
+
"jest": "^29.0.0",
|
401
|
+
"nodemon": "^2.0.0"
|
402
|
+
}
|
403
|
+
}
|
404
|
+
JSON
|
405
|
+
end
|
406
|
+
|
407
|
+
def node_main_template
|
408
|
+
<<~JAVASCRIPT
|
409
|
+
const express = require('express');
|
410
|
+
const app = express();
|
411
|
+
const port = process.env.PORT || 3000;
|
412
|
+
|
413
|
+
app.get('/', (req, res) => {
|
414
|
+
res.json({ message: 'Hello from <%= project_name %>!' });
|
415
|
+
});
|
416
|
+
|
417
|
+
app.listen(port, () => {
|
418
|
+
console.log(`<%= project_name %> listening on port ${port}`);
|
419
|
+
});
|
420
|
+
|
421
|
+
module.exports = app;
|
422
|
+
JAVASCRIPT
|
423
|
+
end
|
424
|
+
|
425
|
+
def node_test_template
|
426
|
+
<<~JAVASCRIPT
|
427
|
+
const request = require('supertest');
|
428
|
+
const app = require('../src/index');
|
429
|
+
|
430
|
+
describe('GET /', () => {
|
431
|
+
it('should return hello message', async () => {
|
432
|
+
const res = await request(app)
|
433
|
+
.get('/')
|
434
|
+
.expect('Content-Type', /json/)
|
435
|
+
.expect(200);
|
436
|
+
#{" "}
|
437
|
+
expect(res.body.message).toBe('Hello from <%= project_name %>!');
|
438
|
+
});
|
439
|
+
});
|
440
|
+
JAVASCRIPT
|
441
|
+
end
|
442
|
+
|
443
|
+
def rust_cargo_template
|
444
|
+
<<~TOML
|
445
|
+
[package]
|
446
|
+
name = "<%= project_name %>"
|
447
|
+
version = "0.1.0"
|
448
|
+
edition = "2021"
|
449
|
+
authors = ["Your Name <your.email@example.com>"]
|
450
|
+
description = "A new Rust project"
|
451
|
+
license = "MIT"
|
452
|
+
|
453
|
+
[dependencies]
|
454
|
+
TOML
|
455
|
+
end
|
456
|
+
|
457
|
+
def rust_main_template
|
458
|
+
<<~RUST
|
459
|
+
fn main() {
|
460
|
+
println!("Hello from <%= project_name %>!");
|
461
|
+
}
|
462
|
+
|
463
|
+
#[cfg(test)]
|
464
|
+
mod tests {
|
465
|
+
use super::*;
|
466
|
+
|
467
|
+
#[test]
|
468
|
+
fn it_works() {
|
469
|
+
assert_eq!(2 + 2, 4);
|
470
|
+
}
|
471
|
+
}
|
472
|
+
RUST
|
473
|
+
end
|
474
|
+
|
475
|
+
def readme_template
|
476
|
+
<<~MARKDOWN
|
477
|
+
# <%= project_name.split(/[-_]/).map(&:capitalize).join(" ") %>
|
478
|
+
|
479
|
+
A new <%= type %> project created with Makit.
|
480
|
+
|
481
|
+
## Getting Started
|
482
|
+
|
483
|
+
<% case type %>
|
484
|
+
<% when "ruby" %>
|
485
|
+
```bash
|
486
|
+
# Install dependencies
|
487
|
+
bundle install
|
488
|
+
|
489
|
+
# Run tests
|
490
|
+
rake test
|
491
|
+
|
492
|
+
# Build gem
|
493
|
+
rake build
|
494
|
+
```
|
495
|
+
<% when "dotnet" %>
|
496
|
+
```bash
|
497
|
+
# Build project
|
498
|
+
dotnet build
|
499
|
+
|
500
|
+
# Run project
|
501
|
+
dotnet run --project src/<%= project_name %>.csproj
|
502
|
+
|
503
|
+
# Test project
|
504
|
+
dotnet test
|
505
|
+
```
|
506
|
+
<% when "node" %>
|
507
|
+
```bash
|
508
|
+
# Install dependencies
|
509
|
+
npm install
|
510
|
+
|
511
|
+
# Start development server
|
512
|
+
npm run dev
|
513
|
+
|
514
|
+
# Run tests
|
515
|
+
npm test
|
516
|
+
```
|
517
|
+
<% when "rust" %>
|
518
|
+
```bash
|
519
|
+
# Build project
|
520
|
+
cargo build
|
521
|
+
|
522
|
+
# Run project
|
523
|
+
cargo run
|
524
|
+
|
525
|
+
# Test project
|
526
|
+
cargo test
|
527
|
+
```
|
528
|
+
<% end %>
|
529
|
+
|
530
|
+
## Contributing
|
531
|
+
|
532
|
+
1. Fork the repository
|
533
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
534
|
+
3. Commit your changes (`git commit -am 'Add amazing feature'`)
|
535
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
536
|
+
5. Create a Pull Request
|
537
|
+
|
538
|
+
## License
|
539
|
+
|
540
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
541
|
+
MARKDOWN
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
# Initialize existing directory as project
|
546
|
+
class InitProjectCommand < Clamp::Command
|
547
|
+
self.description = <<~DESC
|
548
|
+
Initialize an existing directory as a Makit-managed project.
|
549
|
+
|
550
|
+
Examples:
|
551
|
+
makit project init
|
552
|
+
makit project init --type ruby
|
553
|
+
makit project init /path/to/existing/project
|
554
|
+
DESC
|
555
|
+
|
556
|
+
parameter "PATH", "Path to initialize (default: current directory)", attribute_name: :path, default: Dir.pwd
|
557
|
+
option ["--type", "-t"], "TYPE", "Project type (ruby, dotnet, node, rust)", default: "auto"
|
558
|
+
option ["--force"], :flag, "Force initialization even if project files exist"
|
559
|
+
|
560
|
+
def execute
|
561
|
+
init_path = File.expand_path(path)
|
562
|
+
|
563
|
+
unless Dir.exist?(init_path)
|
564
|
+
puts "Error: Directory does not exist: #{init_path}"
|
565
|
+
exit 1
|
566
|
+
end
|
567
|
+
|
568
|
+
detected_type = detect_project_type(init_path)
|
569
|
+
actual_type = type == "auto" ? detected_type : type
|
570
|
+
|
571
|
+
if actual_type == "unknown"
|
572
|
+
puts "Error: Could not detect project type. Please specify --type explicitly."
|
573
|
+
exit 1
|
574
|
+
end
|
575
|
+
|
576
|
+
puts "Initializing #{actual_type} project in: #{init_path}"
|
577
|
+
|
578
|
+
if has_project_files?(init_path, actual_type) && !force?
|
579
|
+
puts "Error: Project files already exist. Use --force to overwrite."
|
580
|
+
exit 1
|
581
|
+
end
|
582
|
+
|
583
|
+
initialize_project(init_path, actual_type)
|
584
|
+
puts "✅ Successfully initialized #{actual_type} project"
|
585
|
+
end
|
586
|
+
|
587
|
+
private
|
588
|
+
|
589
|
+
def detect_project_type(dir)
|
590
|
+
return "ruby" if File.exist?(File.join(dir, "Gemfile")) || File.exist?(File.join(dir, ".gemspec"))
|
591
|
+
return "dotnet" if Dir.glob(File.join(dir, "*.csproj")).any? || Dir.glob(File.join(dir, "*.sln")).any?
|
592
|
+
return "node" if File.exist?(File.join(dir, "package.json"))
|
593
|
+
return "rust" if File.exist?(File.join(dir, "Cargo.toml"))
|
594
|
+
|
595
|
+
"unknown"
|
596
|
+
end
|
597
|
+
|
598
|
+
def has_project_files?(dir, project_type)
|
599
|
+
case project_type
|
600
|
+
when "ruby"
|
601
|
+
File.exist?(File.join(dir, "Rakefile"))
|
602
|
+
when "dotnet"
|
603
|
+
Dir.glob(File.join(dir, "*.csproj")).any?
|
604
|
+
when "node"
|
605
|
+
File.exist?(File.join(dir, "package.json"))
|
606
|
+
when "rust"
|
607
|
+
File.exist?(File.join(dir, "Cargo.toml"))
|
608
|
+
else
|
609
|
+
false
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
def initialize_project(dir, project_type)
|
614
|
+
case project_type
|
615
|
+
when "ruby"
|
616
|
+
initialize_ruby_project(dir)
|
617
|
+
when "dotnet"
|
618
|
+
initialize_dotnet_project(dir)
|
619
|
+
when "node"
|
620
|
+
initialize_node_project(dir)
|
621
|
+
when "rust"
|
622
|
+
initialize_rust_project(dir)
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
def initialize_ruby_project(dir)
|
627
|
+
File.write(File.join(dir, "Rakefile"), basic_ruby_rakefile) unless File.exist?(File.join(dir, "Rakefile"))
|
628
|
+
|
629
|
+
return if Dir.exist?(File.join(dir, "test"))
|
630
|
+
|
631
|
+
FileUtils.mkdir_p(File.join(dir, "test"))
|
632
|
+
end
|
633
|
+
|
634
|
+
def initialize_dotnet_project(_dir)
|
635
|
+
# Add any .NET-specific initialization if needed
|
636
|
+
puts " ✅ .NET project initialized"
|
637
|
+
end
|
638
|
+
|
639
|
+
def initialize_node_project(_dir)
|
640
|
+
# Add any Node.js-specific initialization if needed
|
641
|
+
puts " ✅ Node.js project initialized"
|
642
|
+
end
|
643
|
+
|
644
|
+
def initialize_rust_project(_dir)
|
645
|
+
# Add any Rust-specific initialization if needed
|
646
|
+
puts " ✅ Rust project initialized"
|
647
|
+
end
|
648
|
+
|
649
|
+
def basic_ruby_rakefile
|
650
|
+
<<~RUBY
|
651
|
+
# frozen_string_literal: true
|
652
|
+
|
653
|
+
require "rake/testtask"
|
654
|
+
|
655
|
+
Rake::TestTask.new(:test) do |t|
|
656
|
+
t.libs << "test"
|
657
|
+
t.libs << "lib"
|
658
|
+
t.test_files = FileList["test/**/test_*.rb"]
|
659
|
+
end
|
660
|
+
|
661
|
+
task default: :test
|
662
|
+
RUBY
|
663
|
+
end
|
664
|
+
end
|
665
|
+
|
666
|
+
# Setup project dependencies and configuration
|
667
|
+
class SetupProjectCommand < Clamp::Command
|
668
|
+
self.description = <<~DESC
|
669
|
+
Setup project dependencies and development environment.
|
670
|
+
|
671
|
+
Examples:
|
672
|
+
makit project setup
|
673
|
+
makit project setup --skip-deps
|
674
|
+
makit project setup /path/to/project
|
675
|
+
DESC
|
676
|
+
|
677
|
+
parameter "PATH", "Path to project (default: current directory)", attribute_name: :path, default: Dir.pwd
|
678
|
+
option ["--skip-deps"], :flag, "Skip dependency installation"
|
679
|
+
option ["--verbose"], :flag, "Show verbose output"
|
680
|
+
|
681
|
+
def execute
|
682
|
+
project_path = File.expand_path(path)
|
683
|
+
|
684
|
+
unless Dir.exist?(project_path)
|
685
|
+
puts "Error: Directory does not exist: #{project_path}"
|
686
|
+
exit 1
|
687
|
+
end
|
688
|
+
|
689
|
+
project_type = detect_project_type(project_path)
|
690
|
+
|
691
|
+
if project_type == "unknown"
|
692
|
+
puts "Error: Could not detect project type in: #{project_path}"
|
693
|
+
exit 1
|
694
|
+
end
|
695
|
+
|
696
|
+
puts "Setting up #{project_type} project dependencies..."
|
697
|
+
|
698
|
+
Dir.chdir(project_path) do
|
699
|
+
setup_project(project_type)
|
700
|
+
end
|
701
|
+
|
702
|
+
puts "✅ Project setup completed successfully"
|
703
|
+
end
|
704
|
+
|
705
|
+
private
|
706
|
+
|
707
|
+
def detect_project_type(dir)
|
708
|
+
return "ruby" if File.exist?(File.join(dir, "Gemfile"))
|
709
|
+
return "dotnet" if Dir.glob(File.join(dir, "*.csproj")).any? || Dir.glob(File.join(dir, "*.sln")).any?
|
710
|
+
return "node" if File.exist?(File.join(dir, "package.json"))
|
711
|
+
return "rust" if File.exist?(File.join(dir, "Cargo.toml"))
|
712
|
+
|
713
|
+
"unknown"
|
714
|
+
end
|
715
|
+
|
716
|
+
def setup_project(project_type)
|
717
|
+
case project_type
|
718
|
+
when "ruby"
|
719
|
+
setup_ruby_project
|
720
|
+
when "dotnet"
|
721
|
+
setup_dotnet_project
|
722
|
+
when "node"
|
723
|
+
setup_node_project
|
724
|
+
when "rust"
|
725
|
+
setup_rust_project
|
726
|
+
end
|
727
|
+
end
|
728
|
+
|
729
|
+
def setup_ruby_project
|
730
|
+
unless skip_deps?
|
731
|
+
puts " Installing Ruby dependencies..."
|
732
|
+
system("bundle install") || puts("Warning: bundle install failed")
|
733
|
+
end
|
734
|
+
|
735
|
+
puts " ✅ Ruby project setup complete"
|
736
|
+
end
|
737
|
+
|
738
|
+
def setup_dotnet_project
|
739
|
+
unless skip_deps?
|
740
|
+
puts " Restoring .NET dependencies..."
|
741
|
+
system("dotnet restore") || puts("Warning: dotnet restore failed")
|
742
|
+
end
|
743
|
+
|
744
|
+
puts " ✅ .NET project setup complete"
|
745
|
+
end
|
746
|
+
|
747
|
+
def setup_node_project
|
748
|
+
unless skip_deps?
|
749
|
+
puts " Installing Node.js dependencies..."
|
750
|
+
if File.exist?("package-lock.json")
|
751
|
+
system("npm ci") || puts("Warning: npm ci failed")
|
752
|
+
else
|
753
|
+
system("npm install") || puts("Warning: npm install failed")
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
puts " ✅ Node.js project setup complete"
|
758
|
+
end
|
759
|
+
|
760
|
+
def setup_rust_project
|
761
|
+
unless skip_deps?
|
762
|
+
puts " Building Rust project..."
|
763
|
+
system("cargo build") || puts("Warning: cargo build failed")
|
764
|
+
end
|
765
|
+
|
766
|
+
puts " ✅ Rust project setup complete"
|
767
|
+
end
|
768
|
+
end
|
769
|
+
|
770
|
+
# Open project in IDE or navigate to directory
|
771
|
+
class WorkProjectCommand < Clamp::Command
|
772
|
+
self.description = <<~DESC
|
773
|
+
Open project in your preferred IDE or navigate to project directory.
|
774
|
+
|
775
|
+
Examples:
|
776
|
+
makit project work
|
777
|
+
makit project work /path/to/project
|
778
|
+
makit project work --editor code
|
779
|
+
DESC
|
780
|
+
|
781
|
+
parameter "PATH", "Path to project (default: current directory)", attribute_name: :path, default: Dir.pwd
|
782
|
+
option ["--editor"], "EDITOR", "Preferred editor (code, subl, atom, vim)", default: "auto"
|
783
|
+
option ["--list-editors"], :flag, "List available editors"
|
784
|
+
|
785
|
+
def execute
|
786
|
+
if list_editors?
|
787
|
+
show_available_editors
|
788
|
+
return
|
789
|
+
end
|
790
|
+
|
791
|
+
project_path = File.expand_path(path)
|
792
|
+
|
793
|
+
unless Dir.exist?(project_path)
|
794
|
+
puts "Error: Directory does not exist: #{project_path}"
|
795
|
+
exit 1
|
796
|
+
end
|
797
|
+
|
798
|
+
editor_cmd = determine_editor
|
799
|
+
|
800
|
+
if editor_cmd
|
801
|
+
puts "Opening project in #{editor_cmd}..."
|
802
|
+
launch_editor(editor_cmd, project_path)
|
803
|
+
else
|
804
|
+
puts "No suitable editor found. Available editors:"
|
805
|
+
show_available_editors
|
806
|
+
puts "\nNavigating to project directory: #{project_path}"
|
807
|
+
puts "Run: cd #{project_path}"
|
808
|
+
end
|
809
|
+
end
|
810
|
+
|
811
|
+
private
|
812
|
+
|
813
|
+
def show_available_editors
|
814
|
+
editors = {
|
815
|
+
"code" => "Visual Studio Code",
|
816
|
+
"subl" => "Sublime Text",
|
817
|
+
"atom" => "Atom",
|
818
|
+
"vim" => "Vim",
|
819
|
+
"nvim" => "Neovim",
|
820
|
+
"emacs" => "Emacs",
|
821
|
+
}
|
822
|
+
|
823
|
+
puts "Available editors:"
|
824
|
+
editors.each do |cmd, name|
|
825
|
+
available = system("which #{cmd} > /dev/null 2>&1")
|
826
|
+
status = available ? "✅" : "❌"
|
827
|
+
puts " #{status} #{name} (#{cmd})"
|
828
|
+
end
|
829
|
+
end
|
830
|
+
|
831
|
+
def determine_editor
|
832
|
+
return editor if editor != "auto" && editor_available?(editor)
|
833
|
+
|
834
|
+
# Try to detect available editors in preference order
|
835
|
+
preferred_editors = %w[code subl atom vim nvim]
|
836
|
+
preferred_editors.find { |ed| editor_available?(ed) }
|
837
|
+
end
|
838
|
+
|
839
|
+
def editor_available?(editor_name)
|
840
|
+
system("which #{editor_name} > /dev/null 2>&1")
|
841
|
+
end
|
842
|
+
|
843
|
+
def launch_editor(editor_cmd, project_path)
|
844
|
+
case editor_cmd
|
845
|
+
when "code"
|
846
|
+
system("code '#{project_path}'")
|
847
|
+
when "subl"
|
848
|
+
system("subl '#{project_path}'")
|
849
|
+
when "atom"
|
850
|
+
system("atom '#{project_path}'")
|
851
|
+
when "vim", "nvim"
|
852
|
+
system("#{editor_cmd} '#{project_path}'")
|
853
|
+
when "emacs"
|
854
|
+
system("emacs '#{project_path}' &")
|
855
|
+
else
|
856
|
+
puts "Unknown editor: #{editor_cmd}"
|
857
|
+
exit 1
|
858
|
+
end
|
859
|
+
end
|
860
|
+
end
|
861
|
+
|
862
|
+
# Add subcommand declarations after all classes are defined
|
863
|
+
ProjectCommand.subcommand "new", "Create new project from template", NewProjectCommand
|
864
|
+
ProjectCommand.subcommand "init", "Initialize existing directory as project", InitProjectCommand
|
865
|
+
ProjectCommand.subcommand "setup", "Setup project dependencies", SetupProjectCommand
|
866
|
+
ProjectCommand.subcommand "work", "Open project in IDE", WorkProjectCommand
|
867
|
+
end
|
868
|
+
end
|