tayo 0.1.13 → 0.2.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.
@@ -17,27 +17,30 @@ module Tayo
17
17
  return
18
18
  end
19
19
 
20
- # --- 로직 순서 변경 ---
20
+ # 1. 도메인 입력받기
21
+ domain_info = get_domain_input
21
22
 
22
- # 2. 토큰 입력받기
23
+ # 2. Cloudflare 토큰 생성 페이지 열기 및 권한 안내
24
+ open_token_creation_page
25
+
26
+ # 3. 토큰 입력받기
23
27
  token = get_cloudflare_token
24
28
 
25
- # 3. Cloudflare 선택 도메인 구성 (새로운 방식)
26
- domain_info = configure_domain_from_zones(token)
27
- selected_zone = domain_info[:selected_zone_object]
28
-
29
- # 4. 기존 DNS 레코드 확인 (참고용)
29
+ # 4. Cloudflare API로 도메인 목록 조회 선택
30
+ selected_zone = select_cloudflare_zone(token)
31
+
32
+ # 5. 루트 도메인 레코드 확인
30
33
  existing_records = check_existing_records(token, selected_zone, domain_info)
31
34
 
32
- # 5. DNS 레코드 추가/수정 (루트 도메인 덮어쓰기 로직 포함)
35
+ # 6. DNS 레코드 추가/수정
33
36
  setup_dns_record(token, selected_zone, domain_info, existing_records)
34
37
 
35
- # 6. config/deploy.yml 업데이트
38
+ # 7. config/deploy.yml 업데이트
36
39
  update_deploy_config(domain_info)
37
40
 
38
41
  puts "\n🎉 Cloudflare DNS 설정이 완료되었습니다!".colorize(:green)
39
42
 
40
- # 7. 변경사항 커밋
43
+ # 변경사항 커밋
41
44
  commit_cloudflare_changes(domain_info)
42
45
  end
43
46
 
@@ -47,59 +50,31 @@ module Tayo
47
50
  File.exist?("Gemfile") && File.exist?("config/application.rb")
48
51
  end
49
52
 
50
- # [신규] Cloudflare Zone 목록에서 도메인을 선택하고 구성하는 메소드
51
- def configure_domain_from_zones(token)
52
- puts "\n🌐 Cloudflare 계정의 도메인 목록을 조회합니다...".colorize(:yellow)
53
+ def get_domain_input
54
+ prompt = TTY::Prompt.new
53
55
 
54
- zones = get_cloudflare_zones(token)
56
+ puts "\n📝 배포할 도메인을 설정합니다.".colorize(:yellow)
55
57
 
