GitLabプロジェクトのパイプライン

gitlab-org/gitlab (dev のインスタンスと同様) のパイプラインは、通常の.gitlab-ci.yml で設定します。 には、メンテナンスしやすいように.gitlab/ci/ のファイルが含まれています。

私たちは GitLabCI/CD の機能とベストプラクティスをできる限りドッグフード化しようと努力しています。

マージリクエストが承認される前の予測テストジョブ

パイプラインのコストを削減し、ジョブ期間を短縮するために、マージリクエストが承認される前に、パイプラインはマージリクエストの変更に対して失敗する可能性の高い RSpec & Jest テストを予測的に実行します。

マージリクエストが承認された後、パイプラインには完全な RSpec & Jest テストがコンテナされます。これにより、マージリクエストがマージされる前に、すべてのテストが実行されるようになります。

GitLab プロジェクトのテスト依存関係の概要

予測テストジョブがどのように実行されるかを理解するためには、GitLabのコード(フロントエンドとバックエンド)とそれぞれのテスト(JestとRSpec)の依存関係を理解する必要があります。この依存関係は以下の図で可視化できます:

flowchart LR subgraph frontend fe["Frontend code"]--tested with-->jest end subgraph backend be["Backend code"]--tested with-->rspec end be--generates-->fixtures["frontend fixtures"] fixtures--used in-->jest

まとめると

  • RSpec のテストはバックエンドのコードに依存します。
  • Jest テストはフロントエンドとバックエンドの両方のコードに依存し、 後者はフロントエンドのフィクスチャに依存します。

予測テストのダッシュボード

detect-tests CIジョブ

gitlab-org/gitlab の CI/CD パイプラインのほとんどはprepare ステージでdetect-tests CI ジョブ を実行し、与えられた MR で変更されたファイルに基づいてどのバックエンド/フロントエンドのテストを実行すべきかを検出します。

detect-tests ジョブは、実行すべきバックエンド/フロントエンドテストを含む多くのファイルを作成します。これらのファイルはパイプラインの後続のジョブで読み込まれ、それらのテストのみが実行されます。

RSpec 予測ジョブ

マージリクエストでの RSpec テストファイルの予測決定

マージリクエストで失敗しそうな RSpec テストを特定するために、静的マッピングと 動的マッピングを使用します。

静的マッピング

カバレッジトレースでマッピングできない特殊なケースのために、tests.yml ファイル に静的マッピングをメンテナーとして保持し、test_file_finder gem を使用しています(使用箇所を参照)。

テストマッピングには、各ソースファイルと、ソースファイルに依存するテストファイルのリストとのマッピングがコンテナで格納されています。

動的マッピング

まず、test_file_finder gem を使って、テストカバレッジトレース(Crystalball gem を使って生成)から動的なマッピングを行います(どこで使われているか参照)。

