Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
branches: [ main ]
paths-ignore:
- '**/*.md'
- 'docs/**'
workflow_dispatch:
inputs:
categories:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
branches: [ main ]
paths-ignore:
- '**/*.md'
- 'docs/**'

jobs:
analyze:
Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/examples.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
name: Examples

# The shared build inputs are the same as in tests.yml and tests-tcp.yml. Directory.Packages.props also sets
# the versions of the packages that only the examples use (Polly, the OpenTelemetry console exporter, and
# some Microsoft.Extensions packages), so a version change runs this workflow.
on:
push:
branches: [main]
Expand All @@ -8,15 +11,29 @@ on:
- "ClickHouse.Driver/**"
- "ClickHouse.Driver.Common/**"
- "ClickHouse.Driver.Tcp/**"
- "Directory.Packages.props"
- "Directory.Build.*"
- "global.json"
- "[Nn]u[Gg]et.[Cc]onfig"
- ".editorconfig"
- "sgKey.snk"
- ".github/workflows/examples.yml"
- "!**/*.md"
pull_request:
branches: [main]
paths:
- "examples/**"
- "ClickHouse.Driver/**"
- "ClickHouse.Driver.Common/**"
- "ClickHouse.Driver.Tcp/**"
- "Directory.Packages.props"
- "Directory.Build.*"
- "global.json"
- "[Nn]u[Gg]et.[Cc]onfig"
- ".editorconfig"
- "sgKey.snk"
- ".github/workflows/examples.yml"
- "!**/*.md"
workflow_dispatch:
inputs:
ref:
Expand Down
31 changes: 29 additions & 2 deletions .github/workflows/reusable-tcp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@ on:
default: latest
required: false
type: string
coverage:
default: false
required: false
type: boolean
ref:
required: false
type: string
secrets:
CODECOV_TOKEN:
required: false

permissions:
contents: read
Expand Down Expand Up @@ -52,10 +59,30 @@ jobs:
# No filter: the Cloud category marks the tests tests-cloud-tcp.yml also runs against a real Cloud
# service, not tests that need one. They run here too, against the container.
#
# The framework is passed through the environment rather than interpolated into the run
# The inputs are passed through the environment rather than interpolated into the run
# script, so a caller-supplied input cannot inject shell.
- name: Test
run: dotnet test ClickHouse.Driver.Tcp.Tests/ClickHouse.Driver.Tcp.Tests.csproj --framework "$FRAMEWORK" --configuration Release --verbosity normal --logger GitHubActions /clp:ErrorsOnly
run: |
coverage_args=()
if [ "$COVERAGE" = "true" ]; then
coverage_args=(/p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:SkipAutoProps=true)
fi
dotnet test ClickHouse.Driver.Tcp.Tests/ClickHouse.Driver.Tcp.Tests.csproj --framework "$FRAMEWORK" --configuration Release --verbosity normal --logger GitHubActions /clp:ErrorsOnly "${coverage_args[@]}"
env:
CLICKHOUSE_VERSION: ${{ inputs.clickhouse-version }}
FRAMEWORK: ${{ inputs.framework }}
COVERAGE: ${{ inputs.coverage }}

# The tcp flag keeps this report apart from the HTTP report (flag http). codecov.yml carries each
# flag forward to the commits that do not run its suite. Codecov records the upload for the commit
# that started the workflow. With an explicit ref, that is not the commit under test, so the job
# does not upload.
- uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7
if: inputs.coverage && !inputs.ref
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
disable_search: true
verbose: true
flags: tcp
files: ./ClickHouse.Driver.Tcp.Tests/coverage.${{ inputs.framework }}.opencover.xml
5 changes: 4 additions & 1 deletion .github/workflows/reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,14 @@ jobs:
CLICKHOUSE_VERSION: ${{ inputs.clickhouse-version }}
FRAMEWORK: ${{ inputs.framework }}

# Codecov records the upload for the commit that started the workflow. With an explicit ref, that is
# not the commit under test, so the job does not upload.
- uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7
if: inputs.coverage
if: inputs.coverage && !inputs.ref
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
disable_search: true
verbose: true
flags: http
files: ./ClickHouse.Driver.Tests/coverage.${{ inputs.framework }}.opencover.xml
69 changes: 66 additions & 3 deletions .github/workflows/tests-tcp.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
name: TCP Tests

