Partager via


Créer un abonnement de hook de service par programmation

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

Vous pouvez utiliser un abonnement pour effectuer une action sur un service externe ou consommateur lorsqu’un événement spécifique se produit dans un projet Azure DevOps. Par exemple, un abonnement peut informer votre service lorsqu'une compilation échoue.

Pour créer un abonnement par programmation, vous pouvez utiliser les API REST Abonnements. Cet article fournit un exemple de requête et d’exemple de code pour la création d’un abonnement.

Conditions préalables

Catégorie Exigences
Accès au projet Membre du projet.
Données - ID de projet. Utilisez l’API REST Project pour obtenir l’ID de projet.
- ID d’événement et paramètres. Consultez les événements de déclenchement de service.
- ID et paramètres du consommateur et de l'action. Consultez consommateurs de hooks de service.

Événements pris en charge

Azure DevOps prend en charge de nombreux événements déclencheurs. Voici quelques exemples :

  • Construction terminée
  • Code envoyé (pour les projets Git)
  • Demande de tirage (pull request) créée ou mise à jour (pour les projets Git)
  • Code archivé (pour les projets Team Foundation Version Control)
  • Élément de travail créé, mis à jour, supprimé, restauré ou commenté

Pour contrôler les événements qui déclenchent une action, vous pouvez configurer des filtres sur vos abonnements. Par exemple, vous pouvez filtrer l'événement de build complété en fonction de son état.

Créer une demande

Lorsque vous créez un abonnement, vous utilisez le corps d’une requête HTTP POST pour spécifier l’ID de projet, l’événement, le consommateur, l’action et les paramètres associés.

Vous pouvez utiliser la demande suivante pour créer un abonnement pour un événement de build terminé. Dans cet exemple, lorsque la WebSite.CI build échoue, l’abonnement envoie une requête POST à https://myservice/event.

Requête

{
    "publisherId": "tfs",
    "eventType": "build.complete",
    "resourceVersion": "1.0",
    "consumerId": "webHooks",
    "consumerActionId": "httpRequest",
    "publisherInputs": {
        "buildStatus": "failed",
        "definitionName": "WebSite.CI",
        "projectId": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff",
    },
    "consumerInputs": {
        "url": " https://myservice/event"
    },
}

Nous vous recommandons vivement d’utiliser des URL HTTPS sécurisées pour la sécurité des données privées dans l’objet JSON.

Réponse

La demande de création de l’abonnement génère une réponse similaire à la suivante :

{
    "id": "aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e",
    "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/hooks/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e",
    "publisherId": "tfs",
    "eventType": "build.complete",
    "resourceVersion": "1.0",
    "consumerId": "webHooks",
    "consumerActionId": "httpRequest",
    "createdBy": {
        "id": "22cc22cc-dd33-ee44-ff55-66aa66aa66aa"
    },
    "createdDate": "2014-03-28T16:10:06.523Z",
    "modifiedBy": {
        "id": "22cc22cc-dd33-ee44-ff55-66aa66aa66aa"
    },
    "modifiedDate": "2014-04-25T18:15:26.053Z",
    "publisherInputs": {
        "buildStatus": "failed",
        "definitionName": "WebSite.CI",
        "hostId": "d3d3d3d3-eeee-ffff-aaaa-b4b4b4b4b4b4",
        "projectId": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff",
        "tfsSubscriptionId": "ffff5f5f-aa6a-bb7b-cc8c-dddddd9d9d9d"
    },
    "consumerInputs": {
        "url": "http://myservice/event"
    }
}

Si la demande d’abonnement échoue, vous obtenez un code de réponse HTTP de 400 avec un message contenant des détails supplémentaires.

Que se passe-t-il lorsque l’événement se produit ?

Lorsqu’un événement se produit, tous les abonnements activés dans le projet sont évalués. Ensuite, l'action du consommateur est exécutée pour tous les abonnements correspondants.

Versions de ressources (avancées)

Le contrôle de version des ressources s’applique lorsqu’une API est en préversion. Pour la plupart des scénarios, la spécification de 1.0 comme version de ressource est l’itinéraire le plus sûr.

La charge utile d’événement envoyée à certains consommateurs inclut une représentation JSON d’une ressource d’objet. Par exemple, la charge utile envoyée aux webhooks, Azure Service Bus et Azure Storage incluent des informations sur une build ou une tâche. La représentation de cette ressource peut avoir différentes formes ou versions.

