次の方法で共有


Azure Functions を使用してカスタム ブランチ ポリシーを作成する

Azure DevOps Services |Azure DevOps Server |Azure DevOps Server 2022 |Azure DevOps Server 2020

pull request (PR) ワークフローを使用すると、開発者はピアや自動化されたツールからコードに関するフィードバックを受け取ることができます。 Microsoft 以外のツールとサービスは、PR Status API を使用して PR ワークフローに参加することもできます。 この記事では、 Azure Functions を使用してカスタム ブランチ ポリシーを作成し、Azure DevOps Git リポジトリ内の PR を検証する方法について説明します。 Azure Functions を使用すると、ワークロードが増加しても、サーバーをプロビジョニングして保守する必要がなくなります。 高い信頼性とセキュリティを備えたフル マネージド コンピューティング プラットフォームを提供します。

PR ステータスの詳細については、「プル要求の状態を使用して pull request ワークフローをカスタマイズおよび拡張する」を参照してください。

[前提条件]

カテゴリ 要求事項
組織 Git リポジトリを持つ Azure DevOps 内の組織。
Azure 関数 Azure 関数。Azure DevOps と統合してカスタム ブランチ ポリシーを作成し、PR 検証を自動化する、サーバーレスのイベント ドリブン ソリューションを実装します。
サービス フック プル要求が変更されたときに Azure 関数に通知するように PR イベントのサービス フックを構成します。
認証 Microsoft Entra ID トークンの「コード (状態)」スコープでPR状態を変更する権限を持ちます。 詳細については、Microsoft Entra 認証に関するページを参照してください。

Azure Repos イベントをリッスンするための基本的な Azure 関数を作成する

最初の Azure 関数を作成します。 次に、サンプルのコードを次のコードのように変更します。

using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    try
    {
        log.Info("Service Hook Received.");

        // Get request body
        dynamic data = await req.Content.ReadAsAsync<object>();

        log.Info("Data Received: " + data.ToString());

        // Get the pull request object from the service hooks payload
        dynamic jObject = JsonConvert.DeserializeObject(data.ToString());

        // Get the pull request id
        int pullRequestId;
        if (!Int32.TryParse(jObject.resource.pullRequestId.ToString(), out pullRequestId))
        {
            log.Info("Failed to parse the pull request id from the service hooks payload.");
        };

        // Get the pull request title
        string pullRequestTitle = jObject.resource.title;

        log.Info("Service Hook Received for PR: " + pullRequestId + " " + pullRequestTitle);

        return req.CreateResponse(HttpStatusCode.OK);
    }
    catch (Exception ex)
    {
        log.Info(ex.ToString());
        return req.CreateResponse(HttpStatusCode.InternalServerError);
    }
}

PR イベントのサービス フックを構成する

サービス フックは、特定のイベントが発生したときに外部サービスにアラートを送信できる Azure DevOps 機能です。 このサンプルでは、PR イベントのサービス フックを設定します。プル要求が変更されると、Azure 関数に通知されます。 プル要求が変更されたときに POST 要求を受信するには、サービス フックに Azure 関数 URL を指定します。

