リリースモデル
YY.M.patch.build-type という形式に従います。ここで、YY は西暦の下 2 桁、M はリリース月 (先頭に 0 は付きません) 、patch はそのブランチ内のパッチ番号、build は単調増加するビルド番号、type は stable または lts のいずれかです。
例: 25.3.8.23-lts — 2025 年 3 月の LTS、パッチ 8、ビルド 23。
リリーストラックは 2 つあります。
- Stable リリースは、おおむね毎月公開されます。直近 3 つの stable リリースに対してパッチが提供されるため、各リリースのアクティブサポート期間はおよそ 3 か月です。
- LTS (Long-Term Support) リリースは、毎年 3 月と 8 月に公開されます。2 つの LTS バージョンが同時にサポートされ、それぞれ少なくとも 12 か月間サポートされます。
バックポートポリシー
- セキュリティ修正 — 常にバックポートされます。
- 重大なバグ修正 (例外 (論理エラー) 、データ損失、誤った結果、RBAC の問題) — 一般的なバックポートルールに基づいて自動的にバックポート対象に選ばれます。これは
pr-critical-bugfixラベルで識別され、このラベルによりpr-must-backportが自動的に追加されます。 - 安定性やリグレッションの修正 — バグを残すリスクに比べて変更のリスクが低い場合にバックポートされます。これは、メンテナーが手動で追加する
pr-must-backportによって識別されます。 - 回避策がある軽微なバグ修正 — リリースブランチの安定性を損なうのを避けるため、通常はバックポートされません。
- 新機能、改善、パフォーマンス関連の作業 — バックポートされません。
pr-must-backport ラベルは、PR をバックポート対象として示すためにメンテナーが使う手動オーバーライドです。pr-critical-bugfix ラベルが付くと、CI フックによって pr-must-backport が自動的に追加されます (pr_labels_and_category.py を参照) 。
競合のエスカレーション。 自動バックポートでマージ競合を解決できない場合でも、cherry-pick PR は引き続き作成し、元の PR の著者、マージした人、既存の 担当者 に割り当てる必要があります。これにより、人手で競合を解決し、バックポートを完了できます。
Backport Tool
tests/ci/cherry_pick.py の自動化ツールで実装されています。このツールは ClickHouse のインフラストラクチャ上で GitHub Actions ワークフローとして実行され、アクティブなリリースブランチの検出、バックポート対象となるプルリクエストの選定、2 段階の cherry-pick とバックポート手順の実行、競合の管理、遅延ポリシーの適用、ラベルの同期維持など、必要な要件をすべてカバーしています。
長期的な目標は、この実装を、他のプロジェクトでも採用できるスタンドアロンのオープンソース Python ツールとして切り出すことです。想定している設計は次のとおりです。
- 設定可能 — すべてのポリシーパラメーター (対象ラベル、遅延期間、古いプルリクエストのしきい値、rolling-out 時の挙動など) を設定ファイルで表現し、コードを変更しなくても、あらゆるプロジェクトのバックポート要件に合わせてツールを適応できるようにします。
- 配布可能 — ClickHouse の CI インフラストラクチャに依存せず、PyPI からインストール可能な自己完結型の Python wheel としてパッケージ化します。
- プログラム可能 — プルリクエスト、ラベル、リリースブランチを表す明確なオブジェクトモデルを公開し、ユーザーがコアエンジンの上に独自のワークフローをスクリプト化できるようにします。
テスト
- リリースラインを表す、設定可能な一連のブランチ
- さまざまな組み合わせのバックポートラベルが付いたプルリクエスト
- リリースブランチを対象とし、
releaseラベルが付いたリリース PR
rolling-out のスキップ、遅延ポリシーといった自動化ループ全体を検証できます。同じインフラストラクチャは、ポリシー変更をデプロイする前に回帰テストを行うためにも再利用できます。
アクティブなリリースブランチ
release ラベル付き) が GitHub 上でまだオープンになっているブランチを指します。バックポートの自動化では、実行のたびにこれらを動的に検出するため、新しいリリースが作成されたときや古いリリースがサポート終了を迎えたときでも、設定を変更する必要はありません。
新しいリリースのデプロイ中は、リリースブランチが rolling-out 状態 (リリース PR に rolling-out ラベルが付いている状態) になることがあります。ロールアウトを複雑にしないため、rolling-out 状態のブランチでは通常のバックポートは一時停止されます。バージョン固有のラベル (例: v25.3-must-backport) はこの動作を上書きし、ロールアウト中であってもバックポートを強制します。
実装
概要
CherryPick GitHub Actions ワークフロー (.github/workflows/cherry_pick.yml) として 1 時間ごとに実行され、tests/ci/cherry_pick.py に実装されています。GitHub API と、セルフホストの style-checker-aarch64 ランナー上でのローカルな git 操作によって動作します。
このプロセスは、各 (元の PR、リリースブランチ) ペアごとに 2 段階で進みます。
- 実際のマージ先から競合解決を切り離すために、cherry-pick PR が作成されます。競合がなければ、自動的にマージされます。
- 実際のリリースブランチに対して バックポート PR が作成され、チェリーピックされた変更は 1 つのコミットにまとめられます。
ラベル
| ラベル | 効果 |
|---|---|
pr-must-backport | アクティブなすべてのリリースブランチにバックポートします (rolling-out が付いたブランチはスキップ) |
pr-must-backport-force | rolling-out の制限を無視して、アクティブなすべてのリリースブランチにバックポートします |
pr-critical-bugfix | pr-must-backport を自動的にトリガーします (pr_labels_and_category.py 内の AUTO_BACKPORT 経由) |
v{VER}-must-backport (例: v25.3-must-backport) | その特定のリリースブランチにのみバックポートします。そのブランチでは rolling-out によるスキップより優先されます |
pr-backports-created | 必要なバックポート PR がすべて作成されるとボットによって設定されます。cherry-pick PR が再オープンされると解除されます |
pr-cherrypick | ボットが作成した cherry-pick PR に適用されます |
pr-backport | ボットが作成したバックポート PR に適用されます |
do not test | cherry-pick PR で CI が実行されないように適用されます |
rolling-out | そのブランチが現在ロールアウト中であることを示すために、リリース PR に設定されます。通常のバックポートではこのブランチはスキップされます |
ブランチと PR の命名
N とリリースブランチ release/X.Y について:
- cherry-pick ブランチ:
cherrypick/release/X.Y/N - バックポートブランチ:
backport/release/X.Y/N - cherry-pick PR タイトル:
Cherry pick #N to release/X.Y: <original title> - バックポート PR タイトル:
Backport #N to release/X.Y: <original title>
手順
1. アクティブなリリースを特定する
BackportPRs.receive_release_prs は、release ラベルが付いたオープンな PR をすべて GitHub に対して照会します。これらの PR の head ref がリリースブランチ名です (例: release/25.3) 。そこから、v25.3-must-backport などの互換性ラベルのセットが導き出されます。
2. バックポート対象のPRを見つける
BackportPRs.receive_prs_for_backport は GitHub Search API を使って、次の条件を満たすマージ済みPRを検索します。
- 少なくとも 1 つのバックポートラベル (
pr-must-backport、pr-must-backport-force、pr-critical-bugfix、またはバージョン固有のラベル) が付いており、 - まだ
pr-backports-createdが付与されておらず、 - いずれかのリリースブランチで見つかった最も古いコミット日より後にマージされており、
- 過去 90 日以内に更新されている (検索クエリの効率を保つため) 。
3. rolling-out ブランチの処理
rolling-out ラベルが付いている場合、一般的なバックポートラベル (pr-must-backport、pr-critical-bugfix) ではそのブランチはスキップされます。ボットは、そのブランチ向けに以前作成された cherry-pick または バックポート PR を、説明コメント付きでクローズします。バージョン固有のラベル (例: v25.3-must-backport) は、常にこの動作より優先されます。pr-must-backport-force は、すべてのブランチで rolling-out チェックを無視します。
4. Cherry-pick 段階 (ReleaseBranch.create_cherrypick)
- リリースブランチ をチェックアウトし、そこから バックポートブランチ (
backport/release/X.Y/N) を作成します。 - マージコミットの第1親に対して
git merge -s oursを実行し、内容変更を伴わない合成マージベースを作成します。 - 元の PR のマージコミットを直接指す cherry-pick branch (
cherrypick/release/X.Y/N) を強制的に作成します。 - cherry-pick branch を backport branch に
git merge --no-commit --no-ffでマージします。- すでに最新であれば、その変更は リリースブランチ にすでに含まれているため、完了としてマークしてスキップします。
- それ以外の場合は (競合の有無にかかわらず) 、両方のブランチをリセットして push します。
cherrypick/release/X.Y/Nからbackport/release/X.Y/Nへの cherry-pick PR を作成し、pr-cherrypickとdo not testの label を付与します。- 該当する場合は、元の PR から
pr-bugfixまたはpr-critical-bugfixを引き継ぎます。 - この時点では 担当者 は設定しません。担当者 が追加されるのは、競合が検出された場合のみです。
5. 競合のない cherry-pick PR の自動マージ
6. バックポート段階 (ReleaseBranch.create_backport)
- バックポートブランチをチェックアウトし、pull します。
- リリースブランチとバックポートブランチの間の merge-base を見つけます。
- merge-base に対して
git reset --softを実行し、cherry-pick したすべてのコミットを 1 つにまとめます。 - バックポート PR のタイトルをメッセージとしてコミットします。
- バックポートブランチを force-push し、実際のリリースブランチを対象とするバックポート PR を作成します。
- PR に
pr-backportのラベルを付けます (必要に応じてpr-bugfix/pr-critical-bugfixも付けます) 。 - PR を、元の PR の著者、マージしたユーザー、および既存の担当者 (ロボットアカウントを除く) に割り当てます。
7. 完了
pr-backports-createdを追加します。
8. 事前チェック
ReleaseBranch.pre_check は git merge-base --is-ancestor を実行し、そのマージコミットがリリースブランチからすでにたどれる状態にないことを確認します。すでにたどれる状態にある場合、その PR はすでにバックポート済みと見なされ、スキップされます。
Stale Cherry-pick PR の処理
CherryPickPRs クラスは毎時実行の開始時に動作し、次の 2 つのケースを処理します。
- 孤立した cherry-pick PR: cherry-pick PR のリリースブランチに対応するオープンな release PR が存在しなくなった場合 (つまりリリースがクローズされた場合) 、その cherry-pick PR は自動的にクローズされます。
- 再オープンされた cherry-pick PR: original PR にすでに
pr-backports-createdが付いていても、それに対応する cherry-pick PR がまだオープンであれば、original PR からpr-backports-createdラベルが削除され、再処理できるようになります。
- 3 日間更新がない場合、bot は 担当者 にメンションする ping コメントを投稿します。
- 7 日間更新がない場合、bot はクローズする旨のコメントを投稿し、その PR をクローズします。
競合の解決
- cherry-pick PR から
pr-cherrypickラベルを削除します。 cherrypick/...ブランチを削除します。- original PR に
pr-backports-createdがあれば削除します。
バックポート PR 向け CI
ci/workflows/backport_branches.py で定義されている BackportPR) を使用します。このワークフローでは、CI の主要な一部として、ASan/UBSan および TSan ビルド、リリースビルド、macOS ビルド、ASan での機能テスト、TSan でのストレステスト、結合テストを実行します。また、バックポートブランチにコミットが 1〜50 件あり、変更されたファイルが少なくとも 1 つ含まれていることを確認します (check_backport_branch.py によって強制されます) 。
認証
ROBOT_CLICKHOUSE_SSH_KEY) を使用します。GitHub API の呼び出しでは get_best_robot_token による認証を使用し、この関数は SSM (/github-tokens) に保存されたプールから、残り QUOTA が最も多いトークンを選択します。ROBOT_CLICKHOUSE_COMMIT_TOKEN は API 呼び出し用ではなく、Actions ワークフローの checkout step で使用されます。担当者を割り当てる際は、ロボットアカウント (robot-clickhouse、clickhouse-gh) は除外されます。
GitHub API キャッシュ
GitHubCache (cache_utils.py 内) は PyGithub のオブジェクトcacheを S3 に永続化し、毎時の実行をまたぐ API 呼び出しを削減します。cache は各実行の開始時にダウンロードされ、終了時にアップロードされます。
エラー処理
BackportException が送出されます。CI では、これをトリガーとして CIBuddy 経由でチームチャットに通知されます。