Vous pouvez spécifier la version de la ressource que vous souhaitez envoyer au service consommateur via le resourceVersion champ de l’abonnement.

La version de ressource est la même que la version de l’API . Si vous ne spécifiez pas de version de ressource, la dernière version est latest releasedutilisée. Pour garantir une charge utile d’événement cohérente au fil du temps, spécifiez toujours une version de ressource.

Questions fréquentes (FAQ)

Q : Existe-t-il des services auxquels je peux m’abonner manuellement ?

R : Oui. Pour plus d’informations sur les services auxquels vous pouvez vous abonner à partir d’une page d’administration de projet, consultez Intégrer avec des hooks de service.

Q : Existe-t-il des bibliothèques C# que je peux utiliser pour créer des abonnements ?

R : Non, mais voici un exemple pour vous aider à commencer. Pour l’authentification auprès d’Azure DevOps, le code suivant utilise un jeton d’accès personnel (PAT) stocké dans Azure Key Vault. Dans un environnement de production, utilisez une méthode d’authentification plus sécurisée. Pour plus d’informations, consultez Choisir le mécanisme d’authentification approprié.

using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.ServiceHooks.WebApi;
using Microsoft.VisualStudio.Services.WebApi;

namespace CreateServiceHookSubscription
{
    internal class Program
    {
        // Create a service hook subscription to send a message to an Azure Service Bus queue when code is pushed to a Git repository.

        static async Task Main(string[] args)
        {
            // Get the secrets from the key vault.
            string keyVaultURI = "https://<key-vault-name>.vault.azure.net/";
            var secretClient = new SecretClient(new Uri(keyVaultURI), new DefaultAzureCredential());
            string personalAccessTokenSecretName = "<personal-access-token-secret-name>";
            string serviceBusConnectionStringSecretName = "<Service-Bus-connection-string-secret-name>";
            KeyVaultSecret personalAccessTokenSecret = await secretClient.GetSecretAsync(personalAccessTokenSecretName);
            KeyVaultSecret serviceBusConnectionStringSecret = await secretClient.GetSecretAsync(serviceBusConnectionStringSecretName);

            // Set up the connection parameters for Azure DevOps.
            var azureDevOpsOrganizationURL = new Uri("https://dev.azure.com/<Azure-DevOps-organization-name>/");
            string azureDevOpsTeamProjectID = "<Azure-DevOps-team-project-ID>";
            string azureDevOpsPersonalAccessToken = personalAccessTokenSecret.Value;

            // Set up the event parameters.
            string eventPublisherID = "tfs";
            string eventID = "git.push";
            string eventDescription = "Any stage in any release";
            string resourceVersion = "1.0";

            // Set up the consumer parameters.
            string consumerID = "azureServiceBus";
            string consumerActionID = "serviceBusQueueSend";
            string serviceBusNamespace = "<Service-Bus-namespace>";
            string serviceBusQueueName = "<Service-Bus-queue-name>";
            string consumerActionDescription = $"Send a message to the Service Bus {serviceBusQueueName} queue in the {serviceBusNamespace} namespace.";
            string serviceBusConnectionString = serviceBusConnectionStringSecret.Value;

            // Configure the subscription.
            var subscription = new Subscription()
            {
                PublisherId = eventPublisherID,
                PublisherInputs = new Dictionary<string, string>
                {
                    ["projectId"] = azureDevOpsTeamProjectID
                },
                EventType = eventID,
                EventDescription = eventDescription,
                ResourceVersion = resourceVersion,
                ActionDescription = consumerActionDescription,
                ConsumerActionId = consumerActionID,
                ConsumerId = consumerID,
                ConsumerInputs = new Dictionary<string, string>
                {
                    ["connectionString"] = serviceBusConnectionString,
                    ["queueName"] = serviceBusQueueName
                }
            };

            // Connect to the Azure DevOps organization and get a service hook client.
            var azureDevOpsCredentials = new VssBasicCredential(azureDevOpsPersonalAccessToken, string.Empty);
            var azureDevOpsConnection = new VssConnection(azureDevOpsOrganizationURL, azureDevOpsCredentials);
            var serviceHookClient = azureDevOpsConnection.GetClient<ServiceHooksPublisherHttpClient>();

            // Create the subscription.
            var createdSubscription = await serviceHookClient.CreateSubscriptionAsync(subscription);
            Console.WriteLine($"A subscription was created that has ID {createdSubscription.Id}.");
        }
    }
}