통합 개발 지침

이 페이지는 GitLab 통합을 구현하기 위한 개발 지침을 제공합니다. 이는 주요 Rails 프로젝트의 일부입니다.

또한 통합에 대한 전략적 개요를 보려면 방향 페이지를 참조하세요.

이 가이드는 진행 중인 작업입니다. 궁금한 사항이 있거나 오래된 정보를 발견하면 언제든지 @gitlab-org/manage/import-and-integrate에 문의해 주세요.

새로운 통합 추가

통합 정의

  1. Integration을 확장한 새 모델을 app/models/integrations에 추가합니다.
    • 예: app/models/integrations/foo_bar.rbIntegrations::FooBar.
    • 일부 유형의 통합의 경우 기본 클래스를 확장할 수도 있습니다:
      • Integrations::BaseChatNotification
      • Integrations::BaseCi
      • Integrations::BaseIssueTracker
      • Integrations::BaseMonitoring
      • Integrations::BaseSlashCommands
      • Integrations::BaseThirdPartyWiki
    • 주로 외부 서비스에 HTTP 호출을 트리거하는 통합의 경우, Integrations::HasWebHook를 사용할 수도 있습니다. 이는 ServiceHook 모델을 통해 GitLab의 웹훅 기능을 재사용하고 요청 로그를 자동으로 기록하여 통합 설정에서 볼 수 있습니다.
  2. 통합의 언더스코어 네임('foo_bar')을 Integration::INTEGRATION_NAMES에 추가합니다.
  3. Project에서 통합을 연관시킵니다:

    has_one :foo_bar_integration, class_name: 'Integrations::FooBar'
    

필드 정의

통합은 Integration.field 클래스 메서드를 사용하여 구성을 저장하기 위한 임의의 필드를 정의할 수 있습니다. 값은 integrations.encrypted_properties 열의 암호화된 JSON 해시로 저장됩니다.

예를 들어 다음과 같습니다.

module Integrations
  class FooBar < Integration
    field :url
    field :tags
  end
end

Integration.field는 클래스에 액세서 메서드를 설치합니다. 여기서 #url, #url=, #url_changed?를 통해 url 필드를 관리합니다. 이러한 액세서는 다른 ActiveRecord 속성과 마찬가지로 모델에서 Integration#properties에 직접 액세스해야 합니다.

필드는 반드시 getter를 통해 액세스해야 하며 properties 해시와 직접 상호 작용해서는 안 됩니다. properties 해시에 직접 작성해서는 안 되며, 생성된 세터 메서드를 대신 사용해야 합니다. 이 해시에 직접 작성하는 것은 지속되지 않습니다.

이러한 필드가 전담 통합의 프런트엔드 양식에서 어떻게 노출되는지 확인하려면 프런트엔드 양식 사용자화를 참조하세요.

Integration.prop_accessor 또는 Integration.data_field를 사용하여 다른 접근 방식을 사용할 수도 있지만, 이는 통합의 이전 버전에서 볼 수 있습니다. 새로운 통합에는 이러한 접근 방식을 사용해선 안 됩니다.

유효성 정의

모든 필드에 대한 Rails 유효성을 정의해야 합니다.

유효성은 통합이 활성화된 경우에만 적용해야 합니다. 즉, #activated? 메서드를 테스트하여 유효성을 확인해야 합니다.

required: 속성을 갖는 모든 필드는 프런트엔드 전용이기 때문에 presence에 대한 해당 유효성을 가져야 합니다.

예를 들어:

module Integrations
  class FooBar < Integration
    with_options if: :activated? do
      validates :key, presence: true, format: { with: KEY_REGEX }
      validates :bar, inclusion: [true, false]
    end
    
    field :key, required: true
    field :bar, type: :checkbox
  end
end

트리거 이벤트 정의

통합은 GitLab의 이벤트에 응답하여 이벤트에 관한 세부 정보를 담은 페이로드 해시를 전달받는 #execute 메서드를 호출하여 트리거됩니다.

