Amazon Web Services ブログ

AWS CodeCommitのプルリクエストを使用してコードレビューをリクエストし、コードについて議論する

シニアクラウドアーキテクトのMichael Edge氏のCodeCommitのプルリクエストに関する素晴らしいブログに感謝します。

~~~~~~~~~~~~~
AWS CodeCommitは、プライベートGitリポジトリを安全にホスティングするフルマネージドなサービスです。CodeCommitは今ではプルリクエストをサポートするようになりました。これによってリポジトリのユーザは、コードの変更に対するレビュー、コメント、対話的なイテレーションが可能になります。チームメンバー間のコラボレーションツールとして使用されるプルリクエストは、CodeCommitリポジトリに対する変更の可能性を、リポジトリにそれらの変更をマージする前に確認するのに役立ちます。各プルリクエストは、次のように単純なライフサイクルを通じて実行されます:

  • マージされる新機能は、featureブランチに1つ以上のコミットとして追加されます。コミットは、宛先のブランチにマージされません。
  • プルリクエストが通常は2つのブランチの差異から作成されます。
  • チームメンバーはプルリクエストをレビューし、コメントします。プルリクエストは、追加のコミットで更新される可能性があります。これにはコメントに対応して行われる変更や宛先ブランチとの差分から発生する変更が含まれます。
  • チームメンバーがプルリクエストに満足すれば、それは宛先ブランチにマージされます。 コミットは、プルリクエストに追加されるのと同じ順序で宛先ブランチに適用されます。

コメントの入力は、プルリクエストプロセスの不可欠な部分であり、開発者とレビュー担当者の間のコラボレーションとして利用されます。レビュー担当者は、レビュープロセス中にプルリクエストにコメントと質問を追加し、開発者はそれらに対して説明を行います。プルリクエストコメントは、プルリクエスト全体、プルリクエスト内のファイル、またはファイル内のラインに追加できます。

 

コメントをより利用価値の高いものにするには、AWS管理コンソールにAWS Identity and Access Management(IAM)ユーザーとしてサインインします。ユーザー名はコメントに関連付けられ、コメントの所有者を示します。プルリクエストコメントは、開発チーム全体に対してレビュー担当者がレビューしているものを見える化するので、優れた品質改善ツールになります。 また、ある時点でのチームメンバー間の議論の記録としても役立つので削除すべきではありません。

 

AWS CodeCommitはコミットにコメントを追加する便利な機能も導入しています。これによってチームメンバーがコミットの一部として変更されたコードについて議論することを可能にします。この機能によって、変更が行われた理由、追加の変更が必要かどうか、変更をマージする必要があるかどうかなど、リポジトリに行われた変更について議論する助けになります。プルリクエストコメントの場合と同様に、コミット全体、コミット内のファイル、ファイル内の特定の行や変更についてコメントすることができます。また、他のリポジトリユーザーがコメントに応答できます。 コメントはコミットに限定されず、2つのブランチ間の違いや2つのタグ間のコメントにも使用できます。 コミットコメントはプルリクエストコメントとは別のものです。プルリクエストを確認するときにコミットコメントは表示されません。プルリクエストコメントのみが表示されます。

 

プルリクエストの例

試しにやってみましょう。ここでは、一般的なプルリクエストのシナリオを取り上げ、CodeCommitとAWSマネジメントコンソールをどのように使用するかを見ていきます。

 

このシナリオを試すには、次のものが必要です:

  • マスターブランチにサンプルコードのあるAWS CodeCommitのリポジトリ。以下にサンプルコードを示します。
  • 2つのAWS Identity Access Management(IAM)ユーザ。どちらもAWSCodeCommitのPowerUser管理ポリシーが適用されています。
  • ローカルコンピュータにインストールされたGitと、AWS CodeCommitへアクセスを許可する設定。
    ローカルコンピュータ上のAWS CodeCommitリポジトリのクローン。

 

