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
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ on:
branches: [master]

env:
DOTNET_VERSION: '9.0.x'
# Guarantees global.json's 8.0.404 floor is present. This is NOT a pin: global.json requests
# rollForward: latestMajor, so the SDK actually used is the newest installed on the runner.
# The previous value (9.0.x) implied a pin that never took effect.
DOTNET_VERSION: '8.0.x'

permissions:
contents: read
Expand All @@ -30,4 +33,4 @@ jobs:
run: dotnet restore

- name: Build
run: dotnet build -c Release --no-restore
run: dotnet build -c Release --no-restore -p:ContinuousIntegrationBuild=true
41 changes: 34 additions & 7 deletions .github/workflows/release-nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ jobs:
- name: Build
env:
VERSION: ${{ steps.get_version.outputs.version_without_v }}
run: dotnet build -c Release -p:Version="${VERSION}"
# ContinuousIntegrationBuild must be set at COMPILE time: it is what normalizes the
# source paths embedded in the PDB for SourceLink, and it also promotes RS0016/RS0017
# (public API tracking) to errors. Setting it only on pack would be a no-op for both.
run: dotnet build -c Release -p:Version="${VERSION}" -p:ContinuousIntegrationBuild=true

- name: Test
run: dotnet test -c Release --no-build
Expand All @@ -52,9 +55,29 @@ jobs:
env:
VERSION: ${{ steps.get_version.outputs.version_without_v }}
run: |
dotnet pack src/Resilion/Resilion.csproj -c Release --no-build -p:Version="${VERSION}"
dotnet pack src/Resilion.Extensions/Resilion.Extensions.csproj -c Release --no-build -p:Version="${VERSION}"
dotnet pack src/Resilion.RateLimiting/Resilion.RateLimiting.csproj -c Release --no-build -p:Version="${VERSION}"
# Data-driven so adding a package is a one-line change here and nowhere else.
# The previous form hardcoded three pack commands AND a `-ne 3` assertion below, so a
# fourth package would have broken every release until both were found and edited.
PROJECTS=(Resilion Resilion.Extensions Resilion.RateLimiting Resilion.Http)
for p in "${PROJECTS[@]}"; do
dotnet pack "src/$p/$p.csproj" -c Release --no-build \
-p:Version="${VERSION}" -p:ContinuousIntegrationBuild=true
done
echo "EXPECTED_PACKAGE_COUNT=${#PROJECTS[@]}" >> "$GITHUB_ENV"

- name: Verify symbol packages were produced
env:
VERSION: ${{ steps.get_version.outputs.version_without_v }}
run: |
# `dotnet pack --no-build` produces the .snupkg only if the .pdb is already in the
# output from the Build step. That holds here, but it is the flakiest part of symbol
# publishing, so assert it rather than discovering it missing after a release.
SNUPKGS=$(find . -name "*.snupkg" -path "*${VERSION}*" | wc -l | tr -d ' ')
echo "Found $SNUPKGS symbol packages (expected $EXPECTED_PACKAGE_COUNT)"
if [ "$SNUPKGS" -ne "$EXPECTED_PACKAGE_COUNT" ]; then
echo "Symbol packages missing. Aborting rather than publishing without symbols."
exit 1
fi

