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

gitlab-org/gitlab (또는 dev 인스턴스)의 파이프라인은 일반적으로 관행된 .gitlab-ci.yml 에 구성되어 있으며, 여기에는 더 쉬운 유지보수를 위해 .gitlab/ci/ 에 포함된 파일이 포함되어 있습니다.

가능한 한 많이 GitLab CI/CD 기능과 모범 사례를 “dogfood”하고자 합니다.

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

파이프라인 비용을 줄이고 작업 기간을 단축하기 위해 Merge Request이 승인되기 전에 파이프라인에서는 Merge Request 변경 사항에 대해 실패할 가능성이 높은 RSpec 및 Jest 테스트 세트가 실행될 것입니다.

Merge Request이 승인되면 파이프라인에 완전한 RSpec 및 Jest 테스트가 포함될 것입니다. 이를 통해 Merge Request이 Merge되기 전에 모든 테스트가 실행됨이 보장됩니다.

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 파이프라인은 주어진 MR에서 변경된 파일을 기반으로 실행될 백엔드/프론트엔드 테스트를 감지하기 위해 detect-tests CI 작업prepare 단계에서 실행할 것입니다.

detect-tests 작업은 많은 파일을 생성하는데, 해당 파일에는 실행해야 하는 백엔드/프론트엔드 테스트가 포함됩니다. 이러한 파일은 파이프라인의 후속 작업에서 읽히며 해당 테스트만 실행됩니다.

RSpec 예측 작업

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

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

동적 매핑

