CI를 이용한 테스트
CI 시스템의 주된 목표는 테스트 스위트를 통과시켜 rust-lang/rust의 main 브랜치가 항상 유효한 상태를 유지하도록 보장하는 것입니다.
큰 틀에서 보면, rust-lang/rust에 풀 리퀘스트를 열었을 때 다음과 같은 일이 일어납니다.
- PR에 푸시할 때마다 테스트와 검사의 작은 일부가 실행됩니다. 이를 통해 흔한 오류를 잡아낼 수 있습니다.
- PR이 승인되면 bors 봇이 PR을 병합 대기열에 넣습니다.
- PR이 대기열의 맨 앞에 도달하면 bors가 병합 커밋을 만들고 그 커밋에 대해 전체 테스트 스위트를 실행합니다. 병합 커밋은 특정 PR 하나만 포함할 수도 있고, CI 비용과 병합 지연을 줄이기 위해 여러 PR을 하나로 묶은 “롤업(rollup)”일 수도 있습니다.
- 전체 테스트 스위트가 끝나면 두 가지 중 하나가 일어납니다. 개발자가 해결해야 하는 오류로 CI가 실패하거나, CI가 성공하여 병합 커밋이
main브랜치에 푸시됩니다.
CI에서 실행되는 내용을 수정하려면 CI 작업 수정하기를 참고하십시오.
CI 워크플로
CI는 주로 GitHub Actions에서 실행되며, .github/workflows/ci.yml에 정의된 단일 워크플로를 사용합니다. 이 워크플로에는 실행하는 모든 CI 작업에 공통으로 적용되는 여러 단계가 들어 있습니다. 해당 브랜치나 PR에 커밋이 푸시되면 워크플로는 src/ci/citool 크레이트를 실행하며, 이 크레이트는 실행해야 할 구체적인 CI 작업을 동적으로 생성합니다. 이 스크립트는 모든 CI 작업의 선언적 구성이 담긴 jobs.yml 파일을 입력으로 사용합니다.
거의 모든 빌드 단계는 별도의 스크립트를 셸로 호출합니다. 덕분에 CI는 플랫폼에 상당히 독립적입니다(즉, GitHub Actions에 과도하게 의존하지 않습니다). GitHub Actions는 CI 프로세스를 부트스트래핑하고 프로세스를 구동하는 스크립트를 조율하는 용도로만 사용됩니다.
본질적으로 모든 CI 작업은 다양한 운영 체제, 타깃, 플랫폼에 걸쳐 서로 다른 구성으로 ./x test, ./x dist 또는 그 밖의 명령을 실행합니다. 실행되는 작업은 크게 dist 작업과 비dist 작업의 두 가지 범주로 나뉩니다.
- Dist 작업은 rustup을 통해 배포하는 모든 도구를 포함하여 특정 플랫폼용 컴파일러의 전체 릴리스를 빌드합니다. 그런 다음 이 빌드는
rust-lang-ci2S3 버킷에 업로드되며, rustup-toolchain-install-master 툴체인 설치 도구로 로컬에 설치할 수 있습니다. 동일한 빌드는 실제 릴리스에도 사용됩니다. 우리의 릴리스 프로세스는 기본적으로 이 산출물을rust-lang-ci2에서 프로덕션 엔드포인트로 복사하고 서명하는 것으로 이루어집니다. - 비dist 작업은 해당 플랫폼에서 전체 테스트 스위트와 rustup을 통해 배포하는 모든 도구의 테스트 스위트를 실행합니다. 테스트하는 범위는 플랫폼에 따라 다르며(예를 들어 일부 테스트는 Tier 1 플랫폼에서만 실행됩니다), CI 자원 낭비를 막기 위해 비교적 빠른 일부 플랫폼은 같은 빌더에 묶어서 실행합니다.
입력 이벤트(보통 브랜치에 대한 푸시)에 따라 세 가지 종류의 빌드(작업 집합) 중 하나를 실행합니다.
- PR 빌드
- 자동(Auto) 빌드
- Try 빌드
풀 리퀘스트 빌드
풀 리퀘스트에 푸시할 때마다 pr 작업 묶음이 실행됩니다. 현재는 test-x86_64-gnu-llvm-X, test-x86_64-gnu-tools, test-pr-check-1, test-pr-check-2, test-tidy 작업이 실행되며, 모두 Linux에서 실행됩니다. 이 작업들은 흔한 문제를 잡아낼 수 있도록 비교적 짧고(약 40분) 가벼운 테스트 스위트를 실행합니다. 좀 더 구체적으로 말하면, 이 작업은 일련의 린트를 실행하고, Windows mingw를 대상으로 하는 교차 컴파일 check 빌드를 (산출물을 생성하지 않고) 수행해 보며, LLVM의 시스템 버전을 사용하여 컴파일러를 테스트합니다. 아쉽게도 모든 PR의 커밋마다 전체 테스트 스위트를 실행하려면 너무 많은 자원이 필요합니다.
문서 주석에 관한 참고 사항
2024년 10월 기준 PR CI는 기본적으로
./x doc xxx를 실행하지 않는다는 점에 유의하십시오. 따라서./x doc xxx를 실패하게 만드는 깨진 문서 내부 링크(intradoc link)가 있다면, 그 실패는 전체 병합 대기열 CI 파이프라인의 매우 늦은 단계에서야 드러납니다.그러므로 문서 주석을 변경했다면 로컬에서
./x doc xxx를 실행하여 이러한 문제를 일찍 잡아내는 것이 좋습니다.
PR 작업은 jobs.yml의 pr 섹션에 정의되어 있습니다. 그 결과는 PR 페이지 하단의 “CI checks” 섹션에서 바로 확인할 수 있습니다.
Auto 빌드
커밋을 main 브랜치에 병합하려면 먼저 전체 테스트 스위트를 통과해야 합니다. 이를 auto 빌드라고 합니다. 이 빌드는 여러 운영 체제와 타깃에 걸쳐 다양한 테스트를 수행하는 수십 개의 CI 작업을 실행합니다. 전체 테스트 스위트는 상당히 느려서, 모든 auto CI 작업이 끝나기까지 몇 시간이 걸릴 수 있습니다.
대부분의 플랫폼은 빌드 단계만 실행하고, 일부는 제한된 테스트만 실행하며, 전체 테스트 스위트를 실행하는 플랫폼은 일부에 불과합니다(Rust의 플랫폼 티어를 참고하십시오).
Auto 작업은 jobs.yml의 auto 섹션에 정의되어 있습니다. 이 작업들은 rust-lang/rust 저장소의 automation/bors/auto 브랜치에서 실행되며, 최종 결과는 bors가 해당 PR에 다는 댓글로 보고됩니다. 실시간 결과는 GitHub Actions 워크플로 페이지에서 볼 수 있습니다.
어느 시점에서든 실행되는 auto 빌드는 최대 하나뿐입니다. 자세한 내용은 bors로 PR을 순차적으로 병합하기를 참고하십시오.
일반적으로 auto 작업이 실패하면 전체 CI 워크플로가 즉시 종료됩니다. 하지만 “non-blocking”, 즉 선택적인 auto 작업을 만들어 두고, 해당 작업이 병합을 막도록 하기 전에 한동안 CI에서 테스트해 보는 것이 유용할 수 있습니다. 이는 해당 작업이 불안정(flaky)할 수 있는 경우에 유용합니다.
이렇게 하려면 해당 작업 이름 앞에 optional-를 붙이고, jobs.yml에서 그 작업에 continue_on_error: true를 설정하십시오.
Try 빌드
때로는 특정 PR을 병합하려 하지 않고도 해당 PR에 대해 CI에서 테스트 스위트의 일부를 실행하거나, 그 PR로부터 컴파일러 산출물 일체를 빌드하고 싶을 때가 있습니다. 이를 “try 빌드“라고 합니다. Try 빌드는 적절한 권한을 가진 사용자가 @bors try 명령이 담긴 PR 댓글을 게시하면 시작됩니다.
Try 빌드의 사용 사례는 다음과 같이 여러 가지가 있습니다.
- 저희의 rustc-perf 벤치마크 모음을 사용하여 일련의 성능 벤치마크를 실행합니다. 이를 위해서는 동작하는 컴파일러 빌드가 필요하며, 이 빌드는 Linux에서 최적화된 버전의 컴파일러를 빌드하는 dist-x86_64-linux CI 작업을 실행하는 try 빌드로 생성할 수 있습니다(현재 이 작업은 try 빌드를 시작하면 기본으로 실행됩니다). try 빌드를 생성하고 이를 성능 벤치마크에 예약하려면
@bors try @rust-timer queue명령 조합을 사용할 수 있습니다. - Crater 실행을 사용하여 PR이 Rust 생태계 전반에 미치는 영향을 확인합니다. 이 경우에도 동작하는 컴파일러 빌드가 필요하며, 이는 dist-x86_64-linux CI 작업으로 만들 수 있습니다.
- PR에서 특정 CI 작업(예: Windows 테스트)을 실행하여, 해당 작업이 실행하는 테스트 스위트를 통과하는지 빠르게 테스트하십시오.
기본적으로 @bors try로 댓글을 보내면 jobs.yml의 try 섹션에 정의된 작업이 실행됩니다. 저희는 이 모드를 “빠른 try 빌드“라고 부릅니다. 이러한 try 빌드는 어떤 테스트도 실행하지 않으며, 컴파일 경고를 허용합니다. 완전히 올바르게 동작하지 않을 수도 있더라도, Crater 실행이나 성능 벤치마크를 위해 최적화된 툴체인을 최대한 빨리 얻고 싶을 때 유용합니다.
빠른 try 빌드에서 실행되는 CI 작업에는 기본 try 작업의 전체 빌드와 구별하기 위해 특별한 접미사(-quick)가 붙습니다. 대신 전체 빌드를 수행하려면 작업 패턴(아래에서 설명합니다)에 해당 작업 이름을 지정하십시오.
try 빌드에서 사용자 지정 CI 작업을 실행하고, 그 작업이 모든 테스트를 통과하며 컴파일 경고를 발생시키지 않는지 확인하려면 작업 패턴을 지정하여 실행할 CI 작업을 선택할 수 있으며, 작업 패턴은 다음 두 가지 방법 중 하나로 사용할 수 있습니다:
- PR 설명에
try-job: <job pattern>지시문 집합을 추가한(아래에서 설명합니다) 다음 간단히@bors try를 실행하면 됩니다. CI는 이 지시문을 읽고 지정한 작업을 실행합니다. 이 방법은 PR을 점진적으로 수정한 후 동일한 try 작업 집합을 여러 번 다시 실행하려는 경우에 유용합니다. - try 명령의
jobs매개변수를 사용하여 작업 패턴을 지정할 수 있습니다:@bors try jobs=<job pattern>. 이 방법은 특정 작업으로 일회성 try 빌드를 수행할 때 유용합니다.jobs매개변수가 PR 설명 지시문보다 우선순위가 높다는 점에 유의하십시오.- 예를 들어
@bors try jobs=job1,job2,job3와 같이 여러 패턴을 지정할 수도 있습니다.
- 예를 들어
각 작업 패턴은 작업의 정확한 이름이거나 여러 작업과 일치하는 glob 패턴일 수 있습니다(예: *msvc* 또는 *-alt). 단일 try 빌드에서 최대 20개의 작업을 시작할 수 있습니다. PR 설명에서 glob 패턴을 사용할 때, 패턴에 별표 등이 포함되어 있으면 GitHub가 패턴을 Markdown으로 렌더링하지 않도록 선택적으로 백틱(`)으로 감쌀 수 있습니다. 이 이스케이프는 @bors jobs= 매개변수를 사용할 때는 동작하지 않는다는 점에 유의하십시오.
작업 패턴은 jobs.yml의 auto 또는 optional 섹션에 정의된 하나 이상의 작업과 일치해야 합니다:
auto작업은 커밋이main브랜치에 병합되기 전에 실행됩니다.optional작업은 try 빌드를 통해 명시적으로 요청된 경우에만 실행됩니다. 이 작업은 일반적으로 tier 2 및 tier 3 타깃에 사용됩니다.
try 빌드를 하는 이유 중 하나는 앞서 설명한 대로 @rust-timer queue를 사용하여 perf 실행을 하기 위해서입니다. 그러면 이 성능 빌드는 main의 어떤 커밋과 비교됩니다. @bors try parent=<sha>를 사용하면 try 빌드와 그에 이어지는 perf 실행의 기준을 main의 특정 커밋으로 지정할 수 있으며, 이를 통해 perf 비교를 최대한 공정하게 할 수 있습니다.
try-jobPR 설명 지시문 사용하기
실행하려는 try 작업 집합을 정하십시오. CI 작업의 이름은
jobs.yml에서 확인할 수 있습니다.PR 설명을 수정하여 패턴 집합을 포함하십시오(보통 PR 설명의 끝에 둡니다). 예를 들면 다음과 같습니다.
This PR fixes #123456. try-job: x86_64-msvc try-job: test-various try-job: `*-alt`각
try-job패턴은 한 줄에 하나씩 작성해야 합니다.
@bors try로 지정한 try 작업을 실행하십시오. 앞서 언급했듯이, 이를 위해서는 사용자가 (1)try권한을 가지고 있거나 (2)try권한을 가진 사람으로부터@bors delegate try를 통해try권한을 위임받아야 합니다.이 방법은 보통
jobs.yml을 직접 수정하는 것보다 쉽다는 점에 유의하십시오. 다만 이 방법으로는 실행되는 테스트 집합을 조정할 수 없으므로 유연성이 떨어질 수 있습니다.
try 빌드는 rust-lang/rust 저장소의 automation/bors/try 브랜치에서 실행되며 그 결과는 GitHub Actions 워크플로 페이지에서 확인할 수 있습니다. 다만 보통은 해당 PR에 bors가 남기는 댓글을 통해 결과를 알림받게 됩니다.
서로 다른 PR에서 여러 try 빌드가 동시에 실행될 수 있지만, 하나의 PR에서는 한 번에 최대 하나의 try 빌드만 실행될 수 있습니다.
CI 작업 수정하기
CI에서 실행되는 내용을 수정하려면 jobs.yml 파일의 pr, auto 또는 try 섹션을 수정하기만 하면 됩니다.
로컬에서 테스트하기 어려운 특정 플랫폼이나 구성을 테스트하기 위해 실행되는 내용을 일시적으로 수정할 수도 있습니다(예를 들어 Windows 빌드가 실패했지만 Windows 컴퓨터를 사용할 수 없는 경우). 이런 상황에서는 주저하지 말고 CI 자원을 사용하십시오.
임의의 CI 작업을 실행하는 방법은 두 가지입니다.
- try 빌드 기능을 사용하고, try 빌드에서 실행하려는 CI 작업을 PR 설명에 지정하십시오.
jobs.yml의pr섹션을 수정하여 PR에 푸시할 때마다 실행할 CI 작업을 지정하십시오. 이 방법은 try 빌드를 반복해서 시작하는 것보다 빠를 수 있습니다.
PR에 푸시할 때마다 실행되는 작업을 수정하려면 auto 섹션의 작업 정의 중 하나를 pr 섹션으로 복사하기만 하면 됩니다. 예를 들어 x86_64-msvc 작업은 64비트 MSVC 테스트를 실행하는 역할을 합니다. 다음과 같이 이 작업을 pr 섹션으로 복사하면 PR에 커밋이 푸시된 후 해당 작업이 실행됩니다.
pr:
...
- image: test-x86_64-gnu-tools
<<: *job-linux-16c
# this item was copied from the `auto` section
# vvvvvvvvvvvvvvvvvv
- image: test-x86_64-msvc
env:
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
SCRIPT: make ci-msvc
<<: *job-windows-8c
그런 다음 파일을 커밋하고 GitHub의 PR 브랜치에 푸시하면 됩니다. 그러면 GitHub Actions가 PR에 푸시할 때마다 이 CI 작업을 실행합니다.
실험을 마친 후, jobs.yml에 가한 변경이 일시적인 것이었다면 잊지 말고 모두 되돌리십시오!
try 작업을 실행하는 동안에는 PR 제목 앞에 [WIP]를 붙이고, 테스트 목적으로 CI 작업을 수정하는 커밋에는 [DO NOT MERGE]를 붙이는 것이 좋은 관행입니다.
CI는 얼마든지 사용해도 되지만, 동시 실행 수가 제한된 공유 자원이라는 점을 염두에 두십시오. 한 번에 너무 많은 작업을 활성화하지 마십시오. 대부분의 경우 한두 개면 충분합니다.
bors로 PR을 순차적으로 병합하기
CI 서비스는 보통 브랜치의 마지막 커밋을 main의 마지막 커밋과 병합한 상태로 테스트합니다. 이는 기능이 단독으로 동작하는지 확인하기에는 좋지만, 병합된 후에도 코드가 동작한다는 보장은 제공하지 않습니다. 이러한 문제는 보통 빌드가 실행된 후에 호환되지 않는 다른 PR이 병합될 때 발생합니다.
main 브랜치가 항상 동작하도록 보장하기 위해 저희는 수동 병합을 금지합니다. 대신 모든 PR은 저희 봇인 bors를 통해 승인받아야 합니다. 승인된 모든 PR은 (우선순위와 생성 날짜 순으로 정렬된) 병합 대기열에 들어가며, 한 번에 하나씩 자동으로 테스트됩니다. 모든 빌더가 통과하면 PR이 병합되고, 그렇지 않으면 실패가 기록되며 해당 PR은 다시 승인받아야 합니다.
Bors는 CI 서비스와 직접 상호작용하지 않습니다. 대신 테스트하려는 병합 커밋을 CI 검사를 실행하도록 구성된 특정 브랜치(automation/bors/auto나 automation/bors/try 등)에 푸시하는 방식으로 동작합니다. 그런 다음 Bors는 커밋 상태(Commit Status)나 검사 실행(Check Run)을 수신하여 빌드 결과를 감지합니다. 병합 커밋은 최신 main을 기반으로 하며 한 번에 하나만 테스트할 수 있으므로, 결과가 통과하면 main은 해당 병합 커밋으로 빨리 감기(fast-forward)됩니다.
안타깝게도 한 번에 하나의 PR만 테스트하는 방식에 긴 CI 시간(전체 실행에 약 2시간)까지 더해져, 하루에 많은 PR을 병합할 수 없으며 한 번의 실패가 처리량에 큰 영향을 미칩니다. 하루에 병합할 수 있는 PR의 최대 개수는 약 10개 정도입니다.
CI 실행 시간이 길고 대규모 빌더 풀이 필요한 것은 주로 dist- 빌더에서 전체 릴리스 산출물을 빌드하기 때문입니다. 그럼에도 그만한 가치가 있는 이유는 이 릴리스 산출물이 다음과 같기 때문입니다.
- 나중에라도 성능 테스트를 할 수 있게 합니다.
- 나중에 버그가 발견되었을 때 이분 탐색(bisection)을 할 수 있게 합니다.
- 항상 릴리스하고 있으면 문제를 조기에 발견할 수 있으므로 릴리스 품질을 보장합니다.
롤업
어떤 PR은 전체 테스트 스위트를 실행할 필요가 없습니다. 오타 수정이나 README 개선 같은 사소한 변경은 빌드를 깨뜨릴 리가 없으며, 이런 변경 하나하나를 2시간 넘게 테스트하는 것은 낭비입니다. 이 문제를 해결하기 위해 저희는 “롤업“을 정기적으로 만듭니다. 롤업은 대기 중인 여러 사소한 PR을 병합하여 함께 테스트할 수 있도록 하는 PR입니다. 롤업은 팀 구성원이 병합 대기열의 “create a rollup” 버튼을 사용하여 수동으로 생성합니다. 팀 구성원은 자신의 판단에 따라 PR이 위험한지 여부를 결정합니다.
Docker
macOS와 Windows의 작업을 제외한 모든 CI 작업은 해당 플랫폼 전용 Docker 컨테이너 안에서 실행됩니다. 이 방식에는 저희에게 다음과 같은 많은 장점이 있습니다.
-
기반 이미지가 바뀌어도 빌드 환경이 일관되게 유지됩니다(trusty 이미지에서 xenial로 전환할 때도 전혀 어려움이 없었습니다).
-
최대한의 바이너리 호환성을 보장하기 위해 아주 오래된 빌드 환경을 사용할 수 있습니다. 예를 들어 Linux 빌더에서는 오래된 CentOS 릴리스를 사용합니다.
-
Docker 이미지 캐싱 덕분에 (QEMU나 Android 에뮬레이터 같은) 도구를 매번 다시 설치하지 않아도 됩니다.
-
사용자는 다음 명령을 실행하기만 하면 로컬에서 같은 환경으로 같은 테스트를 실행할 수 있습니다.
cargo run --manifest-path src/ci/citool/Cargo.toml run-local <job-name>이는 실패를 디버깅할 때 유용합니다. 라이선스 및 기타 제약으로 인해 로컬에서는 Linux Docker 이미지만 사용할 수 있다는 점에 유의하십시오.
dist- 접두사가 붙은 Docker 이미지는 산출물을 빌드하는 데 사용되며, 해당 접두사가 없는 이미지는 테스트와 검사를 실행합니다.
저희는 CI에서 덜 일반적인 아키텍처(주로 Tier 2 및 Tier 3 플랫폼)에 대한 테스트도 실행합니다. 이러한 플랫폼은 x86이 아니므로, 모든 것을 QEMU 안에서 실행하거나, 해당 플랫폼의 테스트를 실행하지 않으려는 경우에는 교차 컴파일만 합니다.
이 빌더들은 GitHub가 저희를 위해 구성하고 유지 관리하는 특별한 빌더 풀에서 실행됩니다.
캐싱
우리의 CI 워크플로는 여러 가지 캐싱 메커니즘을 사용하며, 주로 다음 두 가지 용도로 사용합니다:
Docker 이미지 캐싱
대부분의 Linux 기반 빌더를 실행하는 데 사용하는 Docker 이미지는 완전히 빌드하는 데 오랜 시간이 걸립니다. 빌드 속도를 높이기 위해 Docker 레지스트리 캐싱을 사용하여 이미지를 캐시하며, 중간 산출물은 ghcr.io에 저장됩니다. 또한 빌드된 Docker 이미지를 ghcr에 푸시하여 다른 도구(rustup)나 로컬에서 Docker 빌드를 실행하는 개발자가 이미지를 재사용할 수 있도록 합니다(개발자의 빌드 속도를 높이기 위해서입니다).
우리는 서로 갈라진 여러 브랜치(main, beta, stable)를 테스트하므로 이미지에 단일 캐시를 사용할 수 없습니다. 그렇게 하면 한 브랜치의 빌드가 다른 브랜치의 캐시를 덮어쓰게 됩니다. 대신 이미지를 서로 다른 태그로 저장하며, 모든 Dockerfile과 관련 스크립트의 내용으로 만든 사용자 정의 해시로 각 이미지를 식별합니다.
CI는 해시 키를 계산하여, 다음 중 하나가 변경되면 Docker 이미지의 캐시가 무효화되도록 합니다:
- Dockerfile
- Dockerfile에서 Docker 이미지로 복사되는 파일
- GitHub 러너의 아키텍처(x86 또는 ARM)
Sccache를 이용한 LLVM 캐싱
우리는 여러 CI 작업에서 C/C++ 관련 코드를 빌드하며, 중간 LLVM 산출물을 캐시하기 위해 Sccache를 사용합니다. Sccache는 Mozilla가 개발한 분산 ccache로, 객체 스토리지 버킷을 저장소 백엔드로 사용할 수 있습니다.
Sccache를 사용하면 해시 키를 직접 계산할 필요가 없습니다. Sccache는 소스 코드, 컴파일러 버전, 중요한 환경 변수 등 관련 입력의 변경을 감지하면 캐시를 자동으로 무효화합니다. 따라서 Cargo 위에 Sccache 래퍼를 씌우기만 하면 나머지는 Sccache가 처리합니다.
영구 산출물은 S3 버킷 rust-lang-ci-sccache2에 저장합니다. 따라서 CI가 실행될 때 LLVM이 동일한 C/C++ 컴파일러로 컴파일되고 LLVM 소스 코드도 동일하다는 것을 Sccache가 확인하면, Sccache는 이미 컴파일된 개별 번역 단위를 S3에서 가져옵니다.
CI 관련 사용자 정의 도구
우리는 수년에 걸쳐 CI 사용 경험을 개선하기 위해 몇 가지 사용자 정의 도구를 개발했습니다.
PR에 오류 메시지를 표시하는 Rust Log Analyzer
rust-lang/rust의 빌드 로그는 매우 방대하여, 로그를 살펴보며 빌드 실패 원인을 찾는 것은 현실적이지 않습니다. 그래서 우리는 Rust Log Analyzer(RLA)라는 봇을 개발했습니다. 이 봇은 빌드가 실패하면 빌드 로그를 받아 오류 메시지를 자동으로 추출하고 PR 스레드에 게시합니다.
이 봇은 오류 문자열을 찾도록 하드코딩되어 있지 않습니다. 대신 다수의 빌드 실패 사례로 학습하여 어떤 줄이 여러 빌드에 공통으로 나타나고 어떤 줄이 그렇지 않은지 인식합니다. 생성된 코드 조각이 가끔 이상할 수 있지만, 이 봇은 이전에 한 번도 본 적 없는 오류라도 관련된 줄을 꽤 잘 찾아냅니다.
허용된 실패를 지원하는 Toolstate
rust-lang/rust 저장소는 CI에서 컴파일러뿐만 아니라 다양한 도구와 문서도 테스트합니다. 일부 문서는 git 서브모듈을 통해 가져옵니다. 문서가 수정될 때까지 rustc PR의 병합을 막는다면 닭이 먼저냐 달걀이 먼저냐 하는 문제에 빠지게 됩니다. 문서를 업데이트하려면 아직 병합되지 않은 버전의 rustc로 테스트해야 하므로 문서의 CI가 통과하지 못하기 때문입니다(그리고 우리는 보통 CI 통과를 요구합니다).
이 문제를 피하기 위해 서브모듈은 실패해도 되도록 허용되며, 그 상태는 rust-toolstate에 기록됩니다. 서브모듈이 망가지면 봇이 자동으로 메인테이너에게 알림을 보내 문제를 알 수 있게 하고, 실패 사실을 toolstate 저장소에 기록합니다. 그러면 릴리스 과정에서는 nightly의 망가진 도구를 무시하고, 배포되는 nightly에서 해당 도구를 제외합니다.
도구 실패는 대부분의 경우 허용되지만, 릴리스 일주일 전부터는 자동으로 금지됩니다. nightly에서 도구가 망가져 있는 것은 상관없지만 베타와 stable에서는 반드시 동작해야 하므로, nightly를 베타로 승격하기 며칠 전에는 nightly에서도 동작해야 합니다.
자세한 내용은 toolstate 문서에서 확인할 수 있습니다.
공개 CI 대시보드
Rust CI를 모니터링하려면 인프라 팀이 관리하는 공개 대시보드를 살펴보십시오.
대시보드에서 유용한 패널은 다음과 같습니다.
- 파이프라인 소요 시간: auto 빌드를 실행하는 데 걸리는 시간을 확인하십시오.
- Top slowest jobs: 실행하는 데 가장 오래 걸리는 작업이 무엇인지 확인합니다.
- Change in median job duration: 어떤 작업이 이전보다 느려졌는지 확인합니다. 이는 성능 회귀를 찾아내는 데 유용합니다.
- Top failed jobs: 가장 자주 실패하는 작업이 무엇인지 확인합니다.
대시보드에 대해 더 알아보려면 Datadog CI 문서를 참고하십시오.
CI 구성 확인하기
특정 작업에 대해 CI에서 어떤 bootstrap.toml 설정이 사용되는지 확인하려면 빌드 로그를 직접 살펴보는 것이 가장 쉬울 것입니다. 방법은 다음과 같습니다.
- Rust CI 성공 워크플로 실행 페이지로 이동하여 가장 최근 실행을 클릭하십시오.
- 왼쪽에서 원하는 작업을 선택하십시오.
- 톱니바퀴 아이콘을 클릭하고 “View raw logs“를 선택하십시오.
- “Configure the build“라는 빌드 구성 문자열을 검색하십시오.
- 모든 빌드 설정은
build.configure-args텍스트가 있는 줄에 나열되어 있습니다.