Teamcityを使って複数のGitリポジトリを管理する

みなさんが所属する組織ではいくつのGitリポジトリを管理していますか？きっと依存関係にある複数のGitリポジトリが存在するのではないでしょうか？私が所属する会社の顧客向けプロジェクトでは5つのGitリポジトリを用い、各チームがそれぞれのGitリポジトリを管理します。残念ながら全Gitリポジトリが依存関係にあるため、あるチームの変更したコードが他のチームのテストで障害を計上させてしまうことが多々ありました。

GitHub、GitLab、また、その他CI系ツールは素晴らしいパイプライン機能を提供していますが、単一のGitリポジトリ向けである場合が多いです。私が知る限り、複数Gitリポジトリを管理できるものは見たことがありません。「そのGitリポジトリの構成を変えたらいいんじゃないの？」と考えつくかもしれませんが、ライセンス、また、ビジネス上の理由ため、現場では構成変更できないことが多いのです。

そんな背景の中Teamcityと出会い、私なりの方法が見つかったので紹介してみたいと思います。

## Teamcityの紹介
[こちら](https://www.jetbrains.com/ja-jp/teamcity/)を参照してください。

## Docker環境でTeamcityを動かす

### Docker ComposeでTeamcityを起動

1. `teamcity`フォルダを作成し、以下の`docker-compose.yaml`ファイルを配置

    > 以下、`c:\mycode\docker\teamcity`というフォルダパスを用いています。

    ```yaml
    version: "3.9"
    services:
      teamcity-server:
        image: jetbrains/teamcity-server
        volumes:
          - c:/mycode/docker/teamcity/server/config:/data/teamcity_server/datadir/config
          - c:/mycode/docker/teamcity/server/system:/data/teamcity_server/datadir/system
          - c:/mycode/docker/teamcity/server/lib:/data/teamcity_server/datadir/lib
          - c:/mycode/docker/teamcity/server/logs:/opt/teamcity/logs
        ports:
          - "8111:8111"
      teamcity-agent:
        image: jetbrains/teamcity-agent
        user: 0:0
        environment:
          SERVER_URL: teamcity-server:8111 
        volumes:
          - c:/mycode/docker/teamcity/agent:/data/teamcity_agent/conf
          - /var/run/docker.sock:/var/run/docker.sock
        privileged: true
    ```

2. 同じフォルダ内にDocker Volumesマウント用のサブフォルダを作成
    - `agent`
    - `server`
    - `server/config`
    - `server/system`
    - `server/lib`
    - `server/logs`

3. Docker Composeを用いて起動

    ```shell
    docker-compose up -d
    ```

4. `http://localhost:8111/`からTeamcityへアクセスし初期設定を行う。

    1. `Proceed`をクリック
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/f12e506a-ebd4-7ef3-2a80-e9dae8d99283.png)
    2. `Proceed`をクリック
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/6e608adf-9eeb-e28a-6326-d9d2623cb6a8.png)
    3. スクロールダウンし、`Accept license agreement`のチェックを入れ、`Continue`をクリック
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/f8da1283-50e6-c559-b0e7-449e08ed6dbe.png)
    4. 任意のユーザー名とパスワードを入力し、`Create Account`をクリック
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/4dda8a09-f861-562d-20be-12a7fb5234ec.png)
    5. Teamcityのトップ画面が表示されていることを確認
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/3b05c447-2eb7-714d-cee0-95c6d421cef1.png)
    6. ナビゲーションにある`Agents`をクリックし、表示された画面で`Unauthorized`をクリックし。`Authorize`をクリックすることによってTeamcity Agentを登録する。
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/5aa0e64a-8a78-8519-dabc-47ba482d9a68.png)
    7. Teamcity Agentが登録されたことを確認。
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/125309e5-209b-c287-7eb5-6147be0e9200.png)

### サンプルプロジェクトのインポート

1. サンプルプロジェクト（ZIPファイル）をダウンロード
    [ダウンロード](https://github.com/tsmasuda/teamcity-sample-project/blob/main/teamcity-sample-project.zip)

2. ナビゲーションにある`Administration`をクリック
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/3b05c447-2eb7-714d-cee0-95c6d421cef1.png)

3. 左のメニューから`Project Import`をクリックし、前ステップでダウンロードしたZIPファイルをアップロード
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/ef37c9bd-b907-bb93-5147-3fb4636e306c.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/792f4f81-cb80-239e-ee8e-d30e18919587.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/bb5cb8a9-c71c-c0ea-79dd-ae653fb21f4e.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/5770e121-530a-2bc7-9ec7-06c61c725552.png)

4. ナビゲーションにある`Projects`をクリックし、`Sample Project`がインポートされていることを確認
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/92ffd718-fa05-5878-1138-559ce113471a.png)

### サンプルプロジェクトの実行

1. `Trigger`の右にある`Run`をクリックする
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/669cf5cb-5c99-c254-2473-3aaefa21dbe5.png)

2. その後、`Trigger`をクリックし、実行された`Build number`をクリックし、`Dependencies`タブをクリックする
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/66c9052f-c1aa-8bd5-a66d-d747688392e2.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/b375010c-5991-5fb7-6cff-c84ed22aba95.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/81222784-b0c4-5e6f-d391-71c27ef6443a.png)

ここで分かることは`Trigger`は`E2E`に、`E2E`は`Deploy`に、そして、`Deploy`は`Build Repo A`と`Build Repo B`に依存していることです。そのため、依存するジョブを再帰的に実行しているのです。

### 他チーム影響ありのコードを書いた場合

例えば、`Repo B`を扱うBチームが`Repo A`を扱うAチームに影響を与えてしまう変更を新しいGitブランチに作成したとします。その場合、`Trigger`でそのGitブランチを実行すると、以下のような結果を得ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/4979d234-00ad-9658-7609-7903ed9348af.png)

各Gitリポジトリの`Build`やその後の`Deploy`には成功したものの、Gitリポジトリ間の整合性をチェックする`E2E`では失敗しています。このようにして、BチームはPull Requestを作成する時点でチームAへの影響に気づくことができます。

**Teamcityの嬉しいことは選択したGitブランチが依存関係にあるジョブへ受け継がれることです。選択されたGitブランチが存在しない場合はデフォルトのGitブランチを選択してくれます。**

このようなパイプラインと`E2E`ジョブをチーム間で共有することによって、整合性による問題をマージする前に気づくことができるのです。

### `Trigger`ジョブの設定

では、`Trigger`ジョブがどのような設定をしているか見てみましょう。`VCS Roots`に2つのGitリポジトリを登録し、このジョブではチェックアウトをしないようにしているのです。この設定をすることによって、`Trigger`ジョブは2つのGitリポジトリからGitブランチのリストを取得することができるのです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/2f568bb6-d0d2-5d7a-9431-b63c55e68a6a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634234/2b53d55d-d91e-4e43-aaae-bc0febe79053.png)

## 終わりに

開発プロジェクトを行うにあたって、各チームは「停止」することはあっても「後退」することはあってはなりません。しかし、開発規模が大きくなってしまうと、チーム間やGitリポジトリ間の整合性を取るだけでも難しくなってしまいます。今回は私が編み出した方法を紹介させていただきましたが、もし他に複数Gitリポジトリを管理する方法をご存知でしたらぜひ共有してください。