Usar Azure Functions para crear directivas de rama personalizadas

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

El flujo de trabajo de PR proporciona a los desarrolladores una oportunidad para obtener comentarios sobre su código de homólogos, así como de herramientas automatizadas. Las herramientas y servicios de terceros pueden participar en el flujo de trabajo de PR mediante la API de estado de la PR. Este artículo le guía por el proceso de creación de una directiva de rama personalizada mediante Azure Functions para validar las solicitudes de incorporación de cambios en un repositorio de Git de Azure DevOps Services. Con Azure Functions no tiene que preocuparse por el aprovisionamiento y el mantenimiento de servidores, especialmente cuando crece la carga de trabajo. Azure Functions proporcionar una plataforma de proceso totalmente administrada con alta confiabilidad y seguridad.

Para obtener más información sobre el estado de la PR, vea Personalización y extensión de flujos de trabajo de PR con el estado de la PR.

Requisitos previos

Una organización en Azure DevOps con un repositorio de Git. Si no tiene una organización, regístrese para cargar y compartir código en repositorios ilimitados de Git privados y gratuitos.

Creación de una función básica de Azure para escuchar eventos Azure Repos

Siga la documentación Creación de la primera función Azure para crear una función sencilla. Modifique el código del ejemplo para que tenga este aspecto:

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

Configuración de un enlace de servicio para eventos de PR

Los enlaces de servicio son una característica de Azure DevOps Services que puede avisar a servicios externos cuando se producen determinados eventos. En este ejemplo, querrá configurar un enlace de servicio para eventos de solicitud de incorporación de cambios, se notificará a la función de Azure cuando cambie una solicitud de incorporación de cambios. Para recibir POST solicitudes cuando cambien las solicitudes de incorporación de cambios, deberá proporcionar el enlace de servicio con la dirección URL de la función de Azure.

Para este ejemplo, deberá configurar 2 enlaces de servicio. El primero será para el evento de Solicitud de incorporación de cambios creada y el segundo será para el evento de Solicitud de incorporación de cambios actualizada.

  1. Obtenga la dirección URL de la función de la Azure Portal haciendo clic en la dirección URL de obtención de la función en la vista de funciones de Azure y copie la dirección URL.

    Obtener URL de la función

    Copiar función URL

  2. Vaya al proyecto en Azure DevOps, por ejemplo, https://dev.azure.com/<your organization>/<your project name>.

  3. En el menú de navegación, mantenga el puntero sobre el engranaje y seleccione Enlaces de servicio.

    Selección de Enlaces de servicio en el menú de administración

  4. Si este es el primer enlace de servicio, seleccione + Crear suscripción.

    Selección de la opción Crear una suscripción en la barra de herramientas

    Si ya tiene configurados otros enlaces de servicio, seleccione el signo verde más (+) para crear una suscripción de enlace de servicio.

    Selección del signo verde más para crear una suscripción de enlace de servicio.

  5. En el cuadro de diálogo Nueva suscripción de enlaces de servicio, seleccione Enlaces web en la lista de servicios y, después, seleccione Siguiente.

    Selección de enlaces web en la lista de servicios

  6. Seleccione Solicitud de incorporación de cambios creada en la lista de desencadenadores de eventos y, después, seleccione Siguiente.

    Selección de la opción Solicitud de incorporación de cambios creada en la lista de desencadenadores de eventos

  7. En la página Acción, escriba la dirección URL que copió en el paso 1 en el cuadro Dirección URL. Seleccione Probar para enviar un evento de prueba al servidor.

    Introducción de la dirección URL y selección de Probar para probar el enlace de servicio

    En la ventana de registro de funciones de Azure, verá una entrada POST que devolvió un 200 OK, que indica que la función recibió el evento de enlace de servicio.

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

    En la ventana Notificación de prueba, seleccione la pestaña Respuesta para ver los detalles de la respuesta del servidor. Debería ver la respuesta del servidor.

    Selección de la pestaña respuesta para ver los resultados de la prueba

  8. Cierre la ventana Notificación de prueba y seleccione Finalizar para crear el enlace de servicio.

Vuelva a seguir los pasos del 2 al 8, pero esta vez configure el evento Solicitud de incorporación de cambios actualizada.

Importante

Asegúrese de seguir los pasos anteriores dos veces y crear enlaces de servicio para los eventos de Solicitud de incorporación de cambios creada y Solicitud de incorporación de cambios actualizada.

Cree una solicitud de incorporación de cambios para comprobar que la función de Azure recibe notificaciones.

Publicación del estado en PR

Ahora que el servidor puede recibir eventos de enlace de servicio cuando se crean PR, actualícelo para publicar el estado de devolución a la PR. Puede usar la carga JSON publicada por el enlace de servicio para determinar qué estado se debe establecer en la solicitud de incorporación de cambios.

Actualice el código de la función de Azure para que tenga un aspecto similar al del ejemplo siguiente.

Asegúrese de actualizar el código con el nombre de la organización, el nombre del proyecto, el nombre del repositorio y el token PAT. Para tener permiso para cambiar el estado del RP, el PAT requiere el ámbito vso.code_status, que puede conceder seleccionando el ámbito Código (estado) en la página Crear un token de acceso personal.

Importante

Este código de ejemplo almacena el PAT en el código para simplificar el ejemplo. Se recomienda almacenar secretos en KeyVault y recuperarlos desde allí.

En este ejemplo se inspecciona el título de la solicitud de incorporación de cambios para ver si el usuario ha indicado si la solicitud de incorporación de cambios es un trabajo en curso agregando WIP al título. Si es así, el código de ejemplo cambia el estado que se devuelve a la solicitud de incorporación de cambios. Reemplace el código de la función de Azure por el código siguiente para implementar la actualización del estado que se devuelve a la solicitud de incorporación de cambios.

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

Creación de una PR para probar el servidor de estado

Ahora que el servidor está en ejecución y escucha notificaciones de enlace de servicio, cree una PR para probarlo.

  1. Comience en la vista de archivos. Edite el archivo readme.md en el repositorio (o cualquier otro archivo si no tiene uno readme.md).

    Selección de Editar en el menú contextual.

  2. Realice una edición y confirme los cambios en el repositorio.

    Edición del archivo y selección de Confirmar en la barra de herramientas

  3. Asegúrese de confirmar los cambios en una nueva rama para que pueda crear una PR en el paso siguiente.

    Introducción de un nuevo nombre de rama y selección de Confirmar

  4. Seleccione el vínculo Crear una solicitud de incorporación de cambios.

    Selección de Crear una solicitud de incorporación de cambios en la barra de sugerencias

  5. Agregue WIP en el título para probar la función de la aplicación. Seleccione Crear para crear la PR.

    Incorporación de WIP al título de la PR predeterminado

  6. Una vez creada la PR, verá la sección Estado, con la entrada Trabajo en curso que vincula a la dirección URL especificada en la carga.

    Sección Estado con la entrada Trabajo en curso.

  7. Actualice el título de la PR, quite el texto WIP y observe que el estado cambia de Trabajo en curso a Listo para revisión.

Pasos siguientes