GitHubとJIRAでリリース管理

# GitHubとJIRAでリリース管理

どのチームになっても最初に苦労が見えるのはリリース管理だったりします。

 - 次のリリースいつだっけ？
 - これいつリリースしたっけ？
 - この機能っていつリリースされるの？

要件定義からリリースまでのフローとその内容がきっちり管理されていないとよくある話だと思います。
今回は、以前いたチームで数年間運用方法を殆ど変えなかったやり方を紹介します。
うまくいっていたから変えずに済んだのだと今更ながら思ったので。

この記事はサーバーサイドエンジニア目線です。
他の職種の方が見た場合に気分を害すこともあるかと思いますが、悪意は無いので怒らないで優しく指摘してもらえると嬉しいです。


## 参考にしてもらえると嬉しい方々

- 短期間で定期的にリリース作業がある(1〜2週間に1回くらい)
- 機能開発／改善を定常的に行っている
- 少人数のチーム（だいたい20人位まで）
- JIRAとGitHub(GHEやGitLab含む)を使っている

今回は毎日小さなデプロイを何回もしているといった運用の話では無いです。
超有名なサービスで「マイクロサービス何十個もあるぜぃ♪いぇい♪」的な大所帯チームや、
「何となく作って『えぃ、やぁ！』でデプロイしてるし」みたいな方々はあまり参考にならないかもです。

## JIRA編

### 1. リリースサイクル

定期的にリリースするなら毎週水曜日、みたいに決めておいた方が色々計画が立てやすいです。
でもリリースサイクルとスプリントは必ずしも一致しなくても良いと思います。

### 2. 要件定義

常日頃プランナーやディレクターは決まっている戦略やKPIと睨めっこしながら、次のことをリストアップします。

- やりたいこと
- 何故やりたいか
  - どのKPIでどれだけの改善が目的なのか
  - 戦略に沿った一手であるか
- いつまでにやりたいか

### 3. 開発項目の洗い出し

出てきた案にそって、費用対効果や期限を考慮し優先度をつけていきます。
そしてそれを開発項目毎に落としていきます。
この時に

- どの担当の作業が必要か
- それぞれの担当工数
- リリース希望日

とかも洗い出せていると、この先の話がスムーズに進みます。
なので、開発ディレクターはエンジニアやデザイナーとこのフェーズで軽く相談しておくと良いと思います。
このタイミングでエンジニアやデザイナーから逆提案されることもあるので、一番建設的なフェーズだと個人的には思っています。
この時のチーム内の職種はこんな感じでした。

- デザイナー
- Androidエンジニア
- iOSエンジニア
- フロントエンドエンジニア
- サーバーサイドエンジニア

そして整理された項目をJIRAチケットに起こします。
JIRAチケットには要件を詳細に書いておきます。

### 4. スプリントキックオフ

来る１週間、もしくは２週間でできることをエンジニアやデザイナーは項目に沿ってJIRAチケットに起こしていきます。
この時起こしたJIRAチケットは次のルールで作成し、今回のスプリントに登録します。
今回のスプリントに入りきらないものは、次のスプリントやバックログに登録します。

#### 4.1. タイトルにコンポーネントを入れる

ServerとかFrontとかiOSとか。
コンポーネントも別途設定しますが目的が違うので、タイトルにも設定していました。
理由は後述します。

#### 4.2. コンポーネントを割り当てる

これもServerとかFrontとかiOSとか。
JIRAのボードでグルーピングしたり検索する際に役立ちます。

#### 4.3. `is child task of`として関連付ける

のような名前だったと思うのですが、事前に発行されたチケットの関連チケットとして親子関係にしておきます。
サブタスクではないです。JIRAのサブタスクはスプリントを跨げないので使いませんでした。
JIRAの設定上この種のリンクが無い場合は単純に`related to`とかで良いと思います。
但しチケットの上限関係はわかりやすくしておくために、関連付け方向は一方向に統一した方が良いですね。

#### 4.4. 作業見積もりを入れる

何となく大変さをアピールできます。
あまり細かい見積もりはいれず、0.25日単位とかにしてました。1時間で終わる内容でも0.25。

#### 4.5. 担当者を設定する

その職種が複数いる場合は職種リーダーが中心になって決めます。

#### 4.6. 修正バージョンを設定する 

それがいつリリースされるのかを宣言しておきます。
リリースできそうになかったら、周知の上バージョンを付け替えたりします。
リリースバージョンは成果物のまとまりと1:1になるようにJIRAでリリース日と併せて登録しておきます。

- フロントの1.5.0
- サーバーサイドの3.2.0
- Androidの2.1.0
- iOSの3.1.0

みたいな感じで。

