yoker 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +8 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +223 -0
  5. data/Rakefile +12 -0
  6. data/exe/yoker +177 -0
  7. data/exe/yoker (Copy) +87 -0
  8. data/lib/yoker/cli/base.rb +106 -0
  9. data/lib/yoker/cli/init.rb +193 -0
  10. data/lib/yoker/cli/update.rb +457 -0
  11. data/lib/yoker/configuration.rb +290 -0
  12. data/lib/yoker/detectors/database_detector.rb +35 -0
  13. data/lib/yoker/detectors/rails_detector.rb +48 -0
  14. data/lib/yoker/detectors/version_manager_detector.rb +91 -0
  15. data/lib/yoker/errors.rb +149 -0
  16. data/lib/yoker/generators/base_generator.rb +116 -0
  17. data/lib/yoker/generators/container/docker.rb +255 -0
  18. data/lib/yoker/generators/container/docker_compose.rb +255 -0
  19. data/lib/yoker/generators/container/none.rb +314 -0
  20. data/lib/yoker/generators/database/mysql.rb +147 -0
  21. data/lib/yoker/generators/database/postgresql.rb +64 -0
  22. data/lib/yoker/generators/database/sqlite.rb +123 -0
  23. data/lib/yoker/generators/version_manager/mise.rb +140 -0
  24. data/lib/yoker/generators/version_manager/rbenv.rb +165 -0
  25. data/lib/yoker/generators/version_manager/rvm.rb +246 -0
  26. data/lib/yoker/templates/bin/setup.rb.erb +232 -0
  27. data/lib/yoker/templates/config/database_mysql.yml.erb +47 -0
  28. data/lib/yoker/templates/config/database_postgresql.yml.erb +34 -0
  29. data/lib/yoker/templates/config/database_sqlite.yml.erb +40 -0
  30. data/lib/yoker/templates/docker/Dockerfile.erb +124 -0
  31. data/lib/yoker/templates/docker/docker-compose.yml.erb +117 -0
  32. data/lib/yoker/templates/docker/entrypoint.sh.erb +94 -0
  33. data/lib/yoker/templates/docker/init_mysql.sql.erb +44 -0
  34. data/lib/yoker/templates/docker/init_postgresql.sql.erb +203 -0
  35. data/lib/yoker/templates/version_managers/gemrc.erb +61 -0
  36. data/lib/yoker/templates/version_managers/mise.toml.erb +72 -0
  37. data/lib/yoker/templates/version_managers/rbenv_setup.sh.erb +93 -0
  38. data/lib/yoker/templates/version_managers/rvm_setup.sh.erb +99 -0
  39. data/lib/yoker/templates/version_managers/rvmrc.erb +70 -0
  40. data/lib/yoker/version.rb +5 -0
  41. data/lib/yoker.rb +32 -0
  42. data/sig/yoker.rbs +4 -0
  43. metadata +215 -0
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yoker
4
+ module Generators
5
+ module VersionManager
6
+ class Mise
7
+ attr_reader :config, :shell
8
+
9
+ def initialize(config, shell)
10
+ @config = config
11
+ @shell = shell
12
+ end
13
+
14
+ def generate
15
+ generate_mise_toml
16
+ generate_mise_local if local_overrides_needed?
17
+ end
18
+
19
+ private
20
+
21
+ def generate_mise_toml
22
+ tools = base_tools
23
+
24
+ # Add additional tools based on configuration
25
+ tools.merge!(additional_tools)
26
+
27
+ shell.template(
28
+ "version_managers/mise.toml.erb",
29
+ "mise.toml",
30
+ {
31
+ tools: tools,
32
+ tasks: mise_tasks,
33
+ settings: mise_settings
34
+ }
35
+ )
36
+ end
37
+
38
+ def generate_mise_local
39
+ shell.template(
40
+ "version_managers/mise.local.toml.erb",
41
+ ".mise.local.toml",
42
+ {
43
+ local_overrides: local_overrides
44
+ }
45
+ )
46
+ end
47
+
48
+ def base_tools
49
+ {
50
+ "ruby" => config[:ruby_version],
51
+ "node" => "20.0.0" # Default Node version
52
+ }
53
+ end
54
+
55
+ def additional_tools
56
+ tools = {}
57
+
58
+ if config[:container] == "none"
59
+ case config[:database]
60
+ when "postgresql"
61
+ tools["postgres"] = "16"
62
+ when "mysql"
63
+ tools["mysql"] = "8.0"
64
+ end
65
+ end
66
+
67
+ # Add Redis if it's in additional services
68
+ tools["redis"] = "7.0" if config[:additional_services]&.include?("redis")
69
+
70
+ tools
71
+ end
72
+
73
+ def mise_tasks
74
+ {
75
+ "dev:setup" => {
76
+ "description" => "Set up development environment",
77
+ "run" => "./bin/setup"
78
+ },
79
+ "dev:server" => {
80
+ "description" => "Start development server",
81
+ "run" => "bin/rails server"
82
+ },
83
+ "dev:console" => {
84
+ "description" => "Start Rails console",
85
+ "run" => "bin/rails console"
86
+ },
87
+ "test" => {
88
+ "description" => "Run test suite",
89
+ "run" => "bin/rails test"
90
+ }
91
+ }
92
+ end
93
+
94
+ def mise_settings
95
+ {
96
+ "experimental" => true,
97
+ "activate_aggressive" => false,
98
+ "legacy_version_file" => false
99
+ }
100
+ end
101
+
102
+ def local_overrides_needed?
103
+ # Generate local overrides for development-specific settings
104
+ config[:container] != "none" || config[:additional_services]&.any?
105
+ end
106
+
107
+ def local_overrides
108
+ overrides = {}
109
+
110
+ if config[:container] != "none"
111
+ overrides["env"] = {
112
+ "DATABASE_URL" => database_url,
113
+ "RAILS_ENV" => "development"
114
+ }
115
+ end
116
+
117
+ if config[:additional_services]&.include?("redis")
118
+ overrides["env"] ||= {}
119
+ overrides["env"]["REDIS_URL"] = redis_url
120
+ end
121
+
122
+ overrides
123
+ end
124
+
125
+ def database_url
126
+ case config[:database]
127
+ when "postgresql"
128
+ "postgresql://postgres:password@localhost:5432/#{config[:app_name]}_development"
129
+ when "mysql"
130
+ "mysql2://root:password@localhost:3306/#{config[:app_name]}_development"
131
+ end
132
+ end
133
+
134
+ def redis_url
135
+ "redis://localhost:6379/0"
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yoker
4
+ module Generators
5
+ module VersionManager
6
+ class Rbenv
7
+ attr_reader :config, :shell
8
+
9
+ def initialize(config, shell)
10
+ @config = config
11
+ @shell = shell
12
+ end
13
+
14
+ def generate
15
+ generate_ruby_version_file
16
+ generate_gemrc if needs_gemrc?
17
+ generate_rbenv_vars if needs_env_vars?
18
+ create_rbenv_setup_script
19
+ end
20
+
21
+ private
22
+
23
+ def generate_ruby_version_file
24
+ shell.create_file(
25
+ ".ruby-version",
26
+ "#{config[:ruby_version]}\n"
27
+ )
28
+ end
29
+
30
+ def generate_gemrc
31
+ shell.template(
32
+ "version_managers/gemrc.erb",
33
+ ".gemrc",
34
+ {
35
+ development_mode: true,
36
+ skip_rdoc: true,
37
+ skip_ri: true,
38
+ parallel_install: true,
39
+ verbose: config[:verbose]
40
+ }
41
+ )
42
+ end
43
+
44
+ def generate_rbenv_vars
45
+ env_vars = build_environment_variables
46
+
47
+ return unless env_vars.any?
48
+
49
+ shell.create_file(
50
+ ".rbenv-vars",
51
+ env_vars.map { |key, value| "#{key}=#{value}" }.join("\n") + "\n"
52
+ )
53
+ end
54
+
55
+ def create_rbenv_setup_script
56
+ shell.template(
57
+ "version_managers/rbenv_setup.sh.erb",
58
+ "bin/rbenv-setup",
59
+ {
60
+ ruby_version: config[:ruby_version],
61
+ app_name: config[:app_name],
62
+ bundler_version: detect_bundler_version,
63
+ gems_to_install: development_gems
64
+ }
65
+ )
66
+
67
+ File.chmod(0o755, "bin/rbenv-setup") if File.exist?("bin/rbenv-setup")
68
+ end
69
+
70
+ def build_environment_variables
71
+ vars = {}
72
+
73
+ # Database configuration
74
+ vars["DATABASE_URL"] = database_url if config[:container] != "none" && config[:database] != "sqlite3"
75
+
76
+ # Redis configuration
77
+ if config[:additional_services]&.include?("redis")
78
+ redis_host = config[:container] == "docker-compose" ? "redis" : "localhost"
79
+ vars["REDIS_URL"] = "redis://#{redis_host}:6379/0"
80
+ end
81
+
82
+ # Rails environment
83
+ vars["RAILS_ENV"] = "development"
84
+
85
+ # Performance settings
86
+ vars["RUBY_GC_HEAP_INIT_SLOTS"] = "10000"
87
+ vars["RUBY_GC_HEAP_FREE_SLOTS"] = "4000"
88
+ vars["RUBY_GC_HEAP_GROWTH_FACTOR"] = "1.1"
89
+ vars["RUBY_GC_HEAP_GROWTH_MAX_SLOTS"] = "10000"
90
+
91
+ # Development-specific settings
92
+ vars["BUNDLE_JOBS"] = "4"
93
+ vars["BUNDLE_RETRY"] = "3"
94
+
95
+ # Editor configuration
96
+ vars["EDITOR"] = detect_editor
97
+ vars["VISUAL"] = detect_editor
98
+
99
+ vars.compact
100
+ end
101
+
102
+ def database_url
103
+ case config[:database]
104
+ when "postgresql"
105
+ host = config[:container] == "docker-compose" ? "db" : "localhost"
106
+ "postgresql://postgres:password@#{host}:5432/#{config[:app_name]}_development"
107
+ when "mysql"
108
+ host = config[:container] == "docker-compose" ? "db" : "localhost"
109
+ "mysql2://rails:password@#{host}:3306/#{config[:app_name]}_development"
110
+ end
111
+ end
112
+
113
+ def detect_bundler_version
114
+ # Try to detect current bundler version, fallback to latest
115
+ bundler_version = `bundle --version 2>/dev/null`.match(/\d+\.\d+\.\d+/)&.[](0)
116
+ bundler_version || "latest"
117
+ rescue StandardError
118
+ "latest"
119
+ end
120
+
121
+ def development_gems
122
+ gems = []
123
+
124
+ # Always useful development gems
125
+ gems << { name: "debug", version: "~> 1.8" }
126
+ gems << { name: "pry", version: "~> 0.14" }
127
+ gems << { name: "pry-rails", version: "~> 0.3" }
128
+
129
+ # Database-specific gems
130
+ case config[:database]
131
+ when "postgresql"
132
+ gems << { name: "pg", version: "~> 1.5" }
133
+ when "mysql"
134
+ gems << { name: "mysql2", version: "~> 0.5" }
135
+ when "sqlite3"
136
+ gems << { name: "sqlite3", version: "~> 1.6" }
137
+ end
138
+
139
+ # Additional service gems
140
+ gems << { name: "redis", version: "~> 5.0" } if config[:additional_services]&.include?("redis")
141
+
142
+ gems << { name: "sidekiq", version: "~> 7.0" } if config[:additional_services]&.include?("sidekiq")
143
+
144
+ gems
145
+ end
146
+
147
+ def detect_editor
148
+ editors = %w[code subl atom vim nano]
149
+ detected = editors.find { |editor| system("which #{editor} > /dev/null 2>&1") }
150
+ detected || "vim"
151
+ end
152
+
153
+ def needs_gemrc?
154
+ # Always generate .gemrc for better gem installation experience
155
+ true
156
+ end
157
+
158
+ def needs_env_vars?
159
+ # Generate .rbenv-vars if we have containerized services or specific config
160
+ config[:container] != "none" || config[:additional_services]&.any?
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,246 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yoker
4
+ module Generators
5
+ module VersionManager
6
+ class Rvm
7
+ attr_reader :config, :shell
8
+
9
+ def initialize(config, shell)
10
+ @config = config
11
+ @shell = shell
12
+ end
13
+
14
+ def generate
15
+ generate_rvmrc
16
+ generate_ruby_version_file if needs_ruby_version_file?
17
+ generate_ruby_gemset_file
18
+ generate_gemrc
19
+ generate_bundler_config if needs_bundler_config?
20
+ create_rvm_setup_script
21
+ end
22
+
23
+ private
24
+
25
+ def generate_rvmrc
26
+ shell.template(
27
+ "version_managers/rvmrc.erb",
28
+ ".rvmrc",
29
+ {
30
+ ruby_version: config[:ruby_version],
31
+ gemset_name: gemset_name,
32
+ app_name: config[:app_name],
33
+ environment_variables: build_environment_variables,
34
+ rvm_options: rvm_options
35
+ }
36
+ )
37
+ end
38
+
39
+ def generate_ruby_version_file
40
+ # Some tools still look for .ruby-version even with RVM
41
+ shell.create_file(
42
+ ".ruby-version",
43
+ "#{config[:ruby_version]}\n"
44
+ )
45
+ end
46
+
47
+ def generate_ruby_gemset_file
48
+ # Create .ruby-gemset file with app name (RVM standard)
49
+ shell.create_file(
50
+ ".ruby-gemset",
51
+ "#{config[:app_name]}\n"
52
+ )
53
+ end
54
+
55
+ def generate_gemrc
56
+ shell.template(
57
+ "version_managers/gemrc.erb",
58
+ ".gemrc",
59
+ {
60
+ development_mode: true,
61
+ skip_rdoc: true,
62
+ skip_ri: true,
63
+ parallel_install: true,
64
+ verbose: config[:verbose],
65
+ gemset_aware: true
66
+ }
67
+ )
68
+ end
69
+
70
+ def generate_bundler_config
71
+ bundler_config = {
72
+ "BUNDLE_PATH" => ".bundle",
73
+ "BUNDLE_BIN" => "bin",
74
+ "BUNDLE_JOBS" => "4",
75
+ "BUNDLE_RETRY" => "3"
76
+ }
77
+
78
+ # Add database-specific config
79
+ if config[:database] != "sqlite3" && config[:container] != "none"
80
+ if config[:database] == "postgresql"
81
+ bundler_config["BUNDLE_BUILD__PG"] =
82
+ "--with-pg-config=/usr/bin/pg_config"
83
+ end
84
+ if config[:database] == "mysql"
85
+ bundler_config["BUNDLE_BUILD__MYSQL2"] =
86
+ "--with-mysql-config=/usr/bin/mysql_config"
87
+ end
88
+ end
89
+
90
+ shell.create_file(
91
+ ".bundle/config",
92
+ bundler_config.map { |key, value| "#{key}: #{value}" }.join("\n") + "\n"
93
+ )
94
+ end
95
+
96
+ def create_rvm_setup_script
97
+ shell.template(
98
+ "version_managers/rvm_setup.sh.erb",
99
+ "bin/rvm-setup",
100
+ {
101
+ ruby_version: config[:ruby_version],
102
+ gemset_name: gemset_name,
103
+ app_name: config[:app_name],
104
+ gems_to_install: development_gems,
105
+ bundler_version: detect_bundler_version
106
+ }
107
+ )
108
+
109
+ File.chmod(0o755, "bin/rvm-setup") if File.exist?("bin/rvm-setup")
110
+ end
111
+
112
+ def gemset_name
113
+ # Use the app name directly (matches .ruby-gemset file)
114
+ config[:app_name]
115
+ end
116
+
117
+ def rvm_options
118
+ options = []
119
+
120
+ # Always trust the .rvmrc file
121
+ options << "rvm_trust_rvmrcs_flag=1"
122
+
123
+ # Auto-install Ruby if not present
124
+ options << "rvm_install_on_use_flag=1"
125
+
126
+ # Create gemset if it doesn't exist
127
+ options << "rvm_gemset_create_on_use_flag=1"
128
+
129
+ # Project-specific options
130
+ options << "rvm_project_rvmrc=1"
131
+
132
+ options
133
+ end
134
+
135
+ def build_environment_variables
136
+ vars = {}
137
+
138
+ # Database configuration
139
+ vars["DATABASE_URL"] = database_url if config[:container] != "none" && config[:database] != "sqlite3"
140
+
141
+ # Redis configuration
142
+ if config[:additional_services]&.include?("redis")
143
+ redis_host = config[:container] == "docker-compose" ? "redis" : "localhost"
144
+ vars["REDIS_URL"] = "redis://#{redis_host}:6379/0"
145
+ end
146
+
147
+ # Rails environment
148
+ vars["RAILS_ENV"] = "development"
149
+ vars["RACK_ENV"] = "development"
150
+
151
+ # RVM-specific environment variables
152
+ vars["rvm_gemset_name"] = gemset_name
153
+ vars["rvm_ruby_string"] = "ruby-#{config[:ruby_version]}"
154
+
155
+ # Ruby performance tuning
156
+ vars["RUBY_GC_HEAP_INIT_SLOTS"] = "10000"
157
+ vars["RUBY_GC_HEAP_FREE_SLOTS"] = "4000"
158
+ vars["RUBY_GC_HEAP_GROWTH_FACTOR"] = "1.1"
159
+ vars["RUBY_GC_HEAP_GROWTH_MAX_SLOTS"] = "10000"
160
+
161
+ # Development tools
162
+ vars["EDITOR"] = detect_editor
163
+ vars["VISUAL"] = detect_editor
164
+
165
+ # Bundler configuration
166
+ vars["BUNDLE_GEMFILE"] = File.expand_path("Gemfile")
167
+ vars["BUNDLE_PATH"] = File.expand_path(".bundle")
168
+
169
+ vars.compact
170
+ end
171
+
172
+ def database_url
173
+ case config[:database]
174
+ when "postgresql"
175
+ host = config[:container] == "docker-compose" ? "db" : "localhost"
176
+ "postgresql://postgres:password@#{host}:5432/#{config[:app_name]}_development"
177
+ when "mysql"
178
+ host = config[:container] == "docker-compose" ? "db" : "localhost"
179
+ "mysql2://rails:password@#{host}:3306/#{config[:app_name]}_development"
180
+ end
181
+ end
182
+
183
+ def development_gems
184
+ gems = []
185
+
186
+ # Core development gems
187
+ gems << { name: "bundler", version: detect_bundler_version }
188
+ gems << { name: "debug", version: "~> 1.8" }
189
+ gems << { name: "pry", version: "~> 0.14" }
190
+ gems << { name: "pry-rails", version: "~> 0.3" }
191
+
192
+ # Database gems
193
+ case config[:database]
194
+ when "postgresql"
195
+ gems << { name: "pg", version: "~> 1.5" }
196
+ when "mysql"
197
+ gems << { name: "mysql2", version: "~> 0.5" }
198
+ when "sqlite3"
199
+ gems << { name: "sqlite3", version: "~> 1.6" }
200
+ end
201
+
202
+ # Additional service gems
203
+ if config[:additional_services]&.include?("redis")
204
+ gems << { name: "redis", version: "~> 5.0" }
205
+ gems << { name: "hiredis", version: "~> 0.6" } # Fast Redis client
206
+ end
207
+
208
+ if config[:additional_services]&.include?("sidekiq")
209
+ gems << { name: "sidekiq", version: "~> 7.0" }
210
+ gems << { name: "sidekiq-web", version: "~> 7.0" }
211
+ end
212
+
213
+ # Development quality of life gems
214
+ gems << { name: "letter_opener", version: "~> 1.8" }
215
+ gems << { name: "better_errors", version: "~> 2.9" }
216
+ gems << { name: "binding_of_caller", version: "~> 1.0" }
217
+
218
+ gems
219
+ end
220
+
221
+ def detect_bundler_version
222
+ bundler_version = `bundle --version 2>/dev/null`.match(/\d+\.\d+\.\d+/)&.[](0)
223
+ bundler_version || "~> 2.4"
224
+ rescue StandardError
225
+ "~> 2.4"
226
+ end
227
+
228
+ def detect_editor
229
+ editors = %w[code subl atom vim nano]
230
+ detected = editors.find { |editor| system("which #{editor} > /dev/null 2>&1") }
231
+ detected || "vim"
232
+ end
233
+
234
+ def needs_ruby_version_file?
235
+ # Generate .ruby-version for compatibility with other tools
236
+ true
237
+ end
238
+
239
+ def needs_bundler_config?
240
+ # Always generate bundler config for consistent gem management
241
+ true
242
+ end
243
+ end
244
+ end
245
+ end
246
+ end