지원되는 이벤트는 웹훅 이벤트와 일부 중복되는 부분이 있으며, 동일한 페이로드를 받습니다. 모델에서 클래스 메서드 Integration.supported_events를 재정의하여 관심 있는 이벤트를 지정할 수 있습니다.

다음은 통합에서 지원되는 이벤트입니다:

이벤트 유형 기본값 트리거
경보 이벤트   alert 새로운 및 고유한 경보가 기록됩니다.
커밋 이벤트 commit 커밋이 생성되거나 업데이트됩니다.
배포 이벤트   deployment 배포가 시작되거나 완료됩니다.
이슈 이벤트 issue 이슈가 생성되거나 업데이트되거나 닫힙니다.
기밀 이슈 이벤트 confidential_issue 기밀 이슈가 생성되거나 업데이트되거나 닫힙니다.
작업 이벤트   job  
Merge Request 이벤트 merge_request Merge Request이 생성되거나 업데이트되거나 Merge됩니다.
코멘트 이벤트   comment 새로운 코멘트가 추가됩니다.
기밀 코멘트 이벤트   confidential_note 기밀 이슈의 새로운 코멘트가 추가됩니다.
파이프라인 이벤트   pipeline 파이프라인 상태가 변경됩니다.
푸시 이벤트 push 리포지터리에 푸시가 이루어집니다.
태그 푸시 이벤트 tag_push 새로운 태그가 리포지터리에 푸시됩니다.
취약점 이벤트   vulnerability 새로운 및 고유한 취약점이 기록됩니다. 윌티메이트 전용.
위키 페이지 이벤트 wiki_page 위키 페이지가 생성되거나 업데이트됩니다.

이벤트 예시

이 예시는 commitmerge_request 이벤트에 응답하는 통합을 정의합니다:

module Integrations
  class FooBar < Integration
    def self.supported_events
      %w[commit merge_request]
    end
  end
end

통합은 또한 이벤트에 응답하지 않고, 다른 방법으로 사용자 정의 기능을 구현할 수도 있습니다:

module Integrations
  class FooBar < Integration
    def self.supported_events
      []
    end
  end
end

보안 강화 기능

채널 값 가리기

Integrations::BaseChatNotification에서 상속받은 통합은 채널 입력 필드의 값을 숨길 수 있습니다. 통합은 이러한 값들을 보안 토큰과 같은 민감한 정보를 포함할 때마다 이들 값을 숨겨야 합니다.

기본적으로 #mask_configurable_channels?false을 반환합니다. 채널 값을 가리려면 통합에서 #mask_configurable_channels? 메서드를 재정의하여 true를 반환하도록 해야 합니다:

override :mask_configurable_channels?
def mask_configurable_channels?
  true
end

구성 테스트 정의

선택적으로, 통합의 설정에 대한 구성 테스트를 정의할 수 있습니다. 해당 테스트는 통합 양식의 테스트 버튼에서 실행되며, 결과가 사용자에게 반환됩니다.

좋은 구성 테스트는 다음을 포함합니다:

  • 서비스 내에서 데이터를 변경하지 않습니다. 예를 들어, CI 빌드를 트리거해서는 안 됩니다. 메시지를 보내는 것은 괜찮습니다.
  • 의미가 있고 가능한 한 철저합니다.

위의 가이드라인을 따르기 어려운 경우 구성 테스트를 추가하지 않는 것을 고려해보세요.

구성 테스트를 추가하려면 통합 모델에 #test 메서드를 정의합니다.

해당 메서드는 테스트 푸시 이벤트 payload인 data를 받습니다. 그것은 success (필수)와 result (선택)라는 키를 포함한 해시를 반환해야 합니다.

예를 들면:

module Integrations
  class FooBar < Integration
    def test(data)
      success = test_api_key(data)
      
      { success: success, result: 'API 키가 잘못되었습니다' }
    end
  end
end

프론트엔드 양식 사용자 정의

프론트엔드 양식은 모델에서 정의된 메타데이터를 기반으로 동적으로 생성됩니다.

기본적으로, 통합 양식은 다음을 제공합니다:

  • 통합을 활성화하거나 비활성화하기 위한 확인란
  • Integration#configurable_events에서 반환된 각 트리거 이벤트에 대한 확인란

