Usare Funzioni di Azure per creare criteri ramo personalizzati

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

Il flusso di lavoro della richiesta pull offre agli sviluppatori l'opportunità di ottenere commenti e suggerimenti sul codice dai peer e dagli strumenti automatizzati. Gli strumenti e i servizi di terze parti possono partecipare al flusso di lavoro delle richieste pull usando l'API Stato richiesta pull. Questo articolo illustra il processo di creazione di un criterio di ramo personalizzato usando Funzioni di Azure per convalidare le richieste pull in un repository Git di Azure DevOps Services. Con Funzioni di Azure non è necessario preoccuparsi del provisioning e della gestione dei server, soprattutto quando il carico di lavoro aumenta. Funzioni di Azure offrire una piattaforma di calcolo completamente gestita con affidabilità e sicurezza elevate.

Per altre informazioni sullo stato della richiesta pull, vedere Personalizzare ed estendere i flussi di lavoro delle richieste pull con stato della richiesta pull.

Prerequisiti

Un'organizzazione in Azure DevOps con un repository Git. Se non si ha un'organizzazione, iscriversi per caricare e condividere codice in repository Git privati gratuiti senza limiti.

Creare una funzione di Azure di base per ascoltare gli eventi di Azure Repos

Seguire la documentazione relativa alla creazione della prima funzione di Azure per creare una funzione semplice. Modificare il codice nell'esempio in modo che sia simile al seguente:

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

Configurare un hook del servizio per gli eventi di richiesta pull

Gli hook del servizio sono una funzionalità di Azure DevOps Services che può avvisare i servizi esterni quando si verificano determinati eventi. Per questo esempio, si vuole configurare un hook del servizio per gli eventi pr, la funzione di Azure riceverà una notifica quando viene modificata una richiesta pull. Per ricevere POST richieste quando le richieste pull cambiano, è necessario fornire all'hook del servizio l'URL della funzione di Azure.

Per questo esempio è necessario configurare 2 hook di servizio. Il primo sarà per l'evento creato dalla richiesta pull e il secondo sarà per l'evento aggiornato della richiesta pull.

  1. Ottenere l'URL della funzione dal portale di Azure facendo clic sull'URL get function (Ottieni URL funzione) nella visualizzazione funzione di Azure e copiare l'URL.

    Ottenere l'URL della funzione

    Copiare l'URL della funzione

  2. Passare al progetto in Azure DevOps, ad esempio https://dev.azure.com/<your organization>/<your project name>

  3. Dal menu di spostamento passare il puntatore del mouse sull'ingranaggio e selezionare Hook di servizio.

    Scegliere Hook di servizio dal menu di amministrazione

  4. Se si tratta del primo hook del servizio, selezionare + Crea sottoscrizione.

    Selezionare Crea una nuova sottoscrizione dalla barra degli strumenti

    Se sono già stati configurati altri hook del servizio, selezionare il segno più (+) verde per creare una nuova sottoscrizione hook del servizio.

    Selezionare il segno più verde per creare una nuova sottoscrizione hook del servizio.

  5. Nella finestra di dialogo Nuova sottoscrizione hook del servizio selezionare Web Hook nell'elenco dei servizi e quindi selezionare Avanti.

    Selezionare web hook dall'elenco dei servizi

  6. Selezionare Richiesta pull creata dall'elenco dei trigger di eventi e quindi selezionare Avanti.

    Selezionare la richiesta pull creata dall'elenco dei trigger di evento

  7. Nella pagina Azione immettere l'URL copiato nel passaggio 1 nella casella URL . Selezionare Test per inviare un evento di test al server.

    Immettere l'URL e selezionare Test per testare l'hook del servizio

    Nella finestra del log delle funzioni di Azure verrà visualizzato un oggetto in ingresso POST che ha restituito un 200 OKoggetto , che indica che la funzione ha ricevuto l'evento di hook del servizio.

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

    Nella finestra Notifica test selezionare la scheda Risposta per visualizzare i dettagli della risposta dal server. Verrà visualizzata la risposta dal server.

    Selezionare la scheda risposta per visualizzare i risultati del test

  8. Chiudere la finestra Notifica test e selezionare Fine per creare l'hook del servizio.

Eseguire di nuovo i passaggi da 2 a 8, ma questa volta configurare l'evento aggiornato della richiesta pull.

Importante

Assicurarsi di eseguire due volte i passaggi precedenti e creare hook del servizio per gli eventi aggiornati della richiesta pull creata e della richiesta pull.

Creare una richiesta pull per verificare che la funzione di Azure riceva le notifiche.

Registrare lo stato nelle richieste pull

Ora che il server può ricevere eventi di hook del servizio quando vengono create nuove richieste pull, aggiornarlo per registrare lo stato della richiesta pull. È possibile usare il payload JSON pubblicato dall'hook del servizio per determinare lo stato da impostare nella richiesta pull.

Aggiornare il codice della funzione di Azure in modo che sia simile all'esempio seguente.

Assicurarsi di aggiornare il codice con il nome dell'organizzazione, il nome del progetto, il nome del repository e il token PAT. Per avere l'autorizzazione per modificare lo stato della richiesta pull, il pat richiede vso.code_status ambito, che è possibile concedere selezionando l'ambito Codice (stato) nella pagina Crea un token di accesso personale.

Importante

Questo codice di esempio archivia il pat nel codice per semplificare l'esempio. È consigliabile archiviare i segreti in KeyVault e recuperarli da questa posizione.

Questo esempio esamina il titolo della richiesta pull per verificare se l'utente ha indicato se la richiesta pull è un lavoro in corso aggiungendo WIP al titolo. In tal caso, il codice di esempio modifica lo stato inviato alla richiesta pull. Sostituire il codice nella funzione di Azure con il codice seguente per implementare l'aggiornamento dello stato inviato alla richiesta pull.

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

Creare una nuova richiesta pull per testare il server di stato

Ora che il server è in esecuzione e in ascolto delle notifiche di hook del servizio, creare una richiesta pull per testarla.

  1. Iniziare nella visualizzazione file. Modificare il file readme.md nel repository (o qualsiasi altro file se non si dispone di un readme.md).

    Selezionare Modifica dal menu di scelta rapida

  2. Apportare una modifica ed eseguire il commit delle modifiche nel repository.

    Modificare il file e selezionare Commit dalla barra degli strumenti

  3. Assicurarsi di eseguire il commit delle modifiche in un nuovo ramo in modo da poter creare una richiesta pull nel passaggio successivo.

    Immettere un nuovo nome di ramo e selezionare Commit

  4. Selezionare il collegamento Crea una richiesta pull.

    Selezionare Crea una richiesta pull dalla barra dei suggerimenti

  5. Aggiungere WIP nel titolo per testare la funzionalità dell'app. Selezionare Crea per creare la richiesta pull.

    Aggiungere WIP al titolo predefinito della richiesta pull

  6. Dopo aver creato la richiesta pull, verrà visualizzata la sezione relativa allo stato, con la voce Lavoro in corso che collega all'URL specificato nel payload.

    Sezione Stato con l'immissione Lavoro in corso.

  7. Aggiornare il titolo della richiesta pull e rimuovere il testo wip e notare che lo stato cambia da Lavoro in corso a Pronto per la revisione.

Passaggi successivi

  • In questo articolo sono state illustrate le nozioni di base su come creare una funzione di Azure serverless in ascolto degli eventi di richiesta pull tramite hook del servizio e pubblicare messaggi di stato usando l'API di stato. Per altre informazioni sull'API di stato della richiesta pull, vedere la documentazione dell'API REST.
  • Configurare un criterio di ramo per un servizio esterno.