From f19d95e8178d359c5ce6b0f90af8603231a31083 Mon Sep 17 00:00:00 2001 From: Eric Sitarz Date: Mon, 17 Aug 2026 13:27:05 -0500 Subject: [PATCH 1/4] EX-3857 Publish SDK to NuGet via Trusted Publishing OIDC login replaces the expired API key, nupkg download is scoped to the release tag, and a version bump on master publishes the GitHub release so humans only review the PR. Co-authored-by: Cursor --- .github/workflows/draft-release.yml | 47 ++++++++++++++++++++++------- .github/workflows/publish.yml | 39 +++++++++++++++++++++--- 2 files changed, 70 insertions(+), 16 deletions(-) diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml index 5ac9b03..2b107d5 100644 --- a/.github/workflows/draft-release.yml +++ b/.github/workflows/draft-release.yml @@ -5,12 +5,17 @@ on: branches: [ "master" ] workflow_dispatch: # manual trigger +permissions: + contents: write + jobs: build_test_pack: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Setup .NET uses: actions/setup-dotnet@v3 @@ -25,30 +30,48 @@ jobs: - name: Test run: dotnet test -c Release --no-build --verbosity normal - - # Compare version from csproj with latest release tag. - # If different, create a draft release. - + + # If csproj version differs from the latest GitHub release, publish a release + # (nupkg attached). That triggers publish.yml / NuGet Trusted Publishing. + - name: Get csproj version id: csproj_ver uses: KageKirin/get-csproj-version@v1.0.0 with: file: src/OrderCloud.SDK/OrderCloud.SDK.csproj - + - name: Get latest release tag id: release_ver uses: InsonusK/get-latest-release@v1.0.1 with: - myToken: ${{ github.token }} #required to see drafts + myToken: ${{ github.token }} exclude_types: prerelease view_top: 1 - + - name: Output versions run: | echo "csproj version: ${{ steps.csproj_ver.outputs.version }}" echo "latest release: ${{ steps.release_ver.outputs.tag_name }}" - - - name: Draft release + + - name: Build release notes + id: notes + env: + CSPROJ_VER: ${{ steps.csproj_ver.outputs.version }} + RELEASE_VER: ${{ steps.release_ver.outputs.tag_name }} + if: env.CSPROJ_VER != env.RELEASE_VER + run: | + { + echo "body</dev/null 2>&1; then + echo + echo "### Commits since $RELEASE_VER" + git log --oneline "${RELEASE_VER}..HEAD" --no-merges | head -20 || true + fi + echo "EOF" + } >> "$GITHUB_OUTPUT" + + - name: Create and publish release env: CSPROJ_VER: ${{ steps.csproj_ver.outputs.version }} RELEASE_VER: ${{ steps.release_ver.outputs.tag_name }} @@ -56,6 +79,8 @@ jobs: uses: ncipollo/release-action@v1.10.0 with: tag: ${{ env.CSPROJ_VER }} - body: "- Updates for latest OrderCloud API version" + name: ${{ env.CSPROJ_VER }} + body: ${{ steps.notes.outputs.body }} artifacts: "**/*.nupkg" - draft: true + draft: false + skipIfReleaseExists: true diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 80ccdf1..c524abb 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,24 +3,53 @@ name: Publish on: release: types: [published] - workflow_dispatch: #manual trigger + workflow_dispatch: + inputs: + tag: + description: Release tag to publish (e.g. 0.19.2). Required for workflow_dispatch. + required: true + type: string jobs: publish: runs-on: ubuntu-latest + # No GitHub Environment yet — nuget.org Trusted Publishing policy has Environment blank. + # When adding nuget-prod: set environment here AND on the nuget.org policy. + permissions: + id-token: write + contents: read steps: - name: Setup .NET uses: actions/setup-dotnet@v3 with: dotnet-version: 8.0.x - + + - name: Resolve release tag + id: tag + env: + EVENT_NAME: ${{ github.event_name }} + RELEASE_TAG: ${{ github.event.release.tag_name }} + INPUT_TAG: ${{ inputs.tag }} + run: | + if [ "$EVENT_NAME" = "release" ]; then + echo "name=$RELEASE_TAG" >> "$GITHUB_OUTPUT" + else + echo "name=$INPUT_TAG" >> "$GITHUB_OUTPUT" + fi + - name: Download package uses: robinraju/release-downloader@v1.4 with: - latest: true + tag: ${{ steps.tag.outputs.name }} filename: "*.nupkg" token: ${{ github.token }} - + + - name: NuGet login (OIDC → temp API key) + uses: NuGet/login@v1 + id: login + with: + user: ${{ secrets.NUGET_USER }} + - name: Publish to NuGet - run: dotnet nuget push "*.nupkg" --api-key ${{secrets.nuget_api_key}} --source https://api.nuget.org/v3/index.json --skip-duplicate + run: dotnet nuget push "*.nupkg" --api-key "${{ steps.login.outputs.NUGET_API_KEY }}" --source https://api.nuget.org/v3/index.json --skip-duplicate From ec16f2ba750d49f76f80f1e7de9ebd5ea7627588 Mon Sep 17 00:00:00 2001 From: Eric Sitarz Date: Tue, 18 Aug 2026 13:30:23 -0500 Subject: [PATCH 2/4] EX-3857 Pin NuGet/login to commit SHA Version tags can be moved; the SHA for v1.2.0 cannot. --- .github/workflows/publish.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c524abb..1539f8f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -46,7 +46,8 @@ jobs: token: ${{ github.token }} - name: NuGet login (OIDC → temp API key) - uses: NuGet/login@v1 + # Pin to commit SHA (v1.2.0). Tags like v1 can be moved; the SHA cannot. + uses: NuGet/login@8d196754b4036150537f80ac539e15c2f1028841 id: login with: user: ${{ secrets.NUGET_USER }} From 964c9fe5ef040549ca7a2221a55dc75c03ba926c Mon Sep 17 00:00:00 2001 From: Eric Sitarz Date: Wed, 19 Aug 2026 13:42:20 -0500 Subject: [PATCH 3/4] EX-3857 Call publish.yml from the Release workflow A GitHub release created with GITHUB_TOKEN does not start other workflows. workflow_call keeps Trusted Publishing on publish.yml. --- .github/workflows/draft-release.yml | 42 ++++++++++++++++++++++++----- .github/workflows/publish.yml | 9 +++++++ 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml index 2b107d5..a170122 100644 --- a/.github/workflows/draft-release.yml +++ b/.github/workflows/draft-release.yml @@ -1,4 +1,4 @@ -name: Draft Release +name: Release on: push: @@ -7,10 +7,14 @@ on: permissions: contents: write + id-token: write jobs: build_test_pack: runs-on: ubuntu-latest + outputs: + publish: ${{ steps.decide.outputs.publish }} + tag: ${{ steps.csproj_ver.outputs.version }} steps: - name: Checkout uses: actions/checkout@v3 @@ -31,9 +35,6 @@ jobs: - name: Test run: dotnet test -c Release --no-build --verbosity normal - # If csproj version differs from the latest GitHub release, publish a release - # (nupkg attached). That triggers publish.yml / NuGet Trusted Publishing. - - name: Get csproj version id: csproj_ver uses: KageKirin/get-csproj-version@v1.0.0 @@ -53,12 +54,27 @@ jobs: echo "csproj version: ${{ steps.csproj_ver.outputs.version }}" echo "latest release: ${{ steps.release_ver.outputs.tag_name }}" + # A release created with GITHUB_TOKEN does not start other workflows + # (https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/trigger-a-workflow#triggering-a-workflow-from-a-workflow). + # Call publish.yml via workflow_call instead of relying on the release event. + - name: Decide whether to publish + id: decide + env: + CSPROJ_VER: ${{ steps.csproj_ver.outputs.version }} + RELEASE_VER: ${{ steps.release_ver.outputs.tag_name }} + run: | + if [ "$CSPROJ_VER" != "$RELEASE_VER" ]; then + echo "publish=true" >> "$GITHUB_OUTPUT" + else + echo "publish=false" >> "$GITHUB_OUTPUT" + fi + - name: Build release notes id: notes + if: steps.decide.outputs.publish == 'true' env: CSPROJ_VER: ${{ steps.csproj_ver.outputs.version }} RELEASE_VER: ${{ steps.release_ver.outputs.tag_name }} - if: env.CSPROJ_VER != env.RELEASE_VER run: | { echo "body<> "$GITHUB_OUTPUT" - name: Create and publish release + if: steps.decide.outputs.publish == 'true' env: CSPROJ_VER: ${{ steps.csproj_ver.outputs.version }} - RELEASE_VER: ${{ steps.release_ver.outputs.tag_name }} - if: env.CSPROJ_VER != env.RELEASE_VER uses: ncipollo/release-action@v1.10.0 with: tag: ${{ env.CSPROJ_VER }} @@ -84,3 +99,16 @@ jobs: artifacts: "**/*.nupkg" draft: false skipIfReleaseExists: true + + # Same pipeline, not a GITHUB_TOKEN-triggered release event. Keeps nuget.org + # Trusted Publishing policy pointed at publish.yml. + publish: + needs: build_test_pack + if: needs.build_test_pack.outputs.publish == 'true' + uses: ./.github/workflows/publish.yml + with: + tag: ${{ needs.build_test_pack.outputs.tag }} + secrets: inherit + permissions: + id-token: write + contents: read diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1539f8f..2660ed0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,6 +1,9 @@ name: Publish on: + # Human-created GitHub releases (UI) still fire this. Releases created by + # GITHUB_TOKEN in the Release workflow do not; that path calls this file via + # workflow_call instead. release: types: [published] workflow_dispatch: @@ -9,6 +12,12 @@ on: description: Release tag to publish (e.g. 0.19.2). Required for workflow_dispatch. required: true type: string + workflow_call: + inputs: + tag: + description: Release tag whose nupkg should be pushed to NuGet. + required: true + type: string jobs: publish: From be37cf081b4ed66ac34b9adde233917e914a5f4f Mon Sep 17 00:00:00 2001 From: Eric Sitarz Date: Wed, 19 Aug 2026 14:08:49 -0500 Subject: [PATCH 4/4] EX-3857 Bump Actions off deprecated Node 20 checkout v5, setup-dotnet v5, and release-downloader v1.13 run on Node 24. --- .github/workflows/ci.yml | 4 ++-- .github/workflows/draft-release.yml | 4 ++-- .github/workflows/publish.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 87f359c..2ac819a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,10 +10,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v5 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: 8.0.x diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml index a170122..cb1ac6e 100644 --- a/.github/workflows/draft-release.yml +++ b/.github/workflows/draft-release.yml @@ -17,12 +17,12 @@ jobs: tag: ${{ steps.csproj_ver.outputs.version }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: 8.0.x diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2660ed0..44c7e78 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: 8.0.x @@ -48,10 +48,10 @@ jobs: fi - name: Download package - uses: robinraju/release-downloader@v1.4 + uses: robinraju/release-downloader@v1.13 with: tag: ${{ steps.tag.outputs.name }} - filename: "*.nupkg" + fileName: "*.nupkg" token: ${{ github.token }} - name: NuGet login (OIDC → temp API key)