> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> Обзор системы непрерывной интеграции ClickHouse

# Непрерывная интеграция (CI)

Когда вы отправляете pull request, система [непрерывной интеграции (CI)](/docs/ru/resources/develop-contribute/contribute/tests#test-automation) ClickHouse запускает для вашего кода ряд автоматических проверок.
Это происходит после того, как мейнтейнер репозитория (кто-то из команды ClickHouse) просмотрит ваш код и добавит к вашему pull request метку `can be tested`.
Результаты проверок отображаются на странице pull request в GitHub, как описано в [документации GitHub о проверках](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-status-checks).
Если какая-либо проверка завершается ошибкой, вам может потребоваться её исправить.
На этой странице приведён обзор проверок, с которыми вы можете столкнуться, и того, что можно сделать для их исправления.

Если похоже, что сбой проверки не связан с вашими изменениями, это может быть временный сбой или проблема с инфраструктурой.
Отправьте пустой коммит в pull request, чтобы перезапустить проверки CI:

```shell theme={null}
git commit --allow-empty
git push
```

Если вы не уверены, что делать, обратитесь за помощью к мейнтейнеру.

<div id="merge-with-master">
  ## Слияние с master
</div>

Проверяет, можно ли слить PR с веткой master.
Если нет, проверка завершится с сообщением `Cannot fetch mergecommit`.
Чтобы эта проверка прошла, разрешите конфликт слияния, как описано в [документации GitHub](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-on-github), или слейте ветку `master` в ветку вашего pull request с помощью git.

<div id="docs-check">
  ## Проверка документации (Mintlify)
</div>

Проверяет документацию Mintlify, внутренние ссылки и якоря, перенаправления, импорты фрагментов и журналы изменений. Ошибки внешних ссылок отображаются как предупреждения.
Также отклоняет прямые изменения в сгенерированных разделах и копиях документации, доступных только для чтения. Вместо этого обновляйте структурированную документацию в исходной регистрации; намеренные изменения в сгенерированной документации должны иметь метку `pr-autogenerated-docs`.
Если после изменения документации проверка завершается сбоем, откройте её отчёт и найдите сообщения `ERROR` и `WARNING`.

<div id="description-check">
  ## Проверка описания
</div>

Проверьте, что описание вашего pull request соответствует шаблону [PULL\_REQUEST\_TEMPLATE.md](https://github.com/ClickHouse/ClickHouse/blob/master/.github/PULL_REQUEST_TEMPLATE.md).
Вы должны указать категорию в changelog для вашего изменения (например, Bug Fix) и написать понятное пользователю сообщение с описанием этого изменения для [CHANGELOG.md](/docs/ru/resources/changelogs/oss/2026)

<div id="docker-image">
  ## Docker-образ
</div>

Собирает Docker-образы сервера ClickHouse и Keeper, чтобы убедиться, что их сборка проходит корректно.

<div id="official-docker-library-tests">
  ### Тесты официальной библиотеки Docker
</div>

Запускаются тесты из [официальной библиотеки Docker](https://github.com/docker-library/official-images/tree/master/test#alternate-config-files), чтобы убедиться, что Docker-образ `clickhouse/clickhouse-server` работает корректно.

Чтобы добавить новые тесты, создайте каталог `ci/jobs/scripts/docker_server/tests/$test_name` и поместите в него скрипт `run.sh`.

Дополнительные сведения о тестах можно найти в [документации по скриптам CI-задач](https://github.com/ClickHouse/ClickHouse/tree/master/ci/jobs/scripts/docker_server).

<div id="marker-check">
  ## Проверка маркера
</div>

Эта проверка означает, что система CI начала обрабатывать pull request.
Статус 'pending' означает, что запущены ещё не все проверки.
После запуска всех проверок статус изменится на 'success'.

<div id="style-check">
  ## Проверка стиля
</div>

Выполняет различные проверки стиля кодовой базы. Каждая из перечисленных ниже проверок соответствует `testname` в [`ci/jobs/check_style.py`](https://github.com/ClickHouse/ClickHouse/blob/master/ci/jobs/check_style.py) и может быть запущена отдельно с помощью `--test <name>` (см. ниже).

<div id="cpp">
  ##### cpp
</div>

Проверки стиля C++ на основе регулярных выражений с помощью [`check_cpp.sh`](https://github.com/ClickHouse/ClickHouse/blob/master/ci/jobs/scripts/check_style/check_cpp.sh). Если проверка завершилась ошибкой, исправьте проблемы со стилем в соответствии с [руководством по стилю кода](/docs/ru/resources/develop-contribute/contribute/style).

<div id="whitespace-check">
  ##### whitespace\_check
</div>

Выявляет двойные пробелы после запятых в C++, если они не используются для выравнивания столбцов.

<div id="catch-all">
  ##### catch\_all
</div>

Запрещает `catch (...)` вне деструкторов, `main` и точек входа фаззера, где небезопасно подавлять неизвестные исключения.

<div id="yamllint">
  ##### yamllint
</div>

Проверяет YAML-файлы workflow в каталоге `.github/` с помощью `.yamllint`.

<div id="xmllint">
  ##### xmllint
</div>

Проверяет XML-файлы в каталогах `tests/` и `programs/`.

<div id="functional-tests-check">
  ##### functional\_tests\_check
</div>

Проверяет тесты без сохранения состояния: в запросах с фильтрацией по `event_date` следует использовать `>= yesterday()`, а не `today()` (чтобы избежать нестабильности на границе полуночи), а имена файлов тестов не должны содержать `fail`.

<div id="test-numbers-check">
  ##### test\_numbers\_check
</div>

Выявляет большие пропуски в нумерации тестов без сохранения состояния (`tests/queries/0_stateless/<NNNNN>_*`).

<div id="symlinks">
  ##### симлинки
</div>

Обнаруживает неработающие симлинки в репозитории.

<div id="various">
  ##### разное
</div>

Прочие проверки репозитория через [`various_checks.sh`](https://github.com/ClickHouse/ClickHouse/blob/master/ci/jobs/scripts/check_style/various_checks.sh): запросы к `system.query_log` / `system.parts` / etc. должны фильтроваться по `currentDatabase`, пути ZooKeeper для `Replicated*MergeTree` должны включать отдельный префикс для каждого теста, каталоги интеграционных тестов должны содержать `__init__.py`, файлы не должны содержать UTF BOM, у исходных файлов и файлов данных не должно быть бита исполняемости, в сторонних образах docker-compose нельзя использовать тег `:latest` и многое другое.

<div id="running-style-check-locally">
  ### Запуск задачи проверки стиля локально
</div>

Всю задачу *проверки стиля* можно запустить локально в контейнере Docker с помощью:

```sh theme={null}
python -m ci.praktika run "Style check"
```

Чтобы запустить конкретную проверку (например, *cpp*):

```sh theme={null}
python -m ci.praktika run "Style check" --test cpp
```

Эти команды загружают Docker-образ `clickhouse/style-test` и запускают задачу в контейнерной среде.
Никаких дополнительных зависимостей, кроме Python 3 и Docker, не требуется.

<div id="running-stateless-tests">
  ## Запуск тестов без сохранения состояния
</div>

Локально установленный ClickHouse с настройками по умолчанию может подойти для отдельных тестовых сценариев, но не позволяет корректно выполнять все тестовые запросы. В CI для каждой задачи применяется определённая конфигурация ClickHouse (например, хранилище S3, параллельные реплики), и вручную воспроизвести её бывает затруднительно. Чтобы этого избежать, вы можете локально воспроизвести любую задачу CI, используя ту же оркестрацию, что и в CI, — ручная настройка не требуется.

<div id="ci-prerequisites">
  #### Необходимые условия
</div>

* Python 3 (только стандартная библиотека)
* Docker

При необходимости установите Docker в Ubuntu и войдите в систему заново:

```sh theme={null}
sudo apt-get update
sudo apt-get install docker.io
sudo usermod -aG docker "$USER"
sudo tee /etc/docker/daemon.json <<'EOF'
{
  "ipv6": true,
  "ip6tables": true
}
EOF
sudo systemctl restart docker
```

<div id="run-ci-job-locally">
  #### Запустите задачу CI локально
</div>

Выберите любое название задачи из отчёта CI и запустите её локально:

```bash theme={null}
python -m ci.praktika run "<JOB_NAME>"
```

* Всегда указывайте имя задачи в кавычках и в точности так, как оно приведено в отчёте CI (оно может содержать пробелы и запятые), например: `"Stateless tests (amd_debug, parallel)"`. Это задаёт ту же конфигурацию ClickHouse и запускает те же тесты, что и в CI.
* Архитектура и тип сборки в имени задачи (например, `amd_debug`) — это метки, специфичные для CI. При локальном запуске они ни на что не влияют: задача будет использовать тот бинарный файл, который вы указали, и ту архитектуру, на которой вы её запускаете. Имя задачи определяет только конфигурацию ClickHouse и набор тестов (если это не переопределено через `--test`).
* В CI функциональные тесты разделены на батчи для более эффективного использования ресурсов. Например, `"Stateless tests (amd_debug, parallel)"` и `"Stateless tests (amd_debug, sequential)"` вместе охватывают весь объём: тесты, безопасные для параллельного запуска, выполняются одновременно, а остальные — последовательно. Такое разделение сокращает общее время CI, максимально используя параллелизм там, где это возможно. Чтобы локально воспроизвести полный набор тестов, запустите оба батча.
* Также есть задача CI `"Fast test"`, которая запускает ограниченный набор функциональных тестов для проверки базовой работоспособности ClickHouse. Она использует сборку не со всеми необязательными модулями и позволяет быстрее всего обнаружить регрессии. Её можно запустить локально тем же способом. Поместите бинарный файл ClickHouse в один из стандартных путей поиска (`./ci/tmp/clickhouse`, `./build/programs/clickhouse` или `./clickhouse`) — иначе задача сначала попытается собрать ClickHouse:
  ```bash theme={null}
  python -m ci.praktika run "Fast test"
  ```

<div id="run-specific-tests-within-ci-job">
  #### Запуск отдельных тестов в рамках задачи CI
</div>

С `--test` задача подготавливает ту же конфигурацию ClickHouse, что используется в CI, но запускает только выбранные тесты:

```bash theme={null}
python -m ci.praktika run "Stateless tests (amd_debug, parallel)" \
  --test 00001_select1
```

* Можно указать несколько имен тестов:
  ```bash theme={null}
  python -m ci.praktika run "Stateless tests (amd_debug, parallel)" \
    --test 00001_select1 00002_log_and_exception_messages_formatting
  ```
* Совет: если подходит любая конфигурация ClickHouse и вам нужно запустить только определенные тесты, используйте псевдоним `functional` вместо полного имени задачи:
  ```bash theme={null}
  python -m ci.praktika run functional --test 00001_select1
  ```

<div id="additional-customization-options">
  #### Дополнительные параметры настройки
</div>

* `--path PATH` — пользовательский путь к бинарному файлу ClickHouse. По умолчанию runner ищет в следующем порядке: `./ci/tmp/clickhouse`, `./build/programs/clickhouse`, `./clickhouse`.
* `--count N` — повторить каждый тест N раз.
* `--workers N` — переопределить автоматический расчёт числа параллельных воркеров на основе ресурсов машины.

<div id="build-check">
  ## Проверка сборки
</div>

Сборка ClickHouse в различных конфигурациях для использования на следующих этапах.

<div id="running-builds-locally">
  ### Локальный запуск сборок
</div>

Сборки можно запускать локально в среде, близкой к CI, с помощью:

```bash theme={null}
python -m ci.praktika run "<BUILD_JOB_NAME>"
```

Никаких зависимостей, кроме Python 3 и Docker, не требуется.

<div id="available-build-jobs">
  #### Доступные задачи сборки
</div>

Названия задач сборки в точности совпадают с тем, как они указаны в отчёте CI:

**Сборки AMD64:**

* `Build (amd_debug)` - Отладочная сборка с символами
* `Build (amd_release)` - Оптимизированная релизная сборка
* `Build (amd_asan)` - Сборка с Address Sanitizer
* `Build (amd_tsan)` - Сборка с Thread Sanitizer
* `Build (amd_msan)` - Сборка с Memory Sanitizer
* `Build (amd_ubsan)` - Сборка с Undefined Behavior Sanitizer
* `Build (amd_binary)` - Быстрая релизная сборка без Thin LTO
* `Build (amd_compat)` - Сборка для старых систем
* `Build (amd_musl)` - Сборка с musl libc
* `Build (amd_darwin)` - Сборка для macOS
* `Build (amd_freebsd)` - Сборка для FreeBSD

**Сборки ARM64:**

* `Build (arm_release)` - Оптимизированная релизная сборка ARM64
* `Build (arm_asan)` - Сборка ARM64 с Address Sanitizer
* `Build (arm_coverage)` - Сборка ARM64 с инструментированием для анализа покрытия
* `Build (arm_binary)` - Быстрая релизная сборка ARM64 без Thin LTO
* `Build (arm_darwin)` - Сборка ARM64 для macOS
* `Build (arm_v80compat)` - Сборка для совместимости с ARMv8.0

**Другие архитектуры:**

* `Build (ppc64le)` - PowerPC 64-bit Little Endian
* `Build (riscv64)` - 64-разрядная RISC-V
* `Build (s390x)` - 64-разрядная IBM System/390
* `Build (loongarch64)` - 64-разрядная LoongArch
* `Build (wasm64)` - 64-разрядный WebAssembly через Emscripten. Экспериментальная: собирает бинарный файл `clickhouse` и проверяет, что `clickhouse local` выполняет запросы в Node.js ≥ 24 (модуль также работает в браузерах, но CI пока этого не проверяет)

Если задача завершается успешно, результаты сборки будут доступны в каталоге `<repo_root>/ci/tmp/build`.

**Примечание:** Для сборок, не относящихся к категории "Другие архитектуры" (в которой используется кросс-компиляция), архитектура локальной машины должна соответствовать типу сборки, чтобы получить сборку, указанную в `BUILD_JOB_NAME`.

<div id="example-run-local">
  #### Пример
</div>

Чтобы запустить локальную отладочную сборку:

```bash theme={null}
python -m ci.praktika run "Build (amd_debug)"
```

Если описанный выше подход вам не подходит, используйте параметры cmake из журнала сборки и следуйте [общей процедуре сборки](/docs/ru/resources/develop-contribute/build/build).

<div id="functional-stateless-tests">
  ## Функциональные тесты без сохранения состояния
</div>

Запускает [функциональные тесты без сохранения состояния](/docs/ru/resources/develop-contribute/contribute/tests#functional-tests) для бинарных файлов ClickHouse, собранных в различных конфигурациях — release, debug, с санитайзерами и т. д.
Посмотрите отчет, чтобы понять, какие тесты завершаются ошибкой, а затем воспроизведите сбой локально, как описано [здесь](/docs/ru/resources/develop-contribute/contribute/tests#functional-tests).
Обратите внимание: для воспроизведения нужно использовать правильную конфигурацию сборки — тест может завершаться ошибкой с AddressSanitizer, но проходить в Debug.
Скачайте бинарный файл со [страницы CI build checks](/docs/ru/get-started/setup/self-managed/advanced) или соберите его локально.

<div id="integration-tests">
  ## Интеграционные тесты
</div>

Запускает [интеграционные тесты](/docs/ru/resources/develop-contribute/contribute/tests#integration-tests).

<div id="bugfix-validate-check">
  ## Проверка валидации исправления ошибки
</div>

Проверяет, что либо добавлен новый тест (функциональный или интеграционный), либо есть изменённые тесты, которые завершаются ошибкой при запуске с бинарным файлом, собранным из ветки master.
Эта проверка запускается, когда у pull request есть метка "pr-bugfix".

<div id="stress-test">
  ## Стресс-тест
</div>

Запускает функциональные тесты без сохранения состояния одновременно с нескольких клиентов, чтобы выявить ошибки, связанные с параллелизмом. Если тест завершается сбоем:

* Сначала устраните все остальные сбои тестов;
  * Просмотрите отчет, чтобы найти журналы сервера, и проверьте их на наличие возможных причин
    ошибки.

<div id="compatibility-check">
  ## Проверка совместимости
</div>

Проверяет, запускается ли бинарный файл `clickhouse` в дистрибутивах со старыми версиями libc.
Если нет, обратитесь за помощью к мейнтейнеру.

<div id="ast-fuzzer">
  ## AST-фаззер
</div>

Запускает случайно сгенерированные запросы, чтобы выявлять ошибки в программе.
Если он завершается сбоем, обратитесь за помощью к мейнтейнеру.

<div id="performance-tests">
  ## Тесты производительности
</div>

Оценивайте изменения в производительности запросов.
Это самая длительная проверка, её выполнение занимает чуть менее 6 часов.
Отчёт о тестах производительности подробно описан [здесь](https://github.com/ClickHouse/ClickHouse/blob/master/tests/performance/scripts/README.md#how-to-read-the-report).

<div id="revert-ci-regressions">
  ## Откат регрессий CI
</div>

Это не проверка вашего pull request: задача запускается в `master` каждый час и может откатить уже слитый pull request.

Задача берёт сбойные тесты, записанные базой данных CI для `master` за последние 24 часа, и группирует их по имени теста во всех проверках, где этот тест завершился сбоем.
Сбой одного и того же теста в отладочной сборке и сборке tsan считается одним сбоем с одной причиной, которую нужно найти; проверки, в которых он проявился, становятся доказательствами в расследовании: изменение, ломающие тест, обычно ломает его сразу в нескольких сборках.
Сбои, не связанные ни с каким тестом, например сбой сборки или задача, превысившая лимит времени, исключаются: на вопрос «почему эта проверка завершается сбоем» нет единственного ответа, который можно было бы откатить.
Строки, которые тестовая обвязка записывает обо всём скрипте под именем, похожим на имя теста, например `Test script failed` или `Server died`, исключаются по той же причине.
Тест, завершившийся сбоем более чем на одном коммите `master`, передаётся AI-агенту, которому предоставляются репозиторий с полной историей `master` и доступ к базе данных CI только для чтения; он отвечает на один вопрос: был ли этот сбой внесён недавно слитым pull request и каким именно.
У агента нет учётных данных GitHub и возможности их создать — он запускается от имени отдельного непривилегированного пользователя с пустым окружением, а конечные точки облачных учётных данных для этого пользователя заблокированы межсетевым экраном. Агент работает в одноразовом клоне репозитория, а не в checkout задачи, поэтому ни его выводы, ни оставленные им данные не могут попасть в GitHub иначе как через описанные ниже проверки.
Порог учитывает коммиты, а не строки со сбоями, поэтому один проблемный коммит, в котором сбой возникает в трёх сборках, всё равно считается одним случаем и не приводит к действиям.
Также учитывается режим сбоя: в записанных выводах нормализуются изменчивые части (адреса, временные метки, случайные имена баз данных), а тест, имя которого охватывает две разные причины — регрессию в одном коммите и несвязанный флейк в другом, — не считается повторно сбойным. Поэтому расследование не начинается, пока одна и та же причина не повторится сама по себе.

К действию приводит только однозначный ответ.
Когда агент с высокой уверенностью сообщает о регрессии, а указанный pull request проходит проверки безопасности (слит в `master` в течение последних трёх дней, сам не является откатом, ещё не был откатан и откат применяется без конфликтов), задача откатывает его, немедленно сливает откат, не дожидаясь проверок, и открывает черновик pull request с заголовком `Reapply "..."`, повторно вносящий изменение.
Вердикт о регрессии должен указывать и pull request, и коммит `master`, которым он был внесён, и они должны соответствовать друг другу: задача сверяет номер с записью GitHub о коммите слияния, созданном этим pull request, и не предпринимает никаких действий, если они не совпадают.
Если сбой уже исчез, ничего не откатывается: после исчезновения сбой остаётся в окне наблюдения ещё целый день, поэтому непосредственно перед откатом задача снова запрашивает базу данных CI. Сбой, отсутствующий в новейших коммитах `master`, которые были обработаны всеми затронутыми проверками, отмечается как уже исправленный и игнорируется.
Новейшие коммиты определяются по собственной истории ветки, а не по времени запуска их проверок: старый коммит, проверка которого началась поздно, не должен считаться свежим свидетельством успешного прохождения.
Учитывается отсутствие, а не успешное прохождение, поскольку для большинства случаев, которые расследует эта задача, нет строки об успешном прохождении: логическая ошибка или зависшая проверка записывается под текстом самого сбоя и только в момент его возникновения.
Проверка считается обработавшей коммит только тогда, когда её запуск прошёл все тесты: запуск, прерванный на середине — записанный обвязкой как `Test script failed` или `Server died` рядом со строками тестов, которые он успел создать, — выполнил *некоторые* тесты, но не обязательно этот. Поэтому отсутствие упоминания сбоя не является доказательством, в отличие от повторного запуска той же проверки, успешно завершившегося на том же коммите.
То, насколько длительное отсутствие считается достаточным, зависит от частоты сбоя: пара чистых коммитов ничего не значит для сбоя, возникающего в одном запуске из ста, поэтому требуется период отсутствия, превышающий самый длинный зафиксированный промежуток между проявлениями этого сбоя.
Если на вопрос вообще невозможно ответить — проверка, в которой наблюдался сбой, больше не сообщает о нём под этим именем или история коммитов с начала сбоя длиннее, чем возвращает запрос, — это также записывается, и ничего не откатывается.
За один запуск откатывается не более двух pull request.

Если ваш pull request был откатан:

* В pull request с откатом объясняется, что завершается сбоем и почему изменение сочли причиной. Если атрибуция неверна, сообщите об этом там и верните изменение.
* Черновик pull request `Reapply "..."` содержит ваше изменение без изменений. Исправьте сбой в этой ветке, отметьте pull request как готовый к проверке и дайте ему пройти обычный CI.

Каждое расследование фиксируется в таблице `checks_investigated` базы данных CI, включая те, которые не приводят ни к какому откату.
Значения переносятся из `checks` в том виде, в каком они были там зафиксированы, поэтому две таблицы можно связать обратно: напрямую по `test_name`; с помощью `has(check_names, check_name)` и `has(commit_shas, commit_sha)` — для столбцов, объединяющих несколько строк `checks` в массив; а также с помощью `offending_pull_request_number = pull_request_number` — для pull request, признанного причиной проблемы. Историю того, что проверяла задача, к каким выводам она пришла и что сделала, можно запросить на [play.clickhouse.com](https://play.clickhouse.com/):

```sql theme={null}
SELECT investigation_time, test_name, check_names, failure_count, commit_count, verdict, confidence, action, explanation
FROM checks_investigated
WHERE investigation_time >= now() - INTERVAL 7 DAY
ORDER BY investigation_time DESC;
```

Задача реализована в `ci/jobs/revert_ci_regressions.py` и выполняется в рамках workflow `Hourly`.
Запуск с параметром `--dry-run` проверяет и оценивает каждое условие, но ничего не изменяет: не создаёт ни таблицу, ни строки, ни ветку, ни pull request, ни слияние; вместо этого выводятся строки, которые были бы записаны.
Отдельный workflow `.github/workflows/revert_broken_prs.yml` откатывает слияния, выполненные при красном CI соответствующих pull request; оба используют одно и то же имя ветки `revert-<pull request number>`, поэтому один pull request никогда не откатывается дважды.
Откат, запущенный вручную, тоже учитывается: задача не выполняется, если откат уже присутствует в `master`, существует ветка с именем `revert-<pull request number>` или `revert-<pull request number>-<branch>` (такую создаёт кнопка `Revert` в GitHub) либо если pull request из такой ветки открыт или слит.