- name: NuGet login (OIDC - trusted publishing)
id: login
Expand All @@ -65,10 +88,14 @@ jobs:
- name: Push NuGet packages
run: |
VERSION="${{ steps.get_version.outputs.version_without_v }}"
# The ! -name "*.symbols.nupkg" filter is vestigial with SymbolPackageFormat=snupkg
# (find -name "*.nupkg" does not match a .snupkg), but is kept: if anyone drops that
# property the legacy name returns, and this filter is what keeps the count honest.
NUPKGS=$(find . -name "*.nupkg" -path "*${VERSION}*" ! -name "*.symbols.nupkg")
COUNT=$(echo "$NUPKGS" | wc -l)
if [ "$COUNT" -ne 3 ]; then
echo "Expected exactly 3 matching .nupkg files, found $COUNT. Aborting."
# Note: `echo "" | wc -l` is 1, so count with find directly rather than echoing.
COUNT=$(find . -name "*.nupkg" -path "*${VERSION}*" ! -name "*.symbols.nupkg" | wc -l | tr -d ' ')
if [ "$COUNT" -ne "$EXPECTED_PACKAGE_COUNT" ]; then
echo "Expected exactly $EXPECTED_PACKAGE_COUNT matching .nupkg files, found $COUNT. Aborting."
exit 1
fi
echo "$NUPKGS" | while read -r nupkg; do
Expand Down
54 changes: 46 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,30 @@ jobs:
strategy:
fail-fast: false
matrix:
# The library targets net8.0 only; running the same net8.0 test binaries under both
# the 8.0.x and 9.0.x runtimes catches framework-specific regressions (e.g. runtime
# behavior differences the library depends on) that a single-SDK job would miss.
dotnet-version: ["8.0.x", "9.0.x"]
# The library targets net8.0 only, so the useful axis is which RUNTIME the net8.0 test
# binaries execute on. Varying setup-dotnet's version did not achieve that, for two
# reasons: global.json requests 8.0.404 with rollForward: latestMajor, so the SDK
# actually selected is the newest installed on the runner regardless of this input; and
# Resilion.Tests.runtimeconfig.json pins framework 8.0.0 with the default Minor
# roll-forward policy, so both jobs resolved the same 8.0.x runtime. The matrix ran the
# same configuration twice.
#
# The knob is the RollForward MSBuild property, which writes "rollForward" into the test
# app's runtimeconfig.json and so scopes to that app alone:
# LatestPatch -> stay on the 8.0 runtime, newest installed patch
# LatestMajor -> run on the newest runtime installed below
#
# Two values that look right and are not:
# Disable forbids roll-forward entirely, so it demands the exact 8.0.0 patch and fails
# on any real machine or image (which ship 8.0.x for x > 0).
# Setting the DOTNET_ROLL_FORWARD environment variable instead applies the policy to
# every .NET process in the step, including the dotnet CLI and the test host,
# so the step dies before a test runs.
include:
- label: net8.0-runtime
roll-forward: LatestPatch
- label: newest-runtime
roll-forward: LatestMajor
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -37,13 +57,31 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ matrix.dotnet-version }}
# Both runtimes are installed in both legs, so the matrix does not depend on whatever
# the runner image happens to ship: LatestPatch resolves 8.0.x, LatestMajor resolves
# the highest present. This also satisfies global.json's 8.0.404 floor — it does not
# pin the SDK, since rollForward: latestMajor still selects the newest installed.
dotnet-version: |
8.0.x
9.0.x

- name: Restore dependencies
run: dotnet restore

- name: Build Solution
run: dotnet build --configuration Release --no-restore
run: dotnet build --configuration Release --no-restore -p:RollForward=${{ matrix.roll-forward }}

- name: Verify the roll-forward policy reached the test app
# Without this the matrix is unfalsifiable: if the property ever stops landing, both legs
# silently collapse onto one runtime again — exactly the state this replaced.
run: |
set -eu
for f in tests/*/bin/Release/net8.0/*.runtimeconfig.json; do
echo "== $f"
grep -q '"rollForward": *"${{ matrix.roll-forward }}"' "$f" \
|| { echo "rollForward=${{ matrix.roll-forward }} missing from $f"; cat "$f"; exit 1; }
done
dotnet --list-runtimes | grep Microsoft.NETCore.App

- name: Run Unit Tests
run: dotnet test --configuration Release --no-build -- --report-trx --results-directory ${{ github.workspace }}/TestResults
Expand All @@ -52,15 +90,15 @@ jobs:
uses: actions/upload-artifact@v4
if: success() || failure()
with:
name: test-results-${{ matrix.dotnet-version }}-${{ github.run_id }}
name: test-results-${{ matrix.label }}-${{ github.run_id }}
path: TestResults/*.trx
retention-days: 7

- name: Publish Test Results
uses: dorny/test-reporter@v1
if: success() || failure()
with:
name: Unit Test Results (${{ matrix.dotnet-version }})
name: Unit Test Results (${{ matrix.label }})
path: TestResults/*.trx
reporter: dotnet-trx
fail-on-error: false
Expand Down
Loading
Loading