56
- if zones.empty?
57
- puts " Cloudflare에 등록된 도메인(Zone)이 없습니다.".colorize(:red)
58
- puts "먼저 https://dash.cloudflare.com 에서 도메인을 추가해주세요.".colorize(:cyan)
59
- exit 1
58
+ domain = prompt.ask("배포할 도메인을 입력하세요 (예: myapp.com, api.example.com):") do |q|
59
+ q.validate(/\A[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\z/, "올바른 도메인 형식을 입력해주세요 (예: myapp.com)")
60
60
  end
61
61
 
62
- prompt = TTY::Prompt.new
63
- # 사용자가 Zone을 이름으로 선택하고, 선택 시 전체 Zone 객체를 반환하도록 설정
64
- zone_choices = zones.map { |zone| { name: "#{zone['name']} (#{zone['status']})", value: zone } }
65
-
66
- selected_zone = prompt.select("설정할 도메인(Zone)을 선택하세요:", zone_choices, filter: true, per_page: 10)
67
- zone_name = selected_zone['name']
68
- puts "✅ 선택된 Zone: #{zone_name}".colorize(:green)
69
-
70
- domain_type = prompt.select("\n어떤 종류의 도메인을 설정하시겠습니까?", [
71
- { name: "루트 도메인 (@) - 예: #{zone_name}", value: :root },
72
- { name: "서브도메인 - 예: www.#{zone_name}", value: :subdomain }
73
- ])
74
-
75
- if domain_type == :root
76
- return {
77
- type: :root,
78
- domain: zone_name,
79
- zone: zone_name,
80
- selected_zone_object: selected_zone
81
- }
82
- else # :subdomain
83
- subdomain_part = prompt.ask("사용할 서브도메인을 입력하세요 (예: www, api):") do |q|
84
- q.required true
85
- q.validate(/^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/, "유효한 서브도메인을 입력해주세요 (특수문자, . 사용 불가)")
86
- end
87
-
88
- full_domain = "#{subdomain_part.downcase}.#{zone_name}"
89
- puts "✅ 설정할 전체 도메인: #{full_domain}".colorize(:green)
90
-
91
- return {
92
- type: :subdomain,
93
- domain: full_domain,
94
- zone: zone_name,
95
- subdomain: subdomain_part.downcase,
96
- selected_zone_object: selected_zone
97
- }
62
+ # 도메인이 루트인지 서브도메인인지 판단
63
+ parts = domain.split('.')
64
+ if parts.length == 2
65
+ { type: :root, domain: domain, zone: domain }
66
+ else
67
+ zone = parts[-2..-1].join('.')
68
+ { type: :subdomain, domain: domain, zone: zone, subdomain: parts[0..-3].join('.') }
98
69
  end
99
70
  end
100
71
 
101
72
  def open_token_creation_page
102
73
  puts "\n🔑 Cloudflare API 토큰이 필요합니다.".colorize(:yellow)
74
+ puts "토큰 생성 페이지를 엽니다...".colorize(:cyan)
75
+
76
+ # Cloudflare API 토큰 생성 페이지 열기
77
+ system("open 'https://dash.cloudflare.com/profile/api-tokens'")
103
78
 
104
79
  puts "\n다음 권한으로 토큰을 생성해주세요:".colorize(:yellow)
105
80
  puts ""
@@ -113,28 +88,9 @@ module Tayo
113
88
  puts "• Zone → DNS → Edit".colorize(:white)
114
89
  puts " (Zone Resources: Select 'All zones')".colorize(:gray)
115
90
  puts ""
116
-
117
- puts "토큰 생성 페이지를 엽니다...".colorize(:cyan)
118
-
119
- system("open 'https://dash.cloudflare.com/profile/api-tokens'")
120
91
  end
121
92
 
122
93
  def get_cloudflare_token
123
- existing_token = load_saved_token
124
-
125
- if existing_token
126
- puts "💾 저장된 토큰을 발견했습니다.".colorize(:cyan)
127
- if test_cloudflare_token(existing_token)
128
- puts "✅ 저장된 토큰이 유효합니다.".colorize(:green)
129
- return existing_token
130
- else
131
- puts "❌ 저장된 토큰이 만료되거나 무효합니다. 새 토큰을 입력해주세요.".colorize(:yellow)
132
- open_token_creation_page
133
- end
134
- else
135
- open_token_creation_page
136
- end
137
-
138
94
  prompt = TTY::Prompt.new
139
95
 
140
96
  token = prompt.mask("생성된 Cloudflare API 토큰을 붙여넣으세요:")
@@ -144,9 +100,9 @@ module Tayo
144
100
  exit 1
145
101
  end
146
102
 
103
+ # 토큰 유효성 간단 확인
147
104
  if test_cloudflare_token(token.strip)
148
105
  puts "✅ 토큰이 확인되었습니다.".colorize(:green)
149
- save_token(token.strip)
150
106
  return token.strip
151
107
  else
152
108
  puts "❌ 토큰이 올바르지 않거나 권한이 부족합니다.".colorize(:red)
@@ -169,42 +125,27 @@ module Tayo
169
125
  return false
170
126
  end
171
127
 
172
- def load_saved_token
173
- token_file = File.expand_path("~/.tayo")
174
- return nil unless File.exist?(token_file)
175
-
176
- begin
177
- content = File.read(token_file)
178
- token_line = content.lines.find { |line| line.start_with?("CLOUDFLARE_TOKEN=") }
179
- return nil unless token_line
180
-
181
- token = token_line.split("=", 2)[1]&.strip
182
- return token unless token.nil? || token.empty?
183
-
184
- nil
185
- rescue => e
186
- puts "⚠️ 토큰 파일 읽기 중 오류가 발생했습니다: #{e.message}".colorize(:yellow)
187
- nil
188
- end
189
- end
190
-
191
- def save_token(token)
192
- token_file = File.expand_path("~/.tayo")
193
- timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S")
194
-
195
- content = <<~CONTENT
196
- # Tayo Configuration File
197
- # Created: #{timestamp}
198
- CLOUDFLARE_TOKEN=#{token}
199
- CONTENT
200
-
201
- begin
202
- File.write(token_file, content)
203
- File.chmod(0600, token_file)
204
- puts "💾 토큰이 ~/.tayo 파일에 저장되었습니다.".colorize(:green)
205
- rescue => e
206
- puts "⚠️ 토큰 저장 중 오류가 발생했습니다: #{e.message}".colorize(:yellow)
128
+ def select_cloudflare_zone(token)
129
+ puts "\n🌐 Cloudflare 도메인 목록을 조회합니다...".colorize(:yellow)
130
+
131
+ zones = get_cloudflare_zones(token)
132
+
133
+ if zones.empty?
134
+ puts "❌ Cloudflare에 등록된 도메인이 없습니다.".colorize(:red)
135
+ puts "먼저 https://dash.cloudflare.com 에서 도메인을 추가해주세요.".colorize(:cyan)
136
+ exit 1
207
137
  end
138
+
139
+ prompt = TTY::Prompt.new
140
+ zone_choices = zones.map { |zone| "#{zone['name']} (#{zone['status']})" }
141
+
142
+ selected = prompt.select("도메인을 선택하세요:", zone_choices)
143
+ zone_name = selected.split(' ').first
144
+
145
+ selected_zone = zones.find { |zone| zone['name'] == zone_name }
146
+ puts "✅ 선택된 도메인: #{zone_name}".colorize(:green)
147
+
148
+ return selected_zone
208
149
  end
209
150
 
210
151
  def get_cloudflare_zones(token)
@@ -233,10 +174,13 @@ module Tayo
233
174
  def check_existing_records(token, zone, domain_info)
234
175
  puts "\n🔍 기존 DNS 레코드를 확인합니다...".colorize(:yellow)
235
176
 
236
- target_name = (domain_info[:type] == :root) ? zone['name'] : domain_info[:domain]
237
- records = get_dns_records(token, zone['id'], target_name, ['A', 'CNAME'])
177
+ zone_id = zone['id']
178
+ zone_name = zone['name']
179
+
180
+ # 루트 도메인의 A/CNAME 레코드 확인
181
+ records = get_dns_records(token, zone_id, zone_name, ['A', 'CNAME'])
238
182
 
239
- puts " (확인 대상: #{target_name}, 발견된 A/CNAME 레코드: #{records.length}개)".colorize(:gray)
183
+ puts "기존 레코드: #{records.length}개 발견".colorize(:gray)
240
184
 
241
185
  return records
242
186
  end
@@ -246,7 +190,10 @@ module Tayo
246
190
 
247
191
  types.each do |type|
248
192
  uri = URI("https://api.cloudflare.com/client/v4/zones/#{zone_id}/dns_records")
249
- uri.query = URI.encode_www_form({ type: type, name: name })
193
+ uri.query = URI.encode_www_form({
194
+ type: type,
195
+ name: name
196
+ })
250
197
 
251
198
  http = Net::HTTP.new(uri.host, uri.port)
252
199
  http.use_ssl = true
@@ -268,74 +215,71 @@ module Tayo
268
215
  puts "❌ DNS 레코드 조회 중 오류: #{e.message}".colorize(:red)
269
216
  return []
270
217
  end
271
-
218
+
272
219
  def setup_dns_record(token, zone, domain_info, existing_records)
273
220
  puts "\n⚙️ DNS 레코드를 설정합니다...".colorize(:yellow)
274
221
 
222
+ # 홈서버 IP/URL 입력받기
275
223
  prompt = TTY::Prompt.new
276
224
 
277
- server_info = prompt.ask("연결할 서버 IP 또는 도메인을 입력하세요:") do |q|
225
+ server_info = prompt.ask("홈서버 IP 또는 도메인을 입력하세요:") do |q|
278
226
  q.validate(/\A.+\z/, "서버 정보를 입력해주세요")
279
227
  end
280
228
 
229
+ # SSH 사용자 계정 입력받기
281
230
  ssh_user = prompt.ask("SSH 사용자 계정을 입력하세요:", default: "root")
282
231
 
232
+ # IP인지 도메인인지 판단
283
233
  is_ip = server_info.match?(/\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/)
284
234
  record_type = is_ip ? 'A' : 'CNAME'
285
235
 
286
236
  zone_id = zone['id']
287
237
  zone_name = zone['name']
288
238
 
239
+ # 도메인 정보에 따라 레코드 설정
289
240
  final_domain = determine_final_domain(domain_info, zone_name, existing_records)
241
+
242
+ # 대상 도메인의 모든 A/CNAME 레코드 확인
290
243
  all_records = get_dns_records(token, zone_id, final_domain[:name], ['A', 'CNAME'])
291
244
 
292
- is_already_configured = all_records.length == 1 &&
293
- all_records.first['type'] == record_type &&
294
- all_records.first['content'] == server_info
295
-
296
- if is_already_configured
297
- puts "✅ DNS 레코드가 이미 올바르게 설정되어 있습니다.".colorize(:green)
298
- puts " #{final_domain[:full_domain]} → #{server_info} (#{record_type} 레코드)".colorize(:gray)
299
- else
300
- # [수정됨] 기존 레코드가 있으면 사용자에게 확인을 받습니다.
301
- if all_records.any?
302
- puts "\n⚠️ '#{final_domain[:full_domain]}'에 이미 설정된 DNS 레코드가 있습니다.".colorize(:yellow)
303
- puts "--------------------------------------------------"
304
- all_records.each do |record|
305
- puts " - 타입: ".ljust(10) + "#{record['type']}".colorize(:cyan)
306
- puts " 내용: ".ljust(10) + "#{record['content']}".colorize(:cyan)
307
- puts " 프록시: ".ljust(10) + "#{record['proxied'] ? '활성' : '비활성'}".colorize(:cyan)
308
- puts " "
309
- end
310
- puts "--------------------------------------------------"
311
-
312
- message = "이 레코드를 삭제하고 새로 설정하시겠습니까? (이 작업은 되돌릴 수 없습니다)"
313
- unless prompt.yes?(message)
314
- puts "❌ DNS 설정이 사용자에 의해 취소되었습니다. 스크립트를 종료합니다.".colorize(:red)
315
- exit 0
316
- end
317
-
318
- puts "\n✅ 사용자가 승인하여 기존 레코드를 삭제하고 새 레코드를 생성합니다.".colorize(:green)
319
- all_records.each do |record|
320
- delete_dns_record(token, zone_id, record['id'])
321
- end
322
- create_dns_record(token, zone_id, final_domain[:name], record_type, server_info)
323
-
245
+ if all_records.any?
246
+ existing_record = all_records.first
247
+
248
+ # 동일한 타입이고 같은 값이면 건너뛰기
249
+ if existing_record['type'] == record_type && existing_record['content'] == server_info
250
+ puts "✅ DNS 레코드가 이미 올바르게 설정되어 있습니다.".colorize(:green)
251
+ puts " #{final_domain[:full_domain]} → #{server_info} (#{record_type} 레코드)".colorize(:gray)
324
252
  else
325
- # 기존 레코드가 없으면 바로 생성합니다.
253
+ # 타입이 다르거나 값이 다른 경우 삭제 후 재생성
254
+ puts "⚠️ 기존 레코드를 삭제하고 새로 생성합니다.".colorize(:yellow)
255
+ puts " 기존: #{existing_record['content']} (#{existing_record['type']}) → 새로운: #{server_info} (#{record_type})".colorize(:gray)
256
+
257
+ # 기존 레코드 삭제
258
+ delete_dns_record(token, zone_id, existing_record['id'])
259
+
260
+ # 새 레코드 생성
326
261
  create_dns_record(token, zone_id, final_domain[:name], record_type, server_info)
327
262
  end
263
+ else
264
+ # DNS 레코드 생성
265
+ create_dns_record(token, zone_id, final_domain[:name], record_type, server_info)
328
266
  end
329
267
 
268
+ # 최종 도메인 정보 저장
330
269
  @final_domain = final_domain[:full_domain]
331
270
  @server_info = server_info
332
271
  @ssh_user = ssh_user
333
272
  end
334
-
273
+
335
274
  def determine_final_domain(domain_info, zone_name, existing_records)
336
275
  case domain_info[:type]
337
276
  when :root
338
- { name: zone_name, full_domain: zone_name }
277
+ if existing_records.any?
278
+ puts "⚠️ 루트 도메인에 이미 레코드가 있습니다. app.#{zone_name}을 사용합니다.".colorize(:yellow)
279
+ { name: "app.#{zone_name}", full_domain: "app.#{zone_name}" }
280
+ else
281
+ { name: zone_name, full_domain: zone_name }
282
+ end
339
283
  when :subdomain
340
284
  { name: domain_info[:domain], full_domain: domain_info[:domain] }
341
285
  end
@@ -354,8 +298,7 @@ module Tayo
354
298
  type: type,
355
299
  name: name,
356
300
  content: content,
357
- ttl: 300,
358
- proxied: true
301
+ ttl: 300
359
302
  }
