たったこれだけ！チーム開発でコードフォーマット忘れを防ぐ方法

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122958/37d8e44e-07cb-355a-809b-25bf16a3b198.png)

# はじめに

**「コードフォーマットが適用されておりません。」**
こんな指摘をした人、された人。いるのではないでしょうか？
今回はコードフォーマットを**CIツール**で実行し、開発者はフォーマッターの実行をしないような仕組みを紹介します。

# この記事を書こうと思った動機

**お客様指定のコードスタイルのある規約があるプロダクト**において以下の問題に直面し、結果的に工数が増大したため。

:star: **ケース1. ローカルで「コードフォーマッター」が適用されずにPull Requestを出すケース**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122958/4e6534c9-9f34-1a71-6865-0ddd34e1b05a.png)

:star: **ケース2. すり抜けコードをベースに修正し、コードフォーマッターを適用したら、改修箇所以外の差分が抽出された**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122958/0dedbaf2-2f3b-b575-e8cf-38b54abc1ac5.png)

:star: **ケース3. 「クロスチェック」させる体制にして工数増**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122958/8866dace-9e27-03a8-b2ac-f709abf10282.png)


**【コードフォーマッターが適用されないわけ】**

- 開発環境構築手順書・開発フローにコードフォーマッターの記載されていない。（曖昧なドキュメント）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122958/bc2970b5-9b18-d917-e1b8-09a60a79267c.png)

- 開発メンバー間でのフローの引き継ぎもない（開発メンバーが流動的）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122958/c61b9675-217b-da35-e0a4-1263f1d18199.png)

折角コードフォーマッターの設定ファイルを用意しても、**運用されていなければ意味がありません**。
**ドキュメントをしっかり書いたとしても、プロジェクトメンバー全員の開発環境設定が同じであることを確認する**にも限度があります。そのため、同じような悩みを持っているコードオーナの方向けにCIツール側でコードフォーマッターを適用する方法について紹介しようと思いました。

# CIツールでコードフォーマッターを実行する

**解決アイディア** : 開発環境に依存するのでは無く、フォーマッタはレビュー実施前に自動的に適用される方式とする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122958/0769236d-5f7d-56c1-8e55-9348530752f3.png)

## 前提
CIツールとコードフォーマッターを連携するために以下の要件を満たす必要があります。

1. バージョン管理ツールへのPushやPull Request(Merge Request)を検出する仕組み
2. 以下に対応したコードフォーマッターが存在すること
   + コマンドラインから実行可能で且つ、スタンドアロンで動作可能なツールであること
   + CIツールに対応したツールであること

後述の方式は上記の要件を満たしたツールを選定しておりますが、もし存在しない( 特に [1.] ) は自作することもご検討ください。

## コードフォーマット自動適用例

今回のサンプルは以下の仕様のもとで作成するものとする。

| 項目     |      内容      |
|----------|:-------------|
| プログラミング言語 |  Java |
| コードスタイル     |  [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html) に準拠  |
| ツール            |[google-java-format](https://github.com/google/google-java-format) |

## CIツールで自動的にコードフォーマッターを実行する

### CI用コード(GitHub Action)

**コードの前提**
以下のScriptはGitHub Marketplaceで**Verified**となっているプラグインのみ利用して実現しております。
（※手早く実装したい場合はMarketplaceにあるプラグインをどんどん活用しましょう）

```yaml
name: Reformat Java source code

on:
  pull_request:

jobs:
  format:
    runs-on: ubuntu-latest
    steps:
      # Pull Requestされたブランチをチェックアウト
      - uses: actions/checkout@v2
        with:
          ref: ${{ github.head_ref }}
      # Java のセットアップ
      - name: Set up JDK 11
        uses: actions/setup-java@v1
        with:
          java-version: 11
      # Gitの設定
      - name: Git settings
        run: |
          # Git リポジトリの設定
          git config --local user.name "ユーザ名"
          git config --local user.email "E-Mailアドレス"
      # コードフォーマットの実行(※1)
      - name: Code format
        run: |
          wget -q -O google-java-format.jar \
            https://github.com/google/google-java-format/releases/download/google-java-format-1.9/google-java-format-1.9-all-deps.jar
　　　　　 # 以下の例ではすべての変更に対してフォーマッタを加えております。
          # プルリクエスト時の変更を取る場合はgit logで変更差分のみ取得してフォーマッタをかけましょう。(※2)
          java -jar google-java-format.jar -replace $(git ls-files src/**/*.java)
      # 変更確認
      - name: Check for modified files
        id: git-check
        run: echo ::set-output name=modified::$(if git diff-index --quiet HEAD --; then echo "false"; else echo "true"; fi)
      # 変更されていた場合、コミット・プッシュを行う(※3)
      - name: Push
        if: steps.git-check.outputs.modified == 'true'
        run: |
          git commit -am "Automated :Reformat Java source code."
          git push
```
※1 … [google-java-format](https://github.com/marketplace/actions/google-java-format)
※2 … [get-all-changed-files](https://github.com/marketplace/actions/get-all-changed-files)
※3 … [Git Auto Commit](https://github.com/marketplace/actions/git-auto-commit)

### 実行結果

**PullRequst実施、変更時にコードフォーマッターが適用された新しいコミットが追加される**

![github_001.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122958/d6c1a1a7-4808-0239-f12f-3915fc8db924.gif)

**変更差分**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122958/bb78bc67-4881-6ad7-d2cd-bbe15e9c17a7.png)

## サンプルリポジトリ
上記は以下のリポジトリで実現されております。(ブランチ: feature/format-action)
https://github.com/yukiusa/github-action-auto-java-format-sample/tree/feature/format-action

# さいごに

いかがだったでしょうか？
今回はCIツールを利用し「開発環境に依存せずルールを遵守させる仕組み」について紹介しました。
本取り組みを実施することで

- 開発環境の作成の手間を減らす
- チェックの工数を削減する
- レビューア・レビューイの負荷を減らす

などの効果が期待できるかと思います。
今後の業務の改善案の一つとしてお役立ていただければ幸いでございます。

最後まで読んでいただきましてありがとうございました。

# 改訂履歴

@naminodarie 様からの指摘一部修正。ご指摘ありがとうございました。