この例では、AWS CodeCommitコンソールに1人のIAMユーザーとしてサインインしてプルリクエストを作成し、他のIAMユーザーとしてプルリクエストを確認します。IAMユーザーの設定方法と、GitでAWS CodeCommitに接続する方法の詳細については、次のトピックを参照してください:

  • AWSマネジメントコンソールを使用してIAMユーザを作成する方法。
  • Gitを使ってCodeCommitにアクセスする方法。
  • この記事で使用しているのと同じ「hello world」アプリケーションを使用したい場合は、こちらのソースコードを参考にしてください:
package com.amazon.helloworld;

public class Main {
	public static void main(String[] args) {

		System.out.println("Hello, world");
	}
}

 

以下のシナリオでは、us-east-2リージョンが使用されています。

 

ブランチの作成

プルリクエストを作成する前に、少なくとも2つのブランチが必要です。この例では、「GitFlowの説明」と同様の分岐戦略に従います。メインの開発ブランチ(デフォルトのブランチ)から、私たちの機能のための新しいブランチを作成します。featureブランチ上で、この機能を開発します。このブランチで新機能のコードを書いてテストしたら、featureブランチとメインの開発ブランチの差分を含むプルリクエストを作成します。私たちのチームリーダー(2番目のIAMユーザー)はプルリクエストの変更をレビューします。変更がレビューされると、featureブランチの内容が開発ブランチにマージされます。

図1: プルリクエストリンク

 

開発者として使用するIAMユーザーでAWS CodeCommitコンソールにサインインします。既存のリポジトリを使用することも、新しいリポジトリを作成することもできます。リポジトリのマスターブランチに変更をマージすることはありませんので、この例では既存のリポジトリを使用しても安全です。[Pull requests]リンクが[Commits]リンクのすぐ上に追加されていることがわかります(図1を参照)。[Commits]の下に[Branches]リンクがあります。[Branches]をクリックして、masterブランチから分岐したdevelopという新しいブランチを作成します。次に、’develop’ブランチから分岐した’feature1’という新しいブランチを作成します。図2に示すように、3つのブランチになります(リポジトリには、図に示す3つのブランチに加えて、他のブランチが含まれているかもしれません)。

図2: featureブランチの作成

リポジトリをまだクローンしていない場合は、CodeCommitコンソールのCodeリンクにアクセスし、[Connect]ボタンをクリックします。手順に従って、リポジトリをクローンします(詳細な手順はこちら)。ターミナルまたはコマンドラインを開き、リポジトリの接続手順に記載されているgit cloneコマンドを貼り付けます。次の例は、codecommit-demoという名前のリポジトリのクローンを示しています:

git clone https://git-codecommit.us-east-2.amazonaws.com/v1/repos/codecommit-demo

 

もし以前にリポジトリをクローンしていた場合は、作成したブランチと共にローカルのリポジトリを更新する必要があります。ターミナルかコマンドラインを開いてリポジトリのルートディレクトリにいることを確認し、以下のコマンドを実行してください:

git remote update origin

 

ローカルのリポジトリに新しいブランチがプルダウンされたことが確認できます。

$ git remote update origin
Fetching origin
From https://git-codecommit.us-east-2.amazonaws.com/v1/repos/codecommit-demo
 * [new branch]      develop    -> origin/develop
 * [new branch]      feature1   -> origin/feature1

 

タイプすることで新しいブランチを確認することもできます。

git branch --all

$ git branch --all
* master
  remotes/origin/develop
  remotes/origin/feature1
  remotes/origin/master

 

‘feature1’ブランチに変更を加えます。ターミナルかコマンドラインを開いて以下のコマンドを実行し、feature1ブランチをチェックアウトします。

it checkout feature1

$ git checkout feature1
Branch feature1 set up to track remote branch feature1 from origin.
Switched to a new branch 'feature1'

 

コードを変更する

