diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 979763c..d8259e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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: @@ -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 @@ -103,13 +139,6 @@ 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 @@ -117,7 +146,7 @@ jobs: if: always() uses: actions/upload-artifact@v7 with: - name: coverage-${{ matrix.os }} + name: coverage-linux-keyring path: '**/TestResults/*.coverage' if-no-files-found: warn @@ -125,7 +154,7 @@ jobs: # 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 diff --git a/CHANGELOG.md b/CHANGELOG.md index b82616e..22a1ada 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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