-
Notifications
You must be signed in to change notification settings - Fork 0
200 lines (180 loc) · 7.6 KB
/
ci.yml
File metadata and controls
200 lines (180 loc) · 7.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# =============================================================================
# ci.yml -- GitHub Actions CI for chbackup
# =============================================================================
# Jobs:
# check -- cargo fmt, clippy, test (fast feedback, no Docker)
# integration -- ClickHouse version matrix with real S3 (builds from source in Docker)
#
# Required GitHub Secrets:
# TEST_S3_BUCKET -- S3 bucket name for integration tests
# TEST_S3_ACCESS_KEY -- AWS access key ID
# TEST_S3_SECRET_KEY -- AWS secret access key
# TEST_S3_REGION -- (optional) AWS region, defaults to us-east-1
# =============================================================================
name: CI
on:
push:
branches: [main, master]
pull_request:
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-D warnings"
jobs:
# ---------------------------------------------------------------------------
# Job 1: Fast checks (no Docker required)
# ---------------------------------------------------------------------------
check:
name: Check (fmt + clippy + test)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Cache cargo registry and build
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-check-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-check-
- name: cargo fmt
run: cargo fmt -- --check
- name: cargo clippy
run: cargo clippy --all-targets -- -D warnings
- name: cargo test
run: cargo test
- name: Install coverage tools
run: |
rustup component add llvm-tools-preview
cargo install cargo-llvm-cov --locked || true
- name: Unit test coverage gate
run: |
set -euo pipefail
cargo llvm-cov test --all --all-features 2>&1 | tee cov-full.txt
test "${PIPESTATUS[0]}" -eq 0 || exit 1
LINE_PCT=$(grep '^TOTAL' cov-full.txt | grep -oE '[0-9]+\.[0-9]+%' | sed -n '3p' | tr -d '%')
echo "Unit coverage: ${LINE_PCT}%"
python3 -c "assert float('${LINE_PCT}') >= 55, f'Coverage ${LINE_PCT}% < 55%'"
- name: Per-module coverage gates
run: |
python3 -c "
import re, sys
# Module filename -> minimum Lines Cover %
gates = {
'storage/s3.rs': 25,
'restore/mod.rs': 25,
'upload/mod.rs': 35,
'server/routes.rs': 40,
'list.rs': 50,
}
failed, matched = [], set()
with open('cov-full.txt') as f:
for line in f:
for mod_path, threshold in gates.items():
if not line.lstrip().startswith(mod_path):
continue
# Extract all percentages from the line
pcts = re.findall(r'(\d+\.\d+)%', line)
if len(pcts) >= 3:
line_cov = float(pcts[2]) # 3rd pct = Lines Cover
elif len(pcts) >= 1:
line_cov = float(pcts[-1])
else:
continue
matched.add(mod_path)
if line_cov < threshold:
failed.append(f'{mod_path}: {line_cov}% < {threshold}%')
else:
print(f' OK: {mod_path} = {line_cov}% (>= {threshold}%)')
missing = set(gates.keys()) - matched
if missing:
print(f'FAIL: modules not found in coverage output: {missing}')
sys.exit(1)
if failed:
print('Per-module coverage gates FAILED:')
for f in failed:
print(f' FAIL: {f}')
sys.exit(1)
print('All per-module coverage gates passed')
"
# ---------------------------------------------------------------------------
# Job 2: Integration tests with ClickHouse version matrix
# ---------------------------------------------------------------------------
integration:
name: Integration (CH ${{ matrix.ch_version }})
runs-on: ubuntu-latest
needs: check
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
strategy:
matrix:
ch_version:
- "23.8.16.40.altinitystable"
- "24.3.12.76.altinitystable"
- "24.8.13.51.altinitystable"
- "25.1.5.31.altinitystable"
fail-fast: false
env:
S3_BUCKET: ${{ secrets.TEST_S3_BUCKET }}
S3_ACCESS_KEY: ${{ secrets.TEST_S3_ACCESS_KEY }}
S3_SECRET_KEY: ${{ secrets.TEST_S3_SECRET_KEY }}
S3_REGION: ${{ secrets.TEST_S3_REGION }}
steps:
- uses: actions/checkout@v4
- name: Skip if S3 secrets not configured
id: s3-check
run: |
if [ -z "$S3_BUCKET" ] || [ -z "$S3_ACCESS_KEY" ] || [ -z "$S3_SECRET_KEY" ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "S3 secrets not configured -- skipping integration tests"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Start test environment (with coverage)
if: steps.s3-check.outputs.skip != 'true'
env:
CH_VERSION: ${{ matrix.ch_version }}
RUN_ID: ${{ github.run_id }}-${{ matrix.ch_version }}
S3_PATH: chbackup-test/${{ matrix.ch_version }}/${{ github.run_id }}
COVERAGE: "true"
run: |
docker compose -f docker-compose.test.yml up -d --build --wait
- name: Run integration tests
if: steps.s3-check.outputs.skip != 'true'
env:
CH_VERSION: ${{ matrix.ch_version }}
RUN_ID: ${{ github.run_id }}-${{ matrix.ch_version }}
S3_PATH: chbackup-test/${{ matrix.ch_version }}/${{ github.run_id }}
run: |
docker compose -f docker-compose.test.yml exec -T chbackup-test /test/run_tests.sh
- name: Generate merged coverage report
if: steps.s3-check.outputs.skip != 'true' && matrix.ch_version == '24.8.13.51.altinitystable'
env:
CH_VERSION: ${{ matrix.ch_version }}
RUN_ID: ${{ github.run_id }}-${{ matrix.ch_version }}
S3_PATH: chbackup-test/${{ matrix.ch_version }}/${{ github.run_id }}
run: |
# Extract integration profraw from the running container
mkdir -p integ-profraw
docker compose -f docker-compose.test.yml cp \
chbackup-test:/coverage/integ/. integ-profraw/ 2>/dev/null || true
# Run merge+report inside a builder-stage container
docker build --target builder --build-arg COVERAGE=true \
-f Dockerfile.test -t chbackup-cov-reporter .
docker run --rm \
-v $(pwd)/integ-profraw:/integ-profraw:ro \
chbackup-cov-reporter \
sh -c '
PROFRAW_DIR=$(find /build/target -name "*.profraw" -exec dirname {} \; | sort -u | head -1)
if [ -z "$PROFRAW_DIR" ]; then echo "No unit profraw found"; exit 0; fi
find /integ-profraw -name "*.profraw" -exec cp {} "$PROFRAW_DIR/" \; 2>/dev/null || true
cargo llvm-cov report --release --summary-only 2>&1 || true
'
- name: Tear down test environment
if: always() && steps.s3-check.outputs.skip != 'true'
run: |
docker compose -f docker-compose.test.yml down -v