360
303
 
361
304
  request.body = data.to_json
@@ -363,7 +306,7 @@ module Tayo
363
306
 
364
307
  if response.code == '200'
365
308
  puts "✅ DNS 레코드가 생성되었습니다.".colorize(:green)
366
- puts " #{name} → #{content} (#{type} 레코드, 프록시됨)".colorize(:gray)
309
+ puts " #{name} → #{content} (#{type} 레코드)".colorize(:gray)
367
310
  else
368
311
  puts "❌ DNS 레코드 생성에 실패했습니다: #{response.code}".colorize(:red)
369
312
  puts response.body
@@ -385,12 +328,16 @@ module Tayo
385
328
 
386
329
  response = http.request(request)
387
330
 
388
- unless response.code == '200'
331
+ if response.code == '200'
332
+ puts "✅ 기존 DNS 레코드가 삭제되었습니다.".colorize(:green)
333
+ else
389
334
  puts "❌ DNS 레코드 삭제에 실패했습니다: #{response.code}".colorize(:red)
390
335
  puts response.body
336
+ exit 1
391
337
  end
392
338
  rescue => e
393
339
  puts "❌ DNS 레코드 삭제 중 오류: #{e.message}".colorize(:red)
340
+ exit 1
394
341
  end
395
342
 
396
343
  def update_deploy_config(domain_info)