##### 4.7. チケット内容にメモでも何でも書いておく

殆ど担当者本人しか見ないと思うので、メモでも何でも記しておきます。
恒久的に参照したい内容なら別途Wikiに書いてリンクしておきます。

### 5. 実装開始

後はチケットを消化するだけです。
PRレビューが終わりマージまでされたら、チケットを「Resolved」または「Close」します。
個人的にはリリースされたタイミングで「Close」にしていましたが、リリースが次のバージョンに回されたり、そのチケットの作業はそのスプリントで終わる予定でもリリースが更に先だとスプリントを跨いでしまうので、適当なタイミングで「Close」にした方が良いかもしれません。

### 6. リリース

各自リリース作業して終わりです。
簡単なリリースノートはConfluenceでJIRAのバージョン選択して自動生成します。
これはGitHub見れない人用のリリースノートです。

## GitHub編

とここまでは主にJIRAのお話でした。
次からはGitとGitHubの方のお話です。

### 1. ブランチ運用

これが個人的には超絶うまくいったと思っていたりします。
問題点もありましたが。。

基本的には以下のブランチで運用します。

| ブランチ名 | 役割 | 作成元 | マージ先 |
|------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------|----------------------------|
| master | アーカイブ目的。<br>基本的には`production`と同じ。 | - | - |
| develop (default) | 開発ブランチ。<br>ここへはPRレビュー無しにローカルで動作確認が済んだら他の人に確認してもらう目的でどんどんマージしてOK。<br>ただし、直接コミットは無し。 | - | - |
| staging_{version} | ステージングブランチ。<br>このブランチへのマージはPRレビューでOK出ないとマージされない。 | master, stating_{version} | production |
| production | テストを全て終えた`staging_{version}`ブランチのみがこのブランチにマージできる。 | - | master |
| feature/{ticket_id}_{feature name} | 機能開発用ブランチ。この単位でPRを出す。 | master | develop, stating_{version} |
| fix/{ticket_id}_{bug} | バグ修正用ブランチ。この単位もPRを出す。 | master | develop, stating_{version} |
| hotfix/{ticket_id}_{bug} | 緊急バグ修正用ブランチ。この単位もPRを出す。 | master | develop, stating_{version} |

#### ブランチ名のプレースホルダー

ブランチ名にあるプレースホルダーの内容です。

| プレースホルダ | 説明                                                                                                                                                                   |
|----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| version        | リリースバージョンです。<br>タグもこの名前で切ります。                                                                                                                 |
| ticket_id      | JIRAチケットのIDです。<br>プロジェクトコードと番号で形成されていると思います。<br>JIRAとGitHubを連携している場合はJIRAのチケットにPRへのリンクが出現するので便利です。 |
| feature name   | 機能名です。端的に表現しましょう。<br>僕は英語苦手なので長くなること多かったです。。<br>短く表現するとカッコイイです。                                                 |
| bug            | 悲しくもバグは発生するものです。<br>バグの内容を端的に表現しましょう。                                                                                                 |

#### 1.1. バージョンの運用方法

majorバージョンはチームで足並み揃えて気分で上げれば良いと思います。
minorバージョンは定期リリースでインクリメントしていきます。
buid numberは不定期なバグ修正リリースでインクリメントしていきます。

#### 1.2. 緊急リリースでもJIRAチケットを発行する

**緊急でもリリース履歴を残すべきです。
JIRAでバージョン作ってチケット切って、`staging_{version}`ブランチと`hotfix/{ticket_id}_{bug}`を`master`から作って作業しましょう。**
PR後、マージが終わったらステージングで確認してから`production`にマージしてリリースです。

#### 1.3. リリース後は`master`にマージする

`master`をあらゆるブランチ元にしていたので、リリース後は`production`を`master` にマージします。
この時、必ず`fast forward merge`になるはずなので、そうでなかったら差分を確認した方が良いです。
そして、更に進んでいる`develop`や`staging_{version}`にも`master`をマージしておきます。

#### 1.4. 意外に便利な`staging`ブランチの使い捨て

バージョンごとに切ることによって機能単位のリリースバージョンの延期や前倒しがスムーズにできます。
但し、Revertコミットの伝染は要注意です。本当は適切にその機能のコミットをdropした方が良いと思いますけどね。
まぁ、`master`から`staging`にマージする際はRevertコミットが含まれていたら注意するくらいで大丈夫だと思います。

#### 1.5. `develop`ブランチを定期的にクリーンアップする

`develop`は`master`とも`staging_{version}`とも`production`とも交わることはありません。
独自で進んでいきます。
これをそのままにしているとコミット履歴が他のブランチと違いすぎて、次の問題が出てきます。

