Udostępnij przez


Tworzenie niestandardowych zasad rozgałęziania za pomocą usługi Azure Functions

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

Przepływ pracy pull request umożliwia deweloperom otrzymywanie opinii na temat kodu od kolegów i zautomatyzowanych narzędzi. Narzędzia i usługi innych firm mogą również uczestniczyć w przepływie pracy żądania ściągnięcia przy użyciu interfejsu API stanu żądania ściągnięcia. W tym artykule opisano proces tworzenia niestandardowych zasad gałęzi przy użyciu usługi Azure Functions służącego do walidacji PR-ów w repozytorium Git usługi Azure DevOps. Usługa Azure Functions eliminuje konieczność aprowizacji i obsługi serwerów, nawet w miarę wzrostu obciążenia. Zapewniają one w pełni zarządzaną platformę obliczeniową o wysokiej niezawodności i zabezpieczeniach.

Aby uzyskać więcej informacji na temat stanu pull requestu, zobacz Dostosowywanie i rozszerzanie przepływów pracy pull requestów ze statusem pull requestu.

Wymagania wstępne

Kategoria Wymagania
Organizacja Jedna organizacja w ramach Azure DevOps z repozytorium Git.
Funkcja platformy Azure Funkcja Azure, która implementuje bezserwerowe, oparte na zdarzeniach rozwiązanie integrujące się z usługą Azure DevOps w celu tworzenia niestandardowych zasad gałęzi i automatyzowania walidacji pull requestów.
Hooki serwisowe Skonfiguruj webhooki dla zdarzeń pull request, aby powiadomić funkcję Azure o zmianie pull request.
Uwierzytelnianie Token identyfikatora Entra firmy Microsoft z zakresem Kod (stan) umożliwiającym zmianę statusu PR (Pull Request). Aby uzyskać więcej informacji, zobacz Microsoft Entra authentication.

Tworzenie podstawowej funkcji platformy Azure do nasłuchiwania zdarzeń usługi Azure Repos

Utwórz pierwszą funkcję platformy Azure. Następnie zmodyfikuj kod w przykładzie tak, aby wyglądał jak następujący kod:

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

Konfigurowanie haka usługi dla zdarzeń pull request.

Punkty zaczepienia usług to funkcja usługi Azure DevOps, która może powiadamiać usługi zewnętrzne o wystąpieniu niektórych zdarzeń. W tym przykładzie skonfiguruj hook serwisowy dla zdarzeń PR, funkcja Azure zostaje powiadomiona, gdy nastąpi zmiana w żądaniu ściągnięcia. Aby odbierać POST żądania po zmianie pull requestów, podaj adres URL funkcji Azure dla haka serwisowego.

W tym przykładzie skonfiguruj dwa punkty zaczepienia usługi. Pierwszy dotyczy zdarzenia utworzenia żądania ściągnięcia , a drugi dotyczy zaktualizowania żądania ściągnięcia .

  1. Pobierz adres URL funkcji z witryny Azure Portal, klikając pozycję Pobierz adres URL funkcji w widoku funkcji platformy Azure i skopiuj adres URL.

    Uzyskiwanie adresu URL funkcji

    Kopiuj adres URL funkcji

  2. Przejdź do projektu w usłudze Azure DevOps, na przykład https://dev.azure.com/<your organization>/<your project name>

  3. W menu nawigacji najedź kursorem na ikonę koła zębatego i wybierz pozycję Service Hooks.

    Wybierz pozycję Zaczepy usługi z menu administratora

  4. Jeśli jest to pierwszy punkt zaczepienia usługi, wybierz pozycję + Utwórz subskrypcję.

    Wybierz pozycję Utwórz nową subskrypcję na pasku narzędzi

    Jeśli masz już skonfigurowane inne punkty zaczepienia usługi, wybierz zielony plus (+) , aby utworzyć nową subskrypcję punktów zaczepienia usługi.

    Wybierz zielony znak plus, aby utworzyć nową subskrypcję usługi Service Hook.

  5. W oknie dialogowym Nowa subskrypcja usługi wybierz pozycję Web Hooks z listy usług, a następnie wybierz Dalej.

    Wybierz webhook z listy usług

  6. Wybierz pozycję Żądanie ściągnięcia utworzone z listy wyzwalaczy zdarzeń, a następnie wybierz pozycję Dalej.

    Wybierz żądanie ściągnięcia utworzone z listy wyzwalaczy zdarzeń

  7. Na stronie Akcja wprowadź adres URL skopiowany w kroku 1 w polu Adres URL . Wybierz pozycję Test, aby wysłać zdarzenie testowe do serwera.

    Wprowadź adres URL i wybierz pozycję Testuj, aby przetestować punkt zaczepienia usługi

    W oknie dziennika funkcji Azure zobaczysz przychodzące POST, które zwróciło 200 OK, wskazujące, że funkcja odebrała zdarzenie związane z service hook.

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

    W oknie Powiadomienie testowe wybierz kartę Odpowiedź, aby wyświetlić szczegóły odpowiedzi z serwera. Powinna zostać wyświetlona odpowiedź z serwera.

    Wybierz kartę odpowiedź, aby wyświetlić wyniki testu

  8. Zamknij okno Powiadomienia testowego i wybierz Zakończ, aby utworzyć hook serwisowy.

