GitLab 프로젝트를 위한 파이프라인

gitlab-org/gitlabdev 인스턴스의 Pipelines는 일반적으로 설정된 .gitlab-ci.yml으로 구성되어 있습니다. 이 파일 자체는 더 쉬운 유지 관리를 위해 .gitlab/ci/에 포함된 파일을 포함합니다.

우리는 가능한 한 많이 GitLab의 CI/CD 기능과 모범 사례dogfood하기 위해 노력하고 있습니다.

gitlab-org/gitlab 파이프라인에서 CI/CD 컴포넌트dev.gitlab.com 인스턴스에 미러링되지 않은 경우에는 사용하지 마십시오. CI/CD 컴포넌트는 서로 다른 인스턴스간에 작동하지 않으며, 그러한 인스턴스에 존재하지 않는 경우 dev.gitlab.com 미러에서 파이프라인 실패를 유발할 수 있습니다.

Merge Request 승인 전 예측 테스트 작업

파이프라인 비용을 줄이고 작업 기간을 단축시키기 위해 Merge Request이 승인되기 전에 파이프라인에서는 변경 사항으로 인해 실패할 가능성이 높은 일련의 RSpec 및 Jest 테스트를 실행합니다.

Merge Request이 승인된 후에는 파이프라인에 완전한 RSpec 및 Jest 테스트가 포함될 것입니다. 이로써 Merge Request이 Merge되기 전에 모든 테스트가 실행되었음이 보장됩니다.

GitLab 프로젝트 테스트 의존성 개요

예측 테스트 작업이 어떻게 실행되는지 이해하려면 GitLab 코드(프론트엔드 및 백엔드)와 해당 테스트 (Jest 및 RSpec) 간의 의존성을 이해해야 합니다. 이 의존성은 다음 다이어그램에서 시각화할 수 있습니다:

flowchart LR subgraph frontend fe["프론트엔드 코드"]--테스트 됨-->jest end subgraph backend be["백엔드 코드"]--테스트 됨-->rspec end be--생성됨-->fixtures["프론트엔드 fixtures"] fixtures--사용됨-->jest

요약하면:

  • RSpec 테스트는 백엔드 코드에 의존합니다.
  • Jest 테스트는 프론트엔드 및 백엔드 코드, 후자는 프론트엔드 fixtures를 통해 의존합니다.

예측 테스트 대시보드

detect-tests CI 작업

gitlab-org/gitlab의 대부분의 CI/CD 파이프라인은 주어진 MR에서 변경된 파일을 기반으로 실행할 백엔드/프론트엔드 테스트를 감지하기 위해 detect-tests CI 작업을 prepare 단계에서 실행합니다.

detect-tests 작업은 많은 파일을 생성하여 해당 파일을 이후 파이프라인의 후속 작업에서 읽고 해당 테스트만 실행합니다.

RSpec 예측 작업

Merge Request에서 예측적 RSpec 테스트 파일 결정

Merge Request에서 실패할 가능성이 있는 RSpec 테스트를 식별하기 위해 동적 매핑정적 매핑을 사용합니다.

동적 매핑

먼저, test_file_finder gem을 사용하여 동적 매핑 전략을 하는데에 사용합니다. 이전에는 Crystalball gem)에서 동적 매핑 전략을 사용하였습니다 (사용 위치Crystalball에서 사용하는 매핑 전략).

