From b959c5be5d936fa9e163eb6a5dbcadeee8e604f6 Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Thu, 28 May 2026 16:20:18 -0300 Subject: [PATCH 01/12] [PLA-2420] Fix release CI --- .github/workflows/build.yml | 142 +++++++++++++++++++++++++++++++++++- .github/workflows/unity.yml | 104 -------------------------- 2 files changed, 140 insertions(+), 106 deletions(-) delete mode 100644 .github/workflows/unity.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e4f4a3d..f804c58 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,6 +7,11 @@ on: tags: - '*' pull_request: + workflow_dispatch: + inputs: + version: + description: 'UPM version to build (without leading v), e.g. 3.0.0. Only used by the upm job; the main build runs on the current ref.' + required: false permissions: contents: write @@ -52,8 +57,141 @@ jobs: - name: Build NuGet Packages run: dotnet pack ./src/Enjin.Platform.Sdk/Enjin.Platform.Sdk/Enjin.Platform.Sdk.csproj --configuration Release --no-build --output ./src/Enjin.Platform.Sdk/nuget-packages/ - - name: Upload Artifacts + - name: Upload nupkgs to draft release uses: softprops/action-gh-release@v2 - if: startsWith(github.ref, 'refs/tags/') + if: startsWith(github.ref, 'refs/tags/v') with: + # Keep the release in draft mode until the publish-release job flips + # it. softprops/action-gh-release upserts the release, so uploads from + # multiple jobs/workflows on the same tag all attach to the same + # draft. This avoids the "immutable release" upload error that + # happens when assets are pushed after publication. + draft: true files: ./src/Enjin.Platform.Sdk/nuget-packages/*.nupkg + + - name: Publish to NuGet.org + if: startsWith(github.ref, 'refs/tags/v') + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + run: | + dotnet nuget push ./src/Enjin.Platform.Sdk/nuget-packages/*.nupkg \ + --api-key "${NUGET_API_KEY}" \ + --source https://api.nuget.org/v3/index.json \ + --skip-duplicate + + upm: + # Assembles the Unity Package Manager distribution from unity-template/ + + # the freshly-built DLL, pushes it to a parallel `upm/v` git tag + # (which is what users reference in their Unity Package Manager git URL), + # and attaches the tarball to the same draft GitHub Release. + needs: build + if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Need full history + a writable token so we can push the upm/ tag. + fetch-depth: 0 + persist-credentials: true + + - name: Determine version + id: version + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + VERSION="${{ github.event.inputs.version }}" + if [[ -z "${VERSION}" ]]; then + echo "::error::workflow_dispatch requires the 'version' input" + exit 1 + fi + else + # strip leading 'v' from refs/tags/v3.0.0 + VERSION="${GITHUB_REF_NAME#v}" + fi + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + echo "Building UPM package for version ${VERSION}" + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.0.x + + - name: Cache NuGet Packages + uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} + restore-keys: | + ${{ runner.os }}-nuget- + + - name: Build SDK (Release) + run: dotnet build ./src/Enjin.Platform.Sdk/Enjin.Platform.Sdk/Enjin.Platform.Sdk.csproj --configuration Release + + - name: Assemble UPM package + run: ./scripts/assemble-upm.sh ${{ steps.version.outputs.version }} + + - name: Push upm/ tag + # This is what end users reference in their Unity Package Manager git URL: + # https://github.com/enjin/platform-csharp-sdk.git#upm/v3.0.0 + # The tag points at an orphan commit whose tree is exactly the contents + # of upm-staging/, so Unity's git fetcher sees a valid UPM package at + # the repo root (without any ?path= suffix needed). + # + # NOTE: the repo's tag-name ruleset must allow upm/v* tags (or grant a + # bypass to github-actions). Otherwise the push is rejected with + # "Tag name must match a given regex pattern". + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + VERSION="${{ steps.version.outputs.version }}" + UPM_TAG="upm/v${VERSION}" + + WORK="$(mktemp -d)" + cp -R upm-staging/. "${WORK}/" + ( + cd "${WORK}" + git init -q -b "${UPM_TAG}" + git remote add origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" + git add -A + git -c user.name="github-actions[bot]" \ + -c user.email="41898282+github-actions[bot]@users.noreply.github.com" \ + commit -q -m "UPM package v${VERSION}" + git tag -f "${UPM_TAG}" + git push -f origin "refs/tags/${UPM_TAG}" + ) + rm -rf "${WORK}" + echo "Pushed tag ${UPM_TAG}" + + - name: Attach UPM tarball to draft release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/v') + with: + draft: true + files: EnjinPlatformSdk-v${{ steps.version.outputs.version }}-upm.tar.gz + + - name: Upload tarball as workflow artifact + # Always upload (including workflow_dispatch runs) so manual builds are + # downloadable for inspection without needing a release. + uses: actions/upload-artifact@v4 + with: + name: EnjinPlatformSdk-v${{ steps.version.outputs.version }}-upm + path: EnjinPlatformSdk-v${{ steps.version.outputs.version }}-upm.tar.gz + + publish-release: + # Flip the draft release to published once both the nupkgs and UPM tarball + # have been attached. This step is what makes the release "go live" on the + # repo's Releases page and on the GitHub Releases API. + needs: [build, upm] + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + steps: + - name: Publish GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + run: | + set -euo pipefail + TAG="${GITHUB_REF_NAME}" + echo "Publishing release ${TAG}" + gh release edit "${TAG}" --draft=false diff --git a/.github/workflows/unity.yml b/.github/workflows/unity.yml deleted file mode 100644 index 73788e5..0000000 --- a/.github/workflows/unity.yml +++ /dev/null @@ -1,104 +0,0 @@ -name: Unity Package - -# Triggered on version-tag pushes (e.g. v3.0.0). Assembles the UPM distribution -# from unity-template/ + the freshly-built DLL, pushes it to a parallel -# `upm/` git tag (which is what users reference in their Unity -# Package Manager git URL), and attaches the tarball to the GitHub Release. - -on: - push: - tags: - - 'v*' - workflow_dispatch: - inputs: - version: - description: 'Version to build (without leading v), e.g. 3.0.0' - required: true - -permissions: - contents: write - -jobs: - upm: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - # Need full history + a writable token so we can push the upm/ tag. - fetch-depth: 0 - persist-credentials: true - - - name: Determine version - id: version - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - VERSION="${{ github.event.inputs.version }}" - else - # strip leading 'v' from refs/tags/v3.0.0 - VERSION="${GITHUB_REF_NAME#v}" - fi - echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - echo "Building UPM package for version ${VERSION}" - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 9.0.x - - - name: Cache NuGet Packages - uses: actions/cache@v4 - with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} - restore-keys: | - ${{ runner.os }}-nuget- - - - name: Build SDK (Release) - run: dotnet build ./src/Enjin.Platform.Sdk/Enjin.Platform.Sdk/Enjin.Platform.Sdk.csproj --configuration Release - - - name: Assemble UPM package - run: ./scripts/assemble-upm.sh ${{ steps.version.outputs.version }} - - - name: Push upm/ tag - # This is what end users reference in their Unity Package Manager git URL: - # https://github.com/enjin/platform-csharp-sdk.git#upm/v3.0.0 - # The tag points at an orphan commit whose tree is exactly the contents - # of upm-staging/, so Unity's git fetcher sees a valid UPM package at - # the repo root (without any ?path= suffix needed). - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - set -euo pipefail - VERSION="${{ steps.version.outputs.version }}" - UPM_TAG="upm/v${VERSION}" - - WORK="$(mktemp -d)" - cp -R upm-staging/. "${WORK}/" - ( - cd "${WORK}" - git init -q -b "${UPM_TAG}" - git remote add origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" - git add -A - git -c user.name="github-actions[bot]" \ - -c user.email="41898282+github-actions[bot]@users.noreply.github.com" \ - commit -q -m "UPM package v${VERSION}" - git tag -f "${UPM_TAG}" - git push -f origin "refs/tags/${UPM_TAG}" - ) - rm -rf "${WORK}" - echo "Pushed tag ${UPM_TAG}" - - - name: Attach tarball to GitHub Release - uses: softprops/action-gh-release@v2 - if: startsWith(github.ref, 'refs/tags/v') - with: - files: EnjinPlatformSdk-v${{ steps.version.outputs.version }}-upm.tar.gz - - - name: Upload tarball as workflow artifact - # Always upload (including workflow_dispatch runs) so manual builds are - # downloadable for inspection without needing a release. - uses: actions/upload-artifact@v4 - with: - name: EnjinPlatformSdk-v${{ steps.version.outputs.version }}-upm - path: EnjinPlatformSdk-v${{ steps.version.outputs.version }}-upm.tar.gz From cef8d69cb4eeaca3ced78747fdbbbd92bf096ac6 Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Thu, 28 May 2026 16:45:57 -0300 Subject: [PATCH 02/12] add default graphql endpoint --- .../Enjin.Platform.Sdk/Platform/PlatformClient.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk/Platform/PlatformClient.cs b/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk/Platform/PlatformClient.cs index faa9a50..1784ce4 100644 --- a/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk/Platform/PlatformClient.cs +++ b/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk/Platform/PlatformClient.cs @@ -15,6 +15,11 @@ namespace Enjin.Platform.Sdk; [PublicAPI] public sealed class PlatformClient : IPlatformClient { + /// + /// The default base address of the Enjin Platform GraphQL endpoint. + /// + public static readonly Uri DefaultBaseAddress = new("https://platform.enjin.io/graphql"); + private static readonly string DefaultUserAgent = BuildDefaultUserAgent(); private static string BuildDefaultUserAgent() @@ -58,21 +63,18 @@ private static string BuildDefaultUserAgent() /// /// Initializes a new . /// - /// The base address of the platform's GraphQL endpoint (e.g. https://platform.enjin.io/graphql). + /// The base address of the platform's GraphQL endpoint (e.g. https://platform.enjin.io/graphql). Defaults to . /// Optional User-Agent header value. Defaults to Enjin.Platform.Sdk/{assembly-version}. /// Optional logger; when provided HTTP traffic is logged at the given . /// HTTP log level. Ignored when is null. public PlatformClient( - Uri baseAddress, + Uri? baseAddress = null, string? userAgent = null, ILogger? logger = null, HttpLogLevel httpLogLevel = HttpLogLevel.None ) { - if (baseAddress == null) - { - throw new ArgumentNullException(nameof(baseAddress)); - } + baseAddress ??= DefaultBaseAddress; UserAgent = userAgent ?? DefaultUserAgent; From 26becceb1ab091c03ce6f94560813d10edb3f31f Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Thu, 28 May 2026 16:48:03 -0300 Subject: [PATCH 03/12] change user agent --- .../Unit/Platform/PlatformClientSmokeTest.cs | 2 +- .../Enjin.Platform.Sdk/Platform/PlatformClient.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk.Tests/Unit/Platform/PlatformClientSmokeTest.cs b/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk.Tests/Unit/Platform/PlatformClientSmokeTest.cs index c58dc1f..7328dcb 100644 --- a/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk.Tests/Unit/Platform/PlatformClientSmokeTest.cs +++ b/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk.Tests/Unit/Platform/PlatformClientSmokeTest.cs @@ -211,7 +211,7 @@ public void DefaultUserAgentIsDerivedFromAssemblyVersion() version = version[1..]; } - var expected = $"Enjin.Platform.Sdk/{version}"; + var expected = $"Enjin-Platform-CSharp-SDK/{version}"; // Act using var client = new PlatformClient(new Uri(_server.Urls[0] + "/graphql")); diff --git a/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk/Platform/PlatformClient.cs b/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk/Platform/PlatformClient.cs index 1784ce4..a861ced 100644 --- a/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk/Platform/PlatformClient.cs +++ b/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk/Platform/PlatformClient.cs @@ -43,7 +43,7 @@ private static string BuildDefaultUserAgent() version = version[1..]; } - return $"Enjin.Platform.Sdk/{version}"; + return $"Enjin-Platform-CSharp-SDK/{version}"; } private readonly HttpClient _httpClient; @@ -64,7 +64,7 @@ private static string BuildDefaultUserAgent() /// Initializes a new . /// /// The base address of the platform's GraphQL endpoint (e.g. https://platform.enjin.io/graphql). Defaults to . - /// Optional User-Agent header value. Defaults to Enjin.Platform.Sdk/{assembly-version}. + /// Optional User-Agent header value. Defaults to Enjin-Platform-CSharp-SDK/{assembly-version}. /// Optional logger; when provided HTTP traffic is logged at the given . /// HTTP log level. Ignored when is null. public PlatformClient( From b52175c37ba012e0970d3778a6dd15720b892804 Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Fri, 29 May 2026 13:13:45 -0300 Subject: [PATCH 04/12] review feedback --- .github/workflows/build.yml | 5 ++++- .../Unit/Platform/PlatformClientSmokeTest.cs | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f804c58..78834f4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -85,7 +85,10 @@ jobs: # (which is what users reference in their Unity Package Manager git URL), # and attaches the tarball to the same draft GitHub Release. needs: build - if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' + # Run on v* tag pushes, or on manual dispatches that supply a version. A + # workflow_dispatch with an empty version input is treated as "main build + # only" and skips the UPM job rather than hard-failing. + if: startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && github.event.inputs.version != '') runs-on: ubuntu-latest steps: - name: Checkout diff --git a/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk.Tests/Unit/Platform/PlatformClientSmokeTest.cs b/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk.Tests/Unit/Platform/PlatformClientSmokeTest.cs index 7328dcb..821f3c4 100644 --- a/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk.Tests/Unit/Platform/PlatformClientSmokeTest.cs +++ b/src/Enjin.Platform.Sdk/Enjin.Platform.Sdk.Tests/Unit/Platform/PlatformClientSmokeTest.cs @@ -219,4 +219,24 @@ public void DefaultUserAgentIsDerivedFromAssemblyVersion() // Assert Assert.That(client.UserAgent, Is.EqualTo(expected)); } + + [Test] + public void ParameterlessConstructorUsesDefaultBaseAddress() + { + // Act + using var client = new PlatformClient(); + + // Assert + Assert.That(client.BaseAddress, Is.EqualTo(PlatformClient.DefaultBaseAddress)); + } + + [Test] + public void NullBaseAddressUsesDefaultBaseAddress() + { + // Act + using var client = new PlatformClient(null); + + // Assert + Assert.That(client.BaseAddress, Is.EqualTo(PlatformClient.DefaultBaseAddress)); + } } From 7ab360172b4b9e018bc63daaf29c9ea0905ee08d Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Wed, 10 Jun 2026 13:40:00 -0300 Subject: [PATCH 05/12] publish upm to separate repo --- .github/workflows/build.yml | 99 ++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 30 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 78834f4..17fce4a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,6 +4,9 @@ on: push: branches: - master + # TEMP(PLA-2420): exercise the release/upm pipeline on this branch. + # Remove before merge. + - bugfix/PLA-2420/fix-release-ci tags: - '*' pull_request: @@ -81,22 +84,32 @@ jobs: upm: # Assembles the Unity Package Manager distribution from unity-template/ + - # the freshly-built DLL, pushes it to a parallel `upm/v` git tag - # (which is what users reference in their Unity Package Manager git URL), - # and attaches the tarball to the same draft GitHub Release. + # the freshly-built DLL and publishes it to the dedicated + # `enjin/platform-unity-sdk` repo: the package tree is committed to that + # repo's `master` branch (latest, always browsable) and pinned with a + # `v` git tag. Users reference either in their Unity Package + # Manager git URL: + # https://github.com/enjin/platform-unity-sdk.git (latest) + # https://github.com/enjin/platform-unity-sdk.git#v3.0.0 (pinned) + # The tarball is still attached to this repo's draft GitHub Release. needs: build # Run on v* tag pushes, or on manual dispatches that supply a version. A # workflow_dispatch with an empty version input is treated as "main build # only" and skips the UPM job rather than hard-failing. - if: startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && github.event.inputs.version != '') + # + # TEMP(PLA-2420): also run on pushes to bugfix/PLA-2420/fix-release-ci so + # the release/upm path can be smoke-tested before merge. The Determine + # version step below produces a synthetic test version on that branch, and + # the publish step pushes to a `ci-test` branch instead of `master`. Remove + # before merge. + if: | + startsWith(github.ref, 'refs/tags/v') + || (github.event_name == 'workflow_dispatch' && github.event.inputs.version != '') + || github.ref == 'refs/heads/bugfix/PLA-2420/fix-release-ci' runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - with: - # Need full history + a writable token so we can push the upm/ tag. - fetch-depth: 0 - persist-credentials: true - name: Determine version id: version @@ -107,12 +120,23 @@ jobs: echo "::error::workflow_dispatch requires the 'version' input" exit 1 fi - else + TAG="v${VERSION}" + elif [[ "${GITHUB_REF}" == refs/tags/v* ]]; then # strip leading 'v' from refs/tags/v3.0.0 VERSION="${GITHUB_REF_NAME#v}" + TAG="v${VERSION}" + else + # TEMP(PLA-2420): branch-driven smoke test. Use a synthetic + # version so we don't collide with real releases; the publish step + # routes this to a `ci-test` branch rather than master. Remove + # before merge. + SHORT_SHA="${GITHUB_SHA::7}" + VERSION="0.0.0-test.${SHORT_SHA}" + TAG="v${VERSION}" fi echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - echo "Building UPM package for version ${VERSION}" + echo "tag=${TAG}" >> "$GITHUB_OUTPUT" + echo "Building UPM package for version ${VERSION} (tag ${TAG})" - name: Setup .NET uses: actions/setup-dotnet@v4 @@ -133,38 +157,53 @@ jobs: - name: Assemble UPM package run: ./scripts/assemble-upm.sh ${{ steps.version.outputs.version }} - - name: Push upm/ tag - # This is what end users reference in their Unity Package Manager git URL: - # https://github.com/enjin/platform-csharp-sdk.git#upm/v3.0.0 - # The tag points at an orphan commit whose tree is exactly the contents - # of upm-staging/, so Unity's git fetcher sees a valid UPM package at - # the repo root (without any ?path= suffix needed). - # - # NOTE: the repo's tag-name ruleset must allow upm/v* tags (or grant a - # bypass to github-actions). Otherwise the push is rejected with - # "Tag name must match a given regex pattern". - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Setup SSH + # Loads the deploy-key for enjin/platform-unity-sdk so the publish step + # below can push over SSH. webfactory/ssh-agent also adds github.com to + # known_hosts. The matching public key must be registered as a + # write-enabled deploy key on enjin/platform-unity-sdk. + uses: webfactory/ssh-agent@v0.9.0 + with: + ssh-private-key: ${{ secrets.UNITY_SDK_DEPLOY_KEY }} + + - name: Publish package to platform-unity-sdk + # Commits the assembled upm-staging/ tree to the dedicated repo's master + # branch (latest) and pins it with a v tag. End users reference + # either in their Unity Package Manager git URL: + # https://github.com/enjin/platform-unity-sdk.git (latest) + # https://github.com/enjin/platform-unity-sdk.git#v3.0.0 (pinned) + # The package lives at the repo root, so no ?path= suffix is needed. run: | set -euo pipefail VERSION="${{ steps.version.outputs.version }}" - UPM_TAG="upm/v${VERSION}" + TAG="${{ steps.version.outputs.tag }}" + + # TEMP(PLA-2420): route smoke-test runs to a ci-test branch so the + # dedicated repo's master is never touched by test builds. Remove + # before merge. + BRANCH="master" + if [[ "${GITHUB_REF}" == refs/heads/bugfix/PLA-2420/fix-release-ci ]]; then + BRANCH="ci-test" + fi WORK="$(mktemp -d)" - cp -R upm-staging/. "${WORK}/" + git clone --depth 1 git@github.com:enjin/platform-unity-sdk.git "${WORK}" ( cd "${WORK}" - git init -q -b "${UPM_TAG}" - git remote add origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" + git checkout -B "${BRANCH}" + # Replace tracked contents with the freshly assembled package. + git rm -rqf . >/dev/null 2>&1 || true + cp -R "${GITHUB_WORKSPACE}/upm-staging/." . git add -A git -c user.name="github-actions[bot]" \ -c user.email="41898282+github-actions[bot]@users.noreply.github.com" \ - commit -q -m "UPM package v${VERSION}" - git tag -f "${UPM_TAG}" - git push -f origin "refs/tags/${UPM_TAG}" + commit -m "UPM package v${VERSION}" + git tag -f "${TAG}" + git push origin "HEAD:${BRANCH}" + git push -f origin "refs/tags/${TAG}" ) rm -rf "${WORK}" - echo "Pushed tag ${UPM_TAG}" + echo "Published v${VERSION} to platform-unity-sdk (${BRANCH} + tag ${TAG})" - name: Attach UPM tarball to draft release uses: softprops/action-gh-release@v2 From 33893a60babd376d0021cdd848bb4152d79beed2 Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Tue, 16 Jun 2026 11:01:51 -0300 Subject: [PATCH 06/12] use OIDC for nuget --- .github/workflows/build.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 17fce4a..05e1e61 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,6 +22,9 @@ permissions: jobs: build: runs-on: ubuntu-latest + permissions: + contents: write # upload nupkgs to the draft release + id-token: write # mint GitHub OIDC token for NuGet trusted publishing steps: - name: Checkout uses: actions/checkout@v4 @@ -72,13 +75,18 @@ jobs: draft: true files: ./src/Enjin.Platform.Sdk/nuget-packages/*.nupkg + - name: NuGet login (OIDC -> temp API key) + id: nuget-login + if: startsWith(github.ref, 'refs/tags/v') + uses: NuGet/login@v1 + with: + user: enjin + - name: Publish to NuGet.org if: startsWith(github.ref, 'refs/tags/v') - env: - NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} run: | dotnet nuget push ./src/Enjin.Platform.Sdk/nuget-packages/*.nupkg \ - --api-key "${NUGET_API_KEY}" \ + --api-key "${{ steps.nuget-login.outputs.NUGET_API_KEY }}" \ --source https://api.nuget.org/v3/index.json \ --skip-duplicate From 7e07123dcb25cf3a956d394e20e3694d0dce5237 Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Tue, 16 Jun 2026 12:08:16 -0300 Subject: [PATCH 07/12] ci: trigger release pipeline smoke test From 6be2177c705326db98c5efd7465356b0273e9f66 Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Tue, 16 Jun 2026 12:20:15 -0300 Subject: [PATCH 08/12] add temp nuget test --- .github/workflows/build.yml | 46 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 05e1e61..ea849d1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,8 +4,8 @@ on: push: branches: - master - # TEMP(PLA-2420): exercise the release/upm pipeline on this branch. - # Remove before merge. + # TEMP(PLA-2420): run on this branch to verify the NuGet OIDC trusted- + # publishing handshake (login only, no publish). Remove before merge. - bugfix/PLA-2420/fix-release-ci tags: - '*' @@ -77,11 +77,28 @@ jobs: - name: NuGet login (OIDC -> temp API key) id: nuget-login - if: startsWith(github.ref, 'refs/tags/v') + # TEMP(PLA-2420): also run on the smoke-test branch so the OIDC + # handshake can be verified without publishing. Restore to + # `if: startsWith(github.ref, 'refs/tags/v')` before merge. + if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/bugfix/PLA-2420/fix-release-ci' uses: NuGet/login@v1 with: user: enjin + # TEMP(PLA-2420): confirm the trusted-publishing policy matched and a + # temporary key was issued. Does NOT publish. Remove before merge. + - name: Verify OIDC key issued (smoke test) + if: github.ref == 'refs/heads/bugfix/PLA-2420/fix-release-ci' + env: + NUGET_API_KEY: ${{ steps.nuget-login.outputs.NUGET_API_KEY }} + run: | + if [[ -n "${NUGET_API_KEY}" ]]; then + echo "OIDC trusted-publishing handshake succeeded: temporary NuGet API key obtained." + else + echo "::error::NuGet/login returned no API key - check the trusted-publishing policy on nuget.org" + exit 1 + fi + - name: Publish to NuGet.org if: startsWith(github.ref, 'refs/tags/v') run: | @@ -104,16 +121,9 @@ jobs: # Run on v* tag pushes, or on manual dispatches that supply a version. A # workflow_dispatch with an empty version input is treated as "main build # only" and skips the UPM job rather than hard-failing. - # - # TEMP(PLA-2420): also run on pushes to bugfix/PLA-2420/fix-release-ci so - # the release/upm path can be smoke-tested before merge. The Determine - # version step below produces a synthetic test version on that branch, and - # the publish step pushes to a `ci-test` branch instead of `master`. Remove - # before merge. if: | startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && github.event.inputs.version != '') - || github.ref == 'refs/heads/bugfix/PLA-2420/fix-release-ci' runs-on: ubuntu-latest steps: - name: Checkout @@ -134,13 +144,8 @@ jobs: VERSION="${GITHUB_REF_NAME#v}" TAG="v${VERSION}" else - # TEMP(PLA-2420): branch-driven smoke test. Use a synthetic - # version so we don't collide with real releases; the publish step - # routes this to a `ci-test` branch rather than master. Remove - # before merge. - SHORT_SHA="${GITHUB_SHA::7}" - VERSION="0.0.0-test.${SHORT_SHA}" - TAG="v${VERSION}" + echo "::error::upm job triggered on an unsupported ref ${GITHUB_REF}" + exit 1 fi echo "version=${VERSION}" >> "$GITHUB_OUTPUT" echo "tag=${TAG}" >> "$GITHUB_OUTPUT" @@ -185,14 +190,7 @@ jobs: set -euo pipefail VERSION="${{ steps.version.outputs.version }}" TAG="${{ steps.version.outputs.tag }}" - - # TEMP(PLA-2420): route smoke-test runs to a ci-test branch so the - # dedicated repo's master is never touched by test builds. Remove - # before merge. BRANCH="master" - if [[ "${GITHUB_REF}" == refs/heads/bugfix/PLA-2420/fix-release-ci ]]; then - BRANCH="ci-test" - fi WORK="$(mktemp -d)" git clone --depth 1 git@github.com:enjin/platform-unity-sdk.git "${WORK}" From 800bcda2648197caf0e0bcc175f6fb1484f10699 Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Tue, 16 Jun 2026 12:29:11 -0300 Subject: [PATCH 09/12] use NUGET_USER secret --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ea849d1..571c523 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,7 +83,7 @@ jobs: if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/bugfix/PLA-2420/fix-release-ci' uses: NuGet/login@v1 with: - user: enjin + user: ${{ secrets.NUGET_USER }} # TEMP(PLA-2420): confirm the trusted-publishing policy matched and a # temporary key was issued. Does NOT publish. Remove before merge. From 080d22a05eaee508646cdba9886e7fd504499131 Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Tue, 16 Jun 2026 13:18:51 -0300 Subject: [PATCH 10/12] ci: trigger release pipeline smoke test From aa487189a61b9c7eef5fa0367fb30fcd341bfdcc Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Tue, 16 Jun 2026 13:27:38 -0300 Subject: [PATCH 11/12] remove test code --- .github/workflows/build.yml | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 571c523..9351155 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,9 +4,6 @@ on: push: branches: - master - # TEMP(PLA-2420): run on this branch to verify the NuGet OIDC trusted- - # publishing handshake (login only, no publish). Remove before merge. - - bugfix/PLA-2420/fix-release-ci tags: - '*' pull_request: @@ -77,28 +74,11 @@ jobs: - name: NuGet login (OIDC -> temp API key) id: nuget-login - # TEMP(PLA-2420): also run on the smoke-test branch so the OIDC - # handshake can be verified without publishing. Restore to - # `if: startsWith(github.ref, 'refs/tags/v')` before merge. - if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/bugfix/PLA-2420/fix-release-ci' + if: startsWith(github.ref, 'refs/tags/v') uses: NuGet/login@v1 with: user: ${{ secrets.NUGET_USER }} - # TEMP(PLA-2420): confirm the trusted-publishing policy matched and a - # temporary key was issued. Does NOT publish. Remove before merge. - - name: Verify OIDC key issued (smoke test) - if: github.ref == 'refs/heads/bugfix/PLA-2420/fix-release-ci' - env: - NUGET_API_KEY: ${{ steps.nuget-login.outputs.NUGET_API_KEY }} - run: | - if [[ -n "${NUGET_API_KEY}" ]]; then - echo "OIDC trusted-publishing handshake succeeded: temporary NuGet API key obtained." - else - echo "::error::NuGet/login returned no API key - check the trusted-publishing policy on nuget.org" - exit 1 - fi - - name: Publish to NuGet.org if: startsWith(github.ref, 'refs/tags/v') run: | From e9e17eaba1b36084b46736f3f74d1ab81a0076af Mon Sep 17 00:00:00 2001 From: Jay Pavlina Date: Tue, 16 Jun 2026 13:36:20 -0300 Subject: [PATCH 12/12] review feedback --- .github/workflows/build.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9351155..e6b8733 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,7 +5,7 @@ on: branches: - master tags: - - '*' + - 'v*' pull_request: workflow_dispatch: inputs: @@ -181,9 +181,16 @@ jobs: git rm -rqf . >/dev/null 2>&1 || true cp -R "${GITHUB_WORKSPACE}/upm-staging/." . git add -A - git -c user.name="github-actions[bot]" \ - -c user.email="41898282+github-actions[bot]@users.noreply.github.com" \ - commit -m "UPM package v${VERSION}" + # Skip the commit when the assembled package is identical to the + # current branch contents (e.g. re-running a release tag), so the + # job stays idempotent instead of failing on "nothing to commit". + if git diff --cached --quiet; then + echo "UPM package contents unchanged; skipping commit" + else + git -c user.name="github-actions[bot]" \ + -c user.email="41898282+github-actions[bot]@users.noreply.github.com" \ + commit -m "UPM package v${VERSION}" + fi git tag -f "${TAG}" git push origin "HEAD:${BRANCH}" git push -f origin "refs/tags/${TAG}"