お気に入りのエディタを使用してリポジトリ内のファイルを編集し、変更を保存します。ローカルリポジトリへの変更をコミットし、変更をCodeCommitにプッシュします。例えば:

git commit -am 'added new feature'
git push origin feature1

$ git commit -am 'added new feature'
[feature1 8f6cb28] added new feature
1 file changed, 1 insertion(+), 1 deletion(-)

$ git push origin feature1
Counting objects: 9, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (9/9), 617 bytes | 617.00 KiB/s, done.
Total 9 (delta 2), reused 0 (delta 0)
To https://git-codecommit.us-east-2.amazonaws.com/v1/repos/codecommit-demo
   2774a53..8f6cb28  feature1 -> feature1

 

プルリクエストの作成

これで’develop’ブランチとは異なる’feature1’ブランチになりました。この時点で、変更を’develop’ブランチにマージしたいと思います。チームメンバーに対して変更をレビューし、マージの準備が整っていることかどうかを確認するようにプルリクエストを作成します。

AWS CodeCommitコンソールで、[Pull requests]をクリックします。[Create pull request]をクリックします。次のページで、宛先ブランチとして’develop’を選択し、ソースブランチとして’feature1’を選択します。[Compare]をクリックします。CodeCommitはマージの競合をチェックし、fast-forwardオプションを使用してブランチを自動的にマージできるかどうか、または手動マージが必要かどうかを確認します。両方の状況でプルリクエストを作成できます。


図3: プルリクエストの作成

 

2つのブランチを比較した後、CodeCommitコンソールにプルリクエストを作成するために必要な情報が表示されます。’Details’セクションでは、プルリクエストのタイトルが必須です。作成したコードの変更内容とレビューする内容を説明するために、レビュー担当者にオプションでコメントを付けることもできます。’Notifications’セクションには、プルリクエストに対する変更をサブスクライバに送信する通知の設定を行うオプションがあります。通知は、プルリクエストの作成時およびプルリクエストの更新時またはコメント時に送信されます。最後に、このプルリクエストを構成する変更を確認できます。これには個々のコミット(プルリクエストは1つ以上のコミットを含めることができます。これはCommitsタブで確認できます)と、同様に各ファイルに加えられた変更、例えばプルリクエストによって参照される2つのブランチ間の差異(こちらはchangeタブで確認できます)が含まれます。この情報を確認し、プルリクエストのタイトルを追加したら、[Create]ボタンをクリックします。図4に示すように、プルリクエストが正常に作成されたことを示す確認画面が表示され、’develop’ブランチに競合することなくマージ可能な状態となります。

図4: プルリクエスト確認ページ

プルリクエストのレビュー

ではチームリーダーの観点からプルリクエストを見てみましょう。このCodeCommitリポジトリの通知を設定した場合、プルリクエストを作成するとチームリーダーに電子メールの通知が送信され、電子メールのリンクを使用してプルリクエストを直接参照できます。この例では、チームリーダーとして使用しているIAMユーザーでAWS CodeCommitコンソールにサインインして、プルリクエストをクリックします。図5に示すように、プルリクエストの作成時に行った時と同じ情報に加えてプルリクエストに関連するアクティビティの記録が表示されます。


図 5: チームリーダーがプルリクエストをレビューする

 

プルリクエストにコメントする

変更内容に対して全体レビューを実行し、新しいプルリクエストコメント機能を使用していくつかのコメントを作成します。プルリクエストに関する全体的な視点を得るには、まず[Commits]タブに行き、このプルリクエストに含まれるコミットの数を確認します。次に、[Changes]タブにアクセスしてfeatureブランチのコードとdevelopブランチのコードの違いを確認します。この時点で、それぞれの変更に対する作業として、プルリクエストにコメントを追加できます。それではプルリクエストをレビューしてみましょう。レビュー時に、レビューコメントを3つのレベルで追加できます。

 

  • プルリクエスト全体
  • プルリクエスト内のファイル
  • ファイル内の個々の行

 