@@ -409,23 +356,27 @@ module Tayo
409
356
  if content.include?("proxy:")
410
357
  content.gsub!(/(\s+host:\s+).*$/, "\\1#{@final_domain}")
411
358
  else
359
+ # proxy 섹션이 없으면 추가
412
360
  proxy_config = "\n# Proxy configuration\nproxy:\n ssl: true\n host: #{@final_domain}\n"
413
361
  content += proxy_config
414
362
  end
415
363
 
416
364
  # servers 설정 업데이트
417
365
  if content.match?(/servers:\s*\n\s*web:\s*\n\s*-\s*/)
418
- content.gsub!(/(\s*servers:\s*\n\s*web:\s*\n\s*-\s*)[\w.-]+/, "\\1#{@server_info}")
366
+ content.gsub!(/(\s*servers:\s*\n\s*web:\s*\n\s*-\s*)[\d.]+/, "\\1#{@server_info}")
419
367
  end
420
368
 
421
369
  # ssh user 설정 업데이트
422
370
  if @ssh_user && @ssh_user != "root"
423
371
  if content.match?(/^ssh:/)
372
+ # 기존 ssh 섹션 업데이트
424
373
  content.gsub!(/^ssh:\s*\n\s*user:\s*\w+/, "ssh:\n user: #{@ssh_user}")