먼저, 동적 매핑 전략은 Crystalball gem에서 나오는 동적 매핑 전략을 사용하는 test_file_finder 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)
    • JavaScript 파일이 변경된 경우 해당 JS 구성요소를 포함하는 시스템 스펙을 식별합니다.
  • FindFilesUsingFeatureFlags (#407366)
    • Feature 플래그가 변경된 경우 해당 플래그를 포함하고 있는 Ruby 파일을 확인하여 해당 변경 파일을 기반으로 실행할 프론트엔드/백엔드 테스트를 확인합니다.
정적 매핑

우리는 test_file_finder gem을 사용하며, 동적 매핑으로는 매핑할 수 없는 특수한 경우에 대해 tests.yml 파일에 유지되는 정적 매핑을 사용합니다. (사용된 위치 참조).

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

특이한 경우

또한, 몇 가지 상황에서는 항상 전체 RSpec 테스트를 실행해야 합니다:

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

백엔드 예측 테스트에 문제가 있나요?

그렇다면, 예측 테스트 문제에 대한 조치 방법은 예측 테스트에 대한 엔지니어링 프로덕션성 RUNBOOK을 참조하십시오. 또한, 테스트 선택 오류를 확인한 경우 @gl-quality/eng-prod에 알려주어 필요한 조치를 취할 수 있도록 합니다.

Jest 예측 작업

Merge Request에서 예측적인 Jest 테스트 파일 확인

Merge Request에서 실패할 가능성이 있는 jest 테스트를 식별하기 위해 모든 변경된 파일의 디렉터리을 jest에게 --findRelatedTests 옵션을 사용하여 전달합니다. 이 모드에서 jest는 변경된 파일과 관련된 의존성을 해결하며, 이는 이러한 파일이 의존성 체인에 있는 테스트 파일을 포함합니다.

특이한 경우

또한, 몇 가지 상황에서는 항상 전체 Jest 테스트를 실행해야 합니다:

  • pipeline:run-all-jest 라벨이 Merge Request에 설정된 경우
  • 자동화에 의해(예: Gitaly 업데이트 또는 안정적인 브랜치를 대상으로 하는 MR) Merge Request이 생성된 경우
  • 보안 미러에서 Merge Request이 생성된 경우
  • 관련 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에 정의되어 있습니다.

프론트엜드 예측 테스트에 문제가 있나요?

그렇다면, 예측 테스트 문제에 대한 조치 방법은 예측 테스트에 대한 엔지니어링 프로덕션성 RUNBOOK을 참조하십시오.

포크 파이프라인

포크 파이프라인에서는 pipeline:run-all-rspec 라벨이 MR에 설정되지 않는 한 예측 RSpec 및 Jest 작업만을 실행합니다. 이로써 포크 파이프라인에서 소비되는 컴퓨팅 할당량을 줄이는 것이 목표입니다.

실험 이슈를 참조하십시오.

Merge Request 파이프라인에서 fail-fast 작업

기존 테스트를 파괴하는 Merge Request이 발생할 경우 더 빠른 피드백을 제공하기 위해 fail-fast 메커니즘을 구현했습니다.

rspec fail-fast 작업은 Merge Request 파이프라인에서 다른 모든 rspec 작업과 병렬로 추가됩니다. 이 작업은 Merge Request에서 직접적으로 관련된 테스트를 실행합니다.

이러한 테스트 중 하나라도 실패하면 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 --"on failure"--> Z

rspec fail-fast는 Merge Request과 관련된 테스트 파일이 10개 이상인 경우 작동하지 않습니다. 이렇게 함으로써 rspec fail-fast의 기간이 평균 rspec 작업 기간을 초과하여 그 목적을 방해하는 것을 방지합니다.

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

이전에 실패한 테스트 다시 실행하기

Merge Request에서 실패한 테스트를 해결한 후 피드백 시간을 줄이기 위해 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: 테스트 파일 디렉터리"--> B & C

Merge 기차

왜 “안정적인” 마스터 브랜치가 Merge 기차를 활성화하기 위해 필요한가요?

마스터 브랜치가 불안정한 경우(즉, 마스터 브랜치의 CI/CD 파이프라인이 자주 실패하는 경우), 불량한 Merge Request 파이프라인 이후에 추가된 모든 Merge Request 파이프라인은 취소되고 기차에 다시 추가해야 합니다. 이로 인해 Merge 기차가 길 경우 많은 지연이 발생합니다.

Merge 기차를 활성화하려면 마스터 브랜치가 얼마나 안정적이어야 하나요?

구체적인 숫자는 없지만, 우리는 불안정한 테스트 실패 및 인프라 문제에 대해 더 나은 결과를 얻어야 합니다(자세한 내용은 Master Broken Incidents RCA Dashboard 참조).

점진적으로 CI/CD 구성에서 Merge 기차로 이동할 수 있을까요?

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

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

불량 마스터 수정

master수정해야 할 때, Merge Request에서 실행되는 파이프라인을 신속히 처리하려면 pipeline:expedite 레이블을 추가할 수 있습니다.

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

취소 Merge Request(MRs)

취소 Merge Request(MRs)를 빠르게 만들려면, Merge Request을 생성하기 전에 취소 MR 템플릿을 사용하세요. 이 작업은 pipeline:expedite 레이블 및 기타 레이블을 적용하여 Merge Request에서 실행되는 파이프라인을 신속히 처리합니다.

pipeline:expedite 레이블

이 레이블이 할당되면 다음 CI/CD 파이프라인 단계가 건너뜁니다:

Merge Request에 레이블을 적용하고 MR용 새 파이프라인을 실행하세요.

테스트 작업

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

caution
문서 관련 MR에 모든 작업을 강제로 실행하는 경우 사전 작업이 없어 오류가 발생할 수 있습니다.

최종 사용자용 작업

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

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

e2e:test-on-gdk 하위 파이프라인은 코드 패턴 변경에 따라 자동으로 :reliable E2E 스펙을 실행하며, 다른 경우에는 매뉴얼으로 실행됩니다. 구체적인 규칙 디렉터리은 rules.gitlab-ci.yml.qa:rules:e2e-blocking을 참조하세요.

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

리뷰 앱 작업

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

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

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

FOSS처럼 작동하는 작업 및 교차 프로젝트 하향 파이프라인

관련 변경 사항이 FOSS 프로젝트에서 제대로 작동하는지 확인하기 위해 특정 조건에서:

  • 동일한 파이프라인에서 * as-if-foss 작업 실행
  • 교차 프로젝트 하향 FOSS 파이프라인 실행

pipeline:run-as-if-foss 레이블이 Merge Request에 설정되어 있거나 Merge Request이 gitlab-org/security/gitlab 프로젝트에서 생성된 경우 또는 CI 구성 파일이 변경된 경우(예: .gitlab-ci.yml 또는 .gitlab/ci/**/*).

* as-if-foss 작업은 보통 EE-컨텍스트 작업에 추가됩니다. 이들은 FOSS_ONLY='1' 변수를 설정하고 테스트 시작 전에 ee/ 폴더를 제거합니다. 교차 프로젝트 하향 FOSS 파이프라인은 실제 FOSS 환경에 더 가깝게 실행됩니다.

의도는 변경이 gitlab-org/gitlabgitlab-org/gitlab-foss에 동기화한 후에도 실패를 발생시키지 않도록 하는 것입니다.

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

  • AS_IF_FOSS_TOKEN: 이것은 개발자 역할과 write_repository 권한이 있는 GitLab FOSS 프로젝트 토큰으로, 생성된 as-if-foss/* 브랜치를 푸시합니다.
    • 보안 프로젝트에 동일한 이름을 사용하는 경우, 보안 FOSS 프로젝트에서 다른 토큰을 사용해야 합니다. 이렇게 함으로써 보안 변경 사항이 공개 프로젝트로 전달되는 것을 방지합니다.

As-if-JH 크로스 프로젝트 다운스트림 파이프라인

이게 무엇인가요

이 파이프라인은 지후 검증 파이프라인이라고도 불리며, 현재 실패해도 괜찮은 상태입니다. 이 경우에는 검증 파이프라인이 실패했을 때 할 일을 따릅니다.

어떻게 실행되나요

start-as-if-jh 작업은 as if JiHu로 GitLab 테스트 스위트를 실행하는 크로스 프로젝트 다운스트림 파이프라인을 트리거합니다. 이 작업은 다음과 같은 경우에만 생성됩니다.

  • 피처 플래그를 수정했을 때
  • Merge Request에 pipeline:run-as-if-jh 라벨이 지정된 경우

이 파이프라인은 GitLab JH validation 프로젝트의 생성된 브랜치 컨텍스트에서 실행되며, 이 프로젝트는 GitLab JH mirror의 미러입니다.

생성된 브랜치 이름은 Merge Request 브랜치를 기반으로 하며, 또한 해당 JH 브랜치에서 다운로드한 변경 내용을 추가하여 전체 파이프라인을 JiHu처럼 설정합니다.

이 작업의 목적은 GitLab이 GitLab JH로 동기화된 후에 실패를 야기하는 변화가 없는지 확인하는 것입니다.

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

루비 파일의 이름을 변경하고 해당하는 prepend_mod 라인이 있는 경우, 이는 GitLab JH가 해당 파일을 의존하고 있으며 해당 모듈 또는 클래스 이름을 바꾸는 대응 변경이 필요하다는 신호입니다.

Corresponding JH branch

GitLab JH에서 해당하는 JH 브랜치를 만들고 해당 브랜치 이름 뒤에 -jh를 붙여 생성할 수 있습니다. 해당하는 JH 브랜치가 발견되면 as-if-jh 파이프라인은 기본 브랜치 main-jh가 아닌 해당 브랜치에서 파일을 가져옵니다.

note
현재 CI는 GitLab JH mirror에서 브랜치를 가져오려고 시도하기 때문에 새로운 JH 브랜치가 미러에 전파되는 데 시간이 걸릴 수 있습니다.
note
GitLab JH validationGitLab JH mirror의 미러이지만, 기본 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 --"artifacts 다운로드"--> Prepare end subgraph "gitlab-org-sandbox/gitlab-jh-validation" Sync["(*선택 사항) as-if-jh-code-sync 브랜치에서 sync-as-if-jh-branch job 실행"] Start["as-if-jh/* 브랜치에서 start-as-if-jh job 실행"] AsIfJH["as-if-jh 파이프라인"] end Mirror --"master 및 main-jh 미러로 pull"--> 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 브랜치로 미러에서 pull"--> Mirror
프로젝트 변수에 설정된 토큰
  • ADD_JH_FILES_TOKEN: 이것은 read_api 권한이 있는 GitLab JH mirror 프로젝트 토큰으로, JiHu 파일을 다운로드할 수 있습니다.
  • AS_IF_JH_TOKEN: 이것은 개발자 역할과 write_repository 권한이 있는 GitLab JH validation 프로젝트 토큰으로, 생성된 as-if-jh/* 브랜치를 푸시할 수 있습니다.
as-if-JH 브랜치를 생성하는 방법

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

선택 사항으로, Merge Request에 의존성 변경이 있는 경우, 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에서 모든 브랜치를 미러링하며, 발생한 차이점을 덮어쓰고 미러가 업데이트될 때 파이프라인을 트리거하지 않습니다.

풀링 사용자는 @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-validation-bot으로 설정하여 GitLab JH 미러에서 변경 사항을 가져오는 데 사용됩니다.

또한, 매일 캐시를 업데이트하는 maintenanceSCHEDULE_TYPE 변수가 설정된 파이프라인 스케줄도 있습니다.

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

더불어 특별한 브랜치 as-if-jh-code-sync도 설정되어 있으며 보호됩니다. 유지보수자는 푸시할 수 있고, 개발자는 이 브랜치를 머지할 수 있습니다. 개발자가 이 브랜치에 대해 파이프라인을 트리거할 수 있어야 하므로 이를 설정해야 합니다. 이는 Developer-level users no longer able to run pipelines on protected branches 문제를 해결하기 전에 한 가지 타협점입니다.

이 브랜치는 머지 요청에서 의존성을 변경했을 때 의존성을 동기화하기 위해 sync-as-if-jh-branch를 실행하는 데 사용됩니다. 작동 방법은 as-if-JH 브랜치를 생성하는 방법을 참조하세요.

임시 GitLab JH 검증 프로젝트 변수
  • BUNDLER_CHECKSUM_VERIFICATION_OPT_INfalse로 설정되어 있습니다.
왜 미러 프로젝트와 검증 프로젝트를 둘 다 가지고 있는 건가요?

여러 이유로 서로 다른 프로젝트를 갖고 있습니다.

  • 보안: 이전에는 미러 프로젝트만 있었습니다. 그러나 보안 문제를 완전히 해결하기 위해 미러 프로젝트를 비공개로 만들어야 했습니다.
  • 격리: JH 코드를 완전히 격리된 독립적인 프로젝트에서 실행하고 싶습니다. 미러 프로젝트가 있는 gitlab-org 그룹에서 실행하고 싶지 않습니다. 검증 프로젝트는 완전히 격리되어 있습니다.
  • 비용: 각 머지 요청마다 JiHuLab.com에 연결하고 싶지 않습니다. JiHuLab.com에서 GitLab.com의 어딘가로 코드를 미러링하여 머지 요청에서 코드를 가져오는 것이 더 비용 효율적입니다. 이것은 검증 프로젝트가 미러에서 코드를 가져올 수 있기 때문에 JiHuLab.com에서 가져오는 것보다 효과적입니다. 미러 프로젝트는 정기적으로 JiHuLab.com에서 가져옵니다.
  • 브랜치 분리/보안/효율성: 모든 브랜치를 미러링하여 해당하는 JH 브랜치를 JiHuLab.com에서 가져오고 싶습니다. 그러나 검증 프로젝트에서 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는 비활성화되어 있습니다.

두 프로젝트를 Merge하여 설정과 프로세스를 간소화할 수 있지만, 위의 모든 이유가 더는 문제가 되지 않도록 해야 합니다.

rspec:undercoverage 작업

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

rspec:undercoverage 작업은 rspec:coverage 작업에서 커버리지 데이터를 획들합니다.

CE 메소드가 EE에서 재정의된 것으로 인해 커버리지가 누락된 것을 rspec:undercoverage 작업이 감지한 경우, “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 작업

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

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

테스트 스위트 병렬화

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

  1. prepare 단계의 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 작업(일반적으로 the canonical project의 예약 파이프라인에서 실행되며 knapsack/report-master.json을 업데이트합니다):
    1. 기본적으로, 모든 knapsack/rspec*.json 파일을 가져와 하나의 knapsack/report-master.json 파일로 Merge하여 아티팩트로 저장합니다.
    2. (실험적) AVERAGE_KNAPSACK_REPORT 환경 변수가 true로 설정된 경우, 보고서를 Merge하는 대신, 작업은 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 프로세스에서 한 번 더 재시도됩니다. 목표는 이전 테스트의 부작용을 제거하여 후속 테스트 실패를 방지하는 것입니다.

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

실험 이슈를 확인하세요.

호환성 테스트

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

기타 버전(보통 하나의 역호환 버전과 하나의 순방향 호환 버전)은 매일 예약된 파이프라인에서 실행해야 합니다.

이 일반 지침에 예외가 있는 경우 이에 대한 동기와 문서화가 필요합니다.

Ruby 버전 테스트

우리는 GitLab.com에서 Ruby 3.1을 실행하고 있으며, 기본 브랜치에도 동일한 버전이 실행됩니다. 다음 Ruby 버전을 준비하기 위해, 2024년 2월부터 Ruby 3.2에서 Merge Request을 실행할 것입니다. 자세한 내용은 Ruby 3.2 epic에서 로드맵을 확인하세요.

지원되는 Ruby 버전이 정상적으로 작동하는 지 확인하기 위해, 각 지원되는 버전에 대해 2시간마다 예약된 파이프라인에서 테스트 스위트를 실행합니다.

Merge Request에 대해서 다음의 레이블을 추가하여 해당 Ruby 버전에서만 실행할 수 있습니다:

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

이렇게 하면 테스트 스위트가 기본 Ruby 버전에서 실행되지 않게 됩니다. 이 경우, 추가 작업으로 verify-default-ruby가 실행되며, Merge하기 전에 레이블을 제거하고 기본 Ruby에서 실행해야 함을 상기시키기 위해 항상 실패합니다.

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

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

PostgreSQL 버전 테스트

저희 테스트 스위트는 GitLab.com이 PostgreSQL 14에서 실행되고 Omnibus는 새로운 설치 및 업그레이드에 대해 PG14를 기본값으로 설정하기 때문에 PostgreSQL 14에서 실행됩니다.

저희는 PostgreSQL 13, 14, 15 및 16에서 매일 스케줄된 파이프라인으로 저희의 테스트 스위트를 실행합니다.

또한, 특정 데이터베이스 라이브러리 변경 시 Merge Request 및 main 파이프라인에서 PostgreSQL 13에서 저희의 테스트 스위트를 실행합니다 (rspec db-library-code pg13 작업).

현재 버전 테스트

위치 PostgreSQL 버전 Ruby 버전
Merge Request 14 (기본 버전), 데이터베이스 라이브러리 변경 시 13 3.1 (기본 버전)
master 브랜치 커밋 14 (기본 버전), 데이터베이스 라이브러리 변경 시 13 3.1 (기본 버전)
maintenance 스케줄된 파이프라인 (각 짝수 시간 XX:05에 master 브랜치용) 14 (기본 버전), 데이터베이스 라이브러리 변경 시 13 3.1 (기본 버전)
maintenance 스케줄된 파이프라인 (ruby3_0 브랜치를 위한 각 홀수 시간 XX:40에) 14 (기본 버전), 데이터베이스 라이브러리 변경 시 13 3.0
maintenance 스케줄된 파이프라인 (ruby3_2 브랜치를 위한 각 홀수 시간 XX:10에) 14 (기본 버전), 데이터베이스 라이브러리 변경 시 13 3.2
master 브랜치를 위한 매일 스케줄된 파이프라인 14 (기본 버전), 13, 15, 16 3.1 (기본 버전)

각 현재 Ruby 버전에 대해 우리가 테스트하는 스케줄된 유지보수 파이프라인을 매 2시간마다 실행합니다. 이러한 브랜치들은 어떠한 변경도 없어야 합니다. 이러한 브랜치들은 예정된 유지보수 파이프라인에서 해당하는 Ruby 버전과 함께 파이프라인을 실행하기 위한 목적으로만 존재합니다.

게다가, 우리는 ruby-sync 브랜치에서 또한 2시간마다 예정된 파이프라인을 실행하여 ruby\d_\d 브랜치들이 기본 브랜치 master와 최신 상태로 업데이트되도록 합니다. 이 푸시로 인하여 어떤 파이프라인도 트리거되지 않습니다.

ruby-sync 브랜치의 gitlab 작업은 write_repository 범위와 Maintainer 역할이 있는 RUBY_SYNC이라는 프로젝트 토큰을 사용하며, 만료일은 2024-12-01입니다. 이 토큰은 ruby-sync 브랜치의 파이프라인 스케줄에 저장됩니다.

Redis 버전 테스트

저희 테스트 스위트는 GitLab.com이 Redis 6에서 실행되고 Omnibus는 새로운 설치 및 업그레이드에 대해 Redis 6를 기본값으로 설정하기 때문에 Redis 6에서 실행됩니다.

우리는 nightly 스케줄된 파이프라인에서 특히 PostgreSQL 15 작업을 실행할 때 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 레이블을 추가할 수 있습니다.

모니터링

main 브랜치 및 rspec-profile을 포함하는 어떠한 브랜치에 대해 GitLab 테스트 스위트가 모니터링됩니다.

로깅

  • 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분)"]; 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분)"]; 1-3["compile-test-assets (3분)"]; 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분)"]; 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초)"]; click 1-14 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356697&udv=0" 1-15["detect-tests (1분)"]; 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분)"]; 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초)<br/>('needs' 제한 우회)"]; class ac-1 criticalPath; ac-1 --> 2_5-1; 3_2-1["rspec:coverage (3분)"]; 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분)"]; 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분)"]; 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분)"]; 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분)"]; class 2_3-1 criticalPath; 2_3-1 --> 1-5 2_6-1["start-review-app-pipeline (52분)"]; 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;

엔드투엔드 파이프라인

참조 파이프라인.

```mermaid graph RL; classDef criticalPath fill:#f66;

1-2[“build-qa-image (2분)”]; 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분)”]; 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분)”]; class 2_3-1 criticalPath; 2_3-1 –> 1-5

2_4-1[“e2e:package-and-test-ee (103분)”]; 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 구성 성능 페이지를 참조하십시오.


개발 문서로 돌아가기