- `develop`だけコンフリクトする
- リリースしたと思っていたのに`develop`にしかマージされていなかった

これを防ぐためにリリース後、もしくは何回かのリリースに１回は`master`ブランチと同期させます。

```bash
$ git checkout develop
$ git fetch origin
$ git reset --hard origin/master
$ git push origin develop -f
```

これをやると、未リリースのものが`develop`ブランチからいなくなります。
そこで、「あぁーー、これ今作ってる途中なのにー」とか「あれ？これずっと前にリリースしたと思ってたんだけど無くなってない？」みたいな苦情がチラホラ聞こえてくることもあります(笑)
ここでGitHubのブランチ一覧画面です。
`develop`ブランチに対して進んでいるコミットがあれば、最終コミッターに確認し`develop`にマージしていきます。
全てマージが終わればpushして`develop`が動いている環境にデプロイしておきます。

問題は「あれ？これずっと前にリリースしたと思ってたんだけど無くなってない？」とか言い出すやつです。
`develop`が動いている環境しか眼中に無いとこうなります。
でも、これも`master`と同期を取ることで判明するので、悲劇ではありますが早めに把握して対処することが重要です。

あと、`feature`, `fix`, `hotfix`, `staging`ブランチはリリースされたら削除します。
ブランチ一覧のページが長くなってしまうので。

また、`master`を更新したら一度`master`をデフォルトブランチに変更して未リリースブランチが認識済みであるかをチェックしておきます。
チェックが終わったらまた`develop`ブランチに戻しておきます。戻さないと他のメンバーから「GitHub上でcompreしづらい！」と怒られます。

### 2. Pull Request

#### 2.1. `staging`ブランチにPRを出す

- 期限
- Reviewer
- Milestore(version)

を設定します。マイルストーンも検索用途です。
また`develop`へのPRと区別するために`staging`ラベルもつけていました。

#### 2.2. 不安なら`develop`にPRを出す

不安なら後戻りが多くなる前に不完全でも`develop`にPR出して実装内容を確認してもらいます。

### 3. タグ＆リリースノート

リリース後はタグを切ります。
コマンドでやりません。
GitHubのリリースノート機能を使います。
まずJIRAでそのバージョンを「リリース済み」にします。
この時に終わっていないチケットがあれば、JIRAに怒られます。
現在どうなっているか確認して対処しましょう。

次にそのバージョンのリリースノートページに遷移します。
HTMLで出力されているのでそのままコピーして、GitHubのリリースノートに貼っつけます。
リリースノートをPublishするとリリースノートの出来上がりです。
ここでJIRAのタイトルに`Server`とか`Front`とか入れている効力が発揮されます。
サーバーとフロントで同じリポジトリでやっている場合、成果物は同じになります。
ただ、APIはリリースされたけどフロントからのつなぎこみはリリースされていない等は、これにより判断が可能になります。
別リポジトリの場合は気にしなくて大丈夫です。

このリリースノートはJIRAチケットへのリンクがあります。
そこからPRへのリンクへも辿れるので、ここで全て繋がります。
単純にPRだけで見たいときはマイルストーンとラベルで絞り込めばリリース内容がPRの一覧で作れます。

## GitHub運用の問題点

この方法でもいくつかの問題点はありました。

### `develop`のクリーンアップ後のマージ作業が大変なときがある

コンフリクトの嵐にぶつかった場合は悲惨です。
頑張って解消していきます。

### 機能間の依存関係を解消しながら開発するために開発前後でコミットの操作が多少必要なときもある

事前に開発していたAPIが未リリースだが、それを使った別機能の実装とかしている場合は、動作確認でAPIのブランチをマージしてから開発してたりします。
だけどPRにそれのマージコミットまで入ってしまうので、PR前に`rebase`したり`cherry-pick`したりでコーディングよりコミット操作に時間を割いてしまうこともチラホラ。。

### 緊急バグリリースがある場合は一時的にステージング環境が奪われる

これはブランチの問題より環境をどれだけ用意できるかの問題ですかね。
サーバーサイドの話ですが、`staging`ブランチが複数あって環境が一つしか無い場合は必然的に直近のリリースバージョンが当たっています。
しかし別バージョンのテスト中に緊急バグ修正リリースバージョンを当ててテストしたりした場合に、ステージングを使って次期機能の開発をしているアプリエンジニアが困ってしまいます。


## まとめ

JIRAとGitHub連携して、ちゃんとバージョン管理したら幸せになれます。
リリースノートはあんまり頑張って書かないで、JIRAチケットを頑張って書きましょう。
画面キャプチャーも無くすみません。

(初めてコードが無い記事を書いた。。)