다음을 통해 공유


프로그래밍 방식으로 서비스 후크 구독 만들기

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

Azure DevOps 프로젝트에서 특정 이벤트가 발생할 때 구독을 사용하여 외부 또는 소비자 서비스에 대한 작업을 수행할 수 있습니다. 예를 들어 구독은 빌드가 실패할 때 서비스에 알릴 수 있습니다.

프로그래밍 방식으로 구독을 만들려면 구독 REST API를 사용할 수 있습니다. 이 문서에서는 구독을 만들기 위한 샘플 요청 및 샘플 코드를 제공합니다.

필수 구성 요소

범주 요구 사항
프로젝트에 대한 액세스 프로젝트 멤버.
데이터 - 프로젝트 ID입니다. Project REST API 사용하여 프로젝트 ID를 가져옵니다.
- 이벤트 ID 및 설정입니다. 서비스 후크 이벤트를 참조하세요.
- 소비자 및 작업 ID 및 설정. 서비스 후크 소비자를 참조하세요.

지원되는 이벤트

Azure DevOps는 수많은 트리거 이벤트를 지원합니다. 예제에는 다음 이벤트가 포함됩니다.

  • 빌드 완료
  • 푸시된 코드(Git 프로젝트의 경우)
  • 끌어오기 요청 생성 또는 업데이트(Git 프로젝트의 경우)
  • 코드 체크 인(Team Foundation 버전 제어 프로젝트의 경우)
  • 작업 항목 생성, 업데이트, 삭제, 복원 또는 주석 달기

작업을 트리거하는 이벤트를 제어하려면 구독에서 필터를 구성할 수 있습니다. 예를 들어 빌드 상태에 따라 빌드 완료 이벤트를 필터링할 수 있습니다.

요청 만들기

구독을 만들 때 HTTP POST 요청의 본문을 사용하여 프로젝트 ID, 이벤트, 소비자, 작업 및 관련 설정을 지정합니다.

다음 요청을 사용하여 빌드 완료 이벤트에 대한 구독을 만들 수 있습니다. 이 예제에서는 WebSite.CI 빌드가 실패할 경우, 구독에서 https://myservice/event로 POST 요청을 보냅니다.

요청

{
    "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"
    },
}

JSON 개체에서 프라이빗 데이터의 보안을 위해 보안 HTTPS URL을 사용하는 것이 좋습니다.

응답

구독을 만드는 요청은 다음 응답과 유사한 응답을 생성합니다.

{
    "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"
    }
}

구독 요청이 실패하면 추가 세부 정보가 포함된 메시지와 함께 400의 HTTP 응답 코드를 받게 됩니다.

이벤트가 발생하면 어떻게 되나요?

이벤트가 발생하면 프로젝트에서 사용하도록 설정된 모든 구독이 평가됩니다. 그런 다음 일치하는 모든 구독에 대해 소비자 액션이 수행됩니다.

리소스 버전(고급)

리소스 버전 관리는 API가 미리 보기 상태일 때 적용됩니다. 대부분의 시나리오에서 1.0 리소스 버전으로 지정하는 것이 가장 안전한 경로입니다.

특정 소비자에게 전송되는 이벤트 페이로드에는 주체 리소스의 JSON 표현이 포함됩니다. 예를 들어 웹후크, Azure Service Bus 및 Azure Storage로 전송되는 페이로드에는 빌드 또는 작업 항목에 대한 정보가 포함됩니다. 이 리소스의 표현에는 다양한 양식 또는 버전이 있을 수 있습니다.

구독의 필드를 통해 resourceVersion 소비자 서비스에 보낼 리소스의 버전을 지정할 수 있습니다.

리소스 버전은 API 버전동일합니다. 리소스 버전을 지정하지 않으면 최신 버전 latest released이 사용됩니다. 시간이 지남에 따라 일관된 이벤트 페이로드를 보장하려면 항상 리소스 버전을 지정합니다.

FAQ

Q: 수동으로 구독할 수 있는 서비스가 있나요?

A: 예. 프로젝트 관리 페이지에서 구독할 수 있는 서비스에 대한 자세한 내용은 서비스 후크와 통합을 참조하세요.

Q: 구독을 만드는 데 사용할 수 있는 C# 라이브러리가 있나요?

A: 아니요, 하지만 시작하는 데 도움이 되는 샘플은 다음과 같습니다. Azure DevOps에 대한 인증의 경우 다음 코드는 Azure Key Vault에 저장된 PAT(개인용 액세스 토큰)를 사용합니다. 프로덕션 환경에서는 보다 안전한 인증 방법을 사용합니다. 자세한 내용은 올바른 인증 메커니즘 선택을 참조하세요.

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