rufio 0.21.0 → 0.31.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.
data/info/welcome.md ADDED
@@ -0,0 +1,40 @@
1
+ # Welcome to rufio! 🚀
2
+
3
+ Thank you for using **rufio** - a terminal-based file manager inspired by [Yazi](https://github.com/sxyazi/yazi).
4
+
5
+ ## Key Features
6
+
7
+ - **Vim-like keybindings** - Navigate with `j/k/h/l` keys
8
+ - **Real-time filtering** - Press `f` to filter files instantly
9
+ - **Advanced search** - Use `fzf` for file names and `rga` for content search
10
+ - **Bookmark support** - Quick access to favorite directories with number keys
11
+ - **Project mode** - Manage multiple projects efficiently
12
+ - **Plugin system** - Extend functionality with custom plugins
13
+
14
+ ## Quick Start
15
+
16
+ | Key | Action |
17
+ |-----|--------|
18
+ | `j/k` | Move down/up |
19
+ | `h/l` | Go to parent / Enter directory |
20
+ | `f` | Filter files |
21
+ | `b` | Add bookmark |
22
+ | `p` | Project mode |
23
+ | `?` | Help mode |
24
+ | `:` | Command mode |
25
+ | `q` | Quit |
26
+
27
+ ## Getting Help
28
+
29
+ Press `?` to enter **Help Mode** where you can browse all documentation files.
30
+ Press `ESC` to exit Help Mode.
31
+
32
+ ## More Information
33
+
34
+ Visit the GitHub repository for detailed documentation:
35
+ - **Repository**: https://github.com/masisz/rufio
36
+ - **Issues**: https://github.com/masisz/rufio/issues
37
+
38
+ ---
39
+
40
+ *Happy file managing! 📁*
@@ -4,10 +4,11 @@ require 'fileutils'
4
4
 
5
5
  module Rufio
6
6
  class DirectoryListing
7
- attr_reader :current_path
7
+ attr_reader :current_path, :start_directory
8
8
 
9
9
  def initialize(path = Dir.pwd)
10
10
  @current_path = File.expand_path(path)
11
+ @start_directory = @current_path # 起動時のディレクトリを保存
11
12
  @entries = []
12
13
  refresh
13
14
  end
@@ -51,6 +51,14 @@ module Rufio
51
51
  @project_log = ProjectLog.new(log_dir)
52
52
  @in_project_mode = false
53
53
  @in_log_mode = false
54
+
55
+ # Help mode
56
+ @in_help_mode = false
57
+ @pre_help_directory = nil
58
+
59
+ # Preview pane focus and scroll
60
+ @preview_focused = false
61
+ @preview_scroll_offset = 0
54
62
  end
55
63
 
56
64
  def set_directory_listing(directory_listing)
@@ -85,6 +93,16 @@ module Rufio
85
93
  return handle_project_mode_key(key)
86
94
  end
87
95
 
96
+ # プレビューペインフォーカス中の特別処理
97
+ if @preview_focused
98
+ return handle_preview_focus_key(key)
99
+ end
100
+
101
+ # ヘルプモード中のESCキー特別処理
102
+ if @in_help_mode && key == "\e"
103
+ return exit_help_mode
104
+ end
105
+
88
106
  # フィルターモード中は他のキーバインドを無効化
89
107
  return handle_filter_input(key) if @filter_manager.filter_mode
90
108
 
@@ -94,9 +112,11 @@ module Rufio
94
112
  when 'k'
95
113
  move_up
96
114
  when 'h'
97
- navigate_parent
98
- when 'l', "\r", "\n" # l, Enter
115
+ navigate_parent_with_restriction
116
+ when 'l' # l - navigate into directory
99
117
  navigate_enter
118
+ when "\r", "\n" # Enter - focus preview pane or navigate
119
+ handle_enter_key
100
120
  when 'g'
101
121
  move_to_top
102
122
  when 'G'
@@ -153,8 +173,12 @@ module Rufio
153
173
  add_bookmark
154
174
  when 'z' # z - zoxide history navigation
155
175
  show_zoxide_menu
176
+ when '0' # 0 - go to start directory
177
+ goto_start_directory
156
178
  when '1', '2', '3', '4', '5', '6', '7', '8', '9' # number keys - go to bookmark
157
179
  goto_bookmark(key.to_i)
180
+ when '?' # ? - enter help mode
181
+ enter_help_mode
158
182
  when ':' # : - command mode
159
183
  activate_command_mode
160
184
  else
@@ -184,16 +208,197 @@ module Rufio
184
208
  end
185
209
  end
186
210
 
211
+ # ヘルプモード関連メソッド
212
+
213
+ # ヘルプモード中かどうか
214
+ def help_mode?
215
+ @in_help_mode
216
+ end
217
+
218
+ # ヘルプモードに入る
219
+ def enter_help_mode
220
+ return false unless @directory_listing
221
+
222
+ # 現在のディレクトリを保存
223
+ @pre_help_directory = @directory_listing.current_path
224
+
225
+ # info ディレクトリに移動
226
+ rufio_root = File.expand_path('../..', __dir__)
227
+ info_dir = File.join(rufio_root, 'info')
228
+
229
+ # info ディレクトリが存在することを確認
230
+ return false unless Dir.exist?(info_dir)
231
+
232
+ # ヘルプモードを有効化
233
+ @in_help_mode = true
234
+
235
+ # info ディレクトリに移動
236
+ navigate_to_directory(info_dir)
237
+
238
+ true
239
+ end
240
+
241
+ # ヘルプモードを終了
242
+ def exit_help_mode
243
+ return false unless @in_help_mode
244
+ return false unless @pre_help_directory
245
+
246
+ # ヘルプモードを無効化
247
+ @in_help_mode = false
248
+
249
+ # 元のディレクトリに戻る
250
+ navigate_to_directory(@pre_help_directory)
251
+
252
+ # 保存したディレクトリをクリア
253
+ @pre_help_directory = nil
254
+
255
+ true
256
+ end
257
+
258
+ # ヘルプモード時の制限付き親ディレクトリナビゲーション
259
+ def navigate_parent_with_restriction
260
+ if @in_help_mode
261
+ # info ディレクトリより上には移動できない
262
+ rufio_root = File.expand_path('../..', __dir__)
263
+ info_dir = File.join(rufio_root, 'info')
264
+
265
+ current_path = @directory_listing.current_path
266
+
267
+ # 現在のパスが info ディレクトリ以下でない場合は移動を許可しない
268
+ unless current_path.start_with?(info_dir)
269
+ return false
270
+ end
271
+
272
+ # 現在のパスが info ディレクトリそのものの場合は移動を許可しない
273
+ if current_path == info_dir
274
+ return false
275
+ end
276
+
277
+ # info ディレクトリ配下であれば、通常のナビゲーションを実行
278
+ navigate_parent
279
+ else
280
+ # ヘルプモード外では通常のナビゲーション
281
+ navigate_parent
282
+ end
283
+ end
284
+
285
+ # プレビューペイン関連メソッド
286
+
287
+ # プレビューペインがフォーカスされているか
288
+ def preview_focused?
289
+ @preview_focused
290
+ end
291
+
292
+ # プレビューペインにフォーカスを移す
293
+ def focus_preview_pane
294
+ # ファイルが選択されている場合のみフォーカス可能
295
+ entry = current_entry
296
+ return false unless entry
297
+ return false unless entry[:type] == 'file'
298
+
299
+ @preview_focused = true
300
+ @preview_scroll_offset = 0 # フォーカス時にスクロール位置をリセット
301
+ true
302
+ end
303
+
304
+ # プレビューペインのフォーカスを解除
305
+ def unfocus_preview_pane
306
+ return false unless @preview_focused
307
+
308
+ @preview_focused = false
309
+ true
310
+ end
311
+
312
+ # 現在のプレビュースクロールオフセット
313
+ def preview_scroll_offset
314
+ @preview_scroll_offset
315
+ end
316
+
317
+ # プレビューを1行下にスクロール
318
+ def scroll_preview_down
319
+ return false unless @preview_focused
320
+
321
+ @preview_scroll_offset += 1
322
+ true
323
+ end
324
+
325
+ # プレビューを1行上にスクロール
326
+ def scroll_preview_up
327
+ return false unless @preview_focused
328
+
329
+ @preview_scroll_offset = [@preview_scroll_offset - 1, 0].max
330
+ true
331
+ end
332
+
333
+ # プレビューを半画面下にスクロール(Ctrl+D)
334
+ def scroll_preview_page_down
335
+ return false unless @preview_focused
336
+
337
+ # 半画面分スクロール(仮に20行とする)
338
+ page_size = 20
339
+ @preview_scroll_offset += page_size
340
+ true
341
+ end
342
+
343
+ # プレビューを半画面上にスクロール(Ctrl+U)
344
+ def scroll_preview_page_up
345
+ return false unless @preview_focused
346
+
347
+ # 半画面分スクロール(仮に20行とする)
348
+ page_size = 20
349
+ @preview_scroll_offset = [@preview_scroll_offset - page_size, 0].max
350
+ true
351
+ end
352
+
353
+ # プレビュースクロール位置をリセット(ファイル変更時など)
354
+ def reset_preview_scroll
355
+ @preview_scroll_offset = 0
356
+ end
357
+
187
358
  private
188
359
 
360
+ # Enterキーの処理:ファイルならプレビューフォーカス、ディレクトリならナビゲート
361
+ def handle_enter_key
362
+ entry = current_entry
363
+ return false unless entry
364
+
365
+ if entry[:type] == 'file'
366
+ # ファイルの場合はプレビューペインにフォーカス
367
+ focus_preview_pane
368
+ else
369
+ # ディレクトリの場合は通常のナビゲーション
370
+ navigate_enter
371
+ end
372
+ end
373
+
374
+ # プレビューペインフォーカス中のキー処理
375
+ def handle_preview_focus_key(key)
376
+ case key
377
+ when 'j', "\e[B" # j or Down arrow
378
+ scroll_preview_down
379
+ when 'k', "\e[A" # k or Up arrow
380
+ scroll_preview_up
381
+ when "\x04" # Ctrl+D
382
+ scroll_preview_page_down
383
+ when "\x15" # Ctrl+U
384
+ scroll_preview_page_up
385
+ when "\e" # ESC
386
+ unfocus_preview_pane
387
+ else
388
+ false # Unknown key in preview mode
389
+ end
390
+ end
391
+
189
392
  def move_down
190
393
  entries = get_active_entries
191
394
  @current_index = [@current_index + 1, entries.length - 1].min
395
+ reset_preview_scroll # ファイル変更時にスクロール位置をリセット
192
396
  true
193
397
  end
194
398
 
195
399
  def move_up
196
400
  @current_index = [@current_index - 1, 0].max
401
+ reset_preview_scroll # ファイル変更時にスクロール位置をリセット
197
402
  true
198
403
  end
199
404
 
@@ -1012,20 +1217,22 @@ module Rufio
1012
1217
  end
1013
1218
  end
1014
1219
 
1220
+ def goto_start_directory
1221
+ start_dir = @directory_listing&.start_directory
1222
+ return false unless start_dir
1223
+
1224
+ # 起動ディレクトリに移動
1225
+ navigate_to_directory(start_dir)
1226
+ end
1227
+
1015
1228
  def goto_bookmark(number)
1016
1229
  bookmark = @bookmark_manager.find_by_number(number)
1017
1230
 
1018
- return show_error_and_wait('bookmark.not_found', number) unless bookmark
1019
- return show_error_and_wait('bookmark.path_not_exist', bookmark[:path]) unless @bookmark_manager.path_exists?(bookmark)
1231
+ return false unless bookmark
1232
+ return false unless @bookmark_manager.path_exists?(bookmark)
1020
1233
 
1021
1234
  # ディレクトリに移動
1022
- if navigate_to_directory(bookmark[:path])
1023
- puts "\n#{ConfigLoader.message('bookmark.navigated') || 'Navigated to bookmark'}: #{bookmark[:name]}"
1024
- sleep(0.5) # 短時間表示
1025
- true
1026
- else
1027
- show_error_and_wait('bookmark.navigate_failed', bookmark[:name])
1028
- end
1235
+ navigate_to_directory(bookmark[:path])
1029
1236
  end
1030
1237
 
1031
1238
  def add_bookmark
@@ -1405,5 +1612,11 @@ module Rufio
1405
1612
  def in_log_mode?
1406
1613
  @in_log_mode
1407
1614
  end
1615
+
1616
+ # ヘルプダイアログを表示
1617
+ def show_help_dialog
1618
+ @terminal_ui&.show_help_dialog if @terminal_ui
1619
+ true
1620
+ end
1408
1621
  end
1409
1622
  end
@@ -7,7 +7,7 @@ module Rufio
7
7
  class TerminalUI
8
8
  # Layout constants
9
9
  HEADER_HEIGHT = 1 # Header占有行数
10
- FOOTER_HEIGHT = 1 # Footer占有行数
10
+ FOOTER_HEIGHT = 1 # Footer占有行数(ブックマーク一覧 + ステータス情報)
11
11
  HEADER_FOOTER_MARGIN = 3 # Header + Footer分のマージン
12
12
 
13
13
  # Panel layout ratios
@@ -115,6 +115,9 @@ module Rufio
115
115
  end
116
116
 
117
117
  def draw_screen
118
+ # 処理時間測定開始
119
+ start_time = Time.now
120
+
118
121
  # move cursor to top of screen (don't clear)
119
122
  print "\e[H"
120
123
 
@@ -142,8 +145,9 @@ module Rufio
142
145
  draw_directory_list(entries, left_width, content_height)
143
146
  draw_file_preview(selected_entry, right_width, content_height, left_width)
144
147
 
145
- # footer
146
- draw_footer
148
+ # footer (統合されたステータス情報を含む)
149
+ render_time = Time.now - start_time
150
+ draw_footer(render_time)
147
151
 
148
152
  # コマンドモードがアクティブな場合はコマンド入力ウィンドウを表示
149
153
  if @command_mode_active
@@ -161,6 +165,11 @@ module Rufio
161
165
  current_path = @directory_listing.current_path
162
166
  header = "📁 rufio - #{current_path}"
163
167
 
168
+ # Add help mode indicator if in help mode
169
+ if @keybind_handler.help_mode?
170
+ header += " [Help Mode - Press ESC to exit]"
171
+ end
172
+
164
173
  # Add filter indicator if in filter mode
165
174
  if @keybind_handler.filter_active?
166
175
  filter_text = " [Filter: #{@keybind_handler.filter_query}]"
@@ -169,7 +178,12 @@ module Rufio
169
178
 
170
179
  # abbreviate if path is too long
171
180
  if header.length > @screen_width - HEADER_PADDING
172
- if @keybind_handler.filter_active?
181
+ if @keybind_handler.help_mode?
182
+ # prioritize showing help mode indicator
183
+ help_text = " [Help Mode - Press ESC to exit]"
184
+ base_length = @screen_width - help_text.length - FILTER_TEXT_RESERVED
185
+ header = "📁 rufio - ...#{current_path[-base_length..-1]}#{help_text}"
186
+ elsif @keybind_handler.filter_active?
173
187
  # prioritize showing filter when active
174
188
  filter_text = " [Filter: #{@keybind_handler.filter_query}]"
175
189
  base_length = @screen_width - filter_text.length - FILTER_TEXT_RESERVED
@@ -310,12 +324,19 @@ module Rufio
310
324
  if selected_entry && i == 0
311
325
  # プレビューヘッダー
312
326
  header = " #{selected_entry[:name]} "
327
+ # プレビューフォーカス中は表示を追加
328
+ if @keybind_handler&.preview_focused?
329
+ header += "[PREVIEW MODE]"
330
+ end
313
331
  content_to_print = header
314
332
  elsif selected_entry && selected_entry[:type] == 'file' && i >= 2
315
333
  # ファイルプレビュー(折り返し対応)
316
334
  preview_content = get_preview_content(selected_entry)
317
335
  wrapped_lines = TextUtils.wrap_preview_lines(preview_content, safe_width - 1) # スペース分を除く
318
- display_line_index = i - 2
336
+
337
+ # スクロールオフセットを適用
338
+ scroll_offset = @keybind_handler&.preview_scroll_offset || 0
339
+ display_line_index = i - 2 + scroll_offset
319
340
 
320
341
  if display_line_index < wrapped_lines.length
321
342
  line = wrapped_lines[display_line_index] || ''
@@ -376,9 +397,9 @@ module Rufio
376
397
  end
377
398
  end
378
399
 
379
- def draw_footer
380
- # 最下行から1行上に表示してスクロールを避ける
381
- footer_line = @screen_height - FOOTER_HEIGHT
400
+ def draw_footer(render_time = nil)
401
+ # フッタは最下行に表示
402
+ footer_line = @screen_height - FOOTER_HEIGHT + 1
382
403
  print "\e[#{footer_line};1H"
383
404
 
384
405
  if @keybind_handler.filter_active?
@@ -387,14 +408,50 @@ module Rufio
387
408
  else
388
409
  help_text = "Filtered view active - Space to edit filter, ESC to clear filter"
389
410
  end
411
+ # フィルタモードでは通常のフッタを表示
412
+ footer_content = help_text.ljust(@screen_width)[0...@screen_width]
413
+ print "\e[7m#{footer_content}\e[0m"
390
414
  else
391
- help_text = ConfigLoader.message('help.full')
392
- help_text = ConfigLoader.message('help.short') if help_text.length > @screen_width
393
- end
415
+ # 通常モードではブックマーク一覧、ステータス情報、?:helpを1行に表示
416
+ require_relative 'bookmark'
417
+ bookmark = Bookmark.new
418
+ bookmarks = bookmark.list
419
+
420
+ # 起動ディレクトリを取得
421
+ start_dir = @directory_listing&.start_directory
422
+ start_dir_name = if start_dir
423
+ File.basename(start_dir)
424
+ else
425
+ "start"
426
+ end
427
+
428
+ # ブックマーク一覧を作成(0.起動dir を先頭に追加)
429
+ bookmark_parts = ["0.#{start_dir_name}"]
430
+ unless bookmarks.empty?
431
+ bookmark_parts.concat(bookmarks.take(9).map.with_index(1) { |bm, idx| "#{idx}.#{bm[:name]}" })
432
+ end
433
+ bookmark_text = bookmark_parts.join(" ")
394
434
 
395
- # 文字列を確実に画面幅に合わせる
396
- footer_content = help_text.ljust(@screen_width)[0...@screen_width]
397
- print "\e[7m#{footer_content}\e[0m"
435
+ # ステータス情報を作成
436
+ time_info = render_time ? "#{(render_time * 1000).round(1)}ms" : "-ms"
437
+
438
+ # 右側の情報: 処理時間 | ?:help
439
+ right_info = "#{time_info} | ?:help"
440
+
441
+ # ブックマーク一覧を利用可能な幅に収める
442
+ available_width = @screen_width - right_info.length - 3
443
+ if bookmark_text.length > available_width && available_width > 3
444
+ bookmark_text = bookmark_text[0...available_width - 3] + "..."
445
+ elsif available_width <= 3
446
+ bookmark_text = ""
447
+ end
448
+
449
+ # フッタ全体を構築
450
+ padding = @screen_width - bookmark_text.length - right_info.length
451
+ footer_content = "#{bookmark_text}#{' ' * padding}#{right_info}"
452
+ footer_content = footer_content.ljust(@screen_width)[0...@screen_width]
453
+ print "\e[7m#{footer_content}\e[0m"
454
+ end
398
455
  end
399
456
 
400
457
  def handle_input
@@ -656,11 +713,12 @@ module Rufio
656
713
  is_project_selected = (bookmark[:name] == selected_name)
657
714
  selection_mark = is_project_selected ? "✓ " : " "
658
715
 
659
- # ブックマーク名を表示
716
+ # ブックマーク名を表示(番号付き)
717
+ number = index + 1 # 1-based index
660
718
  name = bookmark[:name]
661
- max_name_length = width - 4 # selection_mark分を除く
719
+ max_name_length = width - 8 # selection_mark(2) + number(1-2) + ". "(2) + padding
662
720
  display_name = name.length > max_name_length ? name[0...max_name_length - 3] + '...' : name
663
- line_content = "#{selection_mark}#{display_name}".ljust(width)
721
+ line_content = "#{selection_mark}#{number}. #{display_name}".ljust(width)
664
722
 
665
723
  if index == current_index
666
724
  # カーソル位置は選択色でハイライト
@@ -864,6 +922,69 @@ module Rufio
864
922
  draw_screen
865
923
  end
866
924
 
925
+ # ヘルプダイアログを表示
926
+ def show_help_dialog
927
+ content_lines = [
928
+ '',
929
+ "rufio v#{VERSION}",
930
+ '',
931
+ 'Key Bindings:',
932
+ '',
933
+ 'j/k - Move up/down',
934
+ 'h/l - Navigate back/enter',
935
+ 'g/G - Go to top/bottom',
936
+ 'o - Open file',
937
+ 'f - Filter files',
938
+ 's - Search with fzf',
939
+ 'F - Content search (rga)',
940
+ 'a/A - Create file/directory',
941
+ 'm/c/x - Move/Copy/Delete',
942
+ 'b - Add bookmark',
943
+ 'z - Zoxide navigation',
944
+ '0 - Go to start directory',
945
+ '1-9 - Go to bookmark',
946
+ 'p - Project mode',
947
+ ': - Command mode',
948
+ 'q - Quit',
949
+ ''
950
+ ]
951
+
952
+ # お知らせ情報を追加
953
+ require_relative 'info_notice'
954
+ info_notice = InfoNotice.new
955
+ all_notices = Dir.glob(File.join(info_notice.info_dir, '*.txt'))
956
+
957
+ if !all_notices.empty?
958
+ content_lines << 'Recent Updates:'
959
+ content_lines << ''
960
+ all_notices.take(3).each do |file|
961
+ title = info_notice.extract_title(file)
962
+ content_lines << " • #{title}"
963
+ end
964
+ content_lines << ''
965
+ end
966
+
967
+ content_lines << 'Press any key to continue...'
968
+
969
+ width = 60
970
+ height = [content_lines.length + 4, @screen_height - 4].min
971
+ x, y = @dialog_renderer.calculate_center(width, height)
972
+
973
+ @dialog_renderer.draw_floating_window(x, y, width, height, 'rufio - Help', content_lines, {
974
+ border_color: "\e[36m", # Cyan
975
+ title_color: "\e[1;36m", # Bold cyan
976
+ content_color: "\e[37m" # White
977
+ })
978
+
979
+ require 'io/console'
980
+ IO.console.getch
981
+ @dialog_renderer.clear_area(x, y, width, height)
982
+
983
+ # 画面を再描画
984
+ refresh_display
985
+ draw_screen
986
+ end
987
+
867
988
  # プロジェクトモードでコマンドを実行
868
989
  def activate_project_command_mode(project_mode, project_command, project_log)
869
990
  return unless project_mode.selected_path
data/lib/rufio/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rufio
4
- VERSION = '0.21.0'
4
+ VERSION = '0.31.0'
5
5
  end
data/retag.sh ADDED
@@ -0,0 +1,55 @@
1
+ #!/bin/zsh
2
+
3
+ # 使い方: ./retag.sh v0.31.0
4
+
5
+ # 引数チェック
6
+ if [ $# -eq 0 ]; then
7
+ echo "使い方: $0 <タグ名>"
8
+ echo "例: $0 v0.31.0"
9
+ exit 1
10
+ fi
11
+
12
+ TAG_NAME=$1
13
+
14
+ echo "=== タグ再作成スクリプト ==="
15
+ echo "タグ: $TAG_NAME"
16
+ echo ""
17
+
18
+ # 1. ローカルのタグを削除
19
+ echo "1. ローカルタグを削除中..."
20
+ if git tag -d $TAG_NAME; then
21
+ echo "✓ ローカルタグを削除しました"
22
+ else
23
+ echo "⚠ ローカルタグが存在しないか、削除に失敗しました"
24
+ fi
25
+ echo ""
26
+
27
+ # 2. リモートのタグを削除
28
+ echo "2. リモートタグを削除中..."
29
+ if git push origin :refs/tags/$TAG_NAME; then
30
+ echo "✓ リモートタグを削除しました"
31
+ else
32
+ echo "⚠ リモートタグの削除に失敗しました(存在しない可能性があります)"
33
+ fi
34
+ echo ""
35
+
36
+ # 3. タグを再作成
37
+ echo "3. タグを再作成中..."
38
+ if git tag $TAG_NAME; then
39
+ echo "✓ タグを再作成しました"
40
+ else
41
+ echo "✗ タグの再作成に失敗しました"
42
+ exit 1
43
+ fi
44
+ echo ""
45
+
46
+ # 4. タグをプッシュ
47
+ echo "4. タグをプッシュ中..."
48
+ if git push origin $TAG_NAME; then
49
+ echo "✓ タグをプッシュしました"
50
+ echo ""
51
+ echo "🎉 完了!GitHub Actionsが実行されます。"
52
+ else
53
+ echo "✗ タグのプッシュに失敗しました"
54
+ exit 1
55
+ fi