mirror of
https://github.com/hanzoai/datastore.git
synced 2026-09-26 13:55:07 +00:00
Use BASE_COMMIT for changed_files, FIRST_BASE_COMMIT only for changes.diff The previous fix anchored both the genhtml diff and the changed-files query at FIRST_BASE_COMMIT. This caused master commits in the gap between FIRST_BASE_COMMIT and BASE_COMMIT to appear as PR-changed files: a src/Foo.cpp edit from that gap would end up in _changed_paths, flip _binary_unchanged=False, and suppress the newly-covered analysis even though the PR binary was genuinely unchanged. Fix: use FIRST_BASE_COMMIT only for changes.diff (so genhtml line-number remapping matches the baseline's coordinate system), and keep BASE_COMMIT for the changed_files query (so patterns and _changed_paths reflect only what the PR itself changed). Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
174 lines
6.4 KiB
Bash
Executable File
174 lines
6.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# CI: only C/C++ source files are extracted for differential coverage analysis.
|
|
# Non-C++ changes (cmake, scripts, tests, configs) are intentionally skipped.
|
|
set -euo pipefail
|
|
|
|
# Validate required env vars
|
|
for var in PREV_30_COMMITS CURRENT_COMMIT BASE_COMMIT BRANCH BASE_BRANCH WORKSPACE_PATH; do
|
|
if [ -z "${!var:-}" ]; then
|
|
echo "ERROR: Required environment variable $var is not set"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
cd ci/tmp
|
|
|
|
if [[ ! -f "llvm_coverage.info" ]]; then
|
|
echo "ERROR: llvm_coverage.info not found"
|
|
exit 1
|
|
fi
|
|
|
|
# Try to find .info file from S3, checking up to 30 ancestor commits
|
|
IFS=',' read -ra COMMITS <<< "${PREV_30_COMMITS}"
|
|
|
|
FOUND=0
|
|
FIRST_BASE_COMMIT=""
|
|
for TEST_COMMIT in "${COMMITS[@]}"; do
|
|
COVERAGE_URL="https://clickhouse-builds.s3.amazonaws.com/REFs/master/${TEST_COMMIT}/llvm_coverage/llvm_coverage.info"
|
|
echo "Checking coverage file for commit ${TEST_COMMIT}..."
|
|
if wget --spider "${COVERAGE_URL}" 2>&1 | grep -q '200 OK'; then
|
|
echo "Found coverage file at ${COVERAGE_URL}"
|
|
wget --quiet "${COVERAGE_URL}" -O base_llvm_coverage.info
|
|
FIRST_BASE_COMMIT="${TEST_COMMIT}"
|
|
# Record which commit this baseline came from so line-number remapping
|
|
# in print_newly_covered_code.py can compute git diffs against extras.
|
|
echo "${TEST_COMMIT}" > base_llvm_coverage.sha
|
|
FOUND=1
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ $FOUND -eq 0 ]; then
|
|
echo "ERROR: Could not find baseline coverage file after checking ${#COMMITS[@]} commits"
|
|
exit 1
|
|
fi
|
|
|
|
# Note: additional older master baselines for cross-validation in the
|
|
# newly-covered analysis are downloaded on demand in llvm_coverage_job.py,
|
|
# only when the newly-covered analysis will actually run (tests-only PR,
|
|
# binary unchanged). Doing it here would fetch ~530 MB per baseline even for
|
|
# PRs where the analysis is suppressed.
|
|
|
|
export CURRENT_COMMIT
|
|
export BASE_COMMIT
|
|
export FIRST_BASE_COMMIT
|
|
export PR_NUMBER
|
|
export REPO_NAME
|
|
|
|
# Two separate ranges serve two different purposes:
|
|
#
|
|
# 1. changes.diff (for genhtml --diff-file): anchored at FIRST_BASE_COMMIT so
|
|
# the diff maps the baseline's line numbers to current. The baseline .info was
|
|
# produced at FIRST_BASE_COMMIT, so the "before" side of the diff must match.
|
|
#
|
|
# 2. changed_files (for pattern extraction and downstream analysis): anchored at
|
|
# BASE_COMMIT (the actual PR merge base) so we only see files the PR itself
|
|
# changed. Using FIRST_BASE_COMMIT here would pull in unrelated master commits
|
|
# from the gap between FIRST_BASE_COMMIT and BASE_COMMIT — a src/Foo.cpp edit
|
|
# from that gap would appear in patterns, set _diff_ran=True, and then cause
|
|
# llvm_coverage_job.py to parse it into _changed_paths, flipping
|
|
# _binary_unchanged=False and suppressing the newly-covered analysis even
|
|
# though the PR binary is genuinely unchanged.
|
|
gh api \
|
|
-H "Accept: application/vnd.github.v3.diff" \
|
|
repos/ClickHouse/ClickHouse/compare/${FIRST_BASE_COMMIT}...${CURRENT_COMMIT} \
|
|
> changes.diff
|
|
changed_files=$(gh api \
|
|
repos/ClickHouse/ClickHouse/compare/${BASE_COMMIT}...${CURRENT_COMMIT} \
|
|
--jq '.files[].filename'
|
|
)
|
|
echo "Changed files:"
|
|
echo "$changed_files"
|
|
|
|
if [ -z "$changed_files" ]; then
|
|
echo "ERROR: No changed files reported by GitHub compare API"
|
|
exit 1
|
|
fi
|
|
|
|
patterns=()
|
|
while IFS= read -r f; do
|
|
# Only include C/C++ source files that can appear in lcov coverage data.
|
|
# Skip contrib/ files — coverage is disabled for third-party code, so they
|
|
# produce no records in the tracefile and cause lcov to fail with "(empty)".
|
|
if [[ "$f" =~ \.(cpp|cc|cxx|c|h|hpp|hxx|hh)$ ]] && [[ ! "$f" =~ ^contrib/ ]]; then
|
|
patterns+=("*$f")
|
|
fi
|
|
done < <(echo "$changed_files")
|
|
|
|
if [ ${#patterns[@]} -eq 0 ]; then
|
|
echo "No coverable C/C++ source files changed (contrib/ is excluded from coverage), skipping differential coverage report"
|
|
exit 0
|
|
fi
|
|
|
|
lcov --extract llvm_coverage.info "${patterns[@]}" \
|
|
--ignore-errors inconsistent,corrupt,empty,unsupported,unused \
|
|
--quiet \
|
|
-o current.changed.info
|
|
|
|
lcov --extract base_llvm_coverage.info "${patterns[@]}" \
|
|
--ignore-errors inconsistent,corrupt,empty,unsupported,unused \
|
|
--quiet \
|
|
-o baseline.changed.info
|
|
|
|
# Extract the same changed-file slice from each extra master baseline that was
|
|
# downloaded by llvm_coverage_job.py for LBC cross-validation. These small
|
|
# files (one per changed C/C++ file, same patterns as baseline.changed.info)
|
|
# are passed to print_uncovered_code.py which intersects them to avoid
|
|
# false-positive LBC alerts caused by lines that only occasionally fire in
|
|
# background/async code.
|
|
for slot in 2 3 4 5 6; do
|
|
src="base_llvm_coverage_${slot}.info"
|
|
if [ -f "$src" ] && [ -s "$src" ]; then
|
|
lcov --extract "$src" "${patterns[@]}" \
|
|
--ignore-errors inconsistent,corrupt,empty,unsupported,unused \
|
|
--quiet \
|
|
-o "baseline_${slot}.changed.info"
|
|
echo "Extracted changed-file slice from extra baseline #${slot}."
|
|
fi
|
|
done
|
|
|
|
current_sf_count=$(grep -c '^SF:' current.changed.info 2>/dev/null || true)
|
|
baseline_sf_count=$(grep -c '^SF:' baseline.changed.info 2>/dev/null || true)
|
|
|
|
if [ "$current_sf_count" -eq 0 ] && [ "$baseline_sf_count" -eq 0 ]; then
|
|
echo "No coverage data found for changed files (files may be new or not instrumented), skipping differential coverage report"
|
|
exit 0
|
|
fi
|
|
|
|
if [ "$current_sf_count" -eq 0 ]; then
|
|
echo "Current coverage is empty for changed files (tests may have been removed or disabled). Skipping genhtml — LBC analysis will run separately."
|
|
exit 0
|
|
fi
|
|
|
|
echo "Workspace path: $WORKSPACE_PATH"
|
|
|
|
HEADER_TITLE="differential coverage report"
|
|
if [ -n "${PR_NUMBER}" ]; then
|
|
PR_URL="https://github.com/ClickHouse/ClickHouse/pull/${PR_NUMBER}"
|
|
HEADER_TITLE="<a href=\"${PR_URL}\">${PR_URL}</a>"
|
|
fi
|
|
|
|
genhtml \
|
|
--header-title "${HEADER_TITLE}" \
|
|
--title "branch=${BRANCH}, current_commit=${CURRENT_COMMIT}" \
|
|
--baseline-title "base_branch=${BASE_BRANCH}, baseline_commit=${FIRST_BASE_COMMIT}" \
|
|
--baseline-file baseline.changed.info \
|
|
--diff-file changes.diff \
|
|
--output-directory llvm_coverage_diff_html_report \
|
|
--no-function-coverage \
|
|
--css-file $WORKSPACE_PATH/ci/jobs/scripts/css.css \
|
|
--prefix $WORKSPACE_PATH \
|
|
--substitute "s|/home/ubuntu/actions-runner/_work/ClickHouse/ClickHouse|$WORKSPACE_PATH|g" \
|
|
--ignore-errors inconsistent \
|
|
--ignore-errors corrupt \
|
|
--ignore-errors path \
|
|
--ignore-errors source \
|
|
--ignore-errors range \
|
|
--ignore-errors empty \
|
|
--ignore-errors unused \
|
|
--simplified-colors \
|
|
--filter missing \
|
|
--flat \
|
|
current.changed.info
|
|
|