GenerambaからGenesisに移行する

🎄[and factory.inc Advent Calendar 2024](https://qiita.com/advent-calendar/2024/andfactory) 18日目の記事です🎄

# はじめに

この記事では、Swiftプロジェクトのテンプレート生成ツールをGenerambaからGenesisへ移行する方法について解説します。私が担当するプロジェクトではこれまでGenerambaを使用していましたが、Generambaとfastlaneが依存しているライブラリのバージョンコンフリクトが発生し、運用が難しくなってしまいました。

そこで、代替手段としてGenesisを導入することにしました。本記事では、Genesisの基本的な導入手順や使用例を紹介し、移行をスムーズに進めるための手助けとなる内容をお届けします。

Generambaが使えなくなって困っている方や、テンプレート生成ツールの選定で迷っている方にとって、少しでも参考になれば幸いです。

# 背景

これまでテンプレート生成ツールとしてGenerambaを使用してきましたが、長期間メンテナンスが行われておらず、他のライブラリとの依存関係でバージョンのコンフリクトが発生してしまいました。この問題により、別のテンプレート生成ツールに移行する必要が出てきました。

いくつかあるテンプレート生成ツールの中から、社内の他プロジェクトで導入実績があり、必要な機能を備えていたGenesisを選択しました。

# **Genesisの概要**

Genesisは、Swiftプロジェクトでテンプレートを生成するためのCLIツールです。シンプルな設計ながら、テンプレート管理や作成に必要な機能が揃っています。

主な特徴として以下が挙げられます。

•YAMLまたはJSON形式で書かれたテンプレートマニュフェスト

•Stencilテンプレート言語を使用してテンプレートファイルを作成

# Genesisの導入手順

## 環境

- OS: macOS Sonoma 14.5
- Xcode: 16.0.0
- Swift: 6.0.0
- Mint: 0.17.5

## インストール

今回は、Mintを使ってインストールしていきます。Mintをまだインストールしていない方は[こちら](https://qiita.com/uhooi/items/6a41a623b13f6ef4ddf0)の記事を参考にMintをインストールしてください。

### Mintfile

```
yonaskolb/genesis@0.9.0
```

### Mintを使ってGenesisをインストール

```bash
$ mint install genesis
```

## マニフェストファイルの作成

私が担当するプロジェクトでは、MVP+Clean Architectureを採用しています。今回テンプレートを生成する対象は、新規画面を作成する際にPresentation層で必要になるファイル群になります。

Genesisを利用するために、プロジェクトにマニフェストファイルを追加します。このファイルには、テンプレートの設定や生成されるファイルの情報を記述します。ここでは、YAML形式での例を紹介します。

```yaml
files:
  - template: Templates/ViewController.swift
    path: "{{ target }}/Presentation/{{ module }}/View/{{ module }}ViewController.swift"
  - template: Templates/Presenter.swift
    path: "{{ target }}/Presentation/{{ module }}/Presenter/{{ module }}Presenter.swift"
  - template: Templates/Builder.swift
    path: "{{ target }}/Presentation/{{ module }}/Builder/{{ module }}Builder.swift"
  - template: Templates/Wireframe.swift
    path: "{{ target }}/Presentation/{{ module }}/Wireframe/{{ module }}Wireframe.swift"
```

ここで使用している`target`や`module`は、Genesisを実行するときにオプション引数として値を渡します。

また、Genesisはマニフェストファイルにoptionsを設定することで、Genesis実行時に対話形式でオプションの値を渡すこともできます。その場合は、マニフェストファイルは以下のようになります。

詳しい書き方は[README](https://github.com/yonaskolb/Genesis?tab=readme-ov-file#template:~:text=generation%20will%20fail.-,Template,-A%20genesis%20template)を参考にしてください

```yaml
#options:
  - name: target
    description: "テンプレートを追加するターゲット"
    question: "テンプレートを追加するターゲットを入力してください"
    required: true
    type: string
  - name: module
    description: "モジュール名"
    question: "モジュール名を入力してください"
    required: true
    type: string
    # ... その他必要なオプション
files:
  - template: Templates/ViewController.swift
    path: "{{ target }}/Presentation/{{ module }}/View/{{ module }}ViewController.swift"
  - template: Templates/Presenter.swift
    path: "{{ target }}/Presentation/{{ module }}/Presenter/{{ module }}Presenter.swift"
  - template: Templates/Builder.swift
    path: "{{ target }}/Presentation/{{ module }}/Builder/{{ module }}Builder.swift"
  - template: Templates/Wireframe.swift
    path: "{{ target }}/Presentation/{{ module }}/Wireframe/{{ module }}Wireframe.swift"
```

## テンプレートファイルの作成

Genesisでは、テンプレートファイルをStencilテンプレート言語を使用して作成します。これにより、動的な変数や条件分岐を取り入れた柔軟なテンプレートを作成できます。

今回はViewControllerのテンプレートファイルの例を紹介します。

```swift
//
//  {{ module }}ViewController.swift
//  {{ target }}
//
//  Created by {{ developerName }} on {{ date }}
//  Copyright © {{ year }}年 {{ developerCompany }}. All rights reserved.
//

import UIKit

@MainActor
protocol {{ module }}View {
    var presenter: (any {{ module }}Presenter)! { get set }
}

final class {{ module }}ViewController: UIViewController {

    var presenter: {{ module }}Presenter!

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

// MARK: - {{ module }}View
extension {{ module }}ViewController: {{ module }}View {}
```

{{ target }} や {{ module }} など、Genesisに渡したoptionの値を使用してクラス名などを動的に変更しながらファイルを生成します。

今回使用していませんがStencilでは、制御フローやmacroの使用などいろいろな機能が提供されているので、詳しくは[公式ドキュメント](https://stencil.fuller.li/en/latest/)を参照してください。

## ファイル生成

マニフェストファイルとテンプレートファイルの準備ができたので、Genesisを実行してファイルを生成していきます。

Genesisを実行するには以下のコマンドで実行します

```bash
genesis generate template.yml -o "option1: value 2, option2: value 2"
```

ただ、毎回コマンドを入力するのは面倒なので、makeコマンドとscriptを使用して手軽に実行できるようにしていきます。

### Genesis実行用script

今回のテンプレートでは、コメント部分にファイルの生成日時や開発者名などを設定するので、各値を用意してからgenesisコマンドを実行してファイルを生成するようにします。

```bash
#!/usr/bin/env sh

today=`date "+%Y/%m/%d"`
current_year=`date "+%Y"`
echo $today
echo $current_year

developer_company="Company Name"
target="Target"

read -p "new screen name to generate. (e.g. Home): " screen_name
read -p "developer name for header comment. (e.g. Taro Yamada): " developer_name

mint run genesis generate Genesis/Screen/template.yml -o "target: $target, module: $screen_name, date: $today, year: $current_year, developerName: $developer_name, developerCompany: $developer_company"
```

### Makefileの作成

Makefileに先ほど作成したscriptを実行するコマンドを追加し、makeコマンドでファイル生成が行えるようにします。

```
.PHONY: generate-screen
generate-screen: ## Generate Screen Module Templates
	sh generate_screen_module.sh
```

### makeコマンドからGenesisを実行

上記で作成したmakeコマンドを実行してファイルを生成します。

```
$ make generate-screen
```

### 出力結果

コマンドを実行した結果、テンプレートファイルに従って、以下のようなファイルが生成されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520642/a9b81acc-2472-d0f7-c703-6a65458ad768.png)


# **おわりに**

今回は、GenerambaからGenesisへの移行理由とGenesisの概要について紹介しました。Genesisは、シンプルな設定で必要なテンプレートを効率よく生成できるツールです。

テンプレート生成ツールを探している方や、Generambaの運用に困っている方にとって、少しでも参考になれば嬉しいです。