# Runs the ClickHouse.Driver.Tcp test suite, gated on changes to the TCP projects only.
# The TCP project is standalone (no reference to ClickHouse.Driver), so its build/test closure is just
# the two TCP projects plus the shared package versions and the CI wiring itself.
# Runs the ClickHouse.Driver.Tcp test suite. The TCP projects do not reference ClickHouse.Driver, so an
# HTTP-only change does not run this suite. They do reference ClickHouse.Driver.Common, so the path filters
# select it, together with the shared build inputs, the workflows of this suite, and codecov.yml (the
# Codecov settings for its coverage report). tests.yml and examples.yml list the same shared build inputs;
# keep the three lists the same.
on:
push:
# Only the long-lived integration branches run on push (validating what landed). The per-epic tcp/**
Expand All @@ -12,20 +14,36 @@ on:
paths:
- "ClickHouse.Driver.Tcp/**"
- "ClickHouse.Driver.Tcp.Tests/**"
- "ClickHouse.Driver.Common/**"
- "Directory.Packages.props"
- "Directory.Build.*"
- "global.json"
- "[Nn]u[Gg]et.[Cc]onfig"
- ".editorconfig"
- "sgKey.snk"
- "codecov.yml"
- ".github/workflows/tests-tcp.yml"
- ".github/workflows/reusable-tcp.yml"
- ".github/workflows/tests-cloud-tcp.yml"
- "!**/*.md"
pull_request:
# Matches the PR's base branch, so a PR stacked onto another tcp/** epic branch triggers too.
branches: [main, tcp-client, "tcp/**"]
paths:
- "ClickHouse.Driver.Tcp/**"
- "ClickHouse.Driver.Tcp.Tests/**"
- "ClickHouse.Driver.Common/**"
- "Directory.Packages.props"
- "Directory.Build.*"
- "global.json"
- "[Nn]u[Gg]et.[Cc]onfig"
- ".editorconfig"
- "sgKey.snk"
- "codecov.yml"
- ".github/workflows/tests-tcp.yml"
- ".github/workflows/reusable-tcp.yml"
- ".github/workflows/tests-cloud-tcp.yml"
- "!**/*.md"
workflow_dispatch:
inputs:
ref:
Expand All @@ -37,6 +55,15 @@ permissions:
contents: read

jobs:
coverage-tcp:
name: Code Coverage (TCP)
uses: $/.github/workflows/reusable-tcp.yml
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
coverage: true
ref: ${{ inputs.ref }}

regress-clickhouse-tcp:
name: ClickHouse regression (TCP)
uses: $/.github/workflows/reusable-tcp.yml
Expand Down Expand Up @@ -65,6 +92,42 @@ jobs:
matrix:
framework: ["net10.0", "net9.0", "net8.0"] # TCP library targets net8.0+ only

build-http-driver:
name: HTTP driver build (TCP)
# ClickHouse.Driver references ClickHouse.Driver.Tcp for net8.0 and later and compiles against its public
# types, so a TCP change can break the HTTP driver build, possibly on some target frameworks only.
# tests.yml does not run for a TCP-only change, so this job builds ClickHouse.Driver for every target
# framework.
runs-on: ubuntu-22.04
timeout-minutes: 10

steps:
- name: Checkout
uses: actions/checkout@v7
with:
ref: ${{ inputs.ref || github.ref }}
# No step here talks to git again, so the job token does not need to stay in .git/config.
persist-credentials: false

- uses: actions/cache@v6
name: Cache NuGet
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-

# The .NET 10 SDK builds the older target frameworks too: their reference packs come from NuGet.
- name: Setup .NET Core
uses: actions/setup-dotnet@v6
with:
dotnet-version: |
10.x

# GeneratePackageOnBuild=false: compile only, without the NuGet package.
- name: Build
run: dotnet build ClickHouse.Driver/ClickHouse.Driver.csproj --configuration Release -p:GeneratePackageOnBuild=false

cloud-tcp:
name: Cloud (TCP)
# On a pull request only when its branch is in this repository, which needs write access to push. Dependabot
Expand Down
50 changes: 48 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,58 @@
name: Tests

