mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2026-10-28 16:18:23 +08:00
With the label a pull request runs the LLVM coverage family and nothing else: `Build (llvm_coverage_build)`, the `amd_llvm_coverage` stateless, integration and unit test shards, the `excluded_from_llvm` jobs with their `Build (amd_binary)`, and the `LLVM Coverage` merge job. The flaky check of the changed tests runs on the `amd_binary` build, because the coverage shards run without random settings and never fail the pipeline. The style check stays. Every other job is skipped. Made for pull requests that only add tests and need the coverage report, such as the pull requests of the coverage agent. They use `ci-force-all` so far: about 4,400 machine minutes per push, against about 1,400 with this label. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
347 lines
14 KiB
Python
347 lines
14 KiB
Python
from praktika import Workflow
|
|
|
|
from ci.defs.defs import (
|
|
BASE_BRANCH,
|
|
DOCKERS,
|
|
SECRETS,
|
|
ArtifactConfigs,
|
|
JobNames,
|
|
)
|
|
from ci.defs.job_configs import JobConfigs
|
|
from ci.jobs.scripts.workflow_hooks.filter_job import (
|
|
PR_SINGLE_ARCH_SKIPPED_BUILDS,
|
|
PR_SINGLE_ARCH_SKIPPED_JOBS,
|
|
should_skip_job,
|
|
)
|
|
from ci.jobs.scripts.workflow_hooks.trusted import can_be_tested
|
|
|
|
# PR sanitizer jobs repeat tests related to the change to find intermittent failures.
|
|
# Debug and plain binary jobs run the full suite. Master keeps the full suite in
|
|
# every configuration; coverage-based targeting is specific to pull requests.
|
|
FUNCTIONAL_TESTS_JOBS = JobConfigs.functional_tests_pr_jobs
|
|
|
|
ALL_FUNCTIONAL_TESTS = [job.name for job in FUNCTIONAL_TESTS_JOBS]
|
|
|
|
CORE_BLOCKING_JOB_NAMES = [
|
|
job.name
|
|
for job in FUNCTIONAL_TESTS_JOBS
|
|
if any(
|
|
substr in job.name
|
|
for substr in (
|
|
"_debug, parallel",
|
|
"_binary, parallel",
|
|
"_binary, sequential",
|
|
"_asan_ubsan, db disk, distributed plan, targeted",
|
|
)
|
|
)
|
|
] + [
|
|
job.name
|
|
for job in JobConfigs.integration_test_targeted_pr_jobs
|
|
if "_asan_ubsan, db disk, targeted" in job.name
|
|
] + [
|
|
job.name
|
|
for job in JobConfigs.unittest_jobs
|
|
]
|
|
|
|
STYLE_AND_FAST_TESTS = [
|
|
JobNames.STYLE_CHECK,
|
|
JobNames.FAST_TEST,
|
|
*[j.name for j in JobConfigs.tidy_build_arm_jobs],
|
|
]
|
|
|
|
CODE_REVIEW_BLOCKING_JOBS = [
|
|
JobNames.STYLE_CHECK,
|
|
JobNames.FAST_TEST,
|
|
]
|
|
|
|
REGULAR_BUILD_NAMES = [job.name for job in JobConfigs.build_jobs]
|
|
|
|
PLAIN_FUNCTIONAL_TEST_JOB = [
|
|
j for j in JobConfigs.functional_tests_jobs if "amd_debug, parallel" in j.name
|
|
][0]
|
|
|
|
# Pull requests run the integration tests only in targeted jobs (the changed tests, the
|
|
# tests covering the changed lines and the tests that failed in the PR before, each run
|
|
# once), except for the full `arm_binary` run below and, with the `ci-coverage` or
|
|
# `ci-llvm-coverage` label, the full LLVM coverage run and the tests excluded from it.
|
|
INTEGRATION_TARGETED_JOBS = JobConfigs.integration_test_targeted_pr_jobs
|
|
|
|
# The LLVM coverage jobs run in pull requests only with the `ci-coverage` or `ci-llvm-coverage`
|
|
# label (see `should_skip_job`); by default these `arm_binary` jobs run the same configurations instead.
|
|
# Master runs the coverage jobs on every commit.
|
|
FUNCTIONAL_COVERAGE_REPLACEMENT_JOBS = (
|
|
JobConfigs.functional_tests_arm_binary_coverage_replacement_pr_jobs
|
|
)
|
|
INTEGRATION_COVERAGE_REPLACEMENT_JOBS = (
|
|
JobConfigs.integration_test_arm_binary_coverage_replacement_pr_jobs
|
|
)
|
|
|
|
PLAIN_INTEGRATION_TEST_JOB = [
|
|
j for j in INTEGRATION_TARGETED_JOBS if "(amd_tsan, targeted)" in j.name
|
|
][0]
|
|
|
|
workflow = Workflow.Config(
|
|
name="PR",
|
|
event=Workflow.Event.PULL_REQUEST,
|
|
base_branches=[BASE_BRANCH],
|
|
engine=Workflow.Engine.GH_ACTIONS,
|
|
jobs=[
|
|
JobConfigs.style_check,
|
|
JobConfigs.code_review.set_run_after(CODE_REVIEW_BLOCKING_JOBS),
|
|
JobConfigs.docs_job_mintlify,
|
|
JobConfigs.fast_test,
|
|
*JobConfigs.tidy_build_arm_jobs,
|
|
*[job.set_run_after(STYLE_AND_FAST_TESTS) for job in JobConfigs.build_jobs],
|
|
*[
|
|
job.set_run_after(STYLE_AND_FAST_TESTS)
|
|
for job in JobConfigs.extra_validation_build_jobs
|
|
],
|
|
*[
|
|
job.set_run_after(REGULAR_BUILD_NAMES)
|
|
for job in JobConfigs.release_build_jobs_with_examples
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.special_build_jobs
|
|
],
|
|
# Gated like the regular builds rather than like the special ones: it is the only job
|
|
# that compiles the standalone parser at all, and it needs no build artifact, so there
|
|
# is nothing to gain by deferring it behind the functional tests.
|
|
*[
|
|
job.set_run_after(STYLE_AND_FAST_TESTS)
|
|
for job in JobConfigs.wasm_parser_build_jobs
|
|
],
|
|
*[
|
|
job.set_run_after(STYLE_AND_FAST_TESTS)
|
|
for job in JobConfigs.build_llvm_coverage_job
|
|
],
|
|
# TODO: stabilize new jobs and remove set_allow_failure
|
|
JobConfigs.lightweight_functional_tests_job,
|
|
*[j.set_allow_failure() for j in JobConfigs.stateless_tests_targeted_pr_jobs],
|
|
*[
|
|
job.set_run_after(
|
|
CORE_BLOCKING_JOB_NAMES if job.name not in CORE_BLOCKING_JOB_NAMES else []
|
|
)
|
|
for job in INTEGRATION_TARGETED_JOBS
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.integration_test_contrib_tsan_pr_jobs
|
|
],
|
|
JobConfigs.ast_fuzzer_targeted_pr_jobs[0].set_allow_failure(),
|
|
JobConfigs.ast_fuzzer_targeted_pr_jobs[1].set_allow_failure(),
|
|
*JobConfigs.stateless_tests_flaky_pr_jobs,
|
|
# The merge queue's non-sanitizer flaky check also runs here, so a test
|
|
# that is only too slow (or only flaky) without a sanitizer is reported
|
|
# in the PR rather than first bouncing it from the merge queue. Same job
|
|
# config as in `ci/workflows/merge_queue.py`.
|
|
*JobConfigs.stateless_tests_flaky_mq_jobs,
|
|
*JobConfigs.integration_test_asan_flaky_pr_jobs,
|
|
# Per-arch Bugfix Validation Checks (functional + integration tests on
|
|
# both amd64 and aarch64). Each per-arch variant has
|
|
# `allow_failure=True` so an individual FAIL doesn't block PR merge -
|
|
# the aggregate decision (validate iff at least one arch passed) lives
|
|
# in the `new_tests_check.py` workflow post-hook below.
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.bugfix_validation_ft_pr_jobs
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.bugfix_validation_it_jobs
|
|
],
|
|
# Unit-test (gtest) bugfix validation: a single AMD-only job (allow_failure)
|
|
# that builds a merge-base "before" binary and runs the touched suite against it.
|
|
# It is not part of the per-arch FT/IT aggregation; instead new_tests_check.py
|
|
# blocks the unit case iff this job reported a definitive FAIL (failed to
|
|
# reproduce) — a reproduction or an inconclusive ERROR does not block.
|
|
# Like the sibling FT/IT jobs, it is deferred behind the core blocking jobs.
|
|
JobConfigs.bugfix_validation_ut_job.set_run_after(CORE_BLOCKING_JOB_NAMES),
|
|
*[
|
|
j.set_run_after(
|
|
CORE_BLOCKING_JOB_NAMES if j.name not in CORE_BLOCKING_JOB_NAMES else []
|
|
)
|
|
for j in FUNCTIONAL_TESTS_JOBS
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.functional_tests_jobs_azure
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in FUNCTIONAL_COVERAGE_REPLACEMENT_JOBS
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in INTEGRATION_COVERAGE_REPLACEMENT_JOBS
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.functional_test_llvm_coverage_jobs
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.functional_test_excluded_from_llvm_job
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.integration_test_llvm_coverage_jobs
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.integration_test_excluded_from_llvm_job
|
|
],
|
|
*JobConfigs.unittest_jobs,
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.unittest_llvm_coverage_job
|
|
],
|
|
JobConfigs.docker_server.set_run_after(CORE_BLOCKING_JOB_NAMES),
|
|
JobConfigs.docker_keeper.set_run_after(CORE_BLOCKING_JOB_NAMES),
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.install_check_jobs
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.compatibility_test_jobs
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.stress_test_jobs
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.upgrade_test_jobs
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.ast_fuzzer_jobs
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.buzz_fuzzer_jobs
|
|
],
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.performance_comparison_with_master_head_jobs
|
|
],
|
|
JobConfigs.parser_memory_check_job,
|
|
JobConfigs.storage_memory_check_job,
|
|
# ClickBench runs on PRs only when files in its digest change
|
|
# (see `clickbench_jobs.digest_config`), so the cost is bounded.
|
|
*[
|
|
job.set_run_after(CORE_BLOCKING_JOB_NAMES)
|
|
for job in JobConfigs.clickbench_jobs
|
|
],
|
|
JobConfigs.llvm_coverage_job,
|
|
# Waits for the integration jobs of this workflow, which upload the compliance results.
|
|
# The full `arm_binary` run (or, with `ci-coverage`, the LLVM coverage run) is the one that
|
|
# always runs the compliance suite.
|
|
JobConfigs.promql_compliance_job.set_run_after(
|
|
INTEGRATION_TARGETED_JOBS
|
|
+ INTEGRATION_COVERAGE_REPLACEMENT_JOBS
|
|
+ JobConfigs.integration_test_llvm_coverage_jobs
|
|
+ JobConfigs.integration_test_excluded_from_llvm_job,
|
|
reset=True,
|
|
),
|
|
# TODO: stabilize and remove set_allow_failure
|
|
JobConfigs.build_profile_diff_job.set_allow_failure(),
|
|
JobConfigs.sqllogic_test_master_job.set_run_after(CORE_BLOCKING_JOB_NAMES),
|
|
JobConfigs.sqlstorm_test_job.set_run_after(CORE_BLOCKING_JOB_NAMES),
|
|
JobConfigs.docs_examples_job.set_run_after(CORE_BLOCKING_JOB_NAMES),
|
|
# Keeper stress (PR): 3 no-fault scenarios (prod-mix, read-multi, write-multi),
|
|
# default backend only, 15 min each. Runs when src/Coordination or stress test files change.
|
|
JobConfigs.keeper_stress_job.set_name("Keeper Stress Tests (PR)").set_timeout(
|
|
3 * 3600
|
|
),
|
|
*JobConfigs.toolchain_build_jobs,
|
|
],
|
|
artifacts=[
|
|
*ArtifactConfigs.unittests_binaries,
|
|
*ArtifactConfigs.clickhouse_binaries,
|
|
*ArtifactConfigs.clickhouse_darwin_plain_binaries,
|
|
*ArtifactConfigs.clickhouse_debians,
|
|
*ArtifactConfigs.clickhouse_rpms,
|
|
*ArtifactConfigs.clickhouse_tgzs,
|
|
ArtifactConfigs.clickhouse_wasm,
|
|
ArtifactConfigs.wasm_parser,
|
|
ArtifactConfigs.fuzzers,
|
|
ArtifactConfigs.fuzzers_corpus,
|
|
ArtifactConfigs.clickhouse_examples,
|
|
*ArtifactConfigs.llvm_profdata_file,
|
|
ArtifactConfigs.llvm_coverage_info_file,
|
|
ArtifactConfigs.toolchain_pgo_bolt_amd,
|
|
ArtifactConfigs.toolchain_pgo_bolt_arm,
|
|
],
|
|
dockers=DOCKERS,
|
|
enable_dockers_manifest_merge=True,
|
|
secrets=SECRETS,
|
|
enable_job_filtering_by_changes=True,
|
|
enable_cache=True,
|
|
enable_report=True,
|
|
enable_cidb=True,
|
|
enable_merge_ready_status=True,
|
|
enable_gh_summary_comment=True,
|
|
enable_commit_status_on_failure=False,
|
|
enable_open_issues_check=True,
|
|
enable_slack_feed=True,
|
|
pre_hooks=[
|
|
can_be_tested,
|
|
"python3 ./ci/jobs/scripts/workflow_hooks/ci_links.py",
|
|
"python3 ./ci/jobs/scripts/workflow_hooks/store_data.py",
|
|
"python3 ./ci/jobs/scripts/workflow_hooks/pr_labels_and_category.py",
|
|
"python3 ./ci/jobs/scripts/workflow_hooks/version_log.py",
|
|
"python3 ./ci/jobs/scripts/workflow_hooks/team_notifications.py",
|
|
],
|
|
workflow_filter_hooks=[should_skip_job],
|
|
post_hooks=[
|
|
"python3 ./ci/jobs/scripts/workflow_hooks/pr_body_check.py",
|
|
"python3 ./ci/jobs/scripts/workflow_hooks/feature_docs.py",
|
|
"python3 ./ci/jobs/scripts/workflow_hooks/new_tests_check.py",
|
|
"python3 ./ci/jobs/scripts/workflow_hooks/can_be_merged.py",
|
|
"python3 ./ci/jobs/scripts/workflow_hooks/check_report_messages.py",
|
|
],
|
|
job_aliases={
|
|
# plain integration test job, no dist plan; runs `--test` as a regular job locally
|
|
"integration": PLAIN_INTEGRATION_TEST_JOB.name,
|
|
"fast": "Fast test",
|
|
"functional": PLAIN_FUNCTIONAL_TEST_JOB.name,
|
|
"build_debug": "Build (amd_debug)",
|
|
"build": "Build (amd_binary)",
|
|
},
|
|
runs_on_label_prefix="pr-",
|
|
ai_orchestrator=Workflow.OrchestratorAI.Config(
|
|
enabled=False,
|
|
provider="bedrock",
|
|
model="global.anthropic.claude-sonnet-5",
|
|
),
|
|
)
|
|
|
|
# `should_skip_job` skips these builds together with the stress tests that use them, so
|
|
# no other job may require their binaries: it would find no artifact to download.
|
|
_SINGLE_ARCH_SKIPPED_ARTIFACTS = {
|
|
artifact
|
|
for job in workflow.jobs
|
|
if job.name in PR_SINGLE_ARCH_SKIPPED_BUILDS
|
|
for artifact in job.provides
|
|
}
|
|
assert len(_SINGLE_ARCH_SKIPPED_ARTIFACTS) == len(PR_SINGLE_ARCH_SKIPPED_BUILDS), (
|
|
"every build in PR_SINGLE_ARCH_SKIPPED_BUILDS must be in the PR workflow"
|
|
)
|
|
_SINGLE_ARCH_SKIPPED_ARTIFACT_USERS = [
|
|
job.name
|
|
for job in workflow.jobs
|
|
if job.name not in PR_SINGLE_ARCH_SKIPPED_JOBS
|
|
and _SINGLE_ARCH_SKIPPED_ARTIFACTS & set(job.requires or [])
|
|
]
|
|
assert not _SINGLE_ARCH_SKIPPED_ARTIFACT_USERS, (
|
|
f"jobs {_SINGLE_ARCH_SKIPPED_ARTIFACT_USERS} require binaries of "
|
|
f"{PR_SINGLE_ARCH_SKIPPED_BUILDS}, which pull requests skip: remove the build "
|
|
"from PR_SINGLE_ARCH_SKIPPED_BUILDS in ci/jobs/scripts/workflow_hooks/filter_job.py"
|
|
)
|
|
|
|
WORKFLOWS = [
|
|
workflow,
|
|
]
|