Share via


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

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

구독 REST API를 사용하여 Azure DevOps 프로젝트에서 특정 이벤트가 발생할 때 외부/소비자 서비스에서 작업을 수행하는 구독을 프로그래밍 방식으로 만들 수 있습니다. 예를 들어, 빌드가 실패할 때 서비스에 알리도록 구독을 만들 수 있습니다.

지원되는 이벤트:

  • 빌드가 완료됨
  • 코드 푸시됨(Git 프로젝트용)
  • 끌어오기 요청 만들기 또는 업데이트(Git 프로젝트의 경우)
  • 코드 체크인(TFVC 프로젝트)
  • 만들기, 업데이트, 삭제, 복원 또는 댓글이 달린 작업 항목

작업을 트리거하는 이벤트를 제어하기 위해 구독에 대한 필터를 구성할 수 있습니다. 예를 들어, 빌드 상태를 기반으로 빌드 완료 이벤트를 필터링할 수 있습니다. 지원되는 전체 이벤트 및 필터 옵션은 이벤트 참조를 참조하세요.

지원되는 소비자 서비스 및 작업의 전체 집합은 소비자 참조를 참조하세요.

필수 조건

구독을 만들려면 다음 데이터가 필요합니다.

  • 프로젝트 ID 프로젝트 REST API를 사용하여 프로젝트 ID를 가져옵니다.
  • 이벤트 ID 및 설정입니다. 이벤트 참조참조하세요.
  • 소비자 및 작업 ID 및 설정. 소비자 참조를 참조하세요.

요청 만들기

HTTP POST 요청의 본문을 생성하여 프로젝트 ID, 이벤트, 소비자 및 작업에 따라 구독을 만듭니다.

빌드가 실패할 때 WebSite.CI 빌드 이벤트를 POST https://myservice/event 로 만드는 구독을 만들기 위한 다음 예제 요청을 참조하세요.

요청

{
    "publisherId": "tfs",
    "eventType": "build.complete",
    "resourceVersion": "1.0",
    "consumerId": "webHooks",
    "consumerActionId": "httpRequest",
    "publisherInputs": {
        "buildStatus": "failed",
        "definitionName": "WebSite.CI",
        "projectId": "56479caf-1eeb-4bca-86ab-aaa6f29399d9",
    },
    "consumerInputs": {
        "url": " https://myservice/event"
    },
}

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

응답 은 구독을 만들기 위한 요청에 대한 다음 응답을 참조하세요.

{
    "id": "74aeeed0-bf5d-48dc-893f-f862b80987e9",
    "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/hooks/subscriptions/74aeeed0-bf5d-48dc-893f-f862b80987e9",
    "publisherId": "tfs",
    "eventType": "build.complete",
    "resourceVersion": "1.0",
    "consumerId": "webHooks",
    "consumerActionId": "httpRequest",
    "createdBy": {
        "id": "00ca946b-2fe9-4f2a-ae2f-40d5c48001bc"
    },
    "createdDate": "2014-03-28T16:10:06.523Z",
    "modifiedBy": {
        "id": "1c4978ae-7cc9-4efa-8649-5547304a8438"
    },
    "modifiedDate": "2014-04-25T18:15:26.053Z",
    "publisherInputs": {
        "buildStatus": "failed",
        "definitionName": "WebSite.CI",
        "hostId": "17f27955-99bb-4861-9550-f2c669d64fc9",
        "projectId": "56479caf-1eeb-4bca-86ab-aaa6f29399d9",
        "tfsSubscriptionId": "29cde8b4-f37e-4ef9-a6d4-d57d526d82cc"
    },
    "consumerInputs": {
        "url": "http://myservice/event"
    }
}

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

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

이벤트가 발생하면 프로젝트에서 활성화된 모든 구독이 평가되고 일치하는 모든 구독에 대해 소비자 작업이 수행됩니다.

리소스 버전(고급)

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

웹후크, Azure Service Bus 및 Azure Storage와 같은 특정 소비자에게 전송되는 이벤트 페이로드에는 주체 리소스(예: 빌드 또는 작업 항목)의 JSON 표현이 포함됩니다. 이 리소스의 표현은 다른 형식 또는 버전을 가질 수 있습니다.

구독의 필드를 통해 resourceVersion 소비자 서비스로 보내려는 리소스의 버전을 지정할 수 있습니다. 리소스 버전은 API 버전동일합니다. 리소스 버전을 지정하지 않는 것은 "최신 릴리스됨"을 의미합니다. 항상 리소스 버전을 지정해야 하므로 시간이 지남에 따라 일관된 이벤트 페이로드가 보장됩니다.

FAQ

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

A: 예. 프로젝트의 관리 페이지에서 구독할 수 있는 서비스에 대한 자세한 내용은 개요를 참조하세요.

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

A: 아니요, 하지만 시작하는 데 도움이 되는 샘플은 다음과 같습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Mvc;

namespace Microsoft.Samples.VisualStudioOnline
{
    public class ServiceHookEventController : Controller
    {

        // POST: /ServiceHookEvent/workitemcreated
        [HttpPost]
        public HttpResponseMessage WorkItemCreated(Content workItemEvent)
        {
            //Grabbing the title for the new workitem
            var value = RetrieveFieldValue("System.field", workItemEvent.Resource.Fields);

            //Acknowledge event receipt
            return new HttpResponseMessage(HttpStatusCode.OK);
        }

        /// <summary>
        /// Gets the value for a specified work item field.
        /// </summary>
        /// <param name="key">Key used to retrieve matching value</param>
        /// <param name="fields">List of fields for a work item</param>
        /// <returns></returns>
        public String RetrieveFieldValue(String key, IList<FieldInfo> fields)
        {
            if (String.IsNullOrEmpty(key))
                return String.Empty;

            var result = fields.Single(s => s.Field.RefName == key);

            return result.Value;
        }

	}

    public class Content
    {
        public String SubscriptionId { get; set; }

        public int NotificationId { get; set; }

        public String EventType { get; set; }

        public WorkItemResource Resource { get; set; }

    }

    public class WorkItemResource
    {
        public String UpdatesUrl { get; set; }

        public IList<FieldInfo> Fields { get; set;}

        public int Id { get; set; }

        public int Rev { get; set; }

        public String Url { get; set; }

        public String WebUrl { get; set; }
    }

    public class FieldInfo
    {
        public FieldDetailedInfo Field { get; set; }

        public String Value { get; set; }

    }

    public class FieldDetailedInfo
    {
        public int Id { get; set; }

        public String Name { get; set; }

        public String RefName { get; set; }
    }
}