Utiliser Azure Functions pour créer des stratégies de branche personnalisées

Azure DevOps Services | Azure DevOps Server 2022 | Azure DevOps Server 2019

Le workflow de demande de tirage permet aux développeurs d’obtenir des commentaires sur leur code des pairs ainsi que des outils automatisés. Les outils et services tiers peuvent participer au flux de travail de demande de tirage à l’aide de l’API d’état de la demande de tirage. Cet article vous guide tout au long du processus de création d’une stratégie de branche personnalisée à l’aide d’Azure Functions pour valider les demandes de tirage dans un référentiel Git Azure DevOps Services. Avec Azure Functions, vous n’avez pas à vous soucier de l’approvisionnement et de la maintenance des serveurs, en particulier lorsque votre charge de travail augmente. Azure Functions fournit une plateforme de calcul entièrement managée avec une fiabilité et une sécurité élevées.

Pour plus d’informations sur l’état des demandes de tirage, consultez Personnaliser et étendre les flux de travail de demande de tirage avec l’état des demandes de tirage.

Prérequis

Une organisation dans Azure DevOps avec un référentiel Git. Si vous n’avez pas d’organisation, inscrivez-vous pour charger et partager du code dans des référentiels Git privés gratuits illimités.

Créer une fonction Azure de base pour écouter les événements Azure Repos

Suivez la documentation de création de votre première fonction Azure pour créer une fonction simple. Modifiez le code dans l’exemple pour qu’il ressemble à ceci :

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);
    }
}

Configurer un crochet de service pour les événements de demande de tirage

Les crochets de service sont une fonctionnalité Azure DevOps Services qui peut alerter les services externes lorsque certains événements se produisent. Pour cet exemple, si vous souhaitez configurer un crochet de service pour les événements de demande de tirage, votre fonction Azure sera avertie lorsqu’une demande de tirage changera. Pour recevoir des requêtes POST lorsque les demandes de tirage changent, vous devez fournir le crochet de service avec l’URL de la fonction Azure.

Pour cet exemple, vous devez configurer 2 crochets de service. Le premier est destiné à l’événement Demande de tirage créée et le second est destiné à l’événement Demande de tirage mise à jour.

  1. Obtenez l’URL de la fonction à partir du portail Azure en cliquant sur Obtenir l’URL de la fonction dans la vue de votre fonction Azure et copiez l’URL.

    Obtenir l’URL de la fonction

    Copier l’URL de la fonction

  2. Accédez à votre projet dans Azure DevOps, par exemple https://dev.azure.com/<your organization>/<your project name>

  3. Dans le menu de navigation, pointez sur l’engrenage et sélectionnez Crochets de service.

    Choisir des crochets de service dans le menu d’administrateur

  4. S’il s’agit de votre premier crochet de service, sélectionnez + Créer un abonnement.

    Sélectionnez Créer un nouvel abonnement dans la barre d’outils

    Si vous avez déjà configuré d’autres crochets de service, sélectionnez le (+) vert plus pour créer un abonnement de crochet de service.

    Sélectionnez le plus vert pour créer un nouvel abonnement de crochet de service.

  5. Dans la boîte de dialogue Nouvel abonnement de crochets de service, sélectionnez Webhooks dans la liste des services, puis sélectionnez Suivant.

    Sélectionner des webhooks dans la liste des services

  6. Sélectionnez Demande de tirage créée dans la liste des déclencheurs d’événements, puis sélectionnez Suivant.

    Sélectionner la demande de tirage créée dans la liste des déclencheurs d’événements

  7. Dans la page Action, entrez l’URL que vous avez copiée à l’étape 1 dans la zone URL. Sélectionnez Test pour envoyer un événement de test à votre serveur.

    Entrer l’URL et sélectionner Test pour tester le crochet de service

    Dans la fenêtre du journal des fonctions Azure, vous verrez un entrant POST qui a retourné un 200 OK, indiquant que votre fonction a reçu l’événement de crochet de service.

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

    Dans la fenêtre Notification de test, sélectionnez l’onglet Réponse pour afficher les détails de la réponse à partir de votre serveur. Vous devez voir la réponse de votre serveur.

    Sélectionner l’onglet réponse pour afficher les résultats du test

  8. Fermez la fenêtre Notification de test, puis sélectionnez Terminer pour créer le crochet de service.