このサンプルでは、2 つのサービス フックを構成します。 1 つ目はイベントで作成された Pull request 用で、2 つ目は更新された Pull request イベント用です。

  1. Azure 関数ビューで [関数 URL の取得] をクリックして Azure portal から 関数 URL を取得 し、URL をコピーします。

    関数の URL を取得する

    関数の URL をコピーする

  2. Azure DevOps でプロジェクトを参照します (例: https://dev.azure.com/<your organization>/<your project name>

  3. ナビゲーション メニューから、の歯車 上にマウス ポインターを合わせ、サービス フック 選択します。

    管理メニューから [サービス フック] を選択する

  4. 最初のサービス フックの場合は、[ + サブスクリプションの作成] を選択します。

    ツール バーから [新しいサブスクリプションの作成] を選択します

    他のサービス フックが既に構成されている場合は、緑色のプラス (+) を選択して、新しいサービス フック サブスクリプションを作成します。

    緑色のプラスを選択して、新しいサービス フック サブスクリプションを作成します。

  5. [新しいサービス フック サブスクリプション] ダイアログで、サービス一覧から [Web フック] を選択し、[次へ] を選択します。

    サービスの一覧から Web フックを選択する

  6. イベント トリガーの一覧から [Pull request created] を選択し、[次へ] を選択します。

    イベント トリガーの一覧から作成された pull request を選択する

  7. [アクション] ページで、手順 1 でコピーした URL を [URL ] ボックスに入力します。 テスト を選択して、テスト イベントをサーバーに送信します。

    URL を入力し、[テスト] を選択してサービス フックをテストします

    Azure 関数ログ ウィンドウには、関数がサービス フック イベントを受信したことを示す、POSTを返した受信200 OKが表示されます。

    HTTP Requests
    -------------
    
    POST /                         200 OK
    

    [テスト通知] ウィンドウで、[応答] タブを選択して、サーバーからの応答の詳細を表示します。 サーバーからの応答が表示されます。

    [応答] タブを選択して、テストの結果を表示します

  8. [テスト通知] ウィンドウを閉じ、[完了] 選択してサービス フックを作成します。

手順 2 から 8 をもう一度実行しますが、今回は Pull request 更新 イベントを構成します。

Von Bedeutung

前の手順を 2 回実行し、作成された Pull request と、更新された pull request イベント 両方のサービス フックを作成してください。

プル要求を作成して、Azure 関数が通知を受信することを確認します。

PR に状態をポストする

新しい PR が作成されたときにサーバーがサービス フック イベントを受信できるようになったので、それを更新して状態を PR にポストバックします。 サービス フックによって投稿された JSON ペイロードを使用して、PR のステータスを設定するための判断を下せます。

次の例のように、Azure 関数のコードを更新します。

組織名、プロジェクト名、リポジトリ名、Microsoft Entra ID トークンでコードを更新してください。 PR 状態を変更するアクセス許可を持つには、トークン にはvso.code_status スコープが必要です。このスコープは、Microsoft Entra 認証を通じて取得できます。

Von Bedeutung

このサンプル コードでは、トークンをコードに格納し、サンプルを簡略化します。 セキュリティを強化するために、シークレットを Azure Key Vault に格納し、マネージド ID を使用してそこから取得することをお勧めします。

このサンプルでは、PR タイトルを調べて、 タイトルに WIP を追加して、PR が進行中の作業であるかどうかをユーザーが示したかどうかを確認します。 その場合、サンプル コードは PR にポストバックされた状態を変更します。 Azure 関数のコードを、PR にポストバックされた状態を更新する次のコードに置き換えます。

using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json;

private static string organizationName = "[Organization Name]";  // Organization name
private static string projectName      = "[Project Name]";       // Project name
private static string repositoryName   = "[Repo Name]";          // Repository name

/*
    This is here just to simplify the sample, it is recommended to store
    secrets in Azure Key Vault and retrieve them using managed identity.
*/
private static string accessToken = "[MICROSOFT_ENTRA_TOKEN]";

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    try
    {
        log.Info("Service Hook Received.");

        // Get request body
        dynamic data = await req.Content.ReadAsAsync<object>();

        log.Info("Data Received: " + data.ToString());

        // Get the pull request object from the service hooks payload
        dynamic jObject = JsonConvert.DeserializeObject(data.ToString());

        // Get the pull request id
        int pullRequestId;
        if (!Int32.TryParse(jObject.resource.pullRequestId.ToString(), out pullRequestId))
        {
            log.Info("Failed to parse the pull request id from the service hooks payload.");
        };

        // Get the pull request title
        string pullRequestTitle = jObject.resource.title;

        log.Info("Service Hook Received for PR: " + pullRequestId + " " + pullRequestTitle);

        PostStatusOnPullRequest(pullRequestId, ComputeStatus(pullRequestTitle));

        return req.CreateResponse(HttpStatusCode.OK);
    }
    catch (Exception ex)
    {
        log.Info(ex.ToString());
        return req.CreateResponse(HttpStatusCode.InternalServerError);
    }
}

private static void PostStatusOnPullRequest(int pullRequestId, string status)
{
    string Url = string.Format(
        @"https://dev.azure.com/{0}/{1}/_apis/git/repositories/{2}/pullrequests/{3}/statuses?api-version=4.1",
        organizationName,
        projectName,
        repositoryName,
        pullRequestId);

    using (HttpClient client = new HttpClient())
    {
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

        var method = new HttpMethod("POST");
        var request = new HttpRequestMessage(method, Url)
        {
            Content = new StringContent(status, Encoding.UTF8, "application/json")
        };

        using (HttpResponseMessage response = client.SendAsync(request).Result)
        {
            response.EnsureSuccessStatusCode();
        }
    }
}

private static string ComputeStatus(string pullRequestTitle)
{
    string state = "succeeded";
    string description = "Ready for review";

    if (pullRequestTitle.ToLower().Contains("wip"))
    {
        state = "pending";
        description = "Work in progress";
    }

    return JsonConvert.SerializeObject(
        new
        {
            State = state,
            Description = description,
            TargetUrl = "https://visualstudio.microsoft.com",

            Context = new
            {
                Name = "PullRequest-WIT-App",
                Genre = "pr-azure-function-ci"
            }
        });
}

新しい PR を作成し、ステータス サーバーをテストする

サーバーが実行され、サービスフック通知をリッスンできる状態になったら、「プルリクエスト」を作成してテストします。

  1. ファイル ビューから開始します。 リポジトリ内の readme.md ファイル (または readme.md がない場合は他のファイル) を編集します。

    コンテキスト メニューから [編集] を選択する

  2. 編集を行い、変更をリポジトリにコミットします。

    ファイルを編集し、ツール バーから [コミット] を選択します

  3. 次の手順で PR を作成できるように、必ず新しいブランチに変更をコミットしてください。

    新しいブランチ名を入力し、[コミット] を選択します

  4. [プルリクエストの作成] リンクを選択します。

    検索候補バーから [Pull request の作成] を選択する

  5. タイトル WIP を追加して、アプリの機能をテストします。 [作成] を選択して、PR を作成します。

    既定の PR タイトルに WIP を追加する

  6. PR が作成されると、状態セクションが表示され、[ 進行中の作業] エントリがペイロードで指定された URL にリンクされます。

    [進行中の作業] エントリを含む [状態] セクション。

  7. PR タイトルを更新し、WIP テキストを削除すると、状態が "進行中の作業" から "レビュー準備完了" に変わることに注意してください。

次のステップ