tayo 0.2.3 → 0.3.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.
@@ -177,44 +177,48 @@ module Tayo
177
177
  def create_github_repository
178
178
  repo_name = File.basename(Dir.pwd)
179
179
  username = `gh api user -q .login`.strip
180
-
180
+
181
181
  # 조직 목록 가져오기
182
182
  orgs_json = `gh api user/orgs -q '.[].login' 2>/dev/null`
183
183
  orgs = orgs_json.strip.split("\n").reject(&:empty?)
184
-
184
+
185
185
  owner = username
186
-
186
+
187
187
  if orgs.any?
188
188
  prompt = TTY::Prompt.new
189
189
  choices = ["#{username} (개인 계정)"] + orgs.map { |org| "#{org} (조직)" }
190
-
190
+
191
191
  selection = prompt.select("🏢 저장소를 생성할 위치를 선택하세요:", choices)
192
-
192
+
193
193
  if selection != "#{username} (개인 계정)"
194
194
  owner = selection.split(" ").first
195
195
  end
196
196
  end
197
-
197
+
198
+ @repo_name = repo_name
199
+ @username = owner
200
+
198
201
  # 저장소 존재 여부 확인
199
202
  repo_exists = system("gh repo view #{owner}/#{repo_name}", out: File::NULL, err: File::NULL)
200
-
203
+
201
204
  if repo_exists
202
205
  puts "ℹ️ GitHub 저장소가 이미 존재합니다: https://github.com/#{owner}/#{repo_name}".colorize(:yellow)
203
- @repo_name = repo_name
204
- @username = owner
206
+ # remote 설정 확인 및 업데이트
207
+ setup_git_remote(owner, repo_name)
205
208
  else
209
+ # 기존 origin remote 제거 (있다면)
210
+ system("git remote remove origin 2>/dev/null")
211
+
206
212
  create_cmd = if owner == username
207
213
  "gh repo create #{repo_name} --private --source=. --remote=origin --push"
208
214
  else
209
215
  "gh repo create #{owner}/#{repo_name} --private --source=. --remote=origin --push"
210
216
  end
211
-
217
+
212
218
  result = system(create_cmd)
213
-
219
+
214
220
  if result
215
221
  puts "✅ GitHub 저장소를 생성했습니다: https://github.com/#{owner}/#{repo_name}".colorize(:green)
216
- @repo_name = repo_name
217
- @username = owner
218
222
  else
219
223
  puts "❌ GitHub 저장소 생성에 실패했습니다.".colorize(:red)
220
224
  exit 1
@@ -222,13 +226,38 @@ module Tayo
222
226
  end
223
227
  end
224
228
 
229
+ def setup_git_remote(owner, repo_name)
230
+ remote_url = "git@github.com:#{owner}/#{repo_name}.git"
231
+ current_remote = `git remote get-url origin 2>/dev/null`.strip
232
+
233
+ if current_remote.empty?
234
+ # origin이 없으면 추가
235
+ system("git remote add origin #{remote_url}")
236
+ puts " ✅ remote origin을 추가했습니다.".colorize(:green)
237
+ elsif current_remote != remote_url && !current_remote.include?("#{owner}/#{repo_name}")
238
+ # origin이 다른 저장소를 가리키면 업데이트
239
+ system("git remote set-url origin #{remote_url}")
240
+ puts " ✅ remote origin을 업데이트했습니다.".colorize(:green)
241
+ else
242
+ puts " ✅ remote origin이 올바르게 설정되어 있습니다.".colorize(:green)
243
+ end
244
+
245
+ # push 되지 않은 커밋이 있으면 push
246
+ unpushed = `git log origin/main..HEAD 2>/dev/null`.strip
247
+ if !unpushed.empty? || !system("git rev-parse origin/main", out: File::NULL, err: File::NULL)
248
+ puts " 📤 변경사항을 push합니다...".colorize(:yellow)
249
+ system("git push -u origin main")
250
+ end
251
+ end
252
+
225
253
  def create_container_registry
226
254
  # Docker 이미지 태그는 소문자여야 함
227
- registry_url = "ghcr.io/#{@username.downcase}/#{@repo_name.downcase}"
228
- @registry_url = registry_url
255
+ # Kamal은 registry.server + image를 조합하므로 image에는 username/repo만 지정
256
+ @image_name = "#{@username.downcase}/#{@repo_name.downcase}"
257
+ @registry_url = "ghcr.io/#{@image_name}" # 전체 URL (표시용)
229
258
 
230
259
  puts "✅ 컨테이너 레지스트리가 설정되었습니다.".colorize(:green)