# Runs the HTTP driver suite. The path filters select the HTTP driver and its test projects, the shared
# ClickHouse.Driver.Common project, the shared build inputs, the workflows of this suite, and codecov.yml
# (the Codecov settings for its coverage report). The shared build inputs are the files that MSBuild, the
# SDK and NuGet read from the repository root (some do not exist yet), the analyzer settings and the
# strong-name key. tests-tcp.yml and examples.yml list the same shared build inputs; keep the three lists
# the same.
#
# ClickHouse.Driver references ClickHouse.Driver.Tcp (net8.0 and later) to pack the TCP assembly into the
# NuGet package, so it compiles against the TCP public types. No HTTP code or test uses them, so a TCP-only
# change does not run this suite. tests-tcp.yml builds ClickHouse.Driver for every target framework instead.
on:
push:
branches: [main]
paths-ignore:
- "**/*.md"
paths:
- "ClickHouse.Driver/**"
- "ClickHouse.Driver.Tests/**"
- "ClickHouse.Driver.IntegrationTests/**"
- "ClickHouse.Driver.Common/**"
- "Directory.Packages.props"
- "Directory.Build.*"
- "global.json"
- "[Nn]u[Gg]et.[Cc]onfig"
- ".editorconfig"
- "sgKey.snk"
- "codecov.yml"
- ".github/workflows/tests.yml"
- ".github/workflows/reusable.yml"
- ".github/workflows/tests-integration.yml"
- ".github/workflows/tests-cloud.yml"
- ".github/workflows/tests-windows.yml"
- ".github/workflows/tests-macos.yml"
- "!**/*.md"
pull_request:
branches: [main]
paths:
- "ClickHouse.Driver/**"
- "ClickHouse.Driver.Tests/**"
- "ClickHouse.Driver.IntegrationTests/**"
- "ClickHouse.Driver.Common/**"
- "Directory.Packages.props"
- "Directory.Build.*"
- "global.json"
- "[Nn]u[Gg]et.[Cc]onfig"
- ".editorconfig"
- "sgKey.snk"
- "codecov.yml"
- ".github/workflows/tests.yml"
- ".github/workflows/reusable.yml"
- ".github/workflows/tests-integration.yml"
- ".github/workflows/tests-cloud.yml"
- ".github/workflows/tests-windows.yml"
- ".github/workflows/tests-macos.yml"
- "!**/*.md"
workflow_dispatch:
inputs:
ref:
Expand Down
19 changes: 16 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ dotnet test ClickHouse.Driver.IntegrationTests/ClickHouse.Driver.IntegrationTest

### Running tests with code coverage

The project uses Coverlet for code coverage:
The project uses Coverlet for code coverage. The HTTP and TCP drivers have separate test projects:

```bash
dotnet test ClickHouse.Driver.Tests/ClickHouse.Driver.Tests.csproj \
Expand All @@ -102,12 +102,23 @@ dotnet test ClickHouse.Driver.Tests/ClickHouse.Driver.Tests.csproj \
/p:CollectCoverage=true \
/p:CoverletOutputFormat=opencover \
/p:SkipAutoProps=true

dotnet test ClickHouse.Driver.Tcp.Tests/ClickHouse.Driver.Tcp.Tests.csproj \
--framework net9.0 \
-c Release \
/p:CollectCoverage=true \
/p:CoverletOutputFormat=opencover \
/p:SkipAutoProps=true
```

Coverage reports are generated in the test project directory:
The TCP tests start a ClickHouse container with Testcontainers unless `CLICKHOUSE_TCP_CONNECTION` sets a
server connection string.

Coverage reports are generated in each test project directory:

```
ClickHouse.Driver.Tests/coverage.net9.0.opencover.xml
ClickHouse.Driver.Tcp.Tests/coverage.net9.0.opencover.xml
```

### Running benchmarks
Expand Down Expand Up @@ -189,7 +200,9 @@ See `changelog.d/README.md` for the categories and naming convention.
### Expected CI behavior

- **All tests must pass** on all target frameworks and ClickHouse versions
- **Code coverage** is reported to Codecov (must not decrease significantly)
- **Code coverage** is reported to Codecov. The HTTP and TCP suites upload separate reports (flags `http`
and `tcp`), and Codecov shows their combined total. The `codecov/patch` check has a 75% target for the
lines that a pull request changes.
- **Benchmarks** run but don't fail the build (used for performance regression detection)
- **CodeQL** must not find security issues
- **Public API analyzer** will fail if API surface changes aren't documented
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<!-- CHTCP0001: the native-TCP client is experimental; the tests opt in to exercising it. -->
<NoWarn>CS8002;CHTCP0001</NoWarn>
<!-- codecov.yml ignores the vendored source in ClickHouse.Driver.Common/Vendor, so do not instrument it. -->
<ExcludeByFile>**/Vendor/**/*.cs</ExcludeByFile>
</PropertyGroup>

<ItemGroup>
Expand Down
7 changes: 7 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ coverage:
threshold: 1%
target: 75%

# The HTTP suite uploads with the flag http and the TCP suite with the flag tcp. Their path filters let a
# commit run only one suite. Carryforward then copies the other flag's report from the nearest earlier
# commit that has one, so the total of each commit covers both drivers.
flag_management:
default_rules:
carryforward: true

# Vendored third-party source (e.g. the K4os LZ4/xxHash codec) is a verbatim,
# re-derivable copy we don't own; its coverage is not meaningful for this repo.
ignore:
Expand Down
Loading