Redmineカスタマイズを運用機に反映させるTIPS

## はじめに
この記事は、Redmineアドベントカレンダー2023/12/3の記事です

### この記事の前提
1. RedmineのDBはPostgreSQLを使っています。他のDBでも同様のことはできるとおもいますがここでは紹介しません。
1. 開発機から運用機にデータを転送するする部分は書いていません。適宜SCPなどを使って転送してください。
1. サーバはLinuxを使っています。Windows系ではありません。適宜読み替えていただければTIPSとしてはWindows系でも使えるかもしれませんがそこはお任せします。
1. ユーザの切り替えなども書いておりません。適宜権限のあるユーザで実行してください。
1. Redmine本体やプラグインバージョンは開発機、運用機ともに全く同じにしてください。これがずれていると、誤動作しても当然と思われます。バージョンを移行させる方法は別記事に委ねます。

## 運用機にカスタマイズを反映するジレンマ
一部の方はご存じかとおもいますが、Redmineは非常に柔軟なカスタマイズをすることが可能です。カスタムフィールドを追加したり、View Customizeでスクリプトで画面のカスタマイズや機能を追加したり。でもいろいろなことを試すのは、さすがに実ユーザが使っている運用機でやるわけにはいきません。基本的には開発用の環境でいろいろやってみて、ちゃんと動くことを確認してから、実ユーザが使っている環境に提供するわけです。

開発用の環境でカスタムフィールドを追加したり、設定を変えたり、いろいろいじった内容はすべてRedmineのDBの中に入っています。でも、これらを運用機に反映するには、基本的には変えた内容を同じ順序のまま運用機で繰り返す必要があります。同じ順序でやらないと、カスタムフィールドIDが変わってしまったり、設定が抜けてしまったりして、カスタマイズしたものが期待どおりの動きをしなくなります。まとまったプログラムとして実行ファイルを提供するかのような反映は簡単にはできません。

もちろん、開発環境のDBをまるごとダンプして運用機でリストアすれば、当然完全な環境コピーが可能です。でも運用機には、実ユーザが書き込んだチケットの情報があり、それを捨てるわけにはいきません。（逆にいえば、開発機には、実ユーザが書いているチケット情報はない）
開発環境のDBで上書きしてしまったら、開発した機能は提供できますが、チケット情報が上書きされて失われてしまいます。

運用機のチケットは捨てたくない。でも開発用の環境で作ったカスタマイズを楽に提供したい。
そんなジレンマを解決する手段として私がやっている工夫をご紹介します。

## ジレンマを解決する方法

#### 具体的な手順
実はそんなにややこしいことをやるわけではありません。
以下のとおりやるだけです。


1. 開発機のDBを丸ごとダンプ
1. 運用機のDBからチケット情報をダンプ（退避）
1. 開発機のDBを運用機でリストア
1. 運用機のDBで退避しておいたチケット情報をリストア

順番にやっていきましょう。

### 開発機のDBを丸ごとダンプ

開発機のDBを丸ごとダンプする方法は、Redmineガイドにもあるとおり、pg_dumpコマンドで簡単にできます。詳細は[こちら](http://guide.redmine.jp/RedmineBackupRestore/)を参照してください。
細かい説明は割愛しますが、自分の場合はこんな感じでやっています。
```bash
pg_dump -U redmine -h localhost --file=redmine_`hostname`_`date+"%F"`.sql redmine
```
これで、`redmine_ホスト名_2023-12-03.sql`のようなファイルにダンプをすることができます。

### 運用機のDBからチケット情報をダンプ（退避）

運用機のDBからチケット情報をダンプします。Redmineのテーブル構成を確認すると、以下の4つを保存する必要があります。

- チケットテーブル(issues)
- チケットテーブルのIDシーケンス情報(issues_id_seq)
- カスタムフィールド値テーブル(custom_values)
- カスタムフィールド値テーブルのIDシーケンス情報(custom_values_id_seq)

```bash
pg_dump -U redmine -h localhost -t issues -t issues_id_seq -t custom_values -t custom_values_id_seq --file=backups/redmine_`hostname`_issues_`date+"%F"`.sql redmine
```
これで、`redmine_ホスト名_issues_2023-12-03.sql`のようなファイルにダンプすることができます。このなかには、上記４つのテーブル／シーケンスの情報のみが保存されています。

### 開発機のDBを運用機でリストア

RedmineガイドにはリストアのことはTODOになっていて、なにも書かれていないですね。リストアはざっくり以下のような手順でやります。

#### (1)httpdを止める
```bash
systemctl stop httpd
```

#### (2)もともとあるDBをdropする
```bash
dropdb redmine
```

#### (3)新しく（空っぽの）DBを作成
```bash
createdb redmine
```

#### (4)作成したDBにデータをインポート
```bash
psql -h localhost -U redmine -f ダンプしたファイル redmine
```
ここで開発機でダンプしたデータを運用機にインポートします。

### 運用機のDBで退避しておいたチケット情報をリストア

次に、運用機で退避しておいたチケット情報をインポートします。

#### (1)対象となるテーブルをDROP

```bash
psql -d redmine -c "DROP TABLE IF EXISTS issues,custom_values"
```
ここでは、issuesテーブルとcustom_valuesテーブルをDROPしています。シーケンスは削除していませんが、この後のインポートでは特に問題なく動いているようです。
postgresに詳しい方、間違っていたらご指摘ください（汗）

#### (2) 退避しておいた情報をインポート

```bash
psql -h localhost -U redmine -f 退避しておいたファイル redmine
```
この手順で退避しておいた４つの情報をリストアしています。

#### (3)httpdを再開
```bash
systemctl start httpd
```

これで、無事チケット情報とカスタムフィールド情報だけは運用機の情報を維持しつつ、その他の設定（カスタムフィールドの追加や設定の変更等）は開発機の状態をそのまま反映することができました。

## おわりに

私も最初のうちは開発機でやった手順を記録しておき、それと同じ手順で運用機を再現構築するようなことをやっていました。でも、ちょっと複雑なカスタマイズをやろうとするとたちまち破綻してしまいます。
とてもじゃないけどやってられない(ノToT)ノ　┫：･'.::･┻┻:･'.::･
同じ悩みを持っている方のヒントになれば幸いです。