GitLab 프로젝트의 파이프라인

gitlab-org/gitlabdev 인스턴스의 파이프라인은 보통의 .gitlab-ci.yml에 구성되어 있습니다. 이 파일에는 보다 쉬운 유지보수를 위해 .gitlab/ci/에 포함된 파일들이 포함되어 있습니다.

우리는 가능한 한 GitLab의 CI/CD 기능과 모베스트 플랙티스를 꾸준히 사용하고 있습니다.

병합 요청이 승인되기 전 예측 테스트 작업

비용을 줄이고 작업 기간을 단축하기 위해 병합 요청이 승인되기 전에 파이프라인에서는 변경된 병합 요청의 RSpec 및 Jest 테스트를 미리 실행합니다.

병합 요청이 승인되면, 파이프라인에는 전체 RSpec 및 Jest 테스트가 포함될 것입니다. 이는 병합 요청이 병합되기 전에 모든 테스트가 실행되도록 할 것입니다.

GitLab 프로젝트의 테스트 종속성 개요

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

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

요약하면:

  • RSpec 테스트는 백엔드 코드에 종속됩니다.
  • Jest 테스트는 프론트엔드 및 백엔드 코드에 모두 종속되며, 후자는 프론트엔드 fixtures를 통해 종속됩니다.

예측 테스트 대시보드

detect-tests CI 작업

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

detect-tests 작업은 많은 파일을 생성하는데, 이 파일들은 파이프라인의 후속 작업에서 읽히고 해당 테스트만이 실행될 것입니다.

RSpec 예측 작업

병합 요청에서 예측 RSpec 테스트 파일 결정

병합 요청에서 실패할 가능성이 높은 RSpec 테스트를 식별하기 위해 동적 매핑정적 매핑을 사용합니다.

동적 매핑

먼저, 우리는 dynamic mapping strategiesCrystalball gem에서 나오는 test_file_finder gem을 사용합니다(사용 위치 보기, 그리고 Crystalball에서 사용하는 매핑 전략).

