diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 95dc588c..a18a17f4 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -29,12 +29,25 @@ jobs: with: setAllVars: true + # deliberately before restore/build, so the version is legible even when a later step + # fails. Cutting a release means tagging with exactly what a *main* run prints - a PR + # run builds refs/pull/N/merge, whose height includes the branch commits and the merge, + # so its number is not the one that will ship + - name: Report computed version + run: | + $version = nbgv get-version --variable NuGetPackageVersion + if ($env:GITHUB_REF -eq 'refs/heads/main') { + "### Computed package version: ``$version``" >> $env:GITHUB_STEP_SUMMARY + "Tag the release with exactly this." >> $env:GITHUB_STEP_SUMMARY + } else { + "### Computed package version: ``$version``" >> $env:GITHUB_STEP_SUMMARY + "_This is a ``$env:GITHUB_REF`` build - **not** the version that would ship. Read the release version off a main run._" >> $env:GITHUB_STEP_SUMMARY + } + Write-Output "Computed package version: $version (ref: $env:GITHUB_REF)" + - name: Restore dependencies run: dotnet restore Build.csproj - - name: Purge - run: del src/Dapper.*/bin/Release/Dapper.*.nupkg - - name: Build run: dotnet build Build.csproj --no-restore -c Release @@ -48,13 +61,3 @@ jobs: # compared at test time - so without this, a netfx golden can be wrong and CI stays green - name: Test .NET Framework 4.8 run: dotnet test Build.csproj --no-build --verbosity normal -c Release -f net48 --filter FullyQualifiedName!~Integration - - - name: Pack - if: ${{ success() && !github.base_ref }} - run: dotnet pack src/Dapper.AOT/Dapper.AOT.csproj --no-build --verbosity normal -c Release - - - name: Push to MyGet - if: ${{ success() && !github.base_ref }} - run: dotnet nuget push src/Dapper.*/bin/Release/Dapper.*.nupkg --source https://www.myget.org/F/dapper/api/v2/package --api-key "$env:MYGETAPIKEY" - env: - MYGETAPIKEY: ${{ secrets.MYGETAPIKEY }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..8f76b564 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,101 @@ +# Publishes Dapper.AOT and Dapper.Advisor to nuget.org when a GitHub Release is published. +# +# Auth is NuGet Trusted Publishing (OIDC): no long-lived API key is stored anywhere. +# One-time setup on nuget.org, for *each* package: username menu -> Trusted Publishing -> +# add a policy with +# Repository Owner: DapperLib / Repository: DapperAOT / Workflow File: release.yml +# Environment: release +# plus a NUGET_USER repository secret holding the nuget.org profile name to publish as, +# and a GitHub environment named "release". +# +# 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 a green main run's step +# summary ("Report computed version" in dotnet.yml) and create the release with exactly that +# tag; the guard step below fails the run on any mismatch rather than publishing a package +# that disagrees with its release. A leading "v" is accepted and stripped, matching +# publicReleaseRefSpec in version.json. +# +# Deliberately does not run tests: the commit being released already passed CI, and this job's +# only job is to reproduce that build and push it. Runs on Windows to match dotnet.yml, since +# the solution includes a net48 leg and that is the configuration CI already proves. + +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: windows-latest + environment: release + permissions: + id-token: write # for the OIDC exchange with nuget.org + contents: read + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # depth is needed for nbgv + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 6.0.x + 8.0.x + 10.0.x + + - uses: dotnet/nbgv@master + with: + setAllVars: true + + - name: Verify tag matches computed version + if: github.event_name == 'release' + run: | + $computed = nbgv get-version --variable NuGetPackageVersion + $tag = "${{ github.event.release.tag_name }}" -replace '^v', '' + if ($computed -ne $tag) { + Write-Output "::error::Tag '$tag' does not match the computed version '$computed'; retag the release commit so the two agree." + exit 1 + } + "### Publishing: ``$computed``" >> $env:GITHUB_STEP_SUMMARY + Write-Output "Publishing $computed" + + - name: Restore dependencies + run: dotnet restore Build.csproj + + - name: Purge + run: del src/Dapper.*/bin/Release/Dapper.*.nupkg + + # both src projects set GeneratePackageOnBuild for Release, so this produces + # Dapper.AOT and Dapper.Advisor without a separate pack step + - name: Build + run: dotnet build Build.csproj --no-restore -c Release + + - name: Collect packages + run: | + New-Item -ItemType Directory -Force -Path .nupkgs | Out-Null + Copy-Item src/Dapper.*/bin/Release/Dapper.*.nupkg .nupkgs/ + Get-ChildItem .nupkgs/*.nupkg | ForEach-Object { Write-Output $_.Name } + + # 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 2ac0e4b3..67309dc2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +[![Build](https://github.com/DapperLib/DapperAOT/actions/workflows/dotnet.yml/badge.svg)](https://github.com/DapperLib/DapperAOT/actions/workflows/dotnet.yml) +[![Dapper.AOT](https://img.shields.io/nuget/v/Dapper.AOT?label=Dapper.AOT)](https://www.nuget.org/packages/Dapper.AOT) +[![Dapper.Advisor](https://img.shields.io/nuget/v/Dapper.Advisor?label=Dapper.Advisor)](https://www.nuget.org/packages/Dapper.Advisor) + Let's face it: ADO.NET is a complicated API, and writing "good" ADO.NET code by hand is time consuming and error-prone. But a lot of times you also don't want the ceremony of an ORM like EF or LLBLGenPro - you just want to execute SQL! @@ -5,4 +9,4 @@ For years now, Dapper helped by providing a great low-friction way of talking to Dapper.AOT radically changes how Dapper works, generating the necessary code *during build*, and offers a range of usage guidance to improve how you use Dapper. -[Getting Started](https://aot.dapperlib.dev/gettingstarted) | [Documentation](https://aot.dapperlib.dev/) \ No newline at end of file +[Getting Started](https://aot.dapperlib.dev/gettingstarted) | [Documentation](https://aot.dapperlib.dev/) diff --git a/test/Dapper.AOT.Test/Interceptors/CommandDefinitionOverloads.output.netfx.txt b/test/Dapper.AOT.Test/Interceptors/CommandDefinitionOverloads.output.netfx.txt index 5ade3665..7b996834 100644 --- a/test/Dapper.AOT.Test/Interceptors/CommandDefinitionOverloads.output.netfx.txt +++ b/test/Dapper.AOT.Test/Interceptors/CommandDefinitionOverloads.output.netfx.txt @@ -1,4 +1,10 @@ -Generator produced 1 diagnostics: +Generator produced 3 diagnostics: Hidden DAP000 L1 C1 -Dapper.AOT handled 1 of 3 enabled call-sites (0 unsupported API, 0 refused with diagnostics, 2 skipped silently) using 1 interceptors, 1 commands and 0 readers +Dapper.AOT handled 1 of 3 enabled call-sites (0 unsupported API, 2 refused with diagnostics, 0 skipped silently) using 1 interceptors, 1 commands and 0 readers + +Info DAP057 Interceptors/CommandDefinitionOverloads.input.cs L18 C24 +'Query' passes its SQL inside a CommandDefinition, which Dapper.AOT cannot read at build time; use the overload that takes the SQL directly. This call-site is left on vanilla Dapper, which will not work under native AOT + +Info DAP057 Interceptors/CommandDefinitionOverloads.input.cs L19 C24 +'Execute' passes its SQL inside a CommandDefinition, which Dapper.AOT cannot read at build time; use the overload that takes the SQL directly. This call-site is left on vanilla Dapper, which will not work under native AOT diff --git a/version.json b/version.json index 01f9d210..d5f097f4 100644 --- a/version.json +++ b/version.json @@ -1,11 +1,11 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", "version": "1.1", - "versionHeightOffset": -1, + "versionHeightOffset": -3, "assemblyVersion": "1.0.0.0", "publicReleaseRefSpec": [ "^refs/heads/main$", - "^refs/tags/v\\d+\\.\\d+" + "^refs/tags/v?\\d+\\.\\d+" ], "nugetPackageVersion": { "semVer": 2