231
- puts " URL: #{registry_url}".colorize(:gray)
260
+ puts " URL: #{@registry_url}".colorize(:gray)
232
261
  puts " ℹ️ 컨테이너 레지스트리는 첫 이미지 푸시 시 자동으로 생성됩니다.".colorize(:gray)
233
262
 
234
263
  # Docker로 GitHub Container Registry에 로그인
@@ -273,31 +302,44 @@ module Tayo
273
302
 
274
303
  def update_kamal_config
275
304
  content = File.read("config/deploy.yml")
276
-
277
- # 이미지 설정 업데이트 (ghcr.io 중복 제거)
278
- # @registry_url이미 ghcr.io포함하고 있으므로, 그대로 사용
279
- content.gsub!(/^image:\s+.*$/, "image: #{@registry_url}")
280
-
305
+
306
+ # 이미지 설정 업데이트
307
+ # Kamalregistry.server + image조합하므로 image에는 username/repo만 지정
308
+ content.gsub!(/^image:\s+.*$/, "image: #{@image_name}")
309
+
281
310
  # registry 섹션 업데이트
282
311
  if content.include?("registry:")
283
- # 기존 registry 섹션 수정
284
- # server 라인이 주석처리되어 있는지 확인
312
+ # server 설정 (주석 처리된 경우 활성화)
285
313
  if content.match?(/^\s*#\s*server:/)
286
314
  content.gsub!(/^\s*#\s*server:\s*.*$/, " server: ghcr.io")
287
315
  elsif content.match?(/^\s*server:/)
288
316
  content.gsub!(/^\s*server:\s*.*$/, " server: ghcr.io")
317
+ end
318
+
319
+ # username 설정 (주석 처리된 경우 활성화)
320
+ if content.match?(/^\s*#\s*username:/)
321
+ content.gsub!(/^\s*#\s*username:\s*.*$/, " username: #{@username.downcase}")
322
+ elsif content.match?(/^\s*username:/)
323
+ content.gsub!(/^\s*username:\s*.*$/, " username: #{@username.downcase}")
289
324
  else
290
- # server 라인이 없으면 username 위에 추가
291
- content.gsub!(/(\s*username:\s+)/, " server: ghcr.io\n\\1")
325
+ # username이 없으면 server 다음에 추가
326
+ content.gsub!(/(^\s*server:\s*ghcr\.io\s*$)/, "\\1\n username: #{@username.downcase}")
327
+ end
328
+
329
+ # password 설정 (주석 처리된 경우 활성화)
330
+ # 형식: " # password:\n # - KAMAL_REGISTRY_PASSWORD"
331
+ if content.match?(/^(\s*)#\s*password:\s*\n\s*#\s+-\s*KAMAL_REGISTRY_PASSWORD/m)
332
+ content.gsub!(
333
+ /^(\s*)#\s*password:\s*\n\s*#\s+-\s*KAMAL_REGISTRY_PASSWORD/m,
334
+ "\\1password:\n\\1 - KAMAL_REGISTRY_PASSWORD"
335
+ )
292
336
  end
293
- # username도 소문자로 변환
294
- content.gsub!(/^\s*username:\s+.*$/, " username: #{@username.downcase}")
295
337
  else
296
338
  # registry 섹션 추가
297
339
  registry_config = "\n# Container registry configuration\nregistry:\n server: ghcr.io\n username: #{@username.downcase}\n password:\n - KAMAL_REGISTRY_PASSWORD\n"
298
340
  content.gsub!(/^# Credentials for your image host\.\nregistry:.*?^$/m, registry_config)
299
341
  end
300
-
342
+
301
343
  File.write("config/deploy.yml", content)
302
344
 
303
345
  # GitHub 토큰을 Kamal secrets 파일에 설정
@@ -312,35 +354,28 @@ module Tayo
312
354
  def setup_kamal_secrets
313
355
  # .kamal 디렉토리 생성
314
356
  Dir.mkdir(".kamal") unless Dir.exist?(".kamal")
315
-
316
- # 현재 GitHub 토큰 가져오기
317
- token_output = `gh auth token 2>/dev/null`
318
-
319
- if $?.success? && !token_output.strip.empty?
320
- token = token_output.strip
321
- secrets_file = ".kamal/secrets"
322
-
323
- # 기존 secrets 파일 읽기 (있다면)
324
- existing_content = File.exist?(secrets_file) ? File.read(secrets_file) : ""
325
-
326
- # KAMAL_REGISTRY_PASSWORD 이미 있는지 확인
327
- if existing_content.include?("KAMAL_REGISTRY_PASSWORD")
328
- # 기존 값 업데이트
329
- updated_content = existing_content.gsub(/^KAMAL_REGISTRY_PASSWORD=.*$/, "KAMAL_REGISTRY_PASSWORD=#{token}")
330
- else
331
- # 새로 추가
332
- updated_content = existing_content.empty? ? "KAMAL_REGISTRY_PASSWORD=#{token}\n" : "#{existing_content.chomp}\nKAMAL_REGISTRY_PASSWORD=#{token}\n"
333
- end
334
-
335
- File.write(secrets_file, updated_content)
336
- puts "✅ GitHub 토큰이 .kamal/secrets에 설정되었습니다.".colorize(:green)
337
-
338
- # .gitignore에 secrets 파일 추가
339
- add_to_gitignore(".kamal/secrets")
357
+
358
+ secrets_file = ".kamal/secrets"
359
+
360
+ # 기존 secrets 파일 읽기 (있다면)
361
+ existing_content = File.exist?(secrets_file) ? File.read(secrets_file) : ""
362
+
363
+ # KAMAL_REGISTRY_PASSWORD가 실제로 설정되어 있는지 확인 (주석 제외)
364
+ password_line = 'KAMAL_REGISTRY_PASSWORD=$(gh auth token)'
365
+
366
+ if existing_content.match?(/^KAMAL_REGISTRY_PASSWORD=/)
367
+ # 기존 값 업데이트
368
+ updated_content = existing_content.gsub(/^KAMAL_REGISTRY_PASSWORD=.*$/, password_line)
340
369
  else
341
- puts "⚠️ GitHub 토큰을 가져올 수 없습니다. 수동으로 설정해주세요:".colorize(:yellow)
342
- puts " echo 'KAMAL_REGISTRY_PASSWORD=your_github_token' >> .kamal/secrets".colorize(:cyan)
370
+ # 새로 추가 (파일 끝에)
371
+ updated_content = "#{existing_content.chomp}\n#{password_line}\n"
343
372
  end
373
+
374
+ File.write(secrets_file, updated_content)
375
+ puts "✅ KAMAL_REGISTRY_PASSWORD가 .kamal/secrets에 설정되었습니다.".colorize(:green)
376
+
377
+ # .gitignore에 secrets 파일 추가
378
+ add_to_gitignore(".kamal/secrets")
344
379
  end
345
380
 
346
381
  def add_to_gitignore(file_path)
@@ -93,8 +93,21 @@ module Tayo
93
93
 
94
94
  puts "🎨 Welcome 페이지를 생성합니다...".colorize(:yellow)
95
95
 
96
- # Welcome 컨트롤러 생성
97
- system("rails generate controller Welcome index --skip-routes --no-helper --no-assets")
96
+ # Welcome 컨트롤러 생성 시도
97
+ unless system("rails generate controller Welcome index --skip-routes --no-helper --no-assets")
98
+ puts " ⚠️ rails generate 실패. 수동으로 파일을 생성합니다.".colorize(:yellow)
99
+ # 디렉토리와 컨트롤러 파일 직접 생성
100
+ FileUtils.mkdir_p("app/controllers")
101
+ FileUtils.mkdir_p("app/views/welcome")
102
+
103
+ controller_content = <<~RUBY
104
+ class WelcomeController < ApplicationController
105
+ def index
106
+ end
107
+ end
108
+ RUBY
109
+ File.write("app/controllers/welcome_controller.rb", controller_content)
110
+ end
98
111
 
99
112
  # 프로젝트 이름 가져오기
100
113
  project_name = File.basename(Dir.pwd).gsub(/[-_]/, ' ').split.map(&:capitalize).join(' ')
data/lib/tayo/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tayo
4
- VERSION = "0.2.3"
4
+ VERSION = "0.3.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tayo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - 이원섭wonsup Lee/Alfonso
@@ -99,18 +99,10 @@ files:
99
99
  - lib/tayo/commands/cf.rb
100
100
  - lib/tayo/commands/gh.rb
101
101
  - lib/tayo/commands/init.rb
102
- - lib/tayo/commands/proxy.rb
103
102
  - lib/tayo/commands/sqlite.rb
104
103
  - lib/tayo/dockerfile_modifier.rb
105
- - lib/tayo/proxy/cloudflare_client.rb
106
- - lib/tayo/proxy/docker_manager.rb
107
- - lib/tayo/proxy/network_config.rb
108
- - lib/tayo/proxy/traefik_config.rb
109
- - lib/tayo/proxy/welcome_service.rb
110
104
  - lib/tayo/templates/solid-cable-sqlite-setup.md
111
105
  - lib/tayo/version.rb
112
- - lib/templates/welcome/Dockerfile
113
- - lib/templates/welcome/index.html
114
106
  - pkg/homebody-0.1.0.gem
115
107
  - repomix-output.xml
116
108
  - sig/tayo.rbs
@@ -134,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
126
  - !ruby/object:Gem::Version
135
127
  version: '0'
136
128
  requirements: []
137
- rubygems_version: 3.7.1
129
+ rubygems_version: 4.0.3
138
130
  specification_version: 4
139
131
  summary: Rails deployment tool for home servers
140
132
  test_files: []
@@ -1,97 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "colorize"
4
- require "tty-prompt"
5
- require_relative "../proxy/cloudflare_client"
6
- require_relative "../proxy/docker_manager"
7
- require_relative "../proxy/network_config"
8
- require_relative "../proxy/traefik_config"
9
- require_relative "../proxy/welcome_service"
10
-
11
- module Tayo
12
- module Commands
13
- class Proxy
14
- def execute
15
- puts "🚀 Kamal Proxy와 Caddy 설정을 시작합니다...".colorize(:green)
16
- puts ""
17
-
18
- # 1. Cloudflare 설정
19
- cloudflare = Tayo::Proxy::CloudflareClient.new
20
- cloudflare.ensure_token
21
-
22
- # 2. 네트워크 설정
23
- network = Tayo::Proxy::NetworkConfig.new
24
- network.detect_ips
25
- network.configure_ports
26
-
27
- # 3. Docker 확인
28
- docker = Tayo::Proxy::DockerManager.new
29
- docker.check_containers
30
-
31
- # 4. 도메인 선택
32
- selected_domains = cloudflare.select_domains
33
-
34
- if selected_domains.empty?
35
- puts "❌ 도메인이 선택되지 않았습니다. 종료합니다.".colorize(:red)
36
- return
37
- end
38
-
39
- # 5. DNS 설정
40
- puts "\n📝 DNS 레코드를 설정합니다...".colorize(:yellow)
41
- cloudflare.setup_dns_records(selected_domains, network.public_ip)
42
-
43
- # 6. Welcome 서비스 확인
44
- welcome = Tayo::Proxy::WelcomeService.new
45
- welcome.ensure_running
46
-
47
- # 7. Traefik 설정
48
- traefik = Tayo::Proxy::TraefikConfig.new
49
- traefik.setup(selected_domains)
50
-
51
- # 8. 최종 안내
52
- show_summary(selected_domains, network)
53
-
54
- rescue => e
55
- puts "❌ 오류가 발생했습니다: #{e.message}".colorize(:red)
56
- puts e.backtrace.join("\n") if ENV["DEBUG"]
57
- exit 1
58
- end
59
-
60
- private
61
-
62
- def show_summary(domains, network)
63
- puts "\n" + "="*60
64
- puts "✅ Proxy 설정이 완료되었습니다!".colorize(:green)
65
- puts "="*60
66
-
67
- puts "\n📋 설정 요약:".colorize(:yellow)
68
- puts "━"*40
69
- puts "공인 IP: #{network.public_ip}".colorize(:white)
70
- puts "내부 IP: #{network.internal_ip}".colorize(:white)
71
- puts "Traefik: 80, 443 포트 사용 중".colorize(:white)
72
- puts "대시보드: http://localhost:8080".colorize(:white)
73
- puts "━"*40
74
-
75
- puts "\n🌐 활성화된 도메인:".colorize(:yellow)
76
- domains.each do |domain|
77
- if network.use_custom_ports?
78
- puts "• #{domain}".colorize(:cyan)
79
- puts " HTTP: http://#{domain}:#{network.external_http}".colorize(:gray)
80
- puts " HTTPS: https://#{domain}:#{network.external_https}".colorize(:gray)
81
- else
82
- puts "• #{domain}".colorize(:cyan)
83
- puts " HTTP: http://#{domain}".colorize(:gray)
84
- puts " HTTPS: https://#{domain}".colorize(:gray)
85
- end
86
- end
87
-
88
- if network.use_custom_ports?
89
- puts "\n💡 공유기 포트포워딩을 설정하세요!".colorize(:yellow)
90
- network.show_port_forwarding_guide
91
- end
92
-
93
- puts "\n🎉 모든 설정이 완료되었습니다!".colorize(:green)
94
- end
95
- end
96
- end
97
- end