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.
- checksums.yaml +7 -0
- data/.rubocop.yml +8 -0
- data/LICENSE.txt +21 -0
- data/README.md +223 -0
- data/Rakefile +12 -0
- data/exe/yoker +177 -0
- data/exe/yoker (Copy) +87 -0
- data/lib/yoker/cli/base.rb +106 -0
- data/lib/yoker/cli/init.rb +193 -0
- data/lib/yoker/cli/update.rb +457 -0
- data/lib/yoker/configuration.rb +290 -0
- data/lib/yoker/detectors/database_detector.rb +35 -0
- data/lib/yoker/detectors/rails_detector.rb +48 -0
- data/lib/yoker/detectors/version_manager_detector.rb +91 -0
- data/lib/yoker/errors.rb +149 -0
- data/lib/yoker/generators/base_generator.rb +116 -0
- data/lib/yoker/generators/container/docker.rb +255 -0
- data/lib/yoker/generators/container/docker_compose.rb +255 -0
- data/lib/yoker/generators/container/none.rb +314 -0
- data/lib/yoker/generators/database/mysql.rb +147 -0
- data/lib/yoker/generators/database/postgresql.rb +64 -0
- data/lib/yoker/generators/database/sqlite.rb +123 -0
- data/lib/yoker/generators/version_manager/mise.rb +140 -0
- data/lib/yoker/generators/version_manager/rbenv.rb +165 -0
- data/lib/yoker/generators/version_manager/rvm.rb +246 -0
- data/lib/yoker/templates/bin/setup.rb.erb +232 -0
- data/lib/yoker/templates/config/database_mysql.yml.erb +47 -0
- data/lib/yoker/templates/config/database_postgresql.yml.erb +34 -0
- data/lib/yoker/templates/config/database_sqlite.yml.erb +40 -0
- data/lib/yoker/templates/docker/Dockerfile.erb +124 -0
- data/lib/yoker/templates/docker/docker-compose.yml.erb +117 -0
- data/lib/yoker/templates/docker/entrypoint.sh.erb +94 -0
- data/lib/yoker/templates/docker/init_mysql.sql.erb +44 -0
- data/lib/yoker/templates/docker/init_postgresql.sql.erb +203 -0
- data/lib/yoker/templates/version_managers/gemrc.erb +61 -0
- data/lib/yoker/templates/version_managers/mise.toml.erb +72 -0
- data/lib/yoker/templates/version_managers/rbenv_setup.sh.erb +93 -0
- data/lib/yoker/templates/version_managers/rvm_setup.sh.erb +99 -0
- data/lib/yoker/templates/version_managers/rvmrc.erb +70 -0
- data/lib/yoker/version.rb +5 -0
- data/lib/yoker.rb +32 -0
- data/sig/yoker.rbs +4 -0
- metadata +215 -0
@@ -0,0 +1,193 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
require_relative "../generators/base_generator"
|
5
|
+
|
6
|
+
module Yoker
|
7
|
+
module CLI
|
8
|
+
class Init < Base
|
9
|
+
desc "generate", "Generate development environment setup"
|
10
|
+
|
11
|
+
option :database,
|
12
|
+
type: :string,
|
13
|
+
enum: %w[postgresql mysql sqlite3],
|
14
|
+
desc: "Database adapter to use"
|
15
|
+
|
16
|
+
option :version_manager,
|
17
|
+
type: :string,
|
18
|
+
enum: %w[mise rbenv rvm none],
|
19
|
+
desc: "Ruby version manager to use"
|
20
|
+
|
21
|
+
option :container,
|
22
|
+
type: :string,
|
23
|
+
enum: %w[docker-compose docker none],
|
24
|
+
desc: "Containerization approach"
|
25
|
+
|
26
|
+
option :ruby_version,
|
27
|
+
type: :string,
|
28
|
+
desc: "Ruby version to use"
|
29
|
+
|
30
|
+
option :interactive,
|
31
|
+
type: :boolean,
|
32
|
+
default: false,
|
33
|
+
aliases: %w[-i],
|
34
|
+
desc: "Run in interactive mode"
|
35
|
+
|
36
|
+
option :force,
|
37
|
+
type: :boolean,
|
38
|
+
default: false,
|
39
|
+
aliases: %w[-f],
|
40
|
+
desc: "Overwrite existing files"
|
41
|
+
|
42
|
+
def generate
|
43
|
+
detect_rails_app!
|
44
|
+
|
45
|
+
info "Setting up development environment for Rails application: #{current_directory_name}"
|
46
|
+
|
47
|
+
config = build_configuration
|
48
|
+
|
49
|
+
info "Configuration:"
|
50
|
+
display_configuration(config)
|
51
|
+
|
52
|
+
return if !options[:force] && !prompt.yes?("Continue with this configuration?")
|
53
|
+
|
54
|
+
spinner = spinner("Generating development setup files...")
|
55
|
+
spinner.auto_spin
|
56
|
+
|
57
|
+
begin
|
58
|
+
generator = Generators::BaseGenerator.new(config, self)
|
59
|
+
generator.generate_all
|
60
|
+
|
61
|
+
spinner.success("✅ Development setup complete!")
|
62
|
+
|
63
|
+
display_next_steps(config)
|
64
|
+
rescue StandardError => e
|
65
|
+
spinner.error("❌ Setup failed: #{e.message}")
|
66
|
+
puts e.backtrace.join("\n") if ENV["DEBUG"]
|
67
|
+
raise
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def build_configuration
|
74
|
+
config = {}
|
75
|
+
|
76
|
+
config = if options[:interactive]
|
77
|
+
interactive_configuration
|
78
|
+
else
|
79
|
+
options_configuration
|
80
|
+
end
|
81
|
+
|
82
|
+
# Fill in detected or default values
|
83
|
+
config[:app_name] ||= sanitize_name(current_directory_name)
|
84
|
+
config[:ruby_version] ||= RUBY_VERSION
|
85
|
+
config[:database] ||= detect_database
|
86
|
+
config[:version_manager] ||= detect_version_manager
|
87
|
+
config[:container] ||= detect_container_preference
|
88
|
+
|
89
|
+
config
|
90
|
+
end
|
91
|
+
|
92
|
+
def interactive_configuration
|
93
|
+
config = {}
|
94
|
+
|
95
|
+
config[:database] = prompt.select(
|
96
|
+
"Which database would you like to use?",
|
97
|
+
%w[postgresql mysql sqlite3],
|
98
|
+
default: detect_database
|
99
|
+
)
|
100
|
+
|
101
|
+
config[:version_manager] = prompt.select(
|
102
|
+
"Which Ruby version manager are you using?",
|
103
|
+
%w[mise rbenv rvm none],
|
104
|
+
default: detect_version_manager
|
105
|
+
)
|
106
|
+
|
107
|
+
config[:container] = prompt.select(
|
108
|
+
"How would you like to handle containerization?",
|
109
|
+
{
|
110
|
+
"Docker Compose (recommended)" => "docker-compose",
|
111
|
+
"Standalone Docker" => "docker",
|
112
|
+
"No containers" => "none"
|
113
|
+
}
|
114
|
+
)
|
115
|
+
|
116
|
+
config[:ruby_version] = prompt.ask(
|
117
|
+
"Ruby version to use?",
|
118
|
+
default: RUBY_VERSION
|
119
|
+
)
|
120
|
+
|
121
|
+
if config[:database] != "sqlite3"
|
122
|
+
config[:additional_services] = prompt.multi_select(
|
123
|
+
"Additional services to include?",
|
124
|
+
%w[redis sidekiq mailcatcher],
|
125
|
+
default: []
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
config
|
130
|
+
end
|
131
|
+
|
132
|
+
def options_configuration
|
133
|
+
{
|
134
|
+
database: options[:database],
|
135
|
+
version_manager: options[:version_manager],
|
136
|
+
container: options[:container],
|
137
|
+
ruby_version: options[:ruby_version]
|
138
|
+
}.compact
|
139
|
+
end
|
140
|
+
|
141
|
+
def detect_database
|
142
|
+
Detectors::DatabaseDetector.detect || "postgresql"
|
143
|
+
end
|
144
|
+
|
145
|
+
def detect_version_manager
|
146
|
+
Detectors::VersionManagerDetector.detect || "mise"
|
147
|
+
end
|
148
|
+
|
149
|
+
def detect_container_preference
|
150
|
+
return "docker-compose" if File.exist?("docker-compose.yml")
|
151
|
+
return "docker" if File.exist?("Dockerfile")
|
152
|
+
|
153
|
+
"docker-compose"
|
154
|
+
end
|
155
|
+
|
156
|
+
def display_configuration(config)
|
157
|
+
puts ""
|
158
|
+
puts pastel.cyan(" App name: ") + config[:app_name]
|
159
|
+
puts pastel.cyan(" Database: ") + config[:database]
|
160
|
+
puts pastel.cyan(" Ruby version: ") + config[:ruby_version]
|
161
|
+
puts pastel.cyan(" Version manager: ") + config[:version_manager]
|
162
|
+
puts pastel.cyan(" Containerization: ") + config[:container]
|
163
|
+
|
164
|
+
if config[:additional_services]&.any?
|
165
|
+
puts pastel.cyan(" Additional services: ") + config[:additional_services].join(", ")
|
166
|
+
end
|
167
|
+
puts ""
|
168
|
+
end
|
169
|
+
|
170
|
+
def display_next_steps(config)
|
171
|
+
puts ""
|
172
|
+
puts pastel.bright_green("🎉 Setup complete!")
|
173
|
+
puts ""
|
174
|
+
puts "Next steps:"
|
175
|
+
puts "1. Review the generated files"
|
176
|
+
puts "2. Run #{pastel.cyan("chmod +x bin/setup")} to make setup executable"
|
177
|
+
puts "3. Run #{pastel.cyan("./bin/setup")} to initialize your development environment"
|
178
|
+
|
179
|
+
if (config[:container] != "none") && (config[:container] == "docker-compose")
|
180
|
+
puts "4. Use #{pastel.cyan("docker compose up -d")} to start services"
|
181
|
+
end
|
182
|
+
|
183
|
+
puts ""
|
184
|
+
puts "Files generated:"
|
185
|
+
puts "• bin/setup - Enhanced setup script"
|
186
|
+
puts "• config/database.yml - Database configuration" if config[:database] != "sqlite3"
|
187
|
+
puts "• docker-compose.yml - Container orchestration" if config[:container] == "docker-compose"
|
188
|
+
puts "• Dockerfile - Container definition" if config[:container] != "none"
|
189
|
+
puts "• mise.toml - Version manager configuration" if config[:version_manager] == "mise"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,457 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
require_relative "../generators/base_generator"
|
5
|
+
|
6
|
+
module Yoker
|
7
|
+
module CLI
|
8
|
+
class Update < Base
|
9
|
+
desc "run", "Update existing development environment setup"
|
10
|
+
|
11
|
+
option :database,
|
12
|
+
type: :string,
|
13
|
+
enum: %w[postgresql mysql sqlite3],
|
14
|
+
desc: "Change database adapter"
|
15
|
+
|
16
|
+
option :version_manager,
|
17
|
+
type: :string,
|
18
|
+
enum: %w[mise rbenv rvm none],
|
19
|
+
desc: "Change Ruby version manager"
|
20
|
+
|
21
|
+
option :container,
|
22
|
+
type: :string,
|
23
|
+
enum: %w[docker-compose docker none],
|
24
|
+
desc: "Change containerization approach"
|
25
|
+
|
26
|
+
option :ruby_version,
|
27
|
+
type: :string,
|
28
|
+
desc: "Update Ruby version"
|
29
|
+
|
30
|
+
option :add_service,
|
31
|
+
type: :array,
|
32
|
+
enum: %w[redis sidekiq mailcatcher],
|
33
|
+
desc: "Add additional services"
|
34
|
+
|
35
|
+
option :remove_service,
|
36
|
+
type: :array,
|
37
|
+
enum: %w[redis sidekiq mailcatcher],
|
38
|
+
desc: "Remove services"
|
39
|
+
|
40
|
+
option :interactive,
|
41
|
+
type: :boolean,
|
42
|
+
default: false,
|
43
|
+
aliases: %w[-i],
|
44
|
+
desc: "Run in interactive mode"
|
45
|
+
|
46
|
+
option :backup,
|
47
|
+
type: :boolean,
|
48
|
+
default: true,
|
49
|
+
desc: "Backup existing files before updating"
|
50
|
+
|
51
|
+
option :dry_run,
|
52
|
+
type: :boolean,
|
53
|
+
default: false,
|
54
|
+
desc: "Show what would be changed without making changes"
|
55
|
+
|
56
|
+
def execute
|
57
|
+
detect_rails_app!
|
58
|
+
|
59
|
+
info "Updating development environment for Rails application: #{current_directory_name}"
|
60
|
+
|
61
|
+
current_config = detect_current_configuration
|
62
|
+
new_config = build_updated_configuration(current_config)
|
63
|
+
|
64
|
+
if configs_identical?(current_config, new_config)
|
65
|
+
success "No changes detected. Environment is up to date!"
|
66
|
+
return
|
67
|
+
end
|
68
|
+
|
69
|
+
display_configuration_changes(current_config, new_config)
|
70
|
+
|
71
|
+
if options[:dry_run]
|
72
|
+
info "Dry run mode - no changes made"
|
73
|
+
return
|
74
|
+
end
|
75
|
+
|
76
|
+
unless prompt.yes?("Apply these changes?")
|
77
|
+
info "Update cancelled"
|
78
|
+
return
|
79
|
+
end
|
80
|
+
|
81
|
+
perform_update(current_config, new_config)
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def detect_current_configuration
|
87
|
+
config = {
|
88
|
+
app_name: sanitize_name(current_directory_name),
|
89
|
+
ruby_version: detect_current_ruby_version,
|
90
|
+
database: detect_current_database,
|
91
|
+
version_manager: detect_current_version_manager,
|
92
|
+
container: detect_current_container_setup,
|
93
|
+
additional_services: detect_current_services
|
94
|
+
}
|
95
|
+
|
96
|
+
info "Detected current configuration:"
|
97
|
+
display_simple_config(config)
|
98
|
+
|
99
|
+
config
|
100
|
+
end
|
101
|
+
|
102
|
+
def build_updated_configuration(current_config)
|
103
|
+
if options[:interactive]
|
104
|
+
interactive_update(current_config)
|
105
|
+
else
|
106
|
+
options_update(current_config)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def interactive_update(current_config)
|
111
|
+
new_config = current_config.dup
|
112
|
+
|
113
|
+
# Database update
|
114
|
+
if prompt.yes?("Change database adapter? (currently: #{current_config[:database]})")
|
115
|
+
new_config[:database] = prompt.select(
|
116
|
+
"Select new database:",
|
117
|
+
%w[postgresql mysql sqlite3],
|
118
|
+
default: current_config[:database]
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Version manager update
|
123
|
+
if prompt.yes?("Change version manager? (currently: #{current_config[:version_manager]})")
|
124
|
+
new_config[:version_manager] = prompt.select(
|
125
|
+
"Select version manager:",
|
126
|
+
%w[mise rbenv rvm none],
|
127
|
+
default: current_config[:version_manager]
|
128
|
+
)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Container setup update
|
132
|
+
if prompt.yes?("Change containerization? (currently: #{current_config[:container]})")
|
133
|
+
new_config[:container] = prompt.select(
|
134
|
+
"Select containerization approach:",
|
135
|
+
{
|
136
|
+
"Docker Compose" => "docker-compose",
|
137
|
+
"Standalone Docker" => "docker",
|
138
|
+
"No containers" => "none"
|
139
|
+
},
|
140
|
+
default: current_config[:container]
|
141
|
+
)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Ruby version update
|
145
|
+
if prompt.yes?("Update Ruby version? (currently: #{current_config[:ruby_version]})")
|
146
|
+
new_config[:ruby_version] = prompt.ask(
|
147
|
+
"Enter Ruby version:",
|
148
|
+
default: current_config[:ruby_version]
|
149
|
+
)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Services update
|
153
|
+
if prompt.yes?("Modify additional services?")
|
154
|
+
current_services = current_config[:additional_services] || []
|
155
|
+
new_config[:additional_services] = prompt.multi_select(
|
156
|
+
"Select services:",
|
157
|
+
%w[redis sidekiq mailcatcher],
|
158
|
+
default: current_services
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
new_config
|
163
|
+
end
|
164
|
+
|
165
|
+
def options_update(current_config)
|
166
|
+
new_config = current_config.dup
|
167
|
+
|
168
|
+
# Apply command line options
|
169
|
+
new_config[:database] = options[:database] if options[:database]
|
170
|
+
new_config[:version_manager] = options[:version_manager] if options[:version_manager]
|
171
|
+
new_config[:container] = options[:container] if options[:container]
|
172
|
+
new_config[:ruby_version] = options[:ruby_version] if options[:ruby_version]
|
173
|
+
|
174
|
+
# Handle service additions/removals
|
175
|
+
if options[:add_service] || options[:remove_service]
|
176
|
+
services = Set.new(current_config[:additional_services] || [])
|
177
|
+
|
178
|
+
services.merge(options[:add_service]) if options[:add_service]
|
179
|
+
|
180
|
+
services.subtract(options[:remove_service]) if options[:remove_service]
|
181
|
+
|
182
|
+
new_config[:additional_services] = services.to_a
|
183
|
+
end
|
184
|
+
|
185
|
+
new_config
|
186
|
+
end
|
187
|
+
|
188
|
+
def perform_update(current_config, new_config)
|
189
|
+
backup_existing_files if options[:backup]
|
190
|
+
|
191
|
+
spinner = spinner("Updating development environment...")
|
192
|
+
spinner.auto_spin
|
193
|
+
|
194
|
+
begin
|
195
|
+
# Handle major changes that require cleanup
|
196
|
+
handle_container_migration(current_config, new_config)
|
197
|
+
handle_database_migration(current_config, new_config)
|
198
|
+
handle_version_manager_migration(current_config, new_config)
|
199
|
+
|
200
|
+
# Generate updated configuration
|
201
|
+
generator = Generators::BaseGenerator.new(new_config, self)
|
202
|
+
generator.generate_all
|
203
|
+
|
204
|
+
# Update existing services
|
205
|
+
update_running_services(current_config, new_config)
|
206
|
+
|
207
|
+
spinner.success("✅ Environment updated successfully!")
|
208
|
+
|
209
|
+
display_post_update_instructions(current_config, new_config)
|
210
|
+
rescue StandardError => e
|
211
|
+
spinner.error("❌ Update failed: #{e.message}")
|
212
|
+
offer_rollback if options[:backup]
|
213
|
+
raise
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def handle_container_migration(old_config, new_config)
|
218
|
+
return if old_config[:container] == new_config[:container]
|
219
|
+
|
220
|
+
info "Migrating containerization from #{old_config[:container]} to #{new_config[:container]}"
|
221
|
+
|
222
|
+
case [old_config[:container], new_config[:container]]
|
223
|
+
when %w[docker-compose docker]
|
224
|
+
migrate_compose_to_docker
|
225
|
+
when %w[docker-compose none]
|
226
|
+
migrate_compose_to_native
|
227
|
+
when %w[docker docker-compose]
|
228
|
+
migrate_docker_to_compose
|
229
|
+
when %w[docker none]
|
230
|
+
migrate_docker_to_native
|
231
|
+
when %w[none docker-compose]
|
232
|
+
migrate_native_to_compose
|
233
|
+
when %w[none docker]
|
234
|
+
migrate_native_to_docker
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def handle_database_migration(old_config, new_config)
|
239
|
+
return if old_config[:database] == new_config[:database]
|
240
|
+
|
241
|
+
warning "Database change detected: #{old_config[:database]} → #{new_config[:database]}"
|
242
|
+
warning "You will need to migrate your data manually"
|
243
|
+
|
244
|
+
info "Steps to migrate your database:"
|
245
|
+
puts "1. Export data from #{old_config[:database]}"
|
246
|
+
puts "2. Run './bin/setup' to initialize #{new_config[:database]}"
|
247
|
+
puts "3. Import your data to the new database"
|
248
|
+
end
|
249
|
+
|
250
|
+
def handle_version_manager_migration(old_config, new_config)
|
251
|
+
return if old_config[:version_manager] == new_config[:version_manager]
|
252
|
+
|
253
|
+
info "Migrating version manager: #{old_config[:version_manager]} → #{new_config[:version_manager]}"
|
254
|
+
|
255
|
+
# Clean up old version manager files
|
256
|
+
cleanup_version_manager_files(old_config[:version_manager])
|
257
|
+
end
|
258
|
+
|
259
|
+
def cleanup_version_manager_files(old_manager)
|
260
|
+
files_to_remove = case old_manager
|
261
|
+
when "mise"
|
262
|
+
%w[mise.toml .mise.local.toml]
|
263
|
+
when "rbenv"
|
264
|
+
%w[.ruby-version]
|
265
|
+
when "rvm"
|
266
|
+
%w[.rvmrc]
|
267
|
+
end
|
268
|
+
|
269
|
+
files_to_remove&.each do |file|
|
270
|
+
if File.exist?(file)
|
271
|
+
info "Removing #{file}"
|
272
|
+
File.delete(file) unless options[:dry_run]
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def update_running_services(old_config, new_config)
|
278
|
+
return unless old_config[:container] != "none" && new_config[:container] != "none"
|
279
|
+
|
280
|
+
# Stop old services
|
281
|
+
stop_services(old_config)
|
282
|
+
|
283
|
+
# Start new services
|
284
|
+
start_services(new_config)
|
285
|
+
end
|
286
|
+
|
287
|
+
def stop_services(config)
|
288
|
+
case config[:container]
|
289
|
+
when "docker-compose"
|
290
|
+
system("docker compose down", exception: false) if File.exist?("docker-compose.yml")
|
291
|
+
when "docker"
|
292
|
+
stop_standalone_containers(config)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def start_services(config)
|
297
|
+
info "Starting services with new configuration..."
|
298
|
+
system("./bin/setup", exception: false) if File.exist?("bin/setup")
|
299
|
+
end
|
300
|
+
|
301
|
+
def stop_standalone_containers(config)
|
302
|
+
container_name = "#{config[:app_name]}_#{config[:database]}"
|
303
|
+
system("docker stop #{container_name}", exception: false)
|
304
|
+
|
305
|
+
return unless config[:additional_services]&.include?("redis")
|
306
|
+
|
307
|
+
redis_container = "#{config[:app_name]}_redis"
|
308
|
+
system("docker stop #{redis_container}", exception: false)
|
309
|
+
end
|
310
|
+
|
311
|
+
def backup_existing_files
|
312
|
+
timestamp = Time.now.strftime("%Y%m%d_%H%M%S")
|
313
|
+
backup_dir = "backup_#{timestamp}"
|
314
|
+
|
315
|
+
info "Creating backup in #{backup_dir}/"
|
316
|
+
Dir.mkdir(backup_dir)
|
317
|
+
|
318
|
+
files_to_backup.each do |file|
|
319
|
+
if File.exist?(file)
|
320
|
+
backup_path = File.join(backup_dir, file.gsub("/", "_"))
|
321
|
+
FileUtils.cp(file, backup_path)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def files_to_backup
|
327
|
+
%w[
|
328
|
+
bin/setup
|
329
|
+
config/database.yml
|
330
|
+
docker-compose.yml
|
331
|
+
Dockerfile
|
332
|
+
mise.toml
|
333
|
+
.ruby-version
|
334
|
+
.tool-versions
|
335
|
+
Procfile.dev
|
336
|
+
]
|
337
|
+
end
|
338
|
+
|
339
|
+
def offer_rollback
|
340
|
+
return unless prompt.yes?("Restore from backup?")
|
341
|
+
|
342
|
+
# Implementation for rollback would go here
|
343
|
+
info "Rollback functionality coming soon"
|
344
|
+
end
|
345
|
+
|
346
|
+
def configs_identical?(config1, config2)
|
347
|
+
config1.to_s == config2.to_s
|
348
|
+
end
|
349
|
+
|
350
|
+
def display_configuration_changes(old_config, new_config)
|
351
|
+
puts ""
|
352
|
+
puts pastel.bright_blue("Configuration Changes:")
|
353
|
+
puts ""
|
354
|
+
|
355
|
+
old_config.each do |key, old_value|
|
356
|
+
new_value = new_config[key]
|
357
|
+
next if old_value == new_value
|
358
|
+
|
359
|
+
puts " #{pastel.cyan(key.to_s)}:"
|
360
|
+
puts " #{pastel.red("- #{old_value}")}"
|
361
|
+
puts " #{pastel.green("+ #{new_value}")}"
|
362
|
+
end
|
363
|
+
puts ""
|
364
|
+
end
|
365
|
+
|
366
|
+
def display_simple_config(config)
|
367
|
+
config.each do |key, value|
|
368
|
+
puts " #{pastel.cyan(key)}: #{value}"
|
369
|
+
end
|
370
|
+
puts ""
|
371
|
+
end
|
372
|
+
|
373
|
+
def display_post_update_instructions(old_config, new_config)
|
374
|
+
puts ""
|
375
|
+
puts pastel.bright_green("🎉 Update complete!")
|
376
|
+
puts ""
|
377
|
+
puts "Next steps:"
|
378
|
+
puts "1. Review the updated configuration files"
|
379
|
+
puts "2. Run #{pastel.cyan("./bin/setup")} to apply changes"
|
380
|
+
|
381
|
+
if old_config[:database] != new_config[:database]
|
382
|
+
puts "3. #{pastel.yellow("Important:")} Migrate your database data manually"
|
383
|
+
end
|
384
|
+
|
385
|
+
return unless old_config[:container] != new_config[:container]
|
386
|
+
|
387
|
+
puts "4. Update your development workflow for the new container setup"
|
388
|
+
end
|
389
|
+
|
390
|
+
# Detection methods
|
391
|
+
def detect_current_ruby_version
|
392
|
+
Detectors::VersionManagerDetector.ruby_version_from_file || RUBY_VERSION
|
393
|
+
end
|
394
|
+
|
395
|
+
def detect_current_database
|
396
|
+
Detectors::DatabaseDetector.detect || "sqlite3"
|
397
|
+
end
|
398
|
+
|
399
|
+
def detect_current_version_manager
|
400
|
+
Detectors::VersionManagerDetector.detect || "none"
|
401
|
+
end
|
402
|
+
|
403
|
+
def detect_current_container_setup
|
404
|
+
return "docker-compose" if File.exist?("docker-compose.yml")
|
405
|
+
return "docker" if File.exist?("Dockerfile") && !File.exist?("docker-compose.yml")
|
406
|
+
|
407
|
+
"none"
|
408
|
+
end
|
409
|
+
|
410
|
+
def detect_current_services
|
411
|
+
services = []
|
412
|
+
|
413
|
+
if File.exist?("docker-compose.yml")
|
414
|
+
compose_content = File.read("docker-compose.yml")
|
415
|
+
services << "redis" if compose_content.include?("redis:")
|
416
|
+
services << "sidekiq" if compose_content.include?("sidekiq:")
|
417
|
+
services << "mailcatcher" if compose_content.include?("mailcatcher")
|
418
|
+
end
|
419
|
+
|
420
|
+
services << "sidekiq" if File.exist?("config/sidekiq.yml") && !services.include?("sidekiq")
|
421
|
+
|
422
|
+
services
|
423
|
+
end
|
424
|
+
|
425
|
+
# Container migration methods
|
426
|
+
def migrate_compose_to_docker
|
427
|
+
info "Migrating from Docker Compose to standalone Docker"
|
428
|
+
system("docker compose down", exception: false) if File.exist?("docker-compose.yml")
|
429
|
+
end
|
430
|
+
|
431
|
+
def migrate_compose_to_native
|
432
|
+
info "Migrating from Docker Compose to native setup"
|
433
|
+
system("docker compose down", exception: false) if File.exist?("docker-compose.yml")
|
434
|
+
end
|
435
|
+
|
436
|
+
def migrate_docker_to_compose
|
437
|
+
info "Migrating from standalone Docker to Docker Compose"
|
438
|
+
# Stop existing containers
|
439
|
+
end
|
440
|
+
|
441
|
+
def migrate_docker_to_native
|
442
|
+
info "Migrating from standalone Docker to native setup"
|
443
|
+
# Stop existing containers
|
444
|
+
end
|
445
|
+
|
446
|
+
def migrate_native_to_compose
|
447
|
+
info "Migrating from native setup to Docker Compose"
|
448
|
+
# Stop native services if possible
|
449
|
+
end
|
450
|
+
|
451
|
+
def migrate_native_to_docker
|
452
|
+
info "Migrating from native setup to standalone Docker"
|
453
|
+
# Stop native services if possible
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|