test_file_finder に加えて、さらに多くのテストを検出するための高度なマッピングをいくつか追加しました:

  • FindChanges (!74003)
    • バックエンドの変更時に実行される Jest テストを自動的に検出します (フロントエンドのフィクスチャ経由で)。
  • PartialToViewsMappings(#395016)
    • ビューに含まれるRailsパーシャルがMRで変更されたときにビュー仕様を実行
  • JsToSystemSpecsMappings(#386754)
    • MRでJavaScriptファイルが変更された場合、特定のシステム仕様を実行します。
  • GraphqlBaseTypeMappings(#386756)
    • ある GraphQL タイプのクラスが変更された場合、このタイプを含む可能性のある他の GraphQL タイプを特定し、その仕様を実行するようにします。
  • ViewToSystemSpecsMappings(#395017)
    • ビューが変更されたとき、私たちはコードのその領域をテストする機能仕様を見つけようとします。
  • ViewToJsMappings(#386719)
    • JSファイルが変更された場合、そのJSコンポーネントをカバーしているシステム仕様を特定するようにすべきです。
  • FindFilesUsingFeatureFlags(#407366)
    • 機能フラグが変更された場合、どのRubyファイルがその機能フラグを含んでいるかをチェックし、detect-tests CIジョブの変更ファイルリストに追加します。残りのジョブは、変更されたファイルに基づいてどのフロントエンド/バックエンドのテストを実行すべきかを検出します。

例外的なケース

さらに、常に完全な RSpec テストを実行するような状況もいくつかあります:

  • マージリクエストにpipeline:run-all-rspec ラベルが設定されている場合。このラベルは、as-if-foss ジョブで実行されるテストを含む、すべての RSpec テストをトリガーします。
  • マージリクエストにpipeline:mr-approved ラベルが設定され、コード変更がbackend-patterns ルールを満たす場合。このラベルは、マージ リクエストがいずれかのレビュアーによって承認されたときに、トリアージ オートメーションによって割り当てられることに注意してください。このラベルを手動で適用することはお勧めしません。
  • マージリクエストが自動化によって作成された場合 (たとえば、Gitaly アップデートや 安定版ブランチを対象とした MR など)
  • マージリクエストがセキュリティミラーで作成された場合。
  • CI 設定ファイルが変更されたとき (たとえば、.gitlab-ci.yml.gitlab/ci/**/*)

バックエンドの予測テストで問題が発生しましたか?

もしそうであれば、予測テストの問題に対処する方法について、予測テストに関するエンジニアリング生産性RUNBOOKをご覧ください。さらに、テスト選択のギャップを発見された場合は、@gl-quality/eng-prod までお知らせください。そうすれば、テスト選択を最適化するために必要な措置を講じることができます。

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)
  • フロントエンドの依存ファイルが変更されたとき (例:package.json,yarn.lock,config/webpack.config.js,config/helpers/**/*.js)
  • ベンダーのJavaScriptファイルが変更されたとき (例:vendor/assets/javascripts/**/*)

完全な Jest テストのためのrules 定義は.frontend:rules:jestrules.gitlab-ci.ymlで定義されています。

フロントエンドの予測テストで問題が発生しましたか?

もしそうであれば、予測テストの問題に対処する方法について、予測テストに関するエンジニアリング生産性RUNBOOKをご覧ください。

フォークパイプライン

MRにpipeline:run-all-rspec ラベルが設定されていない限り、フォークパイプラインの予測RSpec & Jestジョブのみを実行します。目的は、フォークパイプラインで消費される計算クォータを削減することです。

実験イシューを参照してください。

マージリクエストパイプラインにおけるフェイルファストジョブ

マージリクエストが既存のテストを破壊した場合に、より迅速なフィードバックを提供するために、fail-fast メカニズムを実装しました。

rspec fail-fast ジョブは、マージリクエストパイプラインの他のすべてのrspec ジョブと並行して追加されます。このジョブはマージリクエストの変更に直接関係するテストを実行します。

これらのテストのいずれかが失敗した場合、rspec fail-fast ジョブは失敗し、fail-pipeline-early ジョブの実行を fail-pipeline-earlyトリガーします。fail-pipeline-early ジョブは fail-pipeline-early

  • 現在実行中のパイプラインと進行中のすべてのジョブをキャンセルします。
  • パイプラインのステータスをfailed に設定します。

使用例:

graph LR subgraph "prepare stage"; A["detect-tests"] end subgraph "test stage"; B["jest"]; C["rspec migration"]; D["rspec unit"]; E["rspec integration"]; F["rspec system"]; G["rspec fail-fast"]; end subgraph "post-test stage"; Z["fail-pipeline-early"]; end A --"artifact: list of test files"--> G G --"on failure"--> Z

rspec fail-fast マージリクエストに関連するテストファイルが 10 個以上 rspec fail-fastある場合、このオプションはrspec fail-fast 使用できません rspec fail-fastrspec fail-fast これは rspec fail-fast、期間が平均rspec ジョブ期間を超え、その目的が達成されなくなることを防ぎます。

この数値はRSPEC_FAIL_FAST_TEST_FILE_COUNT_THRESHOLD という名前の CI/CD 変数を設定することでオーバーライドできます。

マージリクエストパイプラインで、以前に失敗したテストを再実行します。

マージリクエストで失敗したテストを解決した後のフィードバック時間を短縮するために、rspec rspec-pg14-rerun-previous-failed-tests およびrspec 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 "prepare stage"; A["detect-previous-failed-tests"] end subgraph "test stage"; 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

列車のマージ

マージトレインを有効にするには、なぜ “stable” master ブランチが必要なのですか?

マスターブランチが不安定な場合 (つまり、マスターブランチの CI/CD パイプラインが頻繁に失敗する場合)、失敗したマージリクエストパイプラインの後に追加されたすべてのマージリクエストパイプラインをキャンセルして 列車に追加し直さなければなりません。

マージトレインを有効にするために、masterブランチはどれくらい安定していなければならないのでしょうか?

具体的な数値はありませんが、テストの失敗やインフラストラクチャの障害については、よりよい数値が必要です (master Broken Incidents RCA Dashboard を参照ください)。

CI/CDの設定で、徐々にマージトレインに移行できないでしょうか?

あるコントリビューターからの提案がありましたが、このアプローチにはいくつかの欠点があります

いくつかのマージリクエストに対するフィードバックの高速化

壊れたマスターの修正

壊れたmaster を修正する必要がある場合、pipeline:expedite ラベルを追加することで、マージリクエストで実行されるパイプラインを高速化することができます。

マージリクエストにはmaster:broken またはmaster:foss-broken ラベルが設定されている必要があることに注意してください。

MRの復帰

MR の差し戻しを高速化するには、マージリクエストを作成する前に MR の差し戻しテンプレートを使用してください。これにより、pipeline:expedite ラベルや、マージリクエストで実行されるパイプラインを高速化するその他の機能が適用されます。

pipeline:expedite ラベル

このラベルが割り当てられると、CI/CDパイプラインの以下のステップがスキップされます:

ラベルをマージリクエストに適用し、MRの新しいパイプラインを実行します。

テストジョブ

各テストレベル専用のジョブがあり、各ジョブはマージリクエストで行った変更に応じて実行されます。変更に関係なくすべての RSpec ジョブを強制的に実行したい場合は、マージリクエストにpipeline:run-all-rspec ラベルを追加します。

caution
docs にのみ関連する MR にすべてのジョブを強制すると、前提条件となるジョブがなく、エラーになります。

エンド・ツー・エンドのジョブ

e2e:package-and-test 子パイプラインは、変更に応じて自動的にエンドツーエンドジョブを実行し、それ以外の場合は手動で実行します。具体的なルールの一覧はrules.gitlab-ci.yml.qa:rules:package-and-test を参照してください。

変更に関係なくe2e:package-and-test を強制的に実行させたい場合は、マージリクエストにpipeline:run-all-e2e ラベルを追加します。

詳細はエンドツーエンドテスト専用ページを参照してください。

アプリジョブのレビュー

start-review-app-pipeline 子パイプラインはレビューアプリをデプロイし、それに対してエンドツーエンドのテストを変更に応じて自動的に実行します。ルールの具体的な一覧はrules.gitlab-ci.yml.review:rules:start-review-app-pipeline を参照してください。

あなたの変更に関係なくレビューアプリを強制的にデプロイしたい場合は、マージリクエストにpipeline:run-review-app ラベルを追加します。

詳しくはレビューアプリ専用ページをご覧ください。

As-if-FOSSのジョブ

* as-if-foss ジョブは GitLab テストスイートを「あたかも FOSS であるかのように」実行します。つまり、ジョブはgitlab-org/gitlab-foss のコンテキストで実行されるかのように実行されます。これらのジョブは以下の場合にのみ作成されます:

  • マージリクエストにpipeline:run-as-if-foss ラベルが設定されたとき
  • gitlab-org/security/gitlab プロジェクトでマージリクエストが作成されたとき。
  • CI 設定ファイルが変更されたとき (たとえば、.gitlab-ci.yml.gitlab/ci/**/*)

* as-if-foss ジョブは、通常の EE-context ジョブに追加して実行されます。これらのジョブはFOSS_ONLY='1' 変数が設定され、テストが実行される前にee/ フォルダが削除されます。

これは、gitlab-org/gitlabgitlab-org/gitlab-foss に同期された後に、変更によって障害が発生しないようにするためです。

As-if-JH クロスプロジェクト・ダウンストリーム・パイプライン

内容

このパイプラインはJiHuバリデーションパイプラインとも呼ばれ、現在失敗することが許されています。その場合は、検証パイプラインが失敗したときの対処法に従ってください。

実行方法

start-as-if-jh ジョブは、”as if JiHu”、つまりGitLab JH のコンテキストでパイプラインが実行されるかのように GitLab テストスイートを実行するクロスプロジェクトダウンストリームパイプラインをトリガーします。これらのジョブは以下の場合にのみ作成されます:

  • 機能フラグに変更が加えられたとき
  • マージリクエストにpipeline:run-as-if-jh ラベルが設定されたとき

このパイプラインは、GitLab JHのミラーである検証プロジェクトの生成ブランチのコンテキストで実行されます。

生成ブランチ名には、マージリクエストのブランチ名とともにas-if-jh/ が先頭に付きます。この生成ブランチはマージリクエストブランチをベースに、対応する JH ブランチからダウンロードした変更を追加し、パイプライン全体を JiHu のようにします。

この意図は、GitLabが GitLab JHに同期された後、変更によって障害が発生しないようにすることです。

pipeline:run-as-if-jh ラベルの適用を検討するタイミング

Rubyファイルの名前が変更され、それに対応するprepend_modがある場合、GitLab JHがそれに依存している可能性があり、前置するモジュールやクラスの名前を変更する必要があります。

対応する JH ブランチ

ブランチ名に-jh を追加することで、GitLab JHに対応する JH ブランチを作成できます。対応する JH ブランチが見つかった場合、as-if-jh パイプラインはデフォルトのブランチmain-jh ではなく、対応するブランチからファイルを取得します。

note
今のところ、CI はGitLab JH ミラー上のブランチを取得しようとするので、新しい JH ブランチがミラーに伝搬するまで時間がかかるかもしれません。
note
GitLab JH 検証は GitLab JH ミラーのミラーですが、デフォルトの](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab) 以外に対応する 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:JiHuファイルをダウンロードできるようにするための、read_api 権限を持つGitLab JHミラープロジェクトトークンです。
  • AS_IF_JH_TOKEN:生成されたas-if-jh/* ブランチをプッシュするための、write_repository 権限を持つGitLab JH 検証プロジェクトトークンです。
as-if-JHブランチの生成方法

最初のadd-jh-files ジョブは、対応する JH ブランチから必要な JiHu ファイルをダウンロードし、アーティファクトに保存します。次のprepare-as-if-jh-branch ジョブは、マージリクエストブランチから新しいブランチを作成し、変更をコミットして、最後にそのブランチを検証プロジェクトにプッシュします。

オプションとして、マージリクエストに依存関係の変更がある場合、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ミラープロジェクトのセットアップ方法

GitLab JH ミラープロジェクトは非公開で、CI は無効です。

GitLab JH からプルミラーを作成し、すべてのブランチをミラーし、分岐した参照元を上書きし、ミラーが更新されたときにパイプラインをトリガーしません。

プルしているユーザーは@gitlab-jh-botで、プロジェクトのメンテナーです。認証情報は 1password のエンジニアリング保管庫にあります。

GitLab JH は公開プロジェクトなので、ミラーリングのパスワードは使用しません。

GitLab JH検証プロジェクトの設定方法

このGitLab JH検証プロジェクトは公開され、CIが有効になっており、一時的なプロジェクト変数が設定されています。

GitLab JH ミラーからプルミラーを作成し、特定のブランチをミラーしています:(master|main-jh)ミラーが更新されたときにパイプラインは発生しません。

プルユーザーは@gitlab-jh-validation-bot で、プロジェクトのメンテナーであり、GitLab JH ミラーのレポーターでもあります。認証情報は 1password エンジニアリング保管庫にあります。

GitLab JH ミラーから変更をプルするためのパスワードとして、write_repository 権限を持つ@gitlab-jh-validation-bot からの個人アクセストークンが使われます。ユーザー名は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 検証プロジェクトの一時変数
なぜミラープロジェクトと検証プロジェクトの両方があるのですか?

プロジェクトを分けているのにはいくつかの理由があります。

  • セキュリティです:以前はミラープロジェクトだけを持っていました。しかし、セキュリティのイシューを完全に軽減するために、ミラープロジェクトを非公開にする必要がありました。
  • 分離:JHコードを完全に分離されたスタンドアロンのプロジェクトで実行したいのです。ミラープロジェクトがあるgitlab-org グループのもとで実行すべきではありません。検証プロジェクトは完全に分離されています。
  • コスト:マージリクエストのたびにJiHuLab.comに接続したくありません。JiHuLab.comのコードをGitLab.comのどこかにミラーリングして、マージリクエストはそこからコードを取得するほうがコスト効率がよいのです。これは、検証プロジェクトがJiHuLab.comからではなくミラーからコードを取得できることを意味します。ミラープロジェクトは定期的に JiHuLab.com からコードを取得します。
  • ブランチの分離/セキュリティ/効率:JiHuLab.comから対応するJHブランチをフェッチできるように、すべてのブランチをミラーしたいです。しかし、検証プロジェクトのas-if-jh-code-sync ブランチは上書きしたくありません。検証パイプラインを制御するために使用しており、AS_IF_JH_TOKEN へのアクセス権を持っているからです。 しかし、1 つのブランチを除いてすべてのブランチをミラーすることはできません。詳しくはこのイシューをご覧ください。

    このイシューを考慮して、検証プロジェクトはmastermain-jh のみをミラーするように設定されています。技術的にはこれらのブランチは必要ないのですが、すべてのデフォルトブランチでリポジトリを最新に保ちたいので、マージリクエストからの変更をプッシュするときに、マージリクエストからの変更だけをプッシュすればよくなり、効率がよくなります。

  • 懸念の分離:
    • 検証プロジェクトには以下のブランチしかありません:
      • mastermain-jh で変更を最新に保つことができます。
      • as-if-jh-code-sync 依存関係の同期のためです。これをミラーリングすべきではありません。
      • as-if-jh/* マージリクエストからのブランチ。これらをミラーすべきではありません。
    • ミラープロジェクトからのブランチはすべてJiHuLab.comからのものです。ミラープロジェクトには何もプッシュしませんし、パイプラインも実行しません。ミラープロジェクトではCI/CDは無効です。

セットアップとプロセスを簡素化するために2つのプロジェクトをマージすることを検討することはできますが、これらのすべての理由がもはや懸念事項ではないことを確認する必要があります。

rspec:undercoverage ジョブ

GitLab 14.6で導入されました

rspec:undercoverage ジョブはundercover を実行し、マージリクエストで導入された変更のカバレッジがゼロの場合に失敗します。

rspec:undercoverage ジョブはrspec:coverage ジョブからカバレッジデータを取得します。

CEメソッドがEEでオーバーライドされたためにrspec:undercoverage ジョブがカバレッジ不足を検出した場合は、マージリクエストに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: ✅ No coverage is missing in latest changes を返した場合、pipeline:skip-undercoverage を適用してパイプラインの障害を回避することができます。

テストスイートの並列化

現在のRSpecテストの並列化設定は以下の通りです:

  1. prepare ステージのretrieve-tests-metadata ジョブは、knapsack/report-master.json ファイルがあることを保証します:
    • knapsack/report-master.json ファイルは、update-tests-metadata を実行する最新のmain パイプライン(今のところ、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 がそのジョブを実行している場合、実行されたテストファイルはLeftover specs の下ではなくReport specs の下にリストされるはずです。
  3. update-tests-metadata ジョブ(canonicalプロジェクトのスケジュールされたパイプラインでのみ実行されます)は、knapsack/rspec*.json ファイルをすべて受け取り、それらをマージして、アーティファクトとして保存されるknapsack/report-master.json ファイルにまとめます。

その後、次のパイプラインは最新のknapsack/report-master.json

Flakyなテスト

欠陥テストの自動スキップ

以前は、flaky であることが判明しているテストをスキップしていましたが、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.0 を動かしています。マージリクエストやデフォルトブランチでも Ruby 3.0 を動かしています。次のリリースであるRuby 3.1に備えて、Ruby 3.1に対するテストスイートも専用の2時間ごとのパイプラインで実行しています。

マージリクエストの場合は、pipeline:run-in-ruby3_1 というラベルを追加することで、テストスイート全体の実行に使う Ruby のバージョンを 3.1 に切り替えることができます。これを行うと、テストスイートは Ruby 3.0 (デフォルト) では実行されなくなり、verify-ruby-3.0 という追加のジョブも実行され、マージリクエストをマージする前にラベルを削除して Ruby 3.0 で実行するように常に通知されます。

これで

  • Ruby 3.1のテスト変更
  • デフォルトブランチにマージしても何も壊れないことを確認

PostgreSQLバージョンのテスト

GitLab.comはPostgreSQL 14で動作しており、Omnibusは新規インストールとアップグレードのデフォルトをPG14に設定しているため、私たちのテストスイートはPostgreSQL 14で動作しています。

PostgreSQL 14 に対するテストスイートは、毎晩スケジュールされたパイプラインで実行しています。

また、PostgreSQL 12とPostgreSQL 13に対しても、マージリクエストとmain パイプライン(rspec db-library-code pg12rspec db-library-code pg13 ジョブを使用)で特定のデータベースライブラリの変更時にテストスイートを実行しています。

現在のバージョンのテスト

どこで?PostgreSQLのバージョンRubyバージョン
マージリクエスト14 (デフォルトバージョン)、13 (DB ライブラリの変更)3.0(デフォルト・バージョン)
master ブランチコミット14 (デフォルトバージョン)、13 (DB ライブラリの変更)3.0(デフォルト・バージョン)
maintenance master ブランチのパイプラインをスケジュール (偶数時間ごと)14 (デフォルトバージョン)、13 (DB ライブラリの変更)3.0(デフォルト・バージョン)
maintenance ruby3_1 ブランチのパイプラインをスケジュール(奇数時間ごと)。14 (デフォルトバージョン)、13 (DB ライブラリの変更)3.1
nightly master ブランチのパイプラインをスケジュールしました。14 (デフォルトバージョン), 12, 13, 153.0(デフォルト・バージョン)

Ruby 3.1のテストには2つのパイプラインスケジュールがあります。ひとつはruby3_1-sync ブランチでパイプラインを起動し、ruby3_1 ブランチを最新のmaster で更新します。もうひとつのスケジュールは、ruby3_1 ブランチの 5 分後にパイプラインを起動するもので、これはテストスイートの実行とキャッシュの更新を行うメンテナンススケジュールとみなされます。

ruby3_1 ブランチには変更があってはなりません。ブランチは、メンテナンスパイプラインスケジュールでRUBY_VERSION3.1 に設定するためだけに存在します。

ruby3_1-sync ブランチのgitlab ジョブは、write_repository スコープとMaintainer ロール付きのgitlab-org/gitlab プロジェクトトークンを使用します。トークンはgitlab-org/gitlabRUBY3_1_SYNC_TOKEN 変数に格納されます。

Redisのバージョンテスト

GitLab.comはRedis 6で動作しており、Omnibusの新規インストールやアップグレードのデフォルトもRedis 6になっています。

nightly のスケジュールパイプライン、特に PostgreSQL 15 の前方互換ジョブを実行するときには、Redis 7 に対してテストスイートを実行します。

現在のバージョンのテスト

どこで?Redisのバージョン
MRs6
default branch (非定期パイプライン)6
nightly 定期パイプライン7

単一データベースのテスト

デフォルトでは、すべてのテストは複数のデータベースで実行されます。

また、夜間にスケジュールされるパイプラインや、データベース関連のファイルに触れるマージリクエストでも、単一のデータベースでテストを実行します。

単一データベースのテストは、2 つのモードで実行されます:

  1. 一つの接続で一つのデータベース。GitLabが1つの接続プールを使ってすべてのテーブルに接続します。で終わるすべてのジョブを実行します。-single-db
  2. 2つの接続を持つ単一のデータベース。GitLabが異なるデータベース接続を使ってgitlab_main,gitlab_ci データベースのテーブルに接続する場合。これは、-single-db-ci-connectionで終わるすべてのジョブを実行します。

単一のデータベースでテストを実行させたい場合は、マージリクエストにpipeline:run-single-db というラベルを追加します。

モニタリング

GitLabテストスイートはmain ブランチと、名前にrspec-profile を含むブランチを監視しています。

伐採

  • Railsのロギングはパフォーマンス上の理由から、CIではデフォルトでlog/test.log 。この設定を無効にするには、RAILS_ENABLE_TEST_LOG 環境変数を指定します。

マージリクエストのパイプラインタイプ

一般的に、MRのパイプラインは、MRで行われた変更に応じて、以下のタイプ(短いものから長いものまで)のいずれかに分類されます:

パイプライン・タイプ」は抽象的な用語で、主に「クリティカル・パス」(例えば、個々の継続時間の合計がパイプラインの継続時間と等しくなるジョブの連鎖)を表します。私たちはメトリクス・ダッシュボードでこれらの「パイプライン・タイプ」を使用して、最初に最適化する必要があるタイプやジョブを検出します。

複数の領域に接触する MR は、該当する最も長いタイプに関連付けられます。例えば、バックエンドとフロントエンドに触れるMRは、”バックエンド “パイプラインタイプよりも終了に時間がかかるため、”フロントエンド “パイプラインタイプに分類されます。

パイプラインで実行する必要があるジョブを決定するために、rules:needs: キーワードを多用します。複数のタイプの変更を含むMRでは、複数のタイプのジョブを含むパイプラインを持つことに注意してください(例えば、docs-onlyとcode-onlyのパイプラインの組み合わせ)。

以下は、各パイプラインタイプのクリティカルパスのグラフです。クリティカルパスの一部でないジョブは省略されています。

ドキュメントパイプライン

参照パイプライン

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-3["compile-test-assets (5.5 minutes)"]; class 1-3 criticalPath; click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914317&udv=0" 1-6["setup-test-env (3.6 minutes)"]; click 1-6 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914315&udv=0" 1-14["retrieve-tests-metadata"]; click 1-14 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356697&udv=0" 1-15["detect-tests"]; click 1-15 "https://app.periscopedata.com/app/gitlab/652085/EP---Jobs-Durations?widget=10113603&udv=1005715" 2_5-1["rspec & db jobs (24 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-3 & 1-6 & 1-14 & 1-15; ac-1["rspec:artifact-collector (2 minutes)<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設定パフォーマンスページをご覧ください。


開発者向けドキュメントに戻る