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
59 changes: 44 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
strategy:
fail-fast: false # one platform failing must not hide another's result
matrix:
os: [ ubuntu-latest, windows-latest, macos-latest ]
os: [ ubuntu-latest, windows-latest, macos-14, macos-15 ]
runs-on: ${{ matrix.os }}
timeout-minutes: 20
steps:
Expand All @@ -87,12 +87,48 @@ jobs:
key: nuget-${{ runner.os }}-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj') }}
restore-keys: nuget-${{ runner.os }}-

# The libsecret backend exercises the Secret Service D-Bus API, which is not
# running on a bare ubuntu runner. Without this the tests short-circuit through
# the "secret-service-unavailable" probe instead of hitting libsecret. Linux-only;
# the macOS leg uses Security.framework and needs nothing.
# Tests run across every shipped TFM (STANDARD.md 2.3). No --no-build: this job
# does not share a filesystem with `build`, and rebuilding is cheaper and less
# fragile than shipping obj/ between jobs.
# `-- --coverage` passes through to Microsoft.Testing.Platform's coverage
# extension (STANDARD.md 2.6). Referencing a collector without invoking it is
# worse than none: it reads as coverage in the dependency list while producing
# no data, which is exactly what coverlet was doing in a sibling repo.
- name: Test
run: dotnet test --configuration Release --verbosity normal -- --coverage

- name: Upload coverage
if: always()
uses: actions/upload-artifact@v7
with:
name: coverage-${{ matrix.os }}
path: '**/TestResults/*.coverage'
if-no-files-found: warn

# Auth-only fifth job (EXCEPTIONS.md 3.1). The libsecret tests need a Secret Service
# daemon, which only exists on one leg of the matrix — so as a guarded step inside `test`
# it made `test (ubuntu-latest)` report one result for two unrelated things. Split out,
# the matrix leg reports the libsecret tests as skipped (they self-report since #46) and
# this job reports them run, so a libsecret regression names itself.
test-linux-keyring:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v7

- uses: actions/setup-dotnet@v6
with:
dotnet-version: |
8.0.x
10.0.x

- uses: actions/cache@v6
with:
path: ~/.nuget/packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj') }}
restore-keys: nuget-${{ runner.os }}-

- name: Install and start gnome-keyring-daemon
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y gnome-keyring dbus-x11 libsecret-1-0 libsecret-1-dev
Expand All @@ -103,29 +139,22 @@ jobs:
gnome-keyring-daemon --start --components=secrets &
sleep 2

# Tests run across every shipped TFM (STANDARD.md 2.3). No --no-build: this job
# does not share a filesystem with `build`, and rebuilding is cheaper and less
# fragile than shipping obj/ between jobs.
# `-- --coverage` passes through to Microsoft.Testing.Platform's coverage
# extension (STANDARD.md 2.6). Referencing a collector without invoking it is
# worse than none: it reads as coverage in the dependency list while producing
# no data, which is exactly what coverlet was doing in a sibling repo.
- name: Test
run: dotnet test --configuration Release --verbosity normal -- --coverage

- name: Upload coverage
if: always()
uses: actions/upload-artifact@v7
with:
name: coverage-${{ matrix.os }}
name: coverage-linux-keyring
path: '**/TestResults/*.coverage'
if-no-files-found: warn

# THE required status check. Aggregates everything above so the ruleset never has to
# know the matrix shape. `if: always()` is essential — without it the gate is skipped
# when a dependency fails, and a skipped check reads as success to branch protection.
ci:
needs: [ build, test ]
needs: [ build, test, test-linux-keyring ]
if: always()
runs-on: ubuntu-latest
timeout-minutes: 5
Expand Down
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- **CI now runs three macOS versions and splits the libsecret tests into their own job**
(#20, #21). The `test` matrix names `macos-14` and `macos-15` instead of `macos-latest`: this is the only repo with a Security.framework P/Invoke layer, and the
alias only ever exercised whichever release it currently points at — the one place an
OS-version behaviour change would surface as silently missing credentials rather than a
build failure. The `gnome-keyring-daemon` setup moves out of the matrix into a
`test-linux-keyring` job, so `test (ubuntu-latest)` no longer reports one result for both
the portable tests and the libsecret ones; the matrix leg now shows the libsecret tests
skipped and the new job shows them run. Both changes required amending
NextIteration.Standards first (its PR #23) rather than editing this workflow locally, which
§3.0.1 calls forking rather than fixing.

`macos-13` was in the first attempt, as #20 suggested, and is not in the result: that
runner label no longer schedules. Its job sat queued with no runner assigned for over ten
minutes while every other leg finished, so it would have hung each CI run indefinitely
rather than adding coverage.

### Breaking

- **`ICredentialManager` members now take a `CancellationToken`** (#74). Every member gains a
Expand Down