プルリクエスト全体

[Changes]タブ内のページの下部に[Comments on changes]ボックスがあります。ここにプルリクエスト全体に関連するコメントを追加します。図6のようにコメントを追加し、[Save]ボタンをクリックします。

図6:  プルリクエストコメント

 

プルリクエスト内の特定のファイル

[Changes]タブ内のファイル名の上にマウスを移動すると、ファイル名の左側に青い「コメント」アイコンが表示されます。このアイコンをクリックすると、図7の例のように、このファイルに固有のコメントを入力できます。開発者が変更したファイルの1つにコメントを追加しましょう。[Save]ボタンをクリックしてコメントを保存します。

図7: ファイルコメント

 

プルリクエストのファイル内の特定の行

プルリクエストの各ファイル内の個々の行にカーソルを置くと、青い「コメント」アイコンが表示され、追加、削除、または変更されていない行に対してコメントを作成できます。図8では、ソースコードに追加された行に対してコメントを追加して、開発者に対して命名基準を確認することを促しています。開発者によって変更されたファイルの1つに行コメントを追加してください。 [Save]ボタンをクリックしてコメントを保存します。


図8:  ラインコメント

 

3つのレベルすべてでコメントされたプルリクエストは図9のようになります。プルリクエストのコメントは、開かれた[Commanes on changes]セクションに表示され、ファイルとラインレベルのコメントは表示されません。「コメント」アイコンは、ファイルおよび行レベルにコメントが存在することを示します。アイコンをクリックすると、コメントが展開されて表示されます。開発者がコメントに基づき、さらに変更を加えることを期待しているので、この段階でプルリクエストをマージすることはできませんが、フィードバックを待つ間そのままにしておくことができます。それぞれのコメントは開発者に通知が送信され、コメントに応答することができます。これは、開発者とチーム リーダーが異なるタイムゾーンにいるリモート作業には最適です。


図9:  プルリクエストの完全なコメント

 

少し複雑さを加える

典型的な開発チームは定期的にプルリクエストを作成しています。featureブランチ上のプルリクエストがレビュー段階にある間にチームリーダーが他のプルリクエストを’develop’ブランチにマージすることはよくあることです。これにより、プルリクエストの ‘Mergable’(マージ可能)ステータスが変更される可能性があります。このシナリオを追加し、開発者がこれをどのように処理するかを確認しましょう。

 

このシナリオをテストするために、新しいプルリクエストを作成し、これをチームリーダーに’develop’ブランチにマージするように依頼します。しかし、分かり易くするために私たちは簡単な方法を取ります。CodeCommitリポジトリを新しいフォルダにクローンし、’develop’ブランチに切り替えて、プルリクエストで変更されているファイルの1つに変更を加えます。プルリクエストで変更された行と同じコード行を変更してください。変更したファイルをコミットし、CodeCommitにpushします。’feature1’ブランチで変更したコードを’develop’ブランチのコードでも変更したため、’feature1’ブランチを ‘develop’ブランチにクリーンにマージすることはできません。開発者はこのマージの競合を解決する必要があります。

 

プルリクエストをレビューする開発者は、プルリクエストが以前の’Mergable’ステータス(Figue 5参照)ではなく図10のような‘Resolve conflicts’ (競合の解決)ステータスになっていることを知ります。


図10: マージの競合を伴うプルリクエスト

 

レビューコメントを確認する

チームリーダーがレビューを完了すると、開発者はコメントをレビューし、提案された変更を行います。開発者は、図11に示すようにプルリクエストの[Activity]タブでチームリーダーが行ったレビューコメントのリストを見ます。[Activity]タブには、コミットやコメントを含むプルリクエストの履歴が表示されます。レビューコメントに対して[Activity]タブから[Reply]ボタンをクリックすることで直接返信することができます。または[Changes]タブから返信することもできます。 [Changes]タブには、最新のコミットのコメントが表示されます。現在のコミットで変更または削除された行に関連付けられた以前のコミットに関するコメントがあるかもしれません。以前のコミットのコメントは、[Activity]タブで表示および返信することができます。

 

