Module: VivlioStarter::CLI::UpgradeCommands

Extended by:
UpgradeCommands
Included in:
UpgradeCommands
Defined in:
lib/vivlio_starter/cli/upgrade.rb

Defined Under Namespace

Classes: PlanItem

Constant Summary collapse

EMPTY_DICTIONARY_TEMPLATES =

著者辞書がプロジェクトに存在しない場合にだけ追加する「空の辞書」。 雛形のサンプル辞書(開発リポジトリの実辞書)を配ると著者の本に無関係な 用語が混入するため、空の初期形を用意する。

{
  File.join('config', 'index_glossary_terms.yml') => <<~YAML,
  File.join('config', 'index_glossary_rejected.yml') => <<~YAML,
  File.join('config', 'spellcheck_allowlist.yml') => <<~YAML,
  File.join('config', 'textlint_allowlist.yml') => <<~YAML
    # textlint-filter-rule-allowlist で使用する除外語句リスト
    # 書籍名、資格名称、専門用語など、プロジェクト固有の除外対象を記載します
    # 正規表現も使用可能(例: "/pattern/flags")
    []
  YAML
}.freeze
RENAMED_CONFIG_FILES =

改名した設定ファイル(旧名 → 新名)。著者が編集するファイルなので、 名前を変えただけでは中身ごと読まれなくなる——登録した表記ゆれルールや 許可語が黙って効かなくなるため、雛形追従の前に移し替える。

textlint_prh.yml は v0.14.0(2025-11-04)から配っており、ベータ版 (2026-04-26)の利用者の手元にもある。user_words.txt はベータの 2 か月後(2026-06-30)の実装なので既存プロジェクトには無いが、 開発中の本のために同じ経路で拾っておく。

{
  File.join('config', 'textlint_prh.yml') => File.join('config', 'textlint_rewrite.yml'),
  File.join('config', 'user_words.txt') => File.join('config', 'spellcheck_allowlist.yml')
}.freeze
RENAMED_REFERENCES =

改名に伴って中身の参照も書き換えるファイル(著者が編集する設定)

{
  File.join('config', '.textlintrc.yml') => { './textlint_prh.yml' => './textlint_rewrite.yml' }
}.freeze
DIFF_PREVIEW_LINES =
20

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#scaffold_sourceObject



95
# File 'lib/vivlio_starter/cli/upgrade.rb', line 95

def scaffold_source = @scaffold_source || NewCommands::SCAFFOLD_SOURCE

#tool_depsObject



100
# File 'lib/vivlio_starter/cli/upgrade.rb', line 100

def tool_deps = @tool_deps || DoctorCommands::ToolUpgrader.default_deps

Instance Method Details

#run_from_command(cmd) ⇒ Object

Samovar UpgradeCommand から呼び出すメイン処理(終了コードを返す)。 ①本体 gem 更新 → ②雛形追従 → ③外部ツール更新 の順に実行する(順序の理由は ファイル冒頭コメント参照)。①で更新が走った場合は exec で新しい版に置き換わる ため、②③は新しい版の vs が実行する。



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/vivlio_starter/cli/upgrade.rb', line 106

def run_from_command(cmd)
  options = cmd.options

  # --- Phase: ① 本体 gem 更新(--skip-self-update は再起動ループ防止も兼ねる)---
  self_result = options[:skip_self_update] ? :none : self_update!(options, tool_deps)

  # --- Phase: ② 雛形追従(プロジェクト外はスキップ——③は場所を問わず有用)---
  scaffold_code =
    if File.exist?(File.join('config', 'book.yml'))
      sync_scaffold!(cmd)
    else
      Common.log_always('💡 書籍プロジェクト外のため、雛形の追従はスキップします(プロジェクト直下で再実行すると適用できます)。')
      0
    end

  # --- Phase: ③ 外部ツール更新 ---
  tools_code = DoctorCommands::ToolUpgrader.run!(
    { yes: options[:yes], dry_run: options[:dry_run], verbose: options[:verbose] },
    deps: tool_deps
  )

  [self_result == :failed ? 1 : 0, scaffold_code, tools_code].max
end

#self_update!(options, deps, current: VivlioStarter::VERSION) ⇒ Symbol

本体 gem の自己更新。新版があれば確認のうえ gem update し、新しい版の vs で 同じ upgrade を再実行する(relaunch! で exec に置き換わり、戻ってこない)。 更新失敗は警告して現在の版のまま続行——雛形追従・ツール更新の価値は残るため。

Returns:

  • (Symbol)

    :none(新版なし)/ :skipped(案内のみ)/ :failed(更新失敗)



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/vivlio_starter/cli/upgrade.rb', line 134

def self_update!(options, deps, current: VivlioStarter::VERSION)
  latest = DoctorCommands::ToolUpgrader.latest_gem_version(deps, 'vivlio-starter')
  return :none unless latest && Gem::Version.correct?(current) &&
                      Gem::Version.new(latest) > Gem::Version.new(current)

  if options[:dry_run]
    Common.log_always("📣 vivlio-starter #{latest} が公開されています(現在 #{current})。--dry-run のため更新しません。")
    return :skipped
  end
  unless options[:yes] || confirm_self_update?(latest, current, deps)
    Common.log_always("本体の更新をスキップしました(手動更新: gem update vivlio-starter)。今回は現在の版(#{current})の雛形で続行します。")
    return :skipped
  end

  Common.log_always("⬆️  vivlio-starter を #{current}#{latest} に更新しています…")
  unless DoctorCommands::ToolUpgrader.run_gem_command('gem update vivlio-starter', deps)
    Common.log_warn('vivlio-starter の更新に失敗しました。現在の版のまま続行します(手動更新: gem update vivlio-starter)。')
    return :failed
  end

  Common.log_always("🔁 vivlio-starter #{latest} で続きを実行します…")
  relaunch!(options)
end

#sync_scaffold!(cmd) ⇒ Object

--- Phase: 分類(三者比較)以降の雛形追従フェーズ ---



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/vivlio_starter/cli/upgrade.rb', line 159

def sync_scaffold!(cmd)
  # --- Phase: 改名の追随(雛形と比べる前に済ませる) ---
  follow_renames!(dry_run: cmd.options[:dry_run])

  # --- Phase: 分類(三者比較) ---
  Common.log_summary("雛形との差分を確認しています…(gem #{VivlioStarter::VERSION} の雛形)")
  scaffold_digests = ScaffoldLock.digest_scaffold(scaffold_source)
  lock = ScaffoldLock.read
  warn_missing_lock if lock.nil?
  plan = build_plan(scaffold_digests, lock)

  # --- Phase: 計画表示 ---
  display_plan(plan)
  actionable = plan.reject { it.status == :keep }
  if actionable.empty?
    Common.log_result('プロジェクトは雛形の最新状態です。', status: :success)
    record_lock!(scaffold_digests, lock, applied: []) unless cmd.options[:dry_run]
    return 0
  end
  return finish_dry_run(actionable) if cmd.options[:dry_run]

  # --- Phase: 適用(追加・更新 → 競合の個別確認) ---
  applied, skipped, backup_dir = apply_plan(cmd, plan, scaffold_digests)
  return 0 if applied.nil? # 全体確認で中止

  # --- Phase: lock 更新・完了報告 ---
  record_lock!(scaffold_digests, lock, applied:)
  print_summary(plan, applied, skipped, backup_dir)
  0
end