環境ごとに異なる設定ファイルを持つプロジェクトのGitLabのCI/CDを整えた話

# この記事の内容
1ソースなんだけどお客様向け環境と社内向け環境があり、それぞれにテスト環境本番環境とある構成のWebサイトのビルド構成をGitLabのCI/CDを利用して整えてみた話。


# 元の状態
WebサイトのDeploy環境として以下が存在しています。
各Deploy環境に対応するgit branch（branch名）があります。
- 社内向け
    - テスト環境A（develop）
    - テスト環境B（rm_review）
    - 本番環境（public）
- お客様向け
    - テスト環境（function-public）
    - 本番環境（master-public）

ソースコードはmdファイルなのをベースにhexoというツールを使って静的なhtml/css/jsを作ります。
社内向け、お客様向けでは作成されるoutputが異なるため、異なるビルドスクリプトを利用します。

branchをDeploy環境で分けてあるので各branch内のconfig/buildファイルに異なる内容を記載していました。

## ビルドファイルの構成
```
root
┣_config.yml              # hexo用の設定ファイル。branch毎に内容が違う
┣.gitlab-ci.yml           # GitLab CI/CD用のファイル
┣auto_update.sh           # 社内向けテスト環境A用のビルド用シェル
┣build-and-upload.sh      # hexo用のビルドコマンドファイル。branch毎に内容が違う
┗package.json             # npm用のビルドファイル
```

## 課題
### 1. mergeができない
各種のビルドファイルがbranch毎に異なることを正としているため、branch間のマージを行う際に必ず差分が発生をしていました。

### 2. 手作業が発生する
「このファイルはマージ対象外」みたいな判断＆処理を手動で行っていたため、Deploy時にミスが発生しやすくなる状況でした。


# どう変えたか
## 変更方針
- 全環境で同一ファイルとする
- 機械的なマージで完結し、人による判断や手作業を挟まないこと


## 変更内容
### ビルドファイルの構成
```
root
┣config-develop           # 社内向けテスト環境A
┃   ┣_config.yml
┃   ┣_auto_update.sh      # 社内向けテスト環境A用のビルド用シェル
┃   ┗build.sh
┣config-rm_review         # 社内向けテスト環境B
┃   ┣_config.yml
┃   ┗build.sh
┣config-master            # 社内向け本番環境
┃   ┣_config.yml
┃   ┗build.sh
┣config-function-public   # お客様向けテスト環境
┃   ┣_config.yml
┃   ┗build.sh
┣config-master-public     # お客様向け本番環境
┃   ┣_config.yml
┃   ┗build.sh
┣.gitlab-ci.yml           # GitLab CI/CD用のファイル
┗package.json             # npm用のビルドファイル
```

rootの下に各環境用のフォルダを作成して環境差分の発生するファイルはそのフォルダ内に収めました。
基本的には元のbranch毎に分かれていたファイルをフォルダ分けして移動した形です。
これだけだとビルド時にどの設定ファイルを使ってビルドするかがわからなくなるため、GitLab CI/CDで下記の工夫をしました。

### GitLab CI/CD
GitLab CIは rules によってどのタスクを実行するか切り替えられるため、これを利用しました。
```yml
# 環境ごとのbuild.shを呼び出す
build_hexo:
  image: node:latest
  stage: build
  script:
    - bash -x config-${CI_COMMIT_BRANCH}/build.sh
  cache:
    key: global-cache
    paths:
      - public
  rules:
     - if: '$CI_COMMIT_BRANCH == "develop"'
     - if: '$CI_COMMIT_BRANCH == "rm_review"'
     - if: '$CI_COMMIT_BRANCH == "master"'
     - if: '$CI_COMMIT_BRANCH == "master-public"'
     - if: '$CI_COMMIT_BRANCH == "function-public"'

# develop
deploy-to-s3-develop:
  stage: deploy
  # 省略
  rules:
     - if: '$CI_COMMIT_BRANCH == "develop"'

# rm_review
deploy-to-s3-rm_review:
  stage: deploy
  # 省略
  rules:
   - if: '$CI_COMMIT_BRANCH == "rm_review"'

# master
deploy-to-s3-master:
  stage: deploy
  # 省略
  rules:
     - if: '$CI_COMMIT_BRANCH == "master"'

# function-public ブランチ向けの設定
# master-public ブランチ向けの設定
pre-check:
  stage: .pre
  # 省略
  rules:
     - if: '$CI_COMMIT_BRANCH == "function-public"'

# function-public
deploy-to-s3-function-public:
  stage: deploy
  # 省略
  rules:
     - if: '$CI_COMMIT_BRANCH == "function-public"'

# master-public
deploy-to-s3-master-public:
  stage: deploy
  # 省略
  rules:
     - if: '$CI_COMMIT_BRANCH == "master-public"'
```

### hexoの_config.yml
```json
"scripts": {
    "build": "hexo clean && hexo generate",
    "build-develop": "hexo clean && hexo generate --config config-develop/_config.yml",
    "build-rm_review": "hexo clean && hexo generate --config config-rm_review/_config.yml",
    "build-master": "hexo clean && hexo generate --config config-master/_config.yml",
    "build-function-public": "hexo clean && hexo generate --config config-function-public/_config.yml",
    "build-master-public": "hexo clean && hexo generate --config config-master-public/_config.yml",
    "rebuild": "hexo generate",
    "rebuild-develop": "hexo generate --config config-develop/_config.yml",
    "rebuild-rm_review": "hexo generate --config config-rm_review/_config.yml",
    "rebuild-master": "hexo generate --config config-master/_config.yml",
    "rebuild-function-public": "hexo generate --config config-function-public/_config.yml",
    "rebuild-master-public": "hexo generate --config config-master-public/_config.yml",
    "clean": "hexo clean",
    "deploy": "hexo deploy",
    "server": "hexo server"
  }
```
branchによって使用する_config.ymlを切り替えるようにしています。
どのbuild-xxxxを呼び出すかはbuild.sh内にべた書きです。

# まとめ
当初の変更方針は達成できました。
作業のやり方が土曜日に1日時間を取ってペアプロをする感じだったので一日で終われなそうなところは目をつぶって進むという部分もあったので今後継続して改善は必要かなと思っています。

## 今後やりたいこと、やり残したと思ったこと
1. _config.ymlファイルは各環境で大部分が同じ内容なので差分だけ別ファイルに抜き出したい
1. _config.ymlはコマンドラインから環境名を渡してscriptsの定義を少なくしたい

GitLab CI、npm、hexoいずれもちゃんと触ったことが無くて今回のプロジェクト初めて触りました。
なのでもっといいやり方があるよ！とかGitLab CIではこういうものがある～みたいなご指摘をいただけると更に改善につながると思うので是非いい方法があれば教えてください。

## お礼
今回の改善のモチベーションになったのは、社内で「バージョン管理の敗北」と言われたこの状況でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974516/65dfd330-b623-3d86-86f1-77d4af8f3329.png)

前任者から妥協を重ね続けてきた感がありましたが、今回である程度は解消できたかなと思っています。
やはり他人から指摘をもらうことは大切なのでありがとうございました。
これで引き分けくらいにはもっていけたかな？