[Activity]タブでショートカットリンク(このように見えます</>)を使用して、コメントに関連付けられたソースコードにすばやく移動できます。この例では、プルリクエストレビューコメントに対処するためにソースコードをさらに変更しますので、これを実行します。しかし、まず‘Resolve conflicts’のステータスを解決する必要があります。


図11: プルリクエスト アクティビティ

 

‘Resolve conflicts’ステータスの解決

‘Resolve conflicts’ステータスは、 ‘develop’ブランチと ‘feature1’ブランチの間にマージ競合があることを示します。プルリクエストを’Mergable’状態に戻すためにマニュアルの調停が必要になります。ここでは、この矛盾を解決します。

 

ターミナルまたはコマンドラインを開き、次のコマンドを実行して’develop’ブランチをチェックアウトします。

git checkout develop

$ git checkout develop
Switched to branch 'develop'
Your branch is up-to-date with 'origin/develop'.

 

チームリーダーが行った変更を’develop’ブランチに組み込むには、ローカルのコピーでリモートの’develop’ブランチをマージします:

git pull

$ git pull
remote: Counting objects: 9, done.
Unpacking objects: 100% (9/9), done.
From https://git-codecommit.us-east-2.amazonaws.com/v1/repos/codecommit-demo
   af13c82..7b36f52  develop    -> origin/develop
Updating af13c82..7b36f52
Fast-forward
 src/main/java/com/amazon/helloworld/Main.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

 

次に、’feature1’ブランチをチェックアウトします:

git checkout feature1

$ git checkout feature1
Switched to branch 'feature1'
Your branch is up-to-date with 'origin/feature1'.

 

‘develop’ブランチからの変更を ‘feature1’ブランチにマージします:

git merge develop

$ git merge develop
Auto-merging src/main/java/com/amazon/helloworld/Main.java
CONFLICT (content): Merge conflict in src/main/java/com/amazon/helloworld/Main.java
Automatic merge failed; fix conflicts and then commit the result.

はい、これは失敗します。Main.javaファイルが両方のブランチで変更されたため、自動的に解決できないマージの競合が発生します。ただし、Main.javaには、競合するコードの場所を示すマーカーが含まれるようになり、これらを使用して問題を手動で解決できます。お気に入りのIDEを使ってMain.javaを編集すると、次のように表示されます:

package com.amazon.helloworld;

import java.util.*;

/**
 * This class prints a hello world message
 */

public class Main {
   public static void main(String[] args) {

<<<<<<< HEAD
        Date todaysdate = Calendar.getInstance().getTime();

        System.out.println("Hello, earthling. Today's date is: " + todaysdate);
=======
      System.out.println("Hello, earth");
>>>>>>> develop
   }
}

 

HEADと ‘===’の間のコードは、開発者が’feature1’ブランチに追加したコードです(HEADは現在チェックアウトされているブランチのことで’feature1’を表します)。’===’と ‘>>> develop’の間のコードは、チームリーダーによって’develop’ブランチに追加されたコードです。両方の変更を手動でマージして競合を解決し、更新されたMain.javaを生成します:

package com.amazon.helloworld;

import java.util.*;

/**
 * This class prints a hello world message
 */

public class Main {
   public static void main(String[] args) {

        Date todaysdate = Calendar.getInstance().getTime();

        System.out.println("Hello, earth. Today's date is: " + todaysdate);
   }
}

 

変更を保存したら、ローカルリポジトリに追加してコミットできます:

git add src/
git commit -m 'fixed merge conflict by merging changes'

 

レビューアによって提起された問題の修正