양식 상단에 도움말 텍스트를 추가하려면 Integration#help를 재정의하거나 app/views/shared/integrations/$INTEGRATION_NAME/_help.html.haml에 템플릿을 제공할 수 있습니다.

양식에 사용자 정의 속성을 추가하려면 이러한 속성에 대한 메타데이터를 Integration#fields에서 정의할 수 있습니다.

해당 메서드는 필드마다 해시 배열을 반환해야 합니다. 키는 다음과 같을 수 있습니다:

유형 필수 기본값 설명
type: symbol true :text 폼 필드의 유형입니다. :text, :textarea, :password, :checkbox, 또는 :select일 수 있습니다.
name: string true   폼 필드의 속성 이름입니다.
required: boolean false false 폼 필드가 필수인지 선택 사항인지를 지정합니다. 참고로 존재 여부에 대한 백엔드 유효성을 확인합니다.
title: string false name:의 대문자화된 값 폼 필드의 라벨입니다.
placeholder: string false   폼 필드의 플레이스홀더입니다.
help: string false   폼 필드 아래에 표시되는 도움말 텍스트입니다.
api_only: boolean false false 해당 필드가 API를 통해서만 사용 가능하고 프론트엔드 양식에서는 제외되어야 하는지를 지정합니다.
if: boolean or lambda false true 필드를 사용할지 여부를 지정합니다. 값은 부울 또는 람다일 수 있습니다.

type: :checkbox에 대한 추가 키

유형 필수 기본값 설명
checkbox_label: string false title:의 값 확인란 옆에 표시되는 사용자 정의 라벨입니다.

type: :select에 대한 추가 키

유형 필수 기본값 설명
choices: array true   [label, value] 튜플의 중첩 배열입니다.

type: :password에 대한 추가 키

유형 필수 기본값 설명
non_empty_password_title: string false title:의 값 값이 이미 저장되어 있는 경우 표시되는 대체 라벨입니다.
non_empty_password_help: string false help:의 값 값이 이미 저장되어 있는 경우 표시되는 대체 도움말 텍스트입니다.

프론트엔드 양식 예시

다음 예시는 필수 url 필드와 선택적으로 usernamepassword 필드를 정의합니다:

module Integrations
  class FooBar < Integration
    field :url,
      type: :text,
      title: s_('FooBarIntegration|서버 URL'),
      placeholder: 'https://example.com/',
      required: true
    
    field :username,
      type: :text,
      title: s_('FooBarIntegration|사용자명')
    
    field :password,
      type: 'password',
      title: s_('FoobarIntegration|비밀번호'
      non_empty_password_title: s_('FooBarIntegration|새 비밀번호 입력하기')
  end
end

REST API에서 통합 노출

REST API에서 통합을 노출하려면:

  1. 통합 클래스(::Integrations::FooBar)를 API::Helpers::IntegrationsHelpers.integration_classes에 추가합니다.
  2. 노출해야 하는 모든 속성을 API::Helpers::IntegrationsHelpers.integrations에 추가합니다.
  3. doc/api/integrations.md에 참조 문서를 업데이트하고 통합에 대한 새 섹션을 추가하며, 모든 속성을 문서화합니다.

또한 REST API 스타일 가이드를 참조할 수 있습니다.

민감한 필드는 API를 통해 노출되지 않습니다. 민감한 필드는 이름에 다음 중 하나라도 포함하는 필드입니다:

  • key
  • passphrase
  • password
  • secret
  • token
  • webhook

통합 가능성

기본적으로, 통합은 프로젝트, 그룹 및 인스턴스 수준에서 사용할 수 있습니다. 대부분의 통합은 프로젝트 컨텍스트에서만 작동하지만, 그룹 및 인스턴스 수준에서도 구성할 수 있습니다.

일부 통합의 경우 프로젝트 수준에서만 사용할 수 있는 것이 합리적일 수 있습니다. 이를 위해 통합을 Integration::INTEGRATION_NAMES에서 제거하고 대신 Integration::PROJECT_SPECIFIC_INTEGRATION_NAMES에 추가해야 합니다.

새로운 통합을 개발할 때, 우리는 또한 Integration.available_integration_names피처 플래그 뒤에 사용 가능성을 제어하는 것을 권장합니다.

문서

Integration 폼에서 설명된 것처럼, 외부 문서에 대한 링크를 포함하여 통합 폼에서 도움말 텍스트를 제공할 수 있습니다. 도움말 텍스트에 대한 자세한 내용은 사용성 가이드라인을 참조하세요.

더 자세한 문서를 위해서는 doc/user/project/integrations에 해당 페이지를 제공하고 통합 개요에서 이에 대한 링크를 제공할 수 있습니다.

일반적인 문서 지침도 참조할 수 있습니다.

테스트

테스트는 구성 테스트 정의와 혼동해서는 안 됩니다.

일반적으로, spec/models/integrations의 통합 모델에 대한 테스트를 추가하고 spec/factories/integrations.rb에 예제 설정이 포함된 팩토리를 추가하는 것이 충분합니다.

각 통합은 일반화된 테스트의 일부로서도 테스트됩니다. 예를 들어, 모든 통합에 대해 설정 폼이 올바르게 렌더링되는지 확인하는 기능 스펙이 있습니다.

특히 프론트엔드에서 사용자 정의 동작을 구현한 경우, 추가적인 테스트가 필요합니다.

일반적인 테스트 지침도 참조할 수 있습니다.

국제화

모든 UI 문자열은 국제화 가이드라인을 따라 번역을 준비해야 합니다.

문자열은 통합 이름을 네임스페이스로 사용해야 하며, 예를 들어 s_('FooBarIntegration|My string')와 같습니다.

통합 폐기 및 제거

통합을 제거하려면 먼저 통합을 폐기해야 합니다. 자세한 내용은 기능 폐기 지침을 참조하세요.

통합 폐기

통합을 폐기하려면 제거할 예정인 마일스톤에서 늦어도 3번째 이전 마일스톤까지 명시적으로 폐기를 공지해야 합니다:

  • 폐기 항목 추가.
  • 통합 문서를 폐기로 표시(../../development/documentation/versions.md#deprecate-a-page-or-topic).
  • 선택 사항. 새로운 프로젝트 수준 레코드가 생성되는 것을 막기 위해 통합을 Project#disabled_integrations에 추가합니다 (예시 Merge Request).

통합 제거

통합을 안전하게 제거하려면 두 개의 마일스톤에서 제거 단계를 진행해야 합니다.

제거할 예정인 주요 마일스톤(M.0)에서, 통합을 비활성화하고 데이터베이스에서 레코드를 삭제합니다:

  • Integration::INTEGRATION_NAMES에서 통합을 제거합니다.
  • 통합 모델의 #execute#test 메서드(정의된 경우)를 삭제하되 모델은 유지합니다.
  • PostgreSQL에서 통합 레코드를 삭제하기 위한 후행 마이그레이션을 추가합니다 (예시 Merge Request).
  • 통합 문서를 삭제로 표시합니다(../../development/documentation/versions.md#remove-a-page).
  • 통합 API 문서를 업데이트합니다(../../api/integrations.md).

다음 소수릴리즈(M.1)에서:

  • 통합 모델 및 잔여 코드를 제거합니다.
  • 통합 레이블(~Integration::<name>)을 가진 모든 이슈, Merge Request 및 에픽을 닫습니다.
  • gitlab-org에서 통합 레이블(~Integration::<name>)을 삭제합니다.

계속 진행 중인 마이그레이션 및 리팩터링

개발자들은 통합 팀이 통합 속성을 정의하는 방법을 통합하는 과정에 있음을 인식해야 합니다.

통합 예시

새로운 통합 추가에 대한 예시를 보려면 다음 이슈를 참조할 수 있습니다:

  • Datadog: 프로메테우스 통합과 유사한 메트릭 수집기.
  • EWM/RTC: 외부 이슈 트래커.
  • Webex Teams: 채팅 알림.
  • ZenTao: Jira 통합과 유사한 사용자 정의 이슈 뷰를 가진 외부 이슈 트래커.