Passez à nouveau par les étapes 2 à 8, mais cette fois, configurez l’événement Demande de tirage mise à jour.

Important

Veillez à parcourir les étapes précédentes à deux reprises et à créer des crochets de service pour les événements Demande de tirage créée et Demande de tirage mise à jour.

Créez une demande de tirage pour vérifier que votre fonction Azure reçoit des notifications.

Publier l’état sur les demandes de tirage

Maintenant que votre serveur peut recevoir des événements de crochet de service lorsque de nouvelles demandes de tirage sont créées, mettez-le à jour pour publier l’état de retour à la demande de tirage. Vous pouvez utiliser la charge utile JSON publiée par le crochet de service pour déterminer l’état à définir sur votre demande de tirage.

Mettez à jour le code de votre fonction Azure pour qu’il ressemble à l’exemple suivant.

Veillez à mettre à jour le code avec le nom de votre organisation, le nom du projet, le nom du référentiel et le jeton PAT. Pour avoir l’autorisation de modifier l’état de la demande de tirage, le PAT nécessite l’étendue vso.code_status, que vous pouvez accorder en sélectionnant l’étendue Code (état) dans la page Créer un jeton d’accès personnel.

Important

Cet exemple de code stocke le PAT dans le code pour simplifier l’exemple. Il est recommandé de stocker des secrets dans KeyVault et de les récupérer à partir de là.

Cet exemple inspecte le titre de la demande de tirage pour voir si l’utilisateur a indiqué si la demande de tirage est un travail en cours en ajoutant WIP au titre. Si c’est le cas, l’exemple de code modifie l’état de retour publié sur la demande de tirage. Remplacez le code dans votre fonction Azure par le code suivant pour implémenter la mise à jour de l’état de retour publié dans la demande de tirage.

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 KeyVault and retrieve them from there.
*/
private static string pat = "[PAT 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("Basic", Convert.ToBase64String(
                ASCIIEncoding.ASCII.GetBytes(
                string.Format("{0}:{1}", "", pat))));

        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"
            }
        });
}

Créer une nouvelle demande de tirage pour tester le serveur d’état

Maintenant que votre serveur est en cours d’exécution et écoute des notifications de crochet de service, créez une demande de tirage pour la tester.

  1. Démarrez dans la vue fichiers. Modifiez le fichier readme.md dans votre référentiel (ou tout autre fichier si vous n’avez pas de readme.md).

    Sélectionner Modifier dans le menu contextuel

  2. Apportez une modification et validez les modifications apportées au référentiel.

    Modifier le fichier et sélectionner Valider dans la barre d’outils

  3. Veillez à valider les modifications apportées à une nouvelle branche afin de pouvoir créer une demande de tirage à l’étape suivante.

    Entrer un nouveau nom de branche et sélectionner Valider

  4. Sélectionnez le lien Créer une demande de tirage.

    Sélectionnez Créer une demande de tirage à partir de la barre de suggestions

  5. Ajoutez WIP dans le titre pour tester les fonctionnalités de l’application. Sélectionnez Créer pour créer la demande de tirage.

    Ajouter WIP au titre de la demande de tirage par défaut

  6. Une fois la demande de tirage créée, vous verrez la section d’état, avec l’entrée Travail en cours qui lie l’URL spécifiée dans la charge utile.

    Section État avec l’entrée Travail en cours.

  7. Mettez à jour le titre de la demande de tirage et supprimez le texte WIP et notez que l’état passe de Travail en cours à Prêt pour la révision.

Étapes suivantes