425
374
  else
375
+ # ssh 섹션 추가 (accessories 섹션 앞에 추가)
426
376
  if content.match?(/^# Use accessory services/)
427
377
  content.gsub!(/^# Use accessory services/, "# Use a different ssh user than root\nssh:\n user: #{@ssh_user}\n\n# Use accessory services")
428
378
  else
379
+ # 파일 끝에 추가
429
380
  content += "\n# Use a different ssh user than root\nssh:\n user: #{@ssh_user}\n"
430
381
  end
431
382
  end
@@ -435,28 +386,31 @@ module Tayo
435
386
  puts "✅ config/deploy.yml이 업데이트되었습니다.".colorize(:green)
436
387
  puts " proxy.host: #{@final_domain}".colorize(:gray)
437
388
  puts " servers.web: #{@server_info}".colorize(:gray)
438
- if @ssh_user && @ssh_user != "root"
439
- puts " ssh.user: #{@ssh_user}".colorize(:gray)
440
- end
389
+ puts " ssh.user: #{@ssh_user}".colorize(:gray) if @ssh_user && @ssh_user != "root"
441
390
  end
442
391
 
443
392
  def commit_cloudflare_changes(domain_info)
444
393
  puts "\n📝 변경사항을 Git에 커밋합니다...".colorize(:yellow)
445
394
 
446
- status_output = `git status --porcelain config/deploy.yml`.strip
395
+ # 변경된 파일이 있는지 확인
396
+ status_output = `git status --porcelain`.strip
447
397
 
448
398
  if status_output.empty?
449
- puts "ℹ️ 커밋할 변경사항이 없습니다.".colorize(:cyan)
399
+ puts "ℹ️ 커밋할 변경사항이 없습니다.".colorize(:yellow)
450
400
  return
451
401
  end
452
402
 
453
- system("git add config/deploy.yml")
403
+ # Git add
404
+ system("git add -A")
454
405
 
455
- commit_message = "feat: Configure Cloudflare DNS for #{@final_domain}\n\n- Set DNS record for #{@final_domain} to point to #{@server_info}\n- Update deployment configuration in config/deploy.yml\n\n🤖 Generated by Tayo"
406
+ # Commit 메시지 생성
407
+ commit_message = "Configure Cloudflare DNS settings\n\n- Setup DNS for domain: #{domain_info[:domain]}\n- Configure server IP: #{domain_info[:server_ip]}\n- Update deployment configuration\n- Add proxy host settings\n\n🤖 Generated with Tayo"
456
408
 
409
+ # Commit 실행
457
410
  if system("git commit -m \"#{commit_message}\"")
458
411
  puts "✅ 변경사항이 성공적으로 커밋되었습니다.".colorize(:green)
459
412
 
413
+ # GitHub에 푸시
460
414
  if system("git push", out: File::NULL, err: File::NULL)
461
415
  puts "✅ 변경사항이 GitHub에 푸시되었습니다.".colorize(:green)
462
416
  else
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "colorize"
4
- # require_relative "../dockerfile_modifier"
4
+ require_relative "../dockerfile_modifier"
5
5
 
6
6
  module Tayo
7
7
  module Commands
@@ -15,9 +15,9 @@ module Tayo
15
15
  end
16
16
  commit_initial_state
17
17
  check_orbstack
18
- create_welcome_page
18
+ create_welcome_page
19
19
  clear_docker_cache
20
- ensure_dockerfile_exists
20
+ ensure_dockerfile_exists
21
21
  commit_changes
22
22
  puts "✅ Tayo가 성공적으로 설정되었습니다!".colorize(:green)
23
23
  end
@@ -30,19 +30,19 @@ module Tayo
30
30
 
31
31
  def check_orbstack
32
32
  puts "🐳 OrbStack 상태를 확인합니다...".colorize(:yellow)
33
-
33
+
34
34
  # OrbStack 실행 상태 확인
35
35
  orbstack_running = system("pgrep -x OrbStack > /dev/null 2>&1")
36
-
36
+
37
37
  if orbstack_running
38
38
  puts "✅ OrbStack이 실행 중입니다.".colorize(:green)
39
39
  else
40
40
  puts "🚀 OrbStack을 시작합니다...".colorize(:yellow)
41
-
41
+
42
42
  # OrbStack 실행
43
43
  if system("open -a OrbStack")
44
44
  puts "✅ OrbStack이 시작되었습니다.".colorize(:green)
45
-
45
+
46
46
  # OrbStack이 완전히 시작될 때까지 잠시 대기
47
47
  print "Docker 서비스가 준비될 때까지 대기 중".colorize(:yellow)
48
48
  5.times do
@@ -50,7 +50,7 @@ module Tayo
50
50
  print ".".colorize(:yellow)
51
51
  end
52
52
  puts ""
53
-
53
+
54
54
  # Docker가 준비되었는지 확인
55
55
  if system("docker ps > /dev/null 2>&1")
56
56
  puts "✅ Docker가 준비되었습니다.".colorize(:green)
@@ -64,11 +64,11 @@ module Tayo
64
64
  end
65
65
  end
66
66
  end
67
-
67
+
68
68
  def ensure_dockerfile_exists
69
69
  unless File.exist?("Dockerfile")
70
70
  puts "🐳 Dockerfile이 없습니다. 기본 Dockerfile을 생성합니다...".colorize(:yellow)
71
-
71
+
72
72
  # Rails 7의 기본 Dockerfile 생성
73
73
  if system("rails app:update:bin")
74
74
  system("./bin/rails generate dockerfile")
@@ -80,7 +80,7 @@ module Tayo
80
80
  end
81
81
  else
82
82
  puts "✅ Dockerfile이 이미 존재합니다.".colorize(:green)
83
- end
83
+ end
84
84
  end
85
85
 
86
86
  def create_welcome_page
@@ -90,15 +90,15 @@ module Tayo
90
90
  @welcome_page_created = false
91
91
  return
92
92
  end
93
-
93
+
94
94
  puts "🎨 Welcome 페이지를 생성합니다...".colorize(:yellow)
95
-
95
+
96
96
  # Welcome 컨트롤러 생성
97
97
  system("rails generate controller Welcome index --skip-routes --no-helper --no-assets")
98
-
98
+
99
99
  # 프로젝트 이름 가져오기
100
100
  project_name = File.basename(Dir.pwd).gsub(/[-_]/, ' ').split.map(&:capitalize).join(' ')
101
-
101
+
102
102
  # Welcome 페이지 HTML 생성
103
103
  welcome_html = <<~HTML
104
104
  <!DOCTYPE html>
@@ -188,7 +188,7 @@ module Tayo
188
188
  <div class="container">
189
189
  <h1>🏠 #{project_name}</h1>
190
190
  <p class="subtitle">Welcome to your Tayo-powered Rails application!</p>
191
-
191
+
192
192
  <div class="info-grid">
193
193
  <div class="info-card">
194
194
  <h3>📦 Container Ready</h3>
@@ -203,7 +203,7 @@ module Tayo
203
203
  <p>Domain management simplified</p>
204
204
  </div>
205
205
  </div>
206
-
206
+
207
207
  <div class="deploy-badge">
208
208
  Deployed with Tayo 🎉
209
209
  </div>
@@ -211,15 +211,15 @@ module Tayo
211
211
  </body>
212
212
  </html>
213
213
  HTML
214
-
214
+
215
215
  # Welcome 뷰 파일에 저장
216
216
  welcome_view_path = "app/views/welcome/index.html.erb"
217
217
  File.write(welcome_view_path, welcome_html)
218
-
218
+
219
219
  # routes.rb 업데이트
220
220
  routes_file = "config/routes.rb"
221
221
  routes_content = File.read(routes_file)
222
-
222
+
223
223
  # root 경로 설정 - welcome#index가 이미 있는지 확인
224
224
  unless routes_content.include?("welcome#index")
225
225
  if routes_content.match?(/^\s*root\s+/)
@@ -229,18 +229,18 @@ module Tayo
229
229
  # root 설정이 없으면 추가
230
230
  routes_content.gsub!(/Rails\.application\.routes\.draw do\s*\n/, "Rails.application.routes.draw do\n root 'welcome#index'\n")
231
231
  end
232
-
232
+
233
233
  File.write(routes_file, routes_content)
234
234
  puts " ✅ routes.rb에 root 경로를 설정했습니다.".colorize(:green)
235
235
  else
236
236
  puts " ℹ️ routes.rb에 welcome#index가 이미 설정되어 있습니다.".colorize(:yellow)
237
237
  end
238
-
238
+
239
239
  puts "✅ Welcome 페이지가 생성되었습니다!".colorize(:green)
240
240
  puts " 경로: /".colorize(:gray)
241
241
  puts " 컨트롤러: app/controllers/welcome_controller.rb".colorize(:gray)
242
242
  puts " 뷰: app/views/welcome/index.html.erb".colorize(:gray)
243
-
243
+
244
244
  @welcome_page_created = true
245
245
  end
246
246
 
@@ -250,20 +250,20 @@ module Tayo
250
250
  puts "⚠️ Git 저장소가 아닙니다. 커밋을 건너뜁니다.".colorize(:yellow)
251
251
  return
252
252
  end
253
-
253
+
254
254
  puts "📝 초기 상태를 Git에 커밋합니다...".colorize(:yellow)
255
-
255
+
256
256
  # Git 상태 확인
257
257
  git_status = `git status --porcelain`
258
-
258
+
259
259
  if git_status.strip.empty?
260
260
  puts "ℹ️ 커밋할 변경사항이 없습니다.".colorize(:yellow)
261
261
  return
262
262
  end
263
-
263
+
264
264
  # 변경사항 스테이징
265
265
  system("git add .")
266
-
266
+
267
267
  # 커밋
268
268
  commit_message = "Save current state before Tayo initialization"
269
269
  if system("git commit -m '#{commit_message}'")
@@ -280,20 +280,20 @@ module Tayo
280
280
  puts "⚠️ Git 저장소가 아닙니다. 커밋을 건너뜁니다.".colorize(:yellow)
281
281
  return
282
282
  end
283
-
283
+
284
284
  puts "📝 Tayo 설정 완료 상태를 Git에 커밋합니다...".colorize(:yellow)
285
-
285
+
286
286
  # Git 상태 확인
287
287
  git_status = `git status --porcelain`
288
-
288
+
289
289
  if git_status.strip.empty?
290
290
  puts "ℹ️ 커밋할 변경사항이 없습니다.".colorize(:yellow)
291
291
  return
292
292
  end
293
-
293
+
294
294
  # 변경사항 스테이징
295
295
  system("git add .")
296
-
296
+
297
297
  # 커밋
298
298
  commit_message = "Complete Tayo initialization with Welcome page and Docker setup"
299
299
  if system("git commit -m '#{commit_message}'")
@@ -306,14 +306,14 @@ module Tayo
306
306
 
307
307
  def clear_docker_cache
308
308
  puts "🧹 Docker 캐시를 정리합니다...".colorize(:yellow)
309
-
309
+
310
310
  # Docker system prune
311
311
  if system("docker system prune -f > /dev/null 2>&1")
312
312
  puts "✅ Docker 시스템 캐시가 정리되었습니다.".colorize(:green)
313
313
  else
314
314
  puts "⚠️ Docker 시스템 정리에 실패했습니다.".colorize(:yellow)
315
315
  end
316
-
316
+
317
317
  # Kamal build cache clear
318
318
  if File.exist?("config/deploy.yml")
319
319
  puts "🚢 Kamal 빌드 캐시를 정리합니다...".colorize(:yellow)