Add Preview workflows and enforce versioning rules (#1088) #342
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Release | |
| on: | |
| push: | |
| branches: [ main, 'release/*.x' ] | |
| workflow_dispatch: | |
| env: | |
| configuration: Release | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| release: | |
| runs-on: windows-latest | |
| environment: | |
| name: release | |
| permissions: | |
| contents: write | |
| outputs: | |
| nbgv: ${{ steps.nbgv.outputs.SemVer2 }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Validate publish branch | |
| shell: pwsh | |
| env: | |
| REF_NAME: ${{ github.ref_name }} | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| if ($env:REF_NAME -ne 'main' -and $env:REF_NAME -notmatch '^release/(0|[1-9]\d*)\.x$') { | |
| throw "release.yml triggered on '$env:REF_NAME' which is neither 'main' nor 'release/<major>.x'. Refusing to publish." | |
| } | |
| Write-Host "OK: publishing from '$env:REF_NAME'." | |
| - name: Setup .NET (With cache) | |
| uses: actions/setup-dotnet@v5.0.1 | |
| with: | |
| dotnet-version: | | |
| 6.0.x | |
| 7.0.x | |
| 8.0.x | |
| 9.0.x | |
| 10.0.x | |
| cache: true | |
| cache-dependency-path: | | |
| **/Directory.Packages.props | |
| **/*.sln | |
| **/*.csproj | |
| **/global.json | |
| **/nuget.config | |
| - name: NBGV | |
| id: nbgv | |
| uses: dotnet/nbgv@v0.5.1 | |
| with: | |
| setAllVars: true | |
| - name: Verify version matches branch policy | |
| shell: pwsh | |
| env: | |
| SEMVER2: ${{ steps.nbgv.outputs.SemVer2 }} | |
| PRERELEASE: ${{ steps.nbgv.outputs.PrereleaseVersion }} | |
| REF_NAME: ${{ github.ref_name }} | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| if ($env:REF_NAME -eq 'main' -and -not $env:PRERELEASE) { | |
| throw "Refusing to publish stable '$env:SEMVER2' from main. main must always publish prereleases. Check version.json for an accidental switch to a non-prerelease form." | |
| } | |
| if ($env:PRERELEASE -and $env:REF_NAME -match '^release/(0|[1-9]\d*)\.x$') { | |
| throw "Refusing to publish prerelease '$env:SEMVER2' from a release branch ('$env:REF_NAME'). Release branches must only publish stable versions." | |
| } | |
| if (-not $env:PRERELEASE) { | |
| Write-Host "Stable release ($env:SEMVER2); skipping prerelease regression check." | |
| exit 0 | |
| } | |
| if ($env:SEMVER2 -notmatch '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)-') { | |
| throw "Could not parse SemVer2 '$env:SEMVER2'" | |
| } | |
| $major = $matches[1] | |
| $minor = $matches[2] | |
| git fetch --tags --force origin | |
| if ($LASTEXITCODE -ne 0) { throw "git fetch --tags failed (exit $LASTEXITCODE); cannot validate prerelease regression." } | |
| $majorEsc = [regex]::Escape($major) | |
| $minorEsc = [regex]::Escape($minor) | |
| $stableTags = git tag --list "$major.$minor.*" | Where-Object { $_ -match "^${majorEsc}\.${minorEsc}\.\d+$" } | |
| if ($stableTags) { | |
| $list = $stableTags -join ', ' | |
| throw "Stable for $major.$minor has already shipped (tags: $list); cannot publish prerelease '$env:SEMVER2'. Bump main's version.json to the next minor or major preview line." | |
| } | |
| Write-Host "OK: no stable $major.$minor.* tag exists; '$env:SEMVER2' is safe to publish." | |
| - name: NuGet Restore | |
| run: dotnet restore DynamicData.sln | |
| working-directory: src | |
| - name: Run Tests | |
| run: dotnet test --no-restore --configuration Release DynamicData.sln | |
| working-directory: src | |
| - name: Pack | |
| run: dotnet pack --no-restore --no-build --configuration Release DynamicData.sln | |
| working-directory: src | |
| - name: NuGet Push | |
| env: | |
| NUGET_AUTH_TOKEN: ${{ secrets.NUGET_API_KEY }} | |
| SOURCE_URL: https://api.nuget.org/v3/index.json | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $packages = Get-ChildItem -Path src -Recurse -Filter '*.nupkg' | Where-Object { $_.FullName -like '*\bin\Release\*' } | |
| if (-not $packages) { throw "No .nupkg files found under src/**/bin/Release/." } | |
| foreach ($pkg in $packages) { | |
| dotnet nuget push -s $env:SOURCE_URL -k $env:NUGET_AUTH_TOKEN --skip-duplicate $pkg.FullName | |
| if ($LASTEXITCODE -ne 0) { throw "dotnet nuget push failed for $($pkg.Name) (exit $LASTEXITCODE)." } | |
| } | |
| - name: Changelog | |
| uses: glennawatson/ChangeLog@0464dd89b26f61fecf24b41d675f8ffdb11c4c3f # v1 | |
| id: changelog | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2.6.2 | |
| with: | |
| tag_name: ${{ steps.nbgv.outputs.SemVer2 }} | |
| name: ${{ steps.nbgv.outputs.SemVer2 }} | |
| prerelease: ${{ steps.nbgv.outputs.PrereleaseVersion != '' }} | |
| body: | | |
| ${{ steps.changelog.outputs.commitLog }} |