test_file_finder 외에도 실행할 추가 매핑을 여러 개 추가했습니다:

  • FindChanges (!74003)
    • 백엔드 변경 내용(프론트엔드 fixtures를 통해)에 따라 실행할 Jest 테스트 자동 감지
  • PartialToViewsMappings (#395016)
    • MR에서 변경된 경우 해당 views에 포함된 Rails partials을 테스트하기
  • JsToSystemSpecsMappings (#386754)
    • MR에서 JavaScript 파일이 변경된 경우 특정 시스템 테스트를 실행하도록 함
  • GraphqlBaseTypeMappings (#386756)
    • Graphql 타입 클래스가 변경된 경우, 이 타입을 포함하고 있는 다른 GraphQL 타입을 식별하고 해당 타입들의 테스트를 실행
  • ViewToSystemSpecsMappings (#395017)
    • view가 변경된 경우 해당 코드 영역을 테스트하는 feature specs을 찾음
  • ViewToJsMappings (#386719)
    • JS 파일이 변경된 경우 해당 JS 컴포넌트를 포함하는 시스템 테스트를 식별
  • FindFilesUsingFeatureFlags (#407366)
    • feature flag가 변경된 경우, 해당 feature flag를 포함하는 Ruby 파일을 확인하고 detect-tests CI 작업에서 해당 파일에 기반하여 실행해야 할 프론트엔드/백엔드 테스트를 감지합니다.
정적 매핑

test_file_finder gem을(를) 사용하는데, tests.yml 파일에 유지되는 정적 매핑을 사용하여 동적 매핑으로 매핑할 수 없는 특수 경우를 처리합니다 (사용 위치).

test mappings은 각 소스 파일을 해당 소스 파일에 의존하는 테스트 파일 목록에 매핑하는 맵을 포함합니다.

예외적인 경우

게다가, 다음과 같은 몇 가지 경우에는 항상 전체 RSpec 테스트를 실행합니다.

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

백엔드 예측 테스트에 문제가 있습니까?

그렇다면, 백엔드 예측 테스트 문제에 대한 조치 방법은 Engineering Productivity RUNBOOK on predictive tests에서 확인하세요. 게다가, 테스트 선택에 관한 빈틈을 발견했다면 @gl-quality/eng-prod에 알려주어 필요한 조치를 취할 수 있도록 해주세요.

Jest 예측 작업

병합 요청에서 예측적인 Jest 테스트 파일 결정

병합 요청에서 실패 가능성이 높은 jest 테스트를 식별하려면, 모든 변경된 파일 목록을 jest--findRelatedTests 옵션을 사용하여 전달합니다. 이 모드에서 jest는 변경된 파일과 관련된 모든 종속 항목을 해결하며, 변경된 파일이 종속 체인에 있는 테스트 파일을 포함합니다.

예외적인 경우

게다가, 다음과 같은 몇 가지 경우에는 항상 전체 Jest 테스트를 실행합니다.

  • 병합 요청에 pipeline:run-all-jest 레이블이 설정된 경우
  • 자동화에 의해 병합 요청이 생성된 경우 (예: Gitaly 업데이트 또는 안정적인 브랜치를 대상으로 하는 MR)
  • 보안 미러에 병합 요청이 생성된 경우
  • 관련 CI 구성 파일이 변경된 경우 (.gitlab/ci/rules.gitlab-ci.yml, .gitlab/ci/frontend.gitlab-ci.yml)
  • 어떤 프론트엔드 종속성 파일이 변경된 경우 (예: package.json, yarn.lock, config/webpack.config.js, config/helpers/**/*.js)
  • 어떤 벤더화된 JavaScript 파일이 변경된 경우 (예: vendor/assets/javascripts/**/*)

완전한 Jest 테스트에 대한 rules 정의는 rules.gitlab-ci.yml.frontend:rules:jest에서 정의됩니다.

프론트엔드 예측 테스트에 문제가 있습니까?

그렇다면, 프론트엔드 예측 테스트 문제에 대한 조치 방법은 Engineering Productivity RUNBOOK on predictive tests에서 확인하세요.

Fork 파이프라인

pipeline:run-all-rspec 레이블이 MR에 설정되지 않는 한 분기 파이프라인에서는 예측 RSpec 및 Jest 작업만 실행합니다. 분기 파이프라인이 사용하는 컴퓨팅 할당량을 줄이는 것이 목표입니다.

실험 issue를 확인하세요.

병합 요청 파이프라인에서 빠른 실패 작업

기존 테스트를 손상시키는 병합 요청이 발생할 때 빠른 피드백을 제공하기 위해 빠른 실패(fail-fast) 메커니즘을 구현했습니다.

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

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

  • 현재 실행 중인 파이프라인과 모든 진행 중인 작업을 취소합니다.
  • 파이프라인의 상태를 failed로 설정합니다.

예를 들어:

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 --"실패시"--> Z

병합 요청과 관련된 테스트 파일이 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 파이프라인의 실패한 테스트를 실행합니다.

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

작동 방식은 무엇인가요?

  1. detect-previous-failed-tests 작업(prepare 단계)은 이전 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: 테스트 파일 목록"--> B & C

병합 트레인

왜 “안정적인” 마스터 브랜치가 병합 트레인을 활성화하기 위해 필요한가요?

마스터 브랜치가 불안정할 경우(예: 마스터 브랜치의 CI/CD 파이프라인이 빈번히 실패하는 경우) 불량 병합 요청 파이프라인 이후에 추가된 모든 병합 요청 파이프라인은 취소되고 트레인에 다시 추가해야 하므로 병합 트레인이 길 경우 지연이 발생합니다.

병합 트레인을 활성화하기 위해 마스터 브랜치는 얼마나 안정적이어야 하나요?

구체적인 숫자는 없지만, 우리는 변덕스러운 테스트 실패 및 인프라 문제의 숫자를 개선해야 합니다(자세한 내용은 Master Broken Incidents RCA Dashboard를 참조하세요).

CI/CD 구성에서 점진적으로 병합 트레인으로 이동할 수 있을까요?

기여자로부터 제안이 있었지만, 이 방법에는 일부 단점이 있습니다: 원본 제안 및 토론을 확인하세요.

일부 병합 요청에 대한 빠른 피드백

불량 마스터 수정

master수정해야 할 경우, 병합 요청에서 실행되는 파이프라인을 가속화하기 위해 pipeline:expedite 레이블을 추가할 수 있습니다.

병합 요청에는 master:broken 또는 master:foss-broken 레이블 설정이 필요합니다.

Revert MRs

Revert MRs를 더 빠르게 만들려면, 병합 요청을 생성하기 revert MR 템플릿을 사용하세요. 이 작업은 pipeline:expedite 레이블 및 기타 작업을 적용합니다.

pipeline:expedite 레이블

이 레이블이 할당되면, CI/CD 파이프라인의 다음 단계가 스킵됩니다:

병합 요청에 레이블을 적용하고, MR에 대한 새로운 파이프라인을 실행하세요.

테스트 작업

우리는 각 테스트 레벨에 대한 전용 작업이 있으며, 각 작업은 병합 요청에서 수행됩니다. 귀하의 변경에 관계없이 모든 RSpec 작업을 강제로 실행하려면 pipeline:run-all-rspec 레이블을 병합 요청에 추가할 수 있습니다.

경고: 문서 전용 관련 MR에 모든 작업을 강제로 실행하면 선행 작업이 없으므로 오류가 발생할 수 있습니다.

End-to-end 작업

e2e:package-and-test 하위 파이프라인은 변경에 따라 자동으로 e2e 작업을 실행하며, 다른 경우에는 수동으로 실행됩니다. 특정 규칙 목록은 .qa:rules:package-and-testrules.gitlab-ci.yml에서 확인할 수 있습니다.

귀하의 변경에 관계없이 e2e:package-and-test를 강제로 실행하려면 병합 요청에 pipeline:run-all-e2e 레이블을 추가할 수 있습니다.

e2e:test-on-gdk 하위 파이프라인은 :reliable E2E specs를 모든 code patterns changes에 대해 자동으로 실행합니다. 구체적인 규칙 목록은 .qa:rules:e2e-blockingrules.gitlab-ci.yml에서 확인할 수 있습니다.

자세한 내용은 End-to-end Testing 페이지를 참조하세요.

앱 작업 검토

start-review-app-pipeline 자식 파이프라인은 변경 사항에 따라 자동으로 리뷰 앱을 배포하고 end-to-end 테스트를 실행하며, 다른 경우에는 수동으로 실행합니다. 구체적인 규칙 목록은 rules.gitlab-ci.yml.review:rules:start-review-app-pipeline를 참조하십시오.

병합 요청에 상관없이 리뷰 앱을 강제로 배포하려면 pipeline:run-review-app 라벨을 병합 요청에 추가할 수 있습니다.

자세한 내용은 리뷰 앱 전용 페이지를 참고하세요.

FOSS처럼 작동하는 작업과 다른 프로젝트 하향 파이프라인

FOSS 프로젝트에서 관련 변경 사항이 올바르게 작동하는지 확인하려면, 일부 상황에서 다음을 실행합니다.

  • 동일한 파이프라인에서 * as-if-foss 작업을 실행합니다.
  • Cross 프로젝트 하향 FOSS 파이프라인

* as-if-foss 작업은 GitLab 테스트 스위트를 “FOSS처럼” 실행하며, 이는 작업이 gitlab-org/gitlab-foss 컨텍스트에서 실행될 것으로 가정합니다. 반면에 Cross 프로젝트 하향 FOSS 파이프라인은 실제 FOSS 환경에 훨씬 가깝게 실행됩니다.

다음과 같은 경우에 실행됩니다.

  • 병합 요청에 pipeline:run-as-if-foss 라벨이 설정된 경우
  • 병합 요청이 gitlab-org/security/gitlab 프로젝트에서 생성된 경우
  • CI 구성 파일이 변경된 경우(예: .gitlab-ci.yml 또는 .gitlab/ci/**/*)

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

Cross 프로젝트 하향 FOSS 파이프라인은 변경 목록을 포함하여 FOSS 프로젝트의 기본 브랜치로 병합하는 것을 시뮬레이션하는데, 이를 통해 파일 목록이 제거됩니다. 목록은 .gitlab/ci/as-if-foss.gitlab-ci.ymlmerge-train/bin/merge-train에서 찾을 수 있습니다.

이것은 gitlab-org/gitlabgitlab-org/gitlab-foss로 동기화된 후 변경 사항이 실패를 발생시키지 않도록 하는 것을 목적으로 합니다.

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

  • AS_IF_FOSS_TOKEN: 이것은 developer 역할과 write_repository 권한을 가진 GitLab FOSS 프로젝트 토큰으로, 생성된 as-if-foss/* 브랜치를 푸시하기 위한 것입니다.
    • 동일한 이름의 보안 프로젝트의 경우 공개 프로젝트로 보안 변경 사항을 절대로 푸시하지 않도록 다른 토큰을 사용해야 합니다.

As-if-JH Cross 프로젝트 하향 파이프라인

무엇인가요

이 파이프라인은 지후 유효성 검사 파이프라인이라고도 불리며, 현재 실패할 수 있습니다. 이런 경우, 유효성 검사 파이프라인이 실패할 때 해야 할 일을 따르세요.

실행 방법

start-as-if-jh 작업은 GitLab JH의 컨텍스트에서 실행될 것으로 가정하여 “지후처럼” GitLab 테스트 스위트를 실행하는 Cross 프로젝트 하향 파이프라인을 트리거합니다. 이러한 작업은 다음 경우에만 생성됩니다.

  • 기능 플래그에 변경이 있으면
  • 병합 요청에 pipeline:run-as-if-jh 라벨이 설정된 경우

이 파이프라인은 GitLab JH로 동기화된 GitLab을 통해 생성된 브랜치에서 실행되며, 이는 GitLab JH validation 프로젝트에 기반하여 생성됩니다. 생성된 브랜치는 병합 요청 브랜치를 기반으로하며, 추가로 해당 JH 브랜치에서 다운로드한 변경 사항을 추가하여 전체 파이프라인을 지후처럼 변환합니다.

이렇게 함으로써 GitLabGitLab JH로 동기화된 후 변경 사항이 실패를 발생시키지 않도록 하는 것을 목적으로 합니다.

pipeline:run-as-if-jh 라벨을 적용하는 시기

Ruby 파일 이름이 변경되고 해당하는 prepend_mod line이 있는 경우에는 GitLab JH가 이를 의존하고 있으며 해당 모듈 또는 클래스의 이름을 바꿔야 할 필요가 있습니다.

관련 JH 브랜치

GitLab JH에서 해당 JH 브랜치를 만들 수 있으며, 브랜치 이름 뒤에 -jh를 붙이면 됩니다. 해당하는 JH 브랜치가 발견된 경우, as-if-jh 파이프라인은 기본 브랜치인 main-jh가 아닌 해당 브랜치에서 파일을 가져옵니다.

참고: 현재 CI는 GitLab JH 미러에서 브랜치를 가져 오려고 시도하므로 새로운 JH 브랜치가 미러에 전파되기까지 시간이 걸릴 수 있습니다.

참고: GitLab JH 검증GitLab JH 미러의 미러이지만, 기본 main-jh 외에는 해당하는 JH 브랜치를 포함하지 않습니다. 따라서 해당하는 JH 브랜치를 가져오려면 검증 프로젝트가 아닌 본 미러에서 가져와야 합니다.

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

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

참고: 의존성 변경이 있는 경우에만 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 머지 리퀘스트"] Add["add-jh-files 작업"] Prepare["prepare-as-if-jh-branch 작업"] Add --"아티팩트 다운로드"--> Prepare end subgraph "gitlab-org-sandbox/gitlab-jh-validation" Sync["(*optional) as-if-jh-code-sync 브랜치에서 (*optional) sync-as-if-jh-branch 작업 실행"] Start["as-if-jh/* 브랜치에서 start-as-if-jh 작업 실행"] AsIfJH["as-if-jh 파이프라인"] end Mirror --"master 및 main-jh를 사용하여 미러 가져오기"--> gitlab-org-sandbox/gitlab-jh-validation Mirror --"ADD_JH_FILES_TOKEN으로 JiHu 파일 다운로드"--> Add Prepare --"AS_IF_JH_TOKEN으로 as-if-jh 브랜치 푸시"--> Sync Sync --"AS_IF_JH_TOKEN으로 as-if-jh 브랜치 푸시"--> Start Start --> AsIfJH end JH --"해당하는 JH 브랜치와 함께 미러 가져오기"--> Mirror
프로젝트 변수에 설정된 토큰
  • ADD_JH_FILES_TOKEN: read_api 권한이 있는 GitLab JH 미러 프로젝트 토큰으로, JiHu 파일을 다운로드할 수 있습니다.
  • AS_IF_JH_TOKEN: developer 역할과 write_repository 권한이 있는 GitLab JH 검증 프로젝트 토큰으로, 생성된 as-if-jh/* 브랜치를 푸시할 수 있습니다.
as-if-JH 브랜치를 생성하는 방법

먼저 add-jh-files 작업에서 필요한 JiHu 파일을 해당하는 JH 브랜치에서 다운로드하여 아티팩트에 저장합니다. 그 다음 prepare-as-if-jh-branch 작업은 머지 리퀘스트 브랜치에서 새 브랜치를 생성하고 변경 사항을 커밋한 후 해당 브랜치를 validation 프로젝트에 푸시합니다.

선택적으로, 머지 리퀘스트에 의존성 변경이 있는 경우에는 as-if-jh-code-sync 브랜치에서 sync-as-if-jh-branch 작업을 실행하여 검증 프로젝트에서 JiHu code-sync과 동일한 프로세스를 수행하여 의존성 변경이 검증 파이프라인 실행 전에 as-if-jh 브랜치로 가져올 수 있도록 합니다.

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

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

as-if-jh/* 브랜치가 준비되었고 필요한 경우 동기화된 후, start-as-if-jh 작업은 검증 프로젝트에서 교차 프로젝트 다운스트림 파이프라인을 실행합니다.

GitLab JH 미러 프로젝트 설정 방법

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

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

풀 미러를 수행하는 사용자는 @gitlab-jh-validation-bot이며, 해당 사용자는 해당 프로젝트의 관리자입니다. 자격 증명은 1password 엔지니어링 저장소에서 찾을 수 있습니다.

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

GitLab JH 검증 프로젝트 설정 방법

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

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

풀 미러를 수행하는 사용자는 @gitlab-jh-validation-bot이며, 해당 사용자는 해당 프로젝트의 관리자이며 GitLab JH 미러의 관리자이기도 합니다. 자격 증명은 1password 엔지니어링 저장소에서 찾을 수 있습니다.

@gitlab-jh-validation-bot의 개인 액세스 토큰으로 write_repository 권한을 사용하여 GitLab JH 미러에서 변경 사항을 가져오는 데 사용됩니다. 사용자 이름은 gitlab-jh-validation-bot으로 설정됩니다.

또한 파이프라인 스케줄이 있으며, 변수 SCHEDULE_TYPEmaintenance로 설정된 유지 관리 파이프라인이 매일 실행되어 캐시를 업데이트합니다.

기본 CI/CD 구성 파일은 jh/.gitlab-ci.yml에서 설정되어 있으므로 GitLab JH와 정확히 같이 실행됩니다.

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

이 브랜치는 머지 요청이 종속성을 변경했을 때 sync-as-if-jh-branch를 실행하는 데 사용됩니다. 이 동작 방식은 as-if-JH 브랜치를 생성하는 방법을 확인하세요.

임시 GitLab JH 검증 프로젝트 변수
  • BUNDLER_CHECKSUM_VERIFICATION_OPT_INfalse로 설정됩니다.
    • JiHu가 jh/Gemfile.checksum을 커밋한 후에 이 변수를 제거할 수 있습니다. 자세한 내용은 이곳에서 찾을 수 있습니다.
미러 프로젝트와 검증 프로젝트를 둘 다 가지는 이유는 무엇인가요?

여러 가지 이유로 별도의 프로젝트가 있습니다.

  • 보안: 이전에는 미러 프로젝트만 있었습니다. 그러나 보안 이슈를 완전히 해결하려면 미러 프로젝트를 비공개로 설정해야 했습니다.
  • 격리: JH 코드를 완전히 격리되고 독립된 프로젝트에서 실행하려고 합니다. 미러 프로젝트가 있는 gitlab-org 그룹 아래에서 실행하려고는 하지 않습니다. 검증 프로젝트는 완전히 격리됩니다.
  • 비용: 각 머지 요청에서 JiHuLab.com에 연결하려고는 하지 않습니다. JiHuLab.com에서 코드를 GitLab.com의 어딘가로 미러링하고 머지 요청에서 코드를 거기서 가져오는 것이 더 비용 효율적입니다. 이는 검증 프로젝트가 미러에서 코드를 가져올 수 있도록 하기 때문입니다. 미러 프로젝트는 정기적으로 JiHuLab.com에서 코드를 가져올 것입니다.
  • 브랜치 분리/보안/효율성: 모든 브랜치를 미러링하여 해당 브랜치에 해당하는 JH 브랜치를 가져오고 싶습니다. 그러나 검증 프로젝트에서 as-if-jh-code-sync 브랜치를 덮어쓰고 싶지는 않습니다. 이 브랜치는 검증 파이프라인을 제어하며 AS_IF_JH_TOKEN에 액세스할 수 있기 때문입니다. 그러나 하나의 브랜치를 제외한 모든 브랜치를 미러링하고 싶지는 않습니다. 이 이슈에 대해서는 이 이슈에서 자세히 설명되어 있습니다.

    이러한 이슈로 인해 검증 프로젝트는 mastermain-jh만 미러링하도록 설정되어 있습니다. 기술적으로는 이러한 브랜치가 필요하지는 않지만, 모든 기본 브랜치로 저장소를 최신 상태로 유지하려고 합니다. 따라서 머지 요청에서 변경 사항을 푸시할 때 저장소의 모든 기본 브랜치에 대해서만 변경 사항을 푸시하면 됩니다. 이는 더 효율적일 수 있습니다.

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

두 프로젝트를 합칠 수도 있지만, 이러한 모든 이유가 더 이상 문제가 되지 않도록 확인해야 합니다.

rspec:undercoverage 작업

rspec:undercoverage 작업은 undercover를 실행하여 병합 요청에 있는 변경 사항 중 테스트 커버리지가 제로인 경우를 감지하고 실패시킵니다.

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

rspec:undercoverage 작업이 CE 메소드가 EE에서 오버라이드되어 누락된 커버리지를 감지하면, pipeline:run-as-if-foss 라벨을 병합 요청에 추가하고 새로운 파이프라인을 시작하세요.

긴급 상황이나 이 작업으로 인한 잘못된 결과의 경우, 병합 요청에 pipeline:skip-undercoverage 라벨을 추가하여 이 작업을 실패하도록 허용하세요.

rspec:undercoverage 실패의 문제 해결

rspec:undercoverage 작업에는 알려진 버그가 있어 잘못된 양성 결과를 초래할 수 있습니다. pipeline:skip-undercoverage를 적용해도 안전한지 로컬에서 커버리지를 테스트할 수 있습니다. 예를 들어 실패한 테스트의 이름을 <spec>으로 사용하여:

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

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

pajamas_adoption 작업

pajamas_adoption 작업은 병합 요청에서 Pajamas 채택 스캐너를 실행하여 Pajamas 디자인 시스템의 채택에서의 회귀를 방지합니다.

작업은 스캐너가 병합 요청으로 인한 회귀를 감지하면 실패합니다. 만약 회귀를 병합 요청에서 수정할 수 없는 경우, pipeline:skip-pajamas-adoption 라벨을 병합 요청에 추가한 후 작업을 다시 시도하세요.

테스트 스위트 병렬화

현재 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/${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_${CI_NODE_INDEX}_${CI_NODE_TOTA‌​L}_report.json"로 설정합니다.
    • knapsack가 제대로 작동하면 실행된 테스트 파일은 Report specs에 나열되어 있어야 합니다.
  3. update-tests-metadata 작업(이 작업은 canoncial 프로젝트에 대해 스케줄된 파이프라인에서만 실행되고 2가지 방법으로 knapsack/report-master.json을 업데이트합니다):
    1. 기본적으로, 모든 knapsack/rspec*.json 파일을 가져와 하나의 knapsack/report-master.json 파일로 모두 병합하여 아티팩트로 저장합니다.
    2. (실험적) AVERAGE_KNAPSACK_REPORT 환경 변수가 true로 설정된 경우, 보고서를 병합하는 대신, 작업은 knapsack/report-master.jsonknapsack/rspec*.json 사이의 테스트 기간의 평균을 계산하여 테스트 지연 시간을 예측하여 병렬 작업 간의 부하를 더 공정하게 분산할 수 있습니다. 이 실험적인 방법은 테스트 순서, 러너 하드웨어의 차이, 불안정한 테스트 등과 같은 잠재적으로 랜덤한 요소로부터의 성능 영향을 줄이기 위해 목표로 합니다.

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

불안정한 테스트

불안정한 테스트의 자동 스킵

이전에는 실제로 깨진 master로 이어질 수 있기 때문에 알려진 불안정한 테스트들을 건너뛰기도 했지만, 우리는 그러지 않기로 결정했습니다. 대신, #master-broken 이슈에서 보고된 어떤 불안정한 테스트든 빠르게 격리시키기 위한 빠른 격리 프로세스를 도입했습니다.

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

실패한 테스트의 자동 재시도를 별도의 프로세스에서 실행

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

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

실험 이슈를 참조하세요.


호환성 테스트

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

기타 버전(일반적으로 하나의 back-compatible 버전 및 하나의 forward-compatible 버전)은 정기적인 nightly 파이프라인에서 실행되어야 합니다.

일반 가이드라인에 대한 예외는 적절하게 동기화되어 문서화되어야 합니다.


Ruby 버전 테스트

현재 GitLab.com에서 Ruby 3.1을 실행하고 기본 브랜치에서도 Ruby 3.1를 실행합니다. 다음 Ruby 버전에 대비하기 위해 2024년 2월부터 Ruby 3.2에서 병합 요청을 실행할 것입니다. 자세한 내용은 Ruby 3.2 epic의 로드맵을 참조하세요.

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

병합 요청의 경우 해당 Ruby 버전만 실행하려면 다음 레이블을 추가할 수 있습니다:

  • pipeline:run-in-ruby3_0
  • pipeline:run-in-ruby3_1
  • pipeline:run-in-ruby3_2

이렇게 하면 병합 요청의 기본 Ruby 버전에서 테스트 스위트가 더 이상 실행되지 않습니다. 이 경우에는 추가 작업인 verify-default-ruby가 실행되어 항상 실패하여 병합 요청 전에 레이블을 제거하고 기본 Ruby에서 실행하도록 알립니다.

이를 통해 다음을 수행할 수 있습니다:

  • 모든 지원되는 Ruby 버전에 대한 변경 사항 테스트
  • 기본 브랜치로 병합될 때 아무 문제가 발생하지 않도록 확인

PostgreSQL 버전 테스트

저희 테스트 스위트는 GitLab.com에서 PostgreSQL 14에서 실행되고 있으며, Omnibus는 새로운 설치 및 업그레이드를 위해 기본적으로 PG14를 사용합니다.

우리는 매일 정기적으로 스케줄된 파이프라인에서 PostgreSQL 13, 14, 15 및 16에 대해 운영 중입니다.

또한 병합 요청 및 main 파이프라인에서 특정 데이터베이스 라이브러리 변경 사항이 발생할 때 PostgreSQL 13에 대한 운영도 합니다 (rspec db-library-code pg13 작업 사용).

현재 버전 테스트

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

현재 운영 중인 각 Ruby 버전에 대해 maintenance 스케줄된 파이프라인을 매 2시간마다 실행합니다. 이러한 브랜치에는 어떤 변경 사항이 없어야 합니다. 이러한 브랜치는 예약된 유지 관리 파이프라인에서 해당 Ruby 버전과 함께 파이프라인을 실행하기 위해 존재합니다.

또한 ruby-sync 브랜치에서 또한 매 2시간마다 스케줄된 파이프라인을 실행하여 모든 ruby\d_\d 브랜치를 기본 브랜치 master와 동기화합니다. 이 변경으로 인해 파이프라인이 트리거되지는 않습니다.

ruby-sync 브랜치에서의 gitlab 작업은 RUBY_SYNC 프로젝트 토큰(유효 기간 2024-12-01인 write_repository 스코프 및 Maintainer 역할)을 사용합니다. 이 토큰은 RUBY_SYNC_TOKEN 변수에 저장되어 ruby-sync 브랜치의 파이프라인 스케줄에 사용됩니다.

Redis 버전 테스팅

저희 테스트 스위트는 Redis 6에서 실행되며, GitLab.com은 Redis 6에서 실행되므로 Omnibus는 새로운 설치 및 업그레이드에 대해 Redis 6을 기본값으로 설정합니다.

우리는 nightly 스케줄 파이프라인에서 PostgreSQL 15 작업을 실행할 때 특히 Redis 7에서 테스트 스위트를 실행합니다.

현재 버전 테스팅

위치 Redis 버전
MRs 6
default branch (정기 스케줄 파이프라인이 아닌) 6
nightly 스케줄 파이프라인 7

단일 데이터베이스 테스팅

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

또한 우리는 nightly 스케줄 파이프라인 및 데이터베이스 관련 파일을 수정하는 병합 요청에서 단일 데이터베이스로 테스트를 실행합니다.

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

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

테스트를 단일 데이터베이스로 실행하려면 병합 요청에 pipeline:run-single-db 라벨을 추가할 수 있습니다.

모니터링

GitLab 테스트 스위트는 main 브랜치 및 rspec-profile이 이름에 포함된 모든 브랜치에 대해 모니터링됩니다.

로깅

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

병합 요청용 파이프라인 유형

일반적으로 MR에 대한 파이프라인은 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 구성 성능 페이지를 참조하세요.


개발 문서로 돌아가기