これでチームリーダーのコメントに対処する準備が整いました。’feature1’ブランチを指定していない場合は、次のコマンドを実行して ‘feature1’ブランチをチェックアウトしてください:

git checkout feature1

$ git checkout feature1
Branch feature1 set up to track remote branch feature1 from origin.
Switched to a new branch 'feature1'

 

お気に入りのIDEでソースコードを編集し、変更を加えてコメントに対処してください。この例では、開発者は次のようにソースコードを更新しました:

package com.amazon.helloworld;

import java.util.*;

/**
 *  This class prints a hello world message
 *
 * @author Michael Edge
 * @see HelloEarth
 * @version 1.0
 */

public class Main {
   public static void main(String[] args) {

        Date todaysDate = Calendar.getInstance().getTime();

        System.out.println("Hello, earth. Today's date is: " + todaysDate);
   }
}

 

変更を保存した後、以前と同じようにコミットしてCodeCommitの’feature1’ブランチにプッシュします:

git commit -am 'updated based on review comments'
git push origin feature1

 

レビューアへの対応

コードの問題を修正したので、レビューのコメントに対して返信したいと思います。AWS CodeCommitコンソールで、最新のコミットが[pull request Commits]タブに表示されていることを確認します。複数のコミットからなるプルリクエストができました。図12のプルリクエストには4つのコミットがあります。これは次のアクティビティから発生しました。

 

  • 11月8日:このプルリクエストを開始するために使用されたオリジナルのコミット
  • 11月10日、3時間前:チームリーダーによる’develop’ブランチへのコミット、’feature1’ブランチへのマージ
  • 11月10日、24分前:マージの競合を解決した開発者によるコミット
  • 11月10日、4分前:レビューコメントに対処した開発者による最終コミット


図12: 複数のコミットを含むプルリクエスト

 

チームリーダーが提供するレビューコメントに返信しましょう。図13に示すように、[Activity]タブでプルリクエストのコメントに返信して保存します。


図13: プルリクエスト コメントに返信する

 

この段階では、コードがコミットされ、プルリクエストコメントが更新されたので、チームリーダーによる最終レビューの準備が整いました。

 

最終レビュー

チームリーダーは、コードの変更と開発者のコメントを確認します。チームリーダーとして、あなたは’develop’ブランチを所有しており、プルリクエストの変更を’develop’ブランチにマージするかどうかの判断をします。プルリクエストページの下部にある[Merge]と[Close]ボタンを使用して、マージの有無にかかわらずプルリクエストを閉じることができます(図13を参照)。 [Close]をクリックすると、マージせずにプルリクエストをクローズする理由に関するコメントを追加できます。マージは、プルリクエストによって参照されるコミットを組み込んだfast-forwardマージを実行します。[Merge]ボタンをクリックしてプルリクエストを’develop’ブランチにマージしてみましょう。


図14: プルリクエストのマージ

 

プルリクエストをマージした後、その機能の開発は完了し、featureブランチは不要になります。マージ後にfeatureブランチを削除するのが一般的なプラクティスです。CodeCommitは、図14に示すように、マージ中に関連するFeatureブランチを自動的に削除するチェックボックスを提供します。[Merge]ボタンをクリックすると、図15に示すように、プルリクエストが’develop’ブランチにマージされます。これによってプルリクエストの状態が’Merged’更新され、プルリクエストが閉じられます。

図15: プルリクエストのマージ

 

結論

このブログでは、プルリクエストを使用してコードレビューをリクエストしたり、レビュー担当者が変更内容を包括的に把握したり、作成者にフィードバックしたり、コードを製品にマージできることをデモンストレーションしました。プルリクエストの詳細については、ドキュメントを参照してください。

 

日本語訳はSA 福井が担当しました。原文はこちらです。

https://aws.amazon.com/blogs/devops/using-aws-codecommit-pull-requests-to-request-code-reviews-and-discuss-code/