Ponownie wykonaj kroki 2–8, ale tym razem skonfiguruj zaktualizowane zdarzenie żądania ściągnięcia .

Ważne

Pamiętaj, aby wykonać poprzednie kroki dwa razy i utworzyć punkty zaczepienia usługi zarówno dla zdarzenia utworzenia żądania pobrania , jak i zaktualizowania żądania pobrania .

Utwórz pull request, aby sprawdzić, czy funkcja Azure odbiera powiadomienia.

Wysyłanie statusu do pull requestów

Teraz, gdy serwer może odbierać zdarzenia punktu zaczepienia usługi po utworzeniu nowych żądań ściągnięcia, zaktualizuj go, aby przywrócić stan żądania ściągnięcia do żądania ściągnięcia. Możesz użyć ładunku JSON opublikowanego przez hook usługi, aby określić, jaki stan ma być ustawiony na pull request.

Zaktualizuj kod funkcji platformy Azure, podobnie jak w poniższym przykładzie.

Pamiętaj, aby zaktualizować kod przy użyciu nazwy organizacji, nazwy projektu, nazwy repozytorium i tokenu identyfikatora Microsoft Entra. Aby mieć uprawnienia do zmiany statusu żądania przejęcia, token wymaga vso.code_status zakresu, który można uzyskać za pośrednictwem uwierzytelniania Microsoft Entra.

Ważne

Ten przykładowy kod przechowuje token w kodzie, upraszczając przykład. Zalecane jest przechowywanie wpisów tajnych w usłudze Azure Key Vault i pobieranie ich z tego miejsca przy użyciu tożsamości zarządzanej w celu zapewnienia zwiększonych zabezpieczeń.

Ten przykład sprawdza tytuł pull requestu, aby zobaczyć, czy użytkownik wskazał, że pull request jest w trakcie pracy, dodając WIP do tytułu. Jeśli tak, przykładowy kod zmienia status przesłany z powrotem do Pull Request. Zastąp kod w funkcji Azure następującym kodem, który aktualizuje status przesłany z powrotem do 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"
            }
        });
}

Tworzenie nowego żądania ściągnięcia i testowanie serwera stanu

Teraz, gdy serwer jest uruchomiony i nasłuchuje powiadomień o hookach serwisowych, utwórz pull request, aby go przetestować.

  1. Uruchom w widoku plików. Edytuj plik readme.md w repozytorium (lub inny plik, jeśli nie masz readme.md).

    Wybierz pozycję Edytuj z menu kontekstowego

  2. Wprowadź edycję i zatwierdź zmiany w repozytorium.

    Edytuj plik i wybierz pozycję Zatwierdź na pasku narzędzi

  3. Pamiętaj, aby zatwierdzić zmiany w nowej gałęzi, aby można było utworzyć pull request w następnym kroku.

    Wprowadź nową nazwę gałęzi i wybierz pozycję Zatwierdź

  4. Wybierz link Utwórz pull request.

    Wybierz opcję Utwórz pull request z paska sugestii

  5. Dodaj WIP w tytule, aby przetestować działanie aplikacji. Wybierz Utwórz, aby stworzyć żądanie scalenia.

    Dodaj WIP do domyślnego tytułu PR

  6. Po utworzeniu PR sekcja stanu zostanie wyświetlona z wpisem Praca w toku, który łączy się z adresem URL określonym w ładunku.

    Sekcja statusu z wpisem Praca w toku.

  7. Zaktualizuj tytuł PR i usuń tekst WIP oraz zwróć uwagę, że status zmienia się z Praca w toku na Gotowe do przeglądu.

Dalsze kroki