diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml
index dfb80ffa2..a6258a3ab 100644
--- a/.github/actions/run-tests/action.yml
+++ b/.github/actions/run-tests/action.yml
@@ -57,6 +57,14 @@ runs:
8.0.x
10.0.x
+ # Restore is ~80s of the build step on a cold runner, and the package set changes rarely.
+ - name: Cache NuGet packages
+ uses: actions/cache@v4
+ with:
+ path: ~/.nuget/packages
+ key: ${{ runner.os }}-nuget-${{ hashFiles('Directory.Packages.props', 'global.json', '**/*.csproj') }}
+ restore-keys: ${{ runner.os }}-nuget-
+
- name: .NET Build
shell: bash
run: dotnet build Build.csproj -c Release /p:CI=true
@@ -65,6 +73,7 @@ runs:
shell: bash
run: >-
dotnet test tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj
+ --no-build
-c Release
-f net10.0
--logger trx
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index 80f33c9c3..6a50baebc 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -128,6 +128,13 @@ jobs:
redis-cli -p 26381 INFO SERVER | grep redis_version || echo "Failed to get version for port 26381"
continue-on-error: true
+ # Restore is ~80s of the build step on a cold runner, and the package set changes rarely.
+ - name: Cache NuGet packages
+ uses: actions/cache@v4
+ with:
+ path: ~/.nuget/packages
+ key: ${{ runner.os }}-nuget-${{ hashFiles('Directory.Packages.props', 'global.json', '**/*.csproj') }}
+ restore-keys: ${{ runner.os }}-nuget-
- name: .NET Build
run: dotnet build Build.csproj -c Release /p:CI=true
# The analyzer and the props that configures it reach consumers only through the package, and a
@@ -156,7 +163,7 @@ jobs:
run: |
$exitCode = 0
foreach ($tfm in @("net10.0", "net481")) {
- dotnet test tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj -c Release -f $tfm --logger trx --logger GitHubActions --results-directory ./test-results/ /p:CI=true
+ dotnet test tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj --no-build -c Release -f $tfm --logger trx --logger GitHubActions --results-directory ./test-results/ /p:CI=true
if ($LASTEXITCODE -ne 0) {
$exitCode = $LASTEXITCODE
}
diff --git a/AGENTS.md b/AGENTS.md
index b7a4d1bdb..62da6c949 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -41,6 +41,7 @@ dotnet pack src/StackExchange.Redis/StackExchange.Redis.csproj --no-build -c Rel
- SDK is pinned (`global.json`, `allowPrerelease: false`); CI installs the 6/8/10 runtimes. `LangVersion` is 14.
- `TreatWarningsAsErrors=true` everywhere and `Features=strict` — warnings fail the build. Analyzers (StyleCop + the custom `eng` analyzer + PublicApiAnalyzers) run as part of the build.
+- Analyzers run on **one TFM per project** — the newest it builds (see `Directory.Build.targets`), because they cost ~40% of a clean build otherwise and every rule is TFM-agnostic. Source generators still run on every TFM. If you touch code inside a down-level `#if`, build it with `/p:RunAnalyzers=true` to get the full per-TFM sweep. StyleCop applies to `src/` only, not `tests/` or `toys/`.
- Library multi-targets `net461;netstandard2.0;net472;net6.0;net8.0;net10.0`. Conditional compile symbols: `VECTOR_SAFE` (all but net461), `UNIX_SOCKET` (net6.0+). The test project targets `net481;net8.0;net10.0`; `BUILD_CURRENT` is defined on the newest TFM (disables some parallelism for brittle tests).
## Public API tracking (important — easy to trip over)
@@ -113,6 +114,6 @@ Be consise and direct where possible, but with as much detail as is necessary; n
## Conventions
-- Code style is enforced via `.editorconfig` + `Shared.ruleset` + StyleCop; 4-space indent, BOM + final newline on `.cs`, `System.*` usings first, no redundant `this.`. Build will fail on violations.
+- Code style is enforced via `.editorconfig` + `Shared.ruleset` + StyleCop (StyleCop in `src/` only); 4-space indent, BOM + final newline on `.cs`, `System.*` usings first, no redundant `this.`. Build will fail on violations. Match the surrounding style in `tests/`/`toys/` too — the rules are simply not enforced there.
- `InternalsVisibleTo` exposes internals to the test/benchmark/server projects, so tests reach into internal types directly.
- `docs/` markdown is the user-facing documentation; update it for user-visible behavior changes.
diff --git a/Directory.Build.props b/Directory.Build.props
index 2289ce520..62c89b137 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -42,7 +42,6 @@
-
diff --git a/Directory.Build.targets b/Directory.Build.targets
index 687e19684..82752190d 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -2,4 +2,30 @@
-
\ No newline at end of file
+
+
+
+
+ <_AnalyzedTargetFramework Condition="'$(_AnalyzedTargetFramework)' == '' and $(TargetFrameworks.Contains('net10.0'))">net10.0
+ <_AnalyzedTargetFramework Condition="'$(_AnalyzedTargetFramework)' == '' and $(TargetFrameworks.Contains('net8.0'))">net8.0
+ <_AnalyzedTargetFramework Condition="'$(_AnalyzedTargetFramework)' == '' and $(TargetFrameworks.Contains('net6.0'))">net6.0
+ <_AnalyzedTargetFramework Condition="'$(_AnalyzedTargetFramework)' == '' and $(TargetFrameworks.Contains('netstandard2.0'))">netstandard2.0
+ <_AnalyzedTargetFramework Condition="'$(_AnalyzedTargetFramework)' == '' and $(TargetFrameworks.Contains('net481'))">net481
+ <_AnalyzedTargetFramework Condition="'$(_AnalyzedTargetFramework)' == '' and $(TargetFrameworks.Contains('net472'))">net472
+ <_AnalyzedTargetFramework Condition="'$(_AnalyzedTargetFramework)' == '' and $(TargetFrameworks.Contains('net461'))">net461
+ false
+
+
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 2c51b5806..23f221374 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -8,6 +8,10 @@
seredis.png
+
+
diff --git a/src/RESPite.Benchmark/RESPite.Benchmark.csproj b/src/RESPite.Benchmark/RESPite.Benchmark.csproj
index 8397870af..d1b6c1e25 100644
--- a/src/RESPite.Benchmark/RESPite.Benchmark.csproj
+++ b/src/RESPite.Benchmark/RESPite.Benchmark.csproj
@@ -8,7 +8,8 @@
resp-benchmark
true
command-line "RESP" benchmark client, comparable to redis-benchmark
- True
+
readme.md
False
false