Usar Azure Functions para crear directivas de rama personalizadas

Azure Repos | Azure DevOps Server 2020 | Azure DevOps Server 2019 | TFS 2018

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

Para más información sobre el estado de la solicitud de solicitud de extracción, consulte Personalización y ampliación de flujos de trabajo de solicitud de extracción con el estado de solicitud de extracción.

Prerrequisitos

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

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

Siga la documentación de creación de la primera función de Azure para crear una función sencilla. Modifique el código del ejemplo para que se parezca a este:

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 Azure DevOps Services que puede alertar a servicios externos cuando se producen determinados eventos. En este ejemplo, querrá configurar un enlace de servicio para eventos de solicitud de cambios; la función de Azure recibirá una notificación cuando cambie una solicitud de extracción. Para recibir solicitudes cuando cambien las solicitudes de extracción, deberá proporcionar el enlace POST de servicio con la dirección URL de la función de Azure.

Para este ejemplo, deberá configurar dos enlaces de servicio. El primero será para el evento de creación de la solicitud de extracción y el segundo para el evento de actualización de la solicitud de extracción.

  1. Obtenga la dirección URL de la función Azure Portal haga clic en Obtener la dirección URL de la función en la vista de función de Azure y copie la dirección URL.

    Obtener la dirección URL de la función

    Copia de la dirección URL de la función

  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 Service Hooks (Enlaces de servicio).

    Elija Enlaces de servicio en el menú de administración.

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

    Seleccione Crear una nueva suscripción en la barra de herramientas.

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

    Seleccione el signo más verde para crear una nueva suscripción de enlace de servicio.

  5. En el cuadro de diálogo Nueva suscripción de enlaces de servicio, seleccione Web Hooks en la lista de servicios y, a continuación, seleccione Siguiente.

    Selección de web hooks en la lista de servicios

  6. Seleccione Solicitud de extracción creada en la lista de desencadenadores de eventos y, a continuación, seleccione Siguiente.

    Selección de la solicitud de extracción 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.

    Escriba la dirección URL y seleccione Probar para probar el enlace de servicio.

    En la ventana del registro de funciones de Azure, verá una entrada que devolvió un , que indica que la función POST recibió el evento de enlace de 200 OK 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.

    Seleccione 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 de actualización de la solicitud de extracción.

Importante

Asegúrese de seguir los pasos anteriores dos veces y crear enlaces de servicio tanto para la solicitud de extracción creada como para los eventos actualizados de la solicitud de extracción.

Cree una solicitud de extracción para comprobar que la función de Azure está recibiendo notificaciones.

Publicación del estado en las solicitud de solicitud

Ahora que el servidor puede recibir eventos de enlace de servicio cuando se crean nuevos PR, actualíctelo para devolver el estado a la SOLICITUD. Puede usar la carga JSON publicada por el enlace de servicio para determinar qué estado se va a establecer en la solicitud de solicitud.

Actualice el código de la función de Azure para que se parezca al 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 de la solicitud de cambio, el PAT requiere un ámbito de 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 pr para ver si el usuario ha indicado si la PR es un trabajo en curso agregando WIP al título. Si es así, el código de ejemplo cambia el estado publicado de nuevo en la pr. Reemplace el código de la función de Azure por el código siguiente para implementar la actualización del estado publicado de nuevo en la 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 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 nueva pr para probar el servidor de estado

Ahora que el servidor está ejecutando y escuchando notificaciones de enlace de servicio, cree una solicitud de extracción para probarla.

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

    Seleccione Editar en el menú contextual.

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

    Edite el archivo y seleccione Confirmar en la barra de herramientas.

  3. Asegúrese de confirmar los cambios en una nueva rama para poder crear una pr. en el paso siguiente.

    Escriba un nuevo nombre de rama y seleccione Confirmar.

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

    Seleccione Crear una solicitud de extracción en la barra de sugerencias.

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

    Adición de WIP al título de la pr predeterminada

  6. Una vez creada la solicitud de solicitud de acceso, verá la sección de estado, con la entrada Trabajo en curso que se 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. y quite el texto de WIP y observe que el estado cambia de Trabajo en curso a Listo para revisión.

Pasos siguientes