From e2405d89efac3306018611e9293829edb35bf625 Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Thu, 10 Sep 2026 09:53:04 +0100 Subject: [PATCH] Move package publishing from MyGet to NuGet trusted publishing MyGet stopped accepting our pushes, so drop it entirely rather than fight it: CI now just builds/tests and surfaces the nbgv-computed version so a release tag can be cut from it, and a new release.yml (triggered by a published GitHub Release) verifies the tag against nbgv, then packs and pushes to nuget.org via OIDC trusted publishing. Also removes appveyor.yml, which was independently deploying to MyGet on every main push. --- .github/workflows/CI.yml | 16 ++++--- .github/workflows/release.yml | 79 ++++++++++++++++++++++++++++++++ README.md | 8 ++-- appveyor.yml | 84 ----------------------------------- docs/ReleaseNotes.md | 6 +-- 5 files changed, 94 insertions(+), 99 deletions(-) create mode 100644 .github/workflows/release.yml delete mode 100644 appveyor.yml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index e2b810dc2..8178c671b 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -61,6 +61,15 @@ jobs: uses: actions/checkout@v6 with: fetch-depth: 0 # Fetch the full history + # Surfaced early, and before restore/build, so the version to release is visible even if + # something later in this (long) job fails. Cutting a release means creating a GitHub Release + # tagged with whatever this prints; release.yml then verifies the tag agrees with nbgv. + - name: Report computed version + run: | + dotnet tool install --global nbgv + $version = nbgv get-version --project src/StackExchange.Redis --variable NuGetPackageVersion + "### Computed package version: ``$version``" >> $env:GITHUB_STEP_SUMMARY + Write-Output "Computed package version: $version" # Restore is ~80s of the build step on a cold runner, and the package set changes rarely. # # Keep this immediately after checkout, and *before* the WSL/redis steps. The key globs the whole @@ -234,10 +243,3 @@ jobs: name: test-results-windows path: test-results/*.trx retention-days: 14 - # Package and upload to MyGet only on pushes to main/v3, not on PRs - - name: .NET Pack - if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/v3') - run: dotnet pack Build.csproj --no-build -c Release /p:PackageOutputPath=${env:GITHUB_WORKSPACE}\.nupkgs /p:CI=true - - name: Upload to MyGet - if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/v3') - run: dotnet nuget push ${env:GITHUB_WORKSPACE}\.nupkgs\*.nupkg -s https://www.myget.org/F/stackoverflow/api/v2/package -k ${{ secrets.MYGET_API_KEY }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..fdfe1b514 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,79 @@ +# Publishes to nuget.org when a GitHub Release is published. +# +# Auth is NuGet Trusted Publishing (OIDC): no long-lived API key is stored anywhere. +# The one-time setup on nuget.org is: username menu -> Trusted Publishing -> add policy with +# Repository Owner: StackExchange / Repository: StackExchange.Redis / Workflow File: release.yml +# Environment: release +# plus a NUGET_USER repository secret holding the nuget.org profile name to publish as. +# +# Versioning note: Nerdbank.GitVersioning computes the version from version.json plus commit +# height - the tag name does not set it. Read the version to tag off the CI run's step summary +# ("Report computed version" in CI.yml) and create the release with that tag; the guard step +# below fails the run on any mismatch rather than publishing a package that disagrees with its +# release. +# +# Deliberately does not run tests: the commit being released already passed CI, and this job's +# only job is to reproduce that build byte-for-byte and push it. Also deliberately runs on Linux, +# not Windows: net461/net472 build fine against their reference assemblies without a Windows +# runtime, and nothing here executes test code. + +name: Release + +on: + release: + types: [published] + # dry run: everything except the tag check and the push, so the pipeline can be + # proven (and the packages inspected, via the run artifact) without cutting a release + workflow_dispatch: + +jobs: + publish: + runs-on: ubuntu-latest + environment: release + permissions: + id-token: write # for the OIDC exchange with nuget.org + contents: read + + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 # Fetch the full history (for versioning) + - name: Install .NET SDK + uses: actions/setup-dotnet@v5 + with: + dotnet-version: | + 8.0.x + 10.0.x + - name: Verify tag matches computed version + if: github.event_name == 'release' + run: | + dotnet tool install --global nbgv + computed=$(nbgv get-version --project src/StackExchange.Redis --variable NuGetPackageVersion) + tag="${{ github.event.release.tag_name }}" + tag="${tag#v}" + if [ "$computed" != "$tag" ]; then + echo "::error::Tag '$tag' does not match the computed version '$computed'; retag the release commit so the two agree." + exit 1 + fi + echo "Publishing $computed" + - name: Restore dependencies + run: dotnet restore Build.csproj + - name: Build + run: dotnet build Build.csproj --no-restore -c Release /p:CI=true + - name: Pack + run: dotnet pack Build.csproj --no-build -c Release /p:CI=true /p:PackageOutputPath=${{ github.workspace }}/.nupkgs + # The packages survive as a run artifact even if the push fails + - name: Upload packages + uses: actions/upload-artifact@v4 + with: + name: packages + path: .nupkgs/*.nupkg + - name: NuGet login (OIDC to temp API key) + if: github.event_name == 'release' + uses: NuGet/login@v1 + id: login + with: + user: ${{ secrets.NUGET_USER }} + - name: Push to nuget.org + if: github.event_name == 'release' + run: dotnet nuget push .nupkgs/*.nupkg --api-key ${{ steps.login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate diff --git a/README.md b/README.md index 1e7535701..5d2b6cc7e 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,8 @@ For all documentation, [see here](https://seredis.dev/). #### Package Status -MyGet Pre-release feed: https://www.myget.org/gallery/stackoverflow - -| Package | NuGet Stable | NuGet Pre-release | Downloads | MyGet | -| ------- | ------------ | ----------------- | --------- | ----- | -| [StackExchange.Redis](https://www.nuget.org/packages/StackExchange.Redis/) | [![StackExchange.Redis](https://img.shields.io/nuget/v/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/) | [![StackExchange.Redis](https://img.shields.io/nuget/vpre/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/absoluteLatest) | [![StackExchange.Redis](https://img.shields.io/nuget/dt/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/) | [![StackExchange.Redis MyGet](https://img.shields.io/myget/stackoverflow/vpre/StackExchange.Redis.svg)](https://www.myget.org/feed/stackoverflow/package/nuget/StackExchange.Redis) | +| Package | NuGet Stable | NuGet Pre-release | Downloads | +| ------- | ------------ | ----------------- | --------- | +| [StackExchange.Redis](https://www.nuget.org/packages/StackExchange.Redis/) | [![StackExchange.Redis](https://img.shields.io/nuget/v/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/) | [![StackExchange.Redis](https://img.shields.io/nuget/vpre/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/absoluteLatest) | [![StackExchange.Redis](https://img.shields.io/nuget/dt/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/) | Release notes at: [GitHub Releases](https://github.com/StackExchange/StackExchange.Redis/releases) (3.0 onwards; [earlier releases](https://seredis.dev/ReleaseNotes)) diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 678032414..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,84 +0,0 @@ -image: -- Visual Studio 2019 - -init: - - git config --global core.autocrlf input - -install: -- cmd: >- - choco install dotnet-9.0-sdk - - cd tests\RedisConfigs\3.0.503 - - redis-server.exe --service-install --service-name "redis-6379" "..\Basic\primary-6379-3.0.conf" - - redis-server.exe --service-install --service-name "redis-6380" "..\Basic\replica-6380.conf" - - redis-server.exe --service-install --service-name "redis-6381" "..\Basic\secure-6381.conf" - - redis-server.exe --service-install --service-name "redis-6382" "..\Failover\primary-6382.conf" - - redis-server.exe --service-install --service-name "redis-6383" "..\Failover\replica-6383.conf" - - redis-server.exe --service-install --service-name "redis-7000" "..\Cluster\cluster-7000.conf" --dir "..\Cluster" - - redis-server.exe --service-install --service-name "redis-7001" "..\Cluster\cluster-7001.conf" --dir "..\Cluster" - - redis-server.exe --service-install --service-name "redis-7002" "..\Cluster\cluster-7002.conf" --dir "..\Cluster" - - redis-server.exe --service-install --service-name "redis-7003" "..\Cluster\cluster-7003.conf" --dir "..\Cluster" - - redis-server.exe --service-install --service-name "redis-7004" "..\Cluster\cluster-7004.conf" --dir "..\Cluster" - - redis-server.exe --service-install --service-name "redis-7005" "..\Cluster\cluster-7005.conf" --dir "..\Cluster" - - redis-server.exe --service-install --service-name "redis-7010" "..\Sentinel\redis-7010.conf" - - redis-server.exe --service-install --service-name "redis-7011" "..\Sentinel\redis-7011.conf" - - redis-server.exe --service-install --service-name "redis-26379" "..\Sentinel\sentinel-26379.conf" --sentinel - - redis-server.exe --service-install --service-name "redis-26380" "..\Sentinel\sentinel-26380.conf" --sentinel - - redis-server.exe --service-install --service-name "redis-26381" "..\Sentinel\sentinel-26381.conf" --sentinel - - cd ..\..\.. -- ps: >- - if (Get-Command "Start-Service" -errorAction SilentlyContinue) { - Start-Service redis-* - } - -branches: - only: - - main - -skip_branch_with_pr: true -skip_tags: true -skip_commits: - files: - - '**/*.md' - - docs/* - -environment: - Appveyor: true - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - -nuget: - disable_publish_on_pr: true - -build_script: -- ps: .\build.ps1 -PullRequestNumber "$env:APPVEYOR_PULL_REQUEST_NUMBER" -CreatePackages ($env:OS -eq "Windows_NT") -NetCoreOnlyTests - -test: off -artifacts: -- path: .\.nupkgs\*.nupkg -- path: '**\*.trx' - -deploy: -- provider: NuGet - server: https://www.myget.org/F/stackoverflow/api/v2 - on: - branch: main - api_key: - secure: P/UHxq2DEs0GI1SoDXDesHjRVsSVgdywz5vmsnhFQQY5aJgO3kP+QfhwfhXz19Rw - symbol_server: https://www.myget.org/F/stackoverflow/symbols/api/v2/package \ No newline at end of file diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 500a416dd..6c435d6cb 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -2,9 +2,9 @@ Current package versions: -| NuGet Stable | NuGet Pre-release | MyGet | -| ------------ | ----------------- | ----- | -| [![StackExchange.Redis](https://img.shields.io/nuget/v/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/) | [![StackExchange.Redis](https://img.shields.io/nuget/vpre/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/) | [![StackExchange.Redis MyGet](https://img.shields.io/myget/stackoverflow/vpre/StackExchange.Redis.svg)](https://www.myget.org/feed/stackoverflow/package/nuget/StackExchange.Redis) | +| NuGet Stable | NuGet Pre-release | +| ------------ | ----------------- | +| [![StackExchange.Redis](https://img.shields.io/nuget/v/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/) | [![StackExchange.Redis](https://img.shields.io/nuget/vpre/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/) | ## 3.0