test_file_finder 외에도 추가적인 매핑을 추가하여 더 많은 테스트를 실행합니다:

  • FindChanges (!74003)
    • 백엔드 변경 사항에 따라 실행할 Jest 테스트를 자동으로 감지합니다(프론트엔드 fixtures를 통해)
  • PartialToViewsMappings (#395016)
    • MR에서 변경된 경우 Rails partials이 포함된 뷰 스펙을 실행합니다
  • JsToSystemSpecsMappings (#386754)
    • MR에서 JavaScript 파일이 변경된 경우 특정 시스템 스펙을 실행합니다
  • GraphqlBaseTypeMappings (#386756)
    • GraphQL 타입 클래스가 변경된 경우, 해당 타입을 포함하는 다른 GraphQL 타입을 식별하고 해당 스펙을 실행합니다.
  • ViewToSystemSpecsMappings (#395017)
    • 뷰가 변경된 경우 해당 코드 영역을 테스트할 feature 스펙을 찾습니다.
  • ViewToJsMappings (#386719)
    • JS 파일이 변경된 경우 해당 JS 컴포넌트를 포함하는 시스템 스펙을 찾습니다.
  • FindFilesUsingFeatureFlags (#407366)
    • feature flag가 변경된 경우 해당 flag를 포함하는 Ruby 파일을 확인하고 해당 변경된 파일을 기반으로 실행할 프론트엔드/백엔드 테스트를 감지합니다.
정적 매핑

우리는 test_file_finder gem을 사용하며, 동적 매핑으로 매핑할 수 없는 특수 케이스에 대한 정적 매핑은 tests.yml 파일에서 유지됩니다. (사용된 위치 보기).

테스트 매핑에는 각 소스 파일을 해당 소스 파일에 종속된 테스트 파일 디렉터리에 매핑하는 맵이 포함되어 있습니다.

특이한 케이스

또한, 다음과 같은 몇 가지 상황에서 항상 전체 RSpec 테스트를 실행합니다:

  • 머지 요청에 pipeline:run-all-rspec 라벨이 설정된 경우. 이 라벨은 as-if-foss 작업에서 실행된 테스트를 포함하여 모든 RSpec 테스트를 트리거합니다.
  • 머지 요청에 pipeline:mr-approved 라벨이 설정되어 있고, 코드 변경이 backend-patterns 규칙을 만족시키는 경우. 이 라벨은 리뷰어 중 누구든지 머지 요청을 승인하면 triage 자동화에 의해 할당됩니다. 이 라벨을 매뉴얼으로 적용하는 것은 권장되지 않습니다.
  • 자동화에 의해 머지 요청이 생성된 경우(예: Gitaly 업데이트 또는 안정적인 브랜치를 대상으로 하는 MR)
  • 머지 요청이 보안 미러에서 생성된 경우
  • CI 구성 파일이 변경된 경우(예: .gitlab-ci.yml 또는 .gitlab/ci/**/*)

백엔드 예측 테스트에서 문제가 발생했습니까?

그렇다면, 예측 테스트 문제에 대한 조치 방법은 예측 테스트에 대한 엔지니어링 프로덕션성 RUNBOOK에서 확인하세요. 게다가, 테스트 선택 갭을 식별했다면, 필요한 조치를 취할 수 있도록 @gl-quality/eng-prod에 알려주세요.

Jest 예측 작업

머지 요청에서 예측적인 Jest 테스트 파일 식별

머지 요청에서 실패 가능성이 있는 jest 테스트를 식별하려면, 모든 변경된 파일 디렉터리을 jest를 사용하여 --findRelatedTests 옵션을 사용하여 jest에 전달합니다. 이 모드에서 jest는 변경된 파일에 의존되는 모든 종속 항목을 해결하며, 이는 이러한 파일이 종속 체인에 있는 테스트 파일을 포함합니다.

특이한 케이스

또한, 다음과 같은 상황에서 항상 전체 Jest 테스트를 실행합니다:

  • 머지 요청에 pipeline:run-all-jest 라벨이 설정된 경우
  • 머지 요청이 자동화에 의해 생성된 경우(예: Gitaly 업데이트 또는 안정적인 브랜치를 대상으로 하는 MR)
  • 머지 요청이 보안 미러에서 생성된 경우
  • 관련된 CI 구성 파일이 변경된 경우(.gitlab/ci/rules.gitlab-ci.yml, .gitlab/ci/frontend.gitlab-ci.yml)
  • Frontend 의존성 파일이 변경된 경우(예: package.json, yarn.lock, config/webpack.config.js, config/helpers/**/*.js)
  • 어떠한 판매용 JavaScript 파일이 변경된 경우(예: vendor/assets/javascripts/**/*)

전체 Jest 테스트를 위한 rules 정의는 .frontend:rules:jestrules.gitlab-ci.yml에 정의되어 있습니다.

프론트엔드 예측 테스트에서 문제가 발생했습니까?

그렇다면, 예측 테스트 문제에 대한 조치 방법은 예측 테스트에 대한 엔지니어링 프로덕션성 RUNBOOK에서 확인하세요.

Fork 파이프라인

우리는 fork 파이프라인에서는 예측 RSpec 및 Jest 작업만 실행하며, MR에 pipeline:run-all-rspec 라벨이 설정되지 않는 한입니다. 목표는 fork 파이프라인에서 사용하는 연산 할당량을 줄이는 것입니다.

실험 이슈를 참조하세요.

머지 요청 파이프라인에서 빠르게 실패하는 작업

기존 테스트를 깨뜨리는 머지 요청이 생길 때 빠른 피드백을 제공하기 위해 빠르게 실패하는 메커니즘을 구현했습니다.

rspec fail-fast 작업은 머지 요청 파이프라인에서 모든 다른 rspec 작업과 병렬로 추가됩니다. 이 작업은 머지 요청에서의 변경 사항과 직접 관련된 테스트를 실행합니다.

이러한 테스트 중 어느 하나라도 실패하면 rspec fail-fast 작업이 실패하여 fail-pipeline-early 작업을 트리거합니다. fail-pipeline-early 작업:

  • 현재 실행 중인 파이프라인 및 모든 진행 중인 작업을 취소합니다.
  • 파이프라인을 ‘실패’ 상태로 설정합니다.

예시:

graph LR subgraph "준비 단계"; A["detect-tests"] end subgraph "테스트 단계"; B["jest"]; C["rspec migration"]; D["rspec unit"]; E["rspec integration"]; F["rspec system"]; G["rspec fail-fast"]; end subgraph "테스트 후 단계"; Z["fail-pipeline-early"]; end A --"artifact: list of test files"--> G G --"on failure"--> Z

rspec fail-fast 작업은 머지 요청과 관련된 테스트 파일이 10개 이상인 경우에는 동작하지 않습니다. 이는 rspec fail-fast의 기간이 평균 rspec 작업의 기간을 초과하여 목적을 무효화하는 것을 방지합니다.

이 숫자는 RSPEC_FAIL_FAST_TEST_FILE_COUNT_THRESHOLD라는 CI/CD 변수를 설정함으로써 재정의할 수 있습니다.

이전에 실패한 테스트를 머지 요청 파이프라인에서 다시 실행

머지 요청에서 실패한 테스트를 해결한 후 피드백 시간을 줄이기 위해 rspec rspec-pg14-rerun-previous-failed-testsrspec rspec-ee-pg14-rerun-previous-failed-tests 작업은 이전 MR 파이프라인에서 실패한 테스트를 실행합니다.

이것은 https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69053에서 2021년 8월 25일에 도입되었습니다.

작동 방식

  1. detect-previous-failed-tests 작업(준비 단계)은 이전 MR 파이프라인에서 실패한 RSpec 작업과 관련된 테스트 파일을 감지합니다.
  2. rspec rspec-pg14-rerun-previous-failed-testsrspec rspec-ee-pg14-rerun-previous-failed-tests 작업은 detect-previous-failed-tests 작업에 의해 수집된 테스트 파일을 실행합니다.
graph LR subgraph "준비 단계"; A["detect-previous-failed-tests"] end subgraph "테스트 단계"; B["rspec rspec-pg14-rerun-previous-failed-tests"]; C["rspec rspec-ee-pg14-rerun-previous-failed-tests"]; end A --"artifact: list of test files"--> B & C

머지 트레인

왜 “안정한” 마스터 브랜치가 필요한가요?

마스터 브랜치가 (즉, 마스터 브랜치의 CI/CD 파이프라인이 자주 실패하는) 불안정한 경우, 문제가 있는 머지 요청 파이프라인 이후에 추가된 모든 머지 요청 파이프라인은 취소되고 트레인에 다시 추가되어야 하므로, 머지 트레인이 길 경우 많은 지연이 발생할 수 있습니다.

마스터 브랜치가 Merge 기차를 활성화하기 위해 얼마나 안정적이어야 합니까?

특정 숫자는 없지만, 불안정한 테스트 실패 및 인프라 장애에 대한 더 나은 숫자가 필요합니다 (자세한 내용은 Master Broken Incidents RCA Dashboard를 참조하십시오).

점진적으로 CI/CD 구성으로 Merge 기차로 이동할 수 있습니까?

기여자로부터 제안이 있었지만, 접근 방식에는 몇 가지 단점이 있습니다: 원래 제안 및 토론을 참조하십시오.

일부 Merge Request에 대한 빠른 피드백

망가진 마스터 수정

망가진 master수정해야 할 때, Merge Request에서 실행되는 파이프라인을 빠르게하기 위해 pipeline:expedite 레이블을 추가할 수 있습니다.

Merge Request에는 master:broken 또는 master:foss-broken 레이블이 설정되어야 합니다.

Revert MRs

Revert MR을 더 빠르게 만들려면 Merge Request을 생성하기 전에 revert MR 템플릿을 사용하십시오. 이렇게 하면 pipeline:expedite 레이블 및 기타 레이블이 적용되어 Merge Request에서 실행되는 파이프라인을 빠르게 할 수 있습니다.

pipeline:expedite 레이블

이 레이블이 지정되면 다음 단계의 CI/CD 파이프라인이 생략됩니다:

Merge Request에 레이블을 적용하고 MR에 대한 새로운 파이프라인을 실행하십시오.

테스트 작업

테스트 레벨에 대한 전용 작업이 있고 각 작업은 Merge Request에 대한 변경 사항에 따라 실행됩니다. 변경에 상관없이 모든 RSpec 작업을 강제로 실행하려면 Merge Request에 pipeline:run-all-rspec 레이블을 추가할 수 있습니다.

caution
문서에만 관련된 MR에 대해 모든 작업을 강제로 실행하면 선행 작업이 없어서 오류가 발생할 수 있습니다.

최종 사용자 테스트 작업

e2e:package-and-test 자식 파이프라인은 변경 사항에 따라 자동으로 최종 사용자 테스트 작업을 실행하며 다른 경우에는 매뉴얼으로 실행됩니다. 특정 규칙 디렉터리에 대한 자세한 내용은 rules.gitlab-ci.yml.qa:rules:package-and-test을 참조하십시오.

변경에 상관없이 e2e:package-and-test을 강제로 실행하려면 Merge Request에 pipeline:run-all-e2e 레이블을 추가할 수 있습니다.

e2e:test-on-gdk 자식 파이프라인은 신뢰할 수 있는 E2E 사양을 자동으로 실행하며 코드 패턴 변경에 대해 실행됩니다. 특정 규칙 세트에 대한 자세한 내용은 .qa:rules:e2e-blocking rules.gitlab-ci.yml을 참조하십시오.

자세한 내용은 최종 사용자 테스트 전용 페이지를 참조하십시오.

리뷰 앱 작업

start-review-app-pipeline 자식 파이프라인은 리뷰 앱을 배포하고 변경에 따라 자동으로 최종 사용자 테스트를 실행하며 다른 경우에는 매뉴얼으로 실행됩니다. 특정 규칙 디렉터리에 대한 자세한 내용은 .review:rules:start-review-app-pipeline rules.gitlab-ci.yml을 참조하십시오.

변경에 상관없이 리뷰 앱을 배포하려면 Merge Request에 pipeline:run-review-app 레이블을 추가할 수 있습니다.

자세한 내용은 리뷰 앱 전용 페이지를 참조하십시오.

As-if-FOSS 작업 및 교차 프로젝트 하류 파이프라인

FOSS 프로젝트에 관련 변경 사항이 올바르게 작동하는지 확인하기 위해 다음과 같은 조건에서 실행합니다.

  • Merge Request에 pipeline:run-as-if-foss 레이블을 설정했을 때
  • Merge Request이 gitlab-org/security/gitlab 프로젝트에서 생성되었을 때
  • CI 구성 파일이 변경되었을 때(예: .gitlab-ci.yml 또는 .gitlab/ci/**/*)

* as-if-foss 작업은 일반 EE-context 작업에 추가로 실행됩니다. FOSS_ONLY='1' 변수가 설정되어 있으며 테스트가 시작되기 전에 ee/ 폴더가 제거됩니다.

교차 프로젝트 하류 FOSS 파이프라인은 변경 사항을 FOSS 프로젝트의 기본 브랜치에 Merge하는 시뮬레이션을 실행하며 일련의 파일이 제거됩니다. 디렉터리은 .gitlab/ci/as-if-foss.gitlab-ci.ymlmerge-train/bin/merge-train에서 찾을 수 있습니다.

의도는 gitlab-org/gitlabgitlab-org/gitlab-foss로 동기화된 후 변경 사항이 실패를 일으키지 않도록 하는 것입니다.

프로젝트 변수에 설정된 토큰

  • AS_IF_FOSS_TOKEN: 이것은 GitLab FOSS 프로젝트 토큰으로 developer 역할과 write_repository 권한을 가지고 있으며 생성된 as-if-foss/* 브랜치를 푸시합니다.
    • 보안 프로젝트에 동일한 이름이 있으면 보안 변경 사항이 공개 프로젝트에 전달되지 않도록 보안 FOSS 프로젝트의 다른 토큰을 사용해야 합니다.

As-if-JH 교차 프로젝트 하류 파이프라인

이게 무엇입니까

이 파이프라인은 지후 유효성 검사 파이프라인이라고도 하며 현재 실패해도 허용됩니다. 그럴 경우 유효성 검사 파이프라인이 실패했을 때 해야 할 일을 따르십시오.

실행 방법

start-as-if-jh 작업은 GitLab JH에 대한 as if JiHu 컨텍스트에서 실행되는 신규 브랜치를 생성하며 지정된 규칙에 따라 작업이 생성됩니다. 이러한 작업은 다음 경우에만 만들어집니다.

  • 피처 플래그에 변경 사항이 있는 경우
  • Merge Request에 pipeline:run-as-if-jh 레이블이 설정된 경우

이 파이프라인은 GitLab JH mirrorGitLab JH validation 프로젝트에서 생성된 브랜치에 대해 실행됩니다. 생성된 브랜치는 Merge Request 브랜치를 기반으로하며 상당한 규모의 변경을 추가해 전체 파이프라인을 JiHu로 변환합니다.

의도는 GitLabGitLab JH로 동기화된 후 변경 사항이 실패를 일으키지 않도록 하는 것입니다.

pipeline:run-as-if-jh 라벨 적용 여부

루비 파일의 이름이 변경되고 해당하는 prepend_mod 라인이 있는 경우에는 GitLab JH가 이에 의존하고 해당 모듈 또는 클래스 이름을 변경해야 하는 경우일 가능성이 있습니다.

해당 JH 브랜치

GitLab JH에서 해당 JH 브랜치를 생성하려면 브랜치 이름 뒤에 -jh를 추가하면 됩니다. 해당 JH 브랜치가 발견되면, as-if-jh 파이프라인은 기본 브랜치인 main-jh가 아닌 해당 브랜치에서 파일을 가져옵니다.

note
지금은 CI가 GitLab JH 미러에서 브랜치를 가져오려고 시도하기 때문에 새로운 JH 브랜치가 미러로 전파되는 데 시간이 걸릴 수 있습니다.
note
GitLab JH validationGitLab JH 미러의 미러이지만, 기본 main-jh 외에 해당 JH 브랜치를 가져오지 않습니다. 이러한 이유로 해당 JH 브랜치를 가져오려면 검증 프로젝트가 아닌 메인 미러에서 가져와야 합니다.

as-if-JH 파이프라인 구성 방법

전체 과정은 다음과 같습니다:

note
의존성 변경이 있는 경우에만 sync-as-if-jh-branch를 실행합니다.
flowchart TD subgraph "JiHuLab.com" JH["gitlab-cn/gitlab"] end subgraph "GitLab.com" Mirror["gitlab-org/gitlab-jh-mirrors/gitlab"] subgraph MR["gitlab-org/gitlab merge request"] Add["add-jh-files job"] Prepare["prepare-as-if-jh-branch job"] Add --"download artifacts"--> Prepare end subgraph "gitlab-org-sandbox/gitlab-jh-validation" Sync["(*optional) sync-as-if-jh-branch job on branch as-if-jh-code-sync"] Start["start-as-if-jh job on as-if-jh/* branch"] AsIfJH["as-if-jh pipeline"] end Mirror --"pull mirror with master and main-jh"--> gitlab-org-sandbox/gitlab-jh-validation Mirror --"download JiHu files with ADD_JH_FILES_TOKEN"--> Add Prepare --"push as-if-jh branches with AS_IF_JH_TOKEN"--> Sync Sync --"push as-if-jh branches with AS_IF_JH_TOKEN"--> Start Start --> AsIfJH end JH --"pull mirror with corresponding JH branches"--> Mirror
프로젝트 변수에 설정된 토큰
  • ADD_JH_FILES_TOKEN: read_api 권한이 있는 GitLab JH 미러 프로젝트 토큰으로, JiHu 파일을 다운로드할 수 있습니다.
  • AS_IF_JH_TOKEN: developer 역할 및 write_repository 권한이 있는 GitLab JH validation 프로젝트 토큰으로, 생성된 as-if-jh/* 브랜치를 푸시할 수 있습니다.
as-if-JH 브랜치 생성 방법

먼저 add-jh-files 작업은 해당 JH 브랜치에서 필요한 JiHu 파일을 다운로드하여 artifact에 저장합니다. 다음으로 prepare-as-if-jh-branch 작업은 Merge Request 브랜치에서 새로운 브랜치를 만들고 변경 사항을 커밋한 후 해당 브랜치를 검증 프로젝트에 푸시합니다.

선택적으로, Merge Request에 의존성 변경이 있는 경우에는 sync-as-if-jh-branch 작업을 실행하여 as-if-jh-code-sync 브랜치에서 다운스트림 파이프라인을 트리거합니다. 이 작업은 JiHu code-sync와 동일한 프로세스를 수행하여 의존성 변경이 as-if-jh 브랜치로 가져올 수 있도록합니다.

의존성 변경이 없는 경우에는 이 프로세스를 실행하지 않습니다.

as-if-JH 파이프라인을 트리거하고 실행하는 방법

as-if-jh/* 브랜치를 준비하고 선택적으로 동기화한 후, start-as-if-jh 작업은 크로스 프로젝트 다운스트림 파이프라인을 실행하기 위해 검증 프로젝트에서 파이프라인을 트리거합니다.

GitLab JH mirror 프로젝트 설정 방법

GitLab JH mirror 프로젝트는 비공개이며 CI가 비활성화되어 있습니다.

JH 릴리즈는 GitLab JH에서 가져오는 풀 미러로, 모든 브랜치를 미러링하며, 발산 참조를 재정의하고 미러가 업데이트될 때 파이프라인을 트리거하지 않습니다.

@gitlab-jh-validation-bot은 프로젝트의 유지보수자인 풀 유저로서, 미러가 업데이트될 때의 자격증명은 엔지니어링 보안 정보 리포지터리(1password)에서 찾을 수 있습니다.

미러링에 암호를 사용하지 않습니다. GitLab JH는 공개 프로젝트이기 때문입니다.

GitLab JH validation 프로젝트 설정 방법

GitLab JH validation 프로젝트는 공개이며 CI가 활성화되어 있으며, 임시 프로젝트 변수가 설정되어 있습니다.

풀 미러로 GitLab JH mirror에서 가져오는데, 특정 브랜치 (master|main-jh)를 미러링하며, 발산 참조를 재정의하고 미러가 업데이트될 때 파이프라인을 트리거하지 않습니다.

@gitlab-jh-validation-bot은 프로젝트의 유지보수자이며, 또한 GitLab JH mirror의 유지보수자입니다. 자격증명은 1password 엔지니어링 보안 정보 리포지터리에서 찾을 수 있습니다.

GitLab JH mirror에서 변경 사항을 가져오기 위해 @gitlab-jh-validation-bot의 개인 액세스 토큰을 사용하며, 이 토큰은 write_repository 권한을 가지고 있습니다. 사용자 이름은 gitlab-jh-validation-bot으로 설정되어 있습니다.

또한 캐시를 업데이트하는 매일 실행되는 유지보수 파이프라인을 위한 파이프라인 스케줄이 설정되어 있습니다. 변수 SCHEDULE_TYPEmaintenance로 설정되어 매일 실행됩니다.

기본 CI/CD 구성 파일은 jh/.gitlab-ci.yml에 설정되어 있어서 GitLab JH처럼 정확하게 실행됩니다.

또한 특별한 브랜치 as-if-jh-code-sync가 설정되어 있고, 보호되어 있습니다. 유지보수자는 푸시할 수 있고, 개발자는 해당 브랜치를 Merge할 수 있습니다. 이 브랜치를 개발자가 파이프라인을 트리거할 수 있도록 허용해야 하기 때문에 이러한 설정이 필요합니다. 이는 개발자 수준 사용자가 보호된 브랜치에서 더 이상 파이프라인을 실행할 수 없음 문제를 해결하기 전에 우리가 할 수 있는 타협입니다.

이 브랜치는 Merge Request가 의존성 변경을 갖고 있는 경우에만 sync-as-if-jh-branch를 실행하기 위해 사용됩니다. 작동 방식은 as-if-JH 브랜치를 생성하는 방법에서 확인할 수 있습니다.

임시 GitLab JH 유효성 검사 프로젝트 변수
거울 프로젝트와 유효성 검사 프로젝트를 별도로 유지하는 이유는 무엇인가요?

우리는 여러 이유로 별도의 프로젝트를 갖고 있습니다.

  • 보안: 이전에는 거울 프로젝트만 있었습니다. 그러나 보안 이슈를 완전히 완화하기 위해, 거울 프로젝트를 비공개로 만들어야 했습니다.
  • 격리: 우리는 JH 코드를 완전히 격리된 독립된 프로젝트에서 실행하고 싶습니다. 우리는 거울 프로젝트가 속한 gitlab-org 그룹에서 실행하고 싶지 않습니다. 유효성 검사 프로젝트는 완전히 격리되어 있습니다.
  • 비용: 우리는 각 Merge Request에서 JiHuLab.com에 연결하고 싶지 않습니다. JiHuLab.com에서 코드를 GitLab.com의 어느 곳으로 복제하고, Merge Request에서 코드를 가져올 수 있도록 하는 것이 더 비용 효율적입니다. 이는 유효성 검사 프로젝트가 미러에서 코드를 가져오도록 하고, JiHuLab.com에서 가져오지 않도록 합니다. 거울 프로젝트는 정기적으로 JiHuLab.com에서 가져오게 됩니다.
  • 브랜치 분리/보안/효율성: 모든 브랜치를 미러링하여 해당하는 JH 브랜치를 JiHuLab.com에서 가져올 수 있도록 하길 원합니다. 그러나 유효성 검사 프로젝트의 as-if-jh-code-sync 브랜치를 덮어쓰고 싶지 않습니다. 왜냐하면 이것을 사용하여 유효성 검사 파이프라인을 제어하며 AS_IF_JH_TOKEN에 액세스할 수 있기 때문입니다. 그러나 하나를 제외한 모든 브랜치를 미러링하고 싶지 않습니다. 자세한 내용은 이 이슈를 참조하세요.

    이러한 이슈로 인해 유효성 검사 프로젝트는 mastermain-jh만 미러링하도록 설정되어 있습니다. 기술적으로 이러한 브랜치들은 심지어 필요하지 않지만, Merge Request에서 변경 사항을 푸시할 때 기본 브랜치의 변경 사항만 푸시하면 더 효율적일 수 있기 때문에 이를 최신 상태로 유지하길 원합니다.

  • 관심 분리:
    • 유효성 검사 프로젝트에는 다음과 같은 브랜치만 있습니다:
      • 변경 사항을 최신 상태로 유지하기 위한 mastermain-jh 브랜치.
      • 의존성 동기화를 위한 as-if-jh-code-sync 브랜치. 이것은 절대 미러링해서는 안 됩니다.
      • Merge Request의 as-if-jh/* 브랜치. 이것은 절대 미러링해서는 안 됩니다.
    • 거울 프로젝트의 모든 브랜치는 모두 JiHuLab.com에서 가져옵니다. 우리는 절대로 미러 프로젝트에 아무것도 푸시하지 않을 뿐더러 파이프라인도 실행되지 않습니다. 거울 프로젝트에서 CI/CD가 비활성화되어 있습니다.

두 프로젝트를 Merge하여 설정 및 프로세스를 간소화하는 것을 고려할 수 있으나, 모든 이유가 더 이상 걱정되지 않도록 해야 합니다.

rspec:undercoverage 작업

rspec:undercoverage 작업은 undercover를 실행하여 Merge Request에서 도입된 변경 사항에 대한 커버리지가 제로인 경우를 감지하고 실패합니다.

rspec:undercoverage 작업은 rspec:coverage 작업에서 커버리지 데이터를 가져옵니다.

rspec:undercoverage 작업이 CE 메서드가 EE에서 오버라이드되어 커버리지 부재를 감지하면 pipeline:run-as-if-foss 레이블을 Merge Request에 추가하고 새 파이프라인을 시작하세요.

긴급한 상황이나 이 작업으로 인한 잘못된 경고가 있는 경우, pipeline:skip-undercoverage 레이블을 Merge Request에 추가하여 이 작업을 실패하게 허용하세요.

rspec:undercoverage 실패의 문제 해결

rspec:undercoverage 작업에는 알려진 버그가 있어 잘못된 실패를 발생시킬 수 있습니다. pipeline:skip-undercoverage를 적용해도 안전한지 로컬로 커버리지를 테스트하여 확인할 수 있습니다. 예를 들어, 실패하는 테스트의 이름으로 <spec>을 사용하는 경우:

  1. SIMPLECOV=1 bundle exec rspec <spec>을 실행합니다.
  2. scripts/undercoverage를 실행합니다.

만약 이러한 명령이 undercover: ✅ 최신 변경 사항에서 커버리지가 누락되지 않음을 반환한다면, pipeline:skip-undercoverage를 적용하여 파이프라인 실패를 우회할 수 있습니다.

pajamas_adoption 작업

  • GitLab 16.8에서 소개되었습니다.

pajamas_adoption 작업은 Merge Request에서 Pajamas Design System의 채택에 대한 회귀를 방지하기 위해 Pajamas Adoption Scanner를 실행합니다.

이 작업은 Merge Request에서 회귀를 감지하면 실패합니다. 회귀를 Merge Request에서 수정할 수 없는 경우, pipeline:skip-pajamas-adoption 레이블을 Merge Request에 추가한 후 작업을 다시 시도하세요.

테스트 스위트 병렬화

현재 우리의 RSpec 테스트 병렬화 설정은 다음과 같습니다:

  1. 준비 단계의 retrieve-tests-metadata 작업은 knapsack/report-master.json 파일이 있는지 확인합니다:
    • knapsack/report-master.json 파일은 최신 main 파이프라인에서 update-tests-metadata를 실행하여 가져옵니다 (지금은 2시간마다 실행되는 maintenance 예정된 마스터 파이프라인입니다). 이 파일이 없다면 빈 파일로 초기화합니다.
  2. [rspec|rspec-ee] [migration|unit|integration|system|geo] n m 작업은 knapsack rspec을 실행하고 균등하게 분산된 테스트를 가져야 합니다:
    • 작업들은 “이전 단계의 아티팩트가 기본적으로 전달된다”는 이유로 knapsack/report-master.json에 접근할 수 있습니다.
    • 작업들은 자신의 리포트 경로를 "knapsack/${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json"로 설정합니다.
    • knapsack이 제대로 작동한다면 실행된 테스트 파일은 Report specs 아래에 나와야 합니다. Leftover specs 아래에 나와서는 안 됩니다.
  3. update-tests-metadata 작업(오직 기본 프로젝트의 예정된 파이프라인에서만 실행되며 knapsack/report-master.json을 업데이트합니다):
    1. 기본적으로 knapsack/rspec*.json 파일을 모두 Merge하여 단일 knapsack/report-master.json 파일을 만들어 아티팩트로 저장합니다.
    2. (실험적인) AVERAGE_KNAPSACK_REPORT 환경 변수가 true로 설정되어 있는 경우, 보고서를 Merge하는 대신 knapsack/report-master.jsonknapsack/rspec*.json 간의 테스트 소요 시간의 평균을 계산하여 효율적으로 분산 부하를 고르게 하기 위한 성능 영향을 줄입니다. 이 실험적인 접근 방식은 각각의 스펙 파일에 대한 소요 시간을 더 잘 예측하여 작업들이 비슷한 시간에 완료될 수 있도록 하는 데 목적이 있습니다.

이후, 다음 파이프라인은 최신 knapsack/report-master.json 파일을 사용합니다.

Flaky tests

Flaky 테스트 자동 건너뛰기

우리는 알려진 flaky 테스트들을 건너뛰었었지만, 실제로 master를 깨뜨릴 수 있다는 이유로 더는 그렇게하지 않았습니다. 대신, #master-broken 사건에서 보고된 flaky 테스트를 적극적으로 격리하기 위해 빠른 격리 프로세스를 도입했습니다.

이 빠른 격리 프로세스는 $FAST_QUARANTINE 변수를 false로 설정하여 비활성화할 수 있습니다.

실패한 테스트 자동 재시도

$RETRY_FAILED_TESTS_IN_NEW_PROCESS 변수가 false로 설정되지 않는 한 (true가 기본값), 실패한 RSpec 테스트는 자동으로 별도의 RSpec 프로세스에서 한 번 다시 시도됩니다. 이것의 목표는 이전 테스트에서의 대부분의 부작용을 없애서 후속 테스트 실패를 방지하는 것입니다.

재시도된 테스트는 rspec:flaky-tests-report 작업에 의해 아티팩트로 저장된 $RETRIED_TESTS_REPORT_FILE 파일에 기록됩니다.

실험 이슈를 참조하세요.

호환성 테스트

기본적으로 우리는 GitLab.com에서 실행되는 버전으로 모든 테스트를 실행합니다.

다른 버전 (일반적으로 하나는 역호환 버전, 다른 하나는 전방호환 버전)은 매일 스케줄된 파이프라인에서 실행되어야 합니다.

이 일반적인 지침에 대한 예외는 설득력 있게 근거를 제시하고 문서화되어야 합니다.

Ruby 버전 테스트

우리는 GitLab.com에서 Ruby 3.1을 실행하고 기본 브랜치에서도 동일하게 실행합니다. 다음 Ruby 버전을 준비하기 위해, 우리는 Ruby 3.2로 Merge Request을 실행합니다. 자세한 내용은 Ruby 3.2 epic에서 로드맵을 확인하세요.

지원되는 모든 Ruby 버전이 작동하는지 확인하기 위해 각 지원 버전에 대해 2시간마다 스케줄된 파이프라인에서 테스트 스위트를 실행합니다.

Merge Request에 대해 특정 Ruby 버전만 실행하려면 다음 레이블을 추가할 수 있습니다.

  • pipeline:run-in-ruby3_1

PostgreSQL 버전 테스트

우리의 테스트 스위트는 GitLab.com이 PostgreSQL 14에서 실행되고 있기 때문에 PostgreSQL 14에서 실행됩니다. 그리고 새로운 설치 및 업그레이드를 위해 Omnibus는 PG14를 기본으로 사용합니다.

우리는 매일 스케줄된 파이프라인에서 PostgreSQL 13, 14, 15 및 16에서도 테스트를 실행합니다.

또한 Merge Request과 main 파이프라인( rspec db-library-code pg13 작업이 있는 파이프라인)에서 특정 데이터베이스 라이브러리 변경에 대응하여 PostgreSQL 13에서도 테스트를 실행합니다.

현재 버전 테스트

위치 PostgreSQL 버전 Ruby 버전
Merge Request 14 (기본 버전), DB 라이브러리 변경 시 13 3.1 (기본 버전)
master 브랜치 커밋 14 (기본 버전), DB 라이브러리 변경 시 13 3.1 (기본 버전)
maintenance 스케줄 파이프라인 (master 브랜치용, 짝수 시간마다 XX:05) 14 (기본 버전), DB 라이브러리 변경 시 13 3.1 (기본 버전)
maintenance 스케줄 파이프라인 (ruby3_0 브랜치용, 홀수 시간마다 XX:40) 14 (기본 버전), DB 라이브러리 변경 시 13 3.0
maintenance 스케줄 파이프라인 (ruby3_2 브랜치용, 홀수 시간마다 XX:10) 14 (기본 버전), DB 라이브러리 변경 시 13 3.2
nightly 스케줄 파이프라인 (master 브랜치용) 14 (기본 버전), 13, 15, 16 3.1 (기본 버전)

지원되는 각 Ruby 버전에 대해, 이러한 브랜치를 사용하여 2시간마다 유지보수 스케줄 파이프라인을 실행합니다. 이러한 브랜치에는 변경 내용이 없어야 합니다. 이러한 브랜치는 예정된 유지보수 파이프라인에서 해당 Ruby 버전과 함께 파이프라인을 실행하기 위해 존재합니다.

또한 ruby-sync 브랜치에서도 2시간마다 예약된 파이프라인을 실행하여, 해당 ruby\d_\d 브랜치를 기본 브랜치 master와 최신 상태로 유지합니다. 이 명령은 파이프라인을 트리거하지 않습니다.

ruby-sync 브랜치의 gitlab 작업에는 2024-12-01에 만료되는 Maintainer 역할의 write_repository 스코프가 있는 gitlab-org/gitlab 프로젝트 토큰인 RUBY_SYNC이 사용됩니다. 해당 토큰은 RUBY_SYNC_TOKEN 변수에 저장되어 있습니다.

Redis 버전 테스트

우리의 테스트 스위트는 GitLab.com이 Redis 6에서 실행되고 있기 때문에 Redis 6에서 실행됩니다. 또한, 전방호환 PostgreSQL 15 작업을 실행할 때는 nightly 스케줄 파이프라인에서 Redis 7에서도 실행합니다.

현재 버전 테스트

위치 Redis 버전
MRs 6
default branch (스케줄되지 않은 파이프라인) 6
nightly 스케줄 파이프라인 7

단일 데이터베이스 테스트

기본적으로 모든 테스트는 다중 데이터베이스로 실행됩니다.

또한 매일 스케줄된 파이프라인에서 단일 데이터베이스로도 테스트를 실행하고 데이터베이스 관련 파일을 건드리는 Merge Request에서도 테스트를 실행합니다.

단일 데이터베이스 테스트는 두 가지 모드로 실행됩니다:

  1. 하나의 연결로 단일 데이터베이스. GitLab이 하나의 연결 풀을 사용하여 모든 테이블에 연결합니다. 이는 -single-db로 끝나는 모든 작업에서 실행됩니다.
  2. 두 개의 연결로 단일 데이터베이스. GitLab이 다른 데이터베이스 연결을 사용하여 gitlab_main, gitlab_ci 데이터베이스 테이블에 연결합니다. 이는 -single-db-ci-connection로 끝나는 모든 작업에서 실행됩니다.

단일 데이터베이스로 테스트를 실행하려면, Merge Request에 pipeline:run-single-db 레이블을 추가할 수 있습니다.

모니터링

GitLab 테스트 스위트는 main 브랜치와 rspec-profile을 포함하는 모든 브랜치에 대해 모니터링됩니다.

로깅

  • CI에서 log/test.log로의 Rails 로깅은 기본적으로 비활성화되어 있습니다. 이 설정을 재정의하려면 RAILS_ENABLE_TEST_LOG 환경 변수를 제공하세요.

Merge Request을 위한 파이프라인 유형

일반적으로 MR의 파이프라인은 다음 중 하나의 유형으로 분류됩니다 (변경 사항에 따라 짧은 것부터 긴 것까지):

“파이프라인 유형”은 대부분 “중요 경로”(예: 개별 기간의 합이 파이프라인 기간과 같은 일련의 작업에 대한 것)을 설명하는 추상적인 용어입니다. 우리는 메트릭 대시보드에서 이러한 “파이프라인 유형”을 사용하여 최적화해야 할 유형 및 작업을 감지합니다.

여러 영역에 영향을 미치는 MR은 해당되는 가장 긴 유형에 연관됩니다. 예를 들어, 백엔드와 프론트엔드 모두 건드리는 MR은 “프론트엔드” 파이프라인 유형에 포함됩니다. 이유는 해당 유형이 “백엔드” 유형보다 더 많은 시간이 걸리기 때문입니다.

우리는 rules:needs: 키워드를 사용하여 파이프라인에서 실행해야 하는 작업을 결정하는 데 많은 양을 사용합니다. 여러 유형의 변경 사항이 포함된 MR은 여러 유형의 작업이 포함된 파이프라인을 가질 것입니다(예: 문서 전용 및 코드 전용 파이프라인의 조합).

아래에는 각 파이프라인 유형의 핵심 경로 그래프가 나와 있습니다. 핵심 경로에 포함되지 않는 작업은 제외됩니다.

문서화 파이프라인

참조 파이프라인.

graph LR classDef criticalPath fill:#f66; 1-3["docs-lint links (5 minutes)"]; class 1-3 criticalPath; click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356757&udv=0"

백엔드 파이프라인

참조 파이프라인.

graph RL; classDef criticalPath fill:#f66; 1-1["clone-gitlab-repo (1 minute)"]; 1-3["compile-test-assets (3 minutes)"]; click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914317&udv=0" 1-6["setup-test-env (4 minutes)"]; class 1-6 criticalPath; click 1-6 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914315&udv=0" 1-14["retrieve-tests-metadata (50 seconds)"]; click 1-14 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356697&udv=0" 1-15["detect-tests (1 minute)"]; click 1-15 "https://app.periscopedata.com/app/gitlab/652085/EP---Jobs-Durations?widget=10113603&udv=1005715" 2_5-1["rspec & db jobs (30~50 minutes)"]; class 2_5-1 criticalPath; click 2_5-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations" 2_5-1 --> 1-1 & 1-3 & 1-6 & 1-14 & 1-15; ac-1["rspec:artifact-collector (30 seconds)<br/>(workaround for 'needs' limitation)"]; class ac-1 criticalPath; ac-1 --> 2_5-1; 3_2-1["rspec:coverage (3 minutes)"]; class 3_2-1 criticalPath; click 3_2-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7248745&udv=0" 3_2-1 --> ac-1; 4_3-1["rspec:undercoverage (1.3 minutes)"]; class 4_3-1 criticalPath; click 4_3-1 "https://app.periscopedata.com/app/gitlab/652085/EP---Jobs-Durations?widget=13446492&udv=1005715" 4_3-1 --> 3_2-1;

검토 앱 파이프라인

참조 파이프라인.

graph RL; classDef criticalPath fill:#f66; 1-2["build-qa-image (2 minutes)"]; click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0" 1-5["compile-production-assets (12 minutes)"]; class 1-5 criticalPath; click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0" 2_3-1["build-assets-image (1.1 minutes)"]; class 2_3-1 criticalPath; 2_3-1 --> 1-5 2_6-1["start-review-app-pipeline (52 minutes)"]; class 2_6-1 criticalPath; click 2_6-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations" 2_6-1 --> 2_3-1 & 1-2;

엔드 투 엔드 파이프라인

참조 파이프라인.

graph RL; classDef criticalPath fill:#f66; 1-2["build-qa-image (2 minutes)"]; click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0" 1-5["compile-production-assets (12 minutes)"]; class 1-5 criticalPath; click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0" 1-15["detect-tests"]; click 1-15 "https://app.periscopedata.com/app/gitlab/652085/EP---Jobs-Durations?widget=10113603&udv=1005715" 2_3-1["build-assets-image (1.1 minutes)"]; class 2_3-1 criticalPath; 2_3-1 --> 1-5 2_4-1["e2e:package-and-test-ee (103 minutes)"]; class 2_4-1 criticalPath; click 2_4-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914305&udv=0" 2_4-1 --> 1-2 & 2_3-1 & 1-15;

CI 구성 내부

전용 CI 구성 내부 페이지를 확인하세요.

성능

전용 CI 구성 성능 페이지를 확인하세요.


개발 문서로 돌아가기