From 2086ce1581d13af8c5d6e8de61a1b828bf2b1b50 Mon Sep 17 00:00:00 2001 From: Mikhail Musin Date: Fri, 4 Sep 2026 17:53:54 +0300 Subject: [PATCH 1/7] ci: publish packages to CodeArtifact on version tags Adds a workflow that packs SqsPoller and SqsPoller.Extensions.Publisher and pushes them to the team_caf-nuget CodeArtifact repository, which is the feed consuming services restore from. Authentication uses the organisation's GitHub OIDC role rather than a long-lived API key. Triggering is on a v* tag instead of a push to master, because the package version comes from the csproj and a push-triggered publish would fail on any commit that does not bump it. Only the two library projects are packed: packing the solution also produces packages for sample/SqsPoller.Sample.Publisher and sample/SqsPoller.Sample.Subscriber, which are not products. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/publish-codeartifact.yml | 72 ++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 .github/workflows/publish-codeartifact.yml diff --git a/.github/workflows/publish-codeartifact.yml b/.github/workflows/publish-codeartifact.yml new file mode 100644 index 0000000..98fa344 --- /dev/null +++ b/.github/workflows/publish-codeartifact.yml @@ -0,0 +1,72 @@ +name: Publish NuGet package to CodeArtifact + +# Publishes on an annotated version tag, not on every push to master. The package +# version comes from the csproj, so a push-triggered publish would fail on any +# commit that does not bump it. Tagging is already how this repository is versioned. +on: + push: + tags: + - 'v*' + workflow_dispatch: + +permissions: + id-token: write + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +jobs: + publish: + runs-on: [gha-runner-scale-set] + env: + DOTNET_INSTALL_DIR: "/home/runner/.dotnet" + DOTNET_ROOT: "/home/runner/.dotnet" + CODEARTIFACT_DOMAIN: "idt" + CODEARTIFACT_DOMAIN_OWNER: "416223954868" + CODEARTIFACT_REPO: "team_caf-nuget" + CODEARTIFACT_TOOL: "dotnet" + + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::101838717447:role/github-actions-role + aws-region: ${{ secrets.AWS_REGION || 'us-east-1' }} + + - name: Log in to CodeArtifact + run: | + aws codeartifact login --tool ${{ env.CODEARTIFACT_TOOL }} \ + --domain ${{ env.CODEARTIFACT_DOMAIN }} \ + --domain-owner ${{ env.CODEARTIFACT_DOMAIN_OWNER }} \ + --repository ${{ env.CODEARTIFACT_REPO }} + + # Pack the two library projects explicitly. `dotnet pack` on the solution also + # packs sample/SqsPoller.Sample.Publisher and sample/SqsPoller.Sample.Subscriber, + # which are not products and would be pushed to the feed as 1.0.0. + - name: Pack + run: | + dotnet pack src/SqsPoller/SqsPoller.csproj -c Release -o ./artifacts + dotnet pack src/SqsPoller.Extensions.Publisher/SqsPoller.Extensions.Publisher.csproj -c Release -o ./artifacts + + # --skip-duplicate makes a re-run of the same tag a no-op instead of a + # failure. CodeArtifact rejects overwriting an existing version. + - name: Push to CodeArtifact + run: | + dotnet nuget push "./artifacts/*.nupkg" \ + --source ${{ env.CODEARTIFACT_DOMAIN }}/${{ env.CODEARTIFACT_REPO }} \ + --api-key unused \ + --skip-duplicate + + - name: Summary + run: | + echo "Pushed to ${CODEARTIFACT_DOMAIN}/${CODEARTIFACT_REPO}:" >> "$GITHUB_STEP_SUMMARY" + ls -1 ./artifacts/*.nupkg | sed 's#.*/# - #' >> "$GITHUB_STEP_SUMMARY" From 83aafe0c2da272bd57ee3c01e370a8560d3c01e1 Mon Sep 17 00:00:00 2001 From: Mikhail Musin Date: Fri, 4 Sep 2026 18:00:13 +0300 Subject: [PATCH 2/7] ci: publish prereleases to CodeArtifact and drop nuget.org publishing Removes both workflows that pushed to public nuget.org and replaces the prerelease one with a CodeArtifact equivalent, so releases and prereleases now go to the same internal feed consuming services restore from. Deletes the committed nuget-apikey file, which only existed to authenticate against nuget.org and is dead once that path is gone. Note that deleting the file does not remove it from history: the key still needs to be revoked. Package metadata pointed RepositoryUrl at a personal fork and ProjectUrl at the public nuget.org listing; both now point at this repository. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/publish-nuget.yml | 35 -------- .../publish-prerelease-codeartifact.yml | 75 ++++++++++++++++++ .../workflows/publish-prerelease-nuget.yml | 35 -------- nuget-apikey | Bin 68 -> 0 bytes .../SqsPoller.Extensions.Publisher.csproj | 4 +- src/SqsPoller/SqsPoller.csproj | 4 +- 6 files changed, 79 insertions(+), 74 deletions(-) delete mode 100644 .github/workflows/publish-nuget.yml create mode 100644 .github/workflows/publish-prerelease-codeartifact.yml delete mode 100644 .github/workflows/publish-prerelease-nuget.yml delete mode 100644 nuget-apikey diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml deleted file mode 100644 index e4e2afc..0000000 --- a/.github/workflows/publish-nuget.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Publish Nuget package - -on: - push: - branches: - master - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v1 - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 6.0.100 - - - name: Build - run: dotnet build --configuration Release - shell: bash - - - name: Publish SqsPoller Nuget release package - shell: bash - env: - NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} - run: dotnet nuget push src/SqsPoller/bin/Release/SqsPoller.*.*.*.nupkg -k $NUGET_API_KEY -s https://api.nuget.org/v3/index.json - - - name: Publish SqsPoller.Extensions.Publisher Nuget release package - shell: bash - env: - NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} - run: dotnet nuget push src/SqsPoller.Extensions.Publisher/bin/Release/SqsPoller.Extensions.Publisher.*.*.*.nupkg -k $NUGET_API_KEY -s https://api.nuget.org/v3/index.json \ No newline at end of file diff --git a/.github/workflows/publish-prerelease-codeartifact.yml b/.github/workflows/publish-prerelease-codeartifact.yml new file mode 100644 index 0000000..4c0e141 --- /dev/null +++ b/.github/workflows/publish-prerelease-codeartifact.yml @@ -0,0 +1,75 @@ +name: Publish NuGet prerelease to CodeArtifact + +# Publishes a prerelease build of each pull request so consumers can test a change +# before it is tagged. Replaces the previous workflow that pushed prereleases to +# public nuget.org. +# +# Pull requests opened from a fork do not receive `id-token: write`, so the OIDC +# step cannot assume the AWS role there and this workflow will fail for them. +# Branches in this repository are unaffected. +on: + pull_request: + branches: + - master + +permissions: + id-token: write + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + publish-prerelease: + runs-on: [gha-runner-scale-set] + env: + DOTNET_INSTALL_DIR: "/home/runner/.dotnet" + DOTNET_ROOT: "/home/runner/.dotnet" + CODEARTIFACT_DOMAIN: "idt" + CODEARTIFACT_DOMAIN_OWNER: "416223954868" + CODEARTIFACT_REPO: "team_caf-nuget" + CODEARTIFACT_TOOL: "dotnet" + + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::101838717447:role/github-actions-role + aws-region: ${{ secrets.AWS_REGION || 'us-east-1' }} + + - name: Log in to CodeArtifact + run: | + aws codeartifact login --tool ${{ env.CODEARTIFACT_TOOL }} \ + --domain ${{ env.CODEARTIFACT_DOMAIN }} \ + --domain-owner ${{ env.CODEARTIFACT_DOMAIN_OWNER }} \ + --repository ${{ env.CODEARTIFACT_REPO }} + + # The csproj declares X.Y.Z$(VersionSuffix), so the suffix + # is concatenated directly and must carry its own leading dash. + - name: Pack prerelease + run: | + SUFFIX="-prerelease-$(date +%Y%m%d%H%M%S)" + dotnet pack src/SqsPoller/SqsPoller.csproj \ + -c Release -o ./artifacts --version-suffix "$SUFFIX" + dotnet pack src/SqsPoller.Extensions.Publisher/SqsPoller.Extensions.Publisher.csproj \ + -c Release -o ./artifacts --version-suffix "$SUFFIX" + + - name: Push to CodeArtifact + run: | + dotnet nuget push "./artifacts/*.nupkg" \ + --source ${{ env.CODEARTIFACT_DOMAIN }}/${{ env.CODEARTIFACT_REPO }} \ + --api-key unused \ + --skip-duplicate + + - name: Summary + run: | + echo "Prerelease pushed to ${CODEARTIFACT_DOMAIN}/${CODEARTIFACT_REPO}:" >> "$GITHUB_STEP_SUMMARY" + ls -1 ./artifacts/*.nupkg | sed 's#.*/# - #' >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/publish-prerelease-nuget.yml b/.github/workflows/publish-prerelease-nuget.yml deleted file mode 100644 index 8f71fea..0000000 --- a/.github/workflows/publish-prerelease-nuget.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Publish Nuget prerelease package - -on: - pull_request: - branches: - master - -jobs: - build: - name: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v1 - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 6.0.100 - - - name: Build - run: dotnet build --configuration Release --version-suffix -prerelease-$(date +%Y%m%d%H%M%S) - shell: bash - - - name: Publish SqsPoller Nuget pre-release package - shell: bash - env: - NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} - run: dotnet nuget push src/SqsPoller/bin/Release/SqsPoller.*.*.*-prerelease-*.nupkg -k $NUGET_API_KEY -s https://api.nuget.org/v3/index.json - - - name: Publish SqsPoller.Extensions.Publisher Nuget pre-release package - shell: bash - env: - NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} - run: dotnet nuget push src/SqsPoller.Extensions.Publisher/bin/Release/SqsPoller.Extensions.Publisher.*.*.*-prerelease-*.nupkg -k $NUGET_API_KEY -s https://api.nuget.org/v3/index.json \ No newline at end of file diff --git a/nuget-apikey b/nuget-apikey deleted file mode 100644 index bf46456fba21ffc89bfa75e6f8924ab14b903efe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmV-K0K5MHM@dveQdv+`06H+{W$x=*^hOjpvkd@aY;P)?{0)MXIbP`1pic!=N3!wn a`Y**&xJBFSG`0b5i!#heGziK)w1@!ChaKwx diff --git a/src/SqsPoller.Extensions.Publisher/SqsPoller.Extensions.Publisher.csproj b/src/SqsPoller.Extensions.Publisher/SqsPoller.Extensions.Publisher.csproj index d71ccd0..62f9994 100644 --- a/src/SqsPoller.Extensions.Publisher/SqsPoller.Extensions.Publisher.csproj +++ b/src/SqsPoller.Extensions.Publisher/SqsPoller.Extensions.Publisher.csproj @@ -7,8 +7,8 @@ Alexey Bogdan Alexey Bogdan A small library that helps ASP.NET Core applications easily consume messages from a SQS queue - https://github.com/AlexeyBogdan95/SqsPoller - https://www.nuget.org/packages/SqsPoller/ + https://github.com/coretech/SqsPoller + https://github.com/coretech/SqsPoller true latest enable diff --git a/src/SqsPoller/SqsPoller.csproj b/src/SqsPoller/SqsPoller.csproj index 40f8275..bca3829 100644 --- a/src/SqsPoller/SqsPoller.csproj +++ b/src/SqsPoller/SqsPoller.csproj @@ -7,8 +7,8 @@ Alexey Bogdan Alexey Bogdan A small library that helps ASP.NET Core applications easily consume messages from a SQS queue - https://github.com/AlexeyBogdan95/SqsPoller - https://www.nuget.org/packages/SqsPoller/ + https://github.com/coretech/SqsPoller + https://github.com/coretech/SqsPoller true latest enable From 74afd24748bece54fe3096ff09957b929a8bbe39 Mon Sep 17 00:00:00 2001 From: Mikhail Musin Date: Fri, 4 Sep 2026 18:28:20 +0300 Subject: [PATCH 3/7] ci: run on hosted runners and fix compose invocation The publish workflows targeted the self-hosted `gha-runner-scale-set` label, which is not available to this repository, so the prerelease job stayed queued with no runner assigned. OIDC role assumption works the same on GitHub-hosted runners, so both workflows now use ubuntu-latest. Integration tests failed with `docker-compose: command not found`: Compose v1 is no longer installed on hosted runners. Uses `docker compose` instead, with --wait so the step blocks on the localstack healthcheck rather than racing it. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/integration-tests.yml | 7 +++++-- .github/workflows/publish-codeartifact.yml | 7 ++++--- .github/workflows/publish-prerelease-codeartifact.yml | 7 ++++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 8ce7fe9..1980c4e 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -16,7 +16,10 @@ jobs: uses: actions/setup-dotnet@v1 with: dotnet-version: 6.0.100 - - name: Run docker-compose - run: docker-compose up -d + # `docker-compose` (Compose v1) is no longer installed on GitHub-hosted + # runners; v2 is a docker subcommand. --wait blocks until the localstack + # healthcheck passes, instead of racing it from the test step. + - name: Run docker compose + run: docker compose up -d --wait - name: Run Integration Tests run: dotnet test ./test/SqsPoller.Extensions.Publisher.Tests.Integration/SqsPoller.Extensions.Publisher.Tests.Integration.csproj \ No newline at end of file diff --git a/.github/workflows/publish-codeartifact.yml b/.github/workflows/publish-codeartifact.yml index 98fa344..8093291 100644 --- a/.github/workflows/publish-codeartifact.yml +++ b/.github/workflows/publish-codeartifact.yml @@ -19,10 +19,11 @@ concurrency: jobs: publish: - runs-on: [gha-runner-scale-set] + # GitHub-hosted: the self-hosted `gha-runner-scale-set` label is not available + # to this repository, so jobs targeting it stay queued forever. OIDC works the + # same on hosted runners. + runs-on: ubuntu-latest env: - DOTNET_INSTALL_DIR: "/home/runner/.dotnet" - DOTNET_ROOT: "/home/runner/.dotnet" CODEARTIFACT_DOMAIN: "idt" CODEARTIFACT_DOMAIN_OWNER: "416223954868" CODEARTIFACT_REPO: "team_caf-nuget" diff --git a/.github/workflows/publish-prerelease-codeartifact.yml b/.github/workflows/publish-prerelease-codeartifact.yml index 4c0e141..2de7290 100644 --- a/.github/workflows/publish-prerelease-codeartifact.yml +++ b/.github/workflows/publish-prerelease-codeartifact.yml @@ -22,10 +22,11 @@ concurrency: jobs: publish-prerelease: - runs-on: [gha-runner-scale-set] + # GitHub-hosted: the self-hosted `gha-runner-scale-set` label is not available + # to this repository, so jobs targeting it stay queued forever. OIDC works the + # same on hosted runners. + runs-on: ubuntu-latest env: - DOTNET_INSTALL_DIR: "/home/runner/.dotnet" - DOTNET_ROOT: "/home/runner/.dotnet" CODEARTIFACT_DOMAIN: "idt" CODEARTIFACT_DOMAIN_OWNER: "416223954868" CODEARTIFACT_REPO: "team_caf-nuget" From e00537673c744438132a979fc068ae83bece3692 Mon Sep 17 00:00:00 2001 From: Mikhail Musin Date: Fri, 4 Sep 2026 18:32:11 +0300 Subject: [PATCH 4/7] ci: disable GeneratePackageOnBuild when packing Both library projects set GeneratePackageOnBuild=true, which wires packing into the build. Hosted runners resolve the newest installed SDK (10.0.400, not the 8.0.x that setup-dotnet requests, since there is no global.json), and there dotnet pack no longer rebuilds under that property, failing with NU5026 because the dll is absent. SDK 8 tolerated the same command locally. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/publish-codeartifact.yml | 7 +++++-- .github/workflows/publish-prerelease-codeartifact.yml | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-codeartifact.yml b/.github/workflows/publish-codeartifact.yml index 8093291..20aab90 100644 --- a/.github/workflows/publish-codeartifact.yml +++ b/.github/workflows/publish-codeartifact.yml @@ -50,13 +50,16 @@ jobs: --domain-owner ${{ env.CODEARTIFACT_DOMAIN_OWNER }} \ --repository ${{ env.CODEARTIFACT_REPO }} + # -p:GeneratePackageOnBuild=false: both csproj set GeneratePackageOnBuild=true, + # which wires packing into build. On SDK 10 `dotnet pack` then does not rebuild + # and fails with NU5026 (dll not found on disk); SDK 8 tolerated it. # Pack the two library projects explicitly. `dotnet pack` on the solution also # packs sample/SqsPoller.Sample.Publisher and sample/SqsPoller.Sample.Subscriber, # which are not products and would be pushed to the feed as 1.0.0. - name: Pack run: | - dotnet pack src/SqsPoller/SqsPoller.csproj -c Release -o ./artifacts - dotnet pack src/SqsPoller.Extensions.Publisher/SqsPoller.Extensions.Publisher.csproj -c Release -o ./artifacts + dotnet pack src/SqsPoller/SqsPoller.csproj -c Release -o ./artifacts -p:GeneratePackageOnBuild=false + dotnet pack src/SqsPoller.Extensions.Publisher/SqsPoller.Extensions.Publisher.csproj -c Release -o ./artifacts -p:GeneratePackageOnBuild=false # --skip-duplicate makes a re-run of the same tag a no-op instead of a # failure. CodeArtifact rejects overwriting an existing version. diff --git a/.github/workflows/publish-prerelease-codeartifact.yml b/.github/workflows/publish-prerelease-codeartifact.yml index 2de7290..adac772 100644 --- a/.github/workflows/publish-prerelease-codeartifact.yml +++ b/.github/workflows/publish-prerelease-codeartifact.yml @@ -53,15 +53,17 @@ jobs: --domain-owner ${{ env.CODEARTIFACT_DOMAIN_OWNER }} \ --repository ${{ env.CODEARTIFACT_REPO }} + # -p:GeneratePackageOnBuild=false: see the release workflow; without it SDK 10 + # fails with NU5026. # The csproj declares X.Y.Z$(VersionSuffix), so the suffix # is concatenated directly and must carry its own leading dash. - name: Pack prerelease run: | SUFFIX="-prerelease-$(date +%Y%m%d%H%M%S)" dotnet pack src/SqsPoller/SqsPoller.csproj \ - -c Release -o ./artifacts --version-suffix "$SUFFIX" + -c Release -o ./artifacts -p:GeneratePackageOnBuild=false --version-suffix "$SUFFIX" dotnet pack src/SqsPoller.Extensions.Publisher/SqsPoller.Extensions.Publisher.csproj \ - -c Release -o ./artifacts --version-suffix "$SUFFIX" + -c Release -o ./artifacts -p:GeneratePackageOnBuild=false --version-suffix "$SUFFIX" - name: Push to CodeArtifact run: | From 236c14e7de3dc64cfc7e26c01e2d26584986fabf Mon Sep 17 00:00:00 2001 From: Mikhail Musin Date: Fri, 4 Sep 2026 18:35:57 +0300 Subject: [PATCH 5/7] ci: print CodeArtifact feed configuration on prerelease publish The push reaches CodeArtifact and is rejected with 400, but dotnet nuget push reports only the status code. Adds a temporary diagnostic step so the run shows the repository upstreams and the package origin configuration. Co-Authored-By: Claude Opus 5 (1M context) --- .../publish-prerelease-codeartifact.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/publish-prerelease-codeartifact.yml b/.github/workflows/publish-prerelease-codeartifact.yml index adac772..b84f4c9 100644 --- a/.github/workflows/publish-prerelease-codeartifact.yml +++ b/.github/workflows/publish-prerelease-codeartifact.yml @@ -65,6 +65,24 @@ jobs: dotnet pack src/SqsPoller.Extensions.Publisher/SqsPoller.Extensions.Publisher.csproj \ -c Release -o ./artifacts -p:GeneratePackageOnBuild=false --version-suffix "$SUFFIX" + # TEMPORARY. `dotnet nuget push` reports only the status code, not the + # CodeArtifact error body. This prints the repository upstreams and the + # package origin configuration, which is the usual reason a push of a name + # that also exists on nuget.org is rejected with 400. + - name: Diagnose feed configuration + continue-on-error: true + run: | + echo "--- repository" + aws codeartifact describe-repository \ + --domain "$CODEARTIFACT_DOMAIN" --domain-owner "$CODEARTIFACT_DOMAIN_OWNER" \ + --repository "$CODEARTIFACT_REPO" || true + echo "--- package SqsPoller" + aws codeartifact describe-package \ + --domain "$CODEARTIFACT_DOMAIN" --domain-owner "$CODEARTIFACT_DOMAIN_OWNER" \ + --repository "$CODEARTIFACT_REPO" --format nuget --package SqsPoller || true + echo "--- caller identity" + aws sts get-caller-identity || true + - name: Push to CodeArtifact run: | dotnet nuget push "./artifacts/*.nupkg" \ From 453d3c39cf477cd3e8b72e25e56553055a5c3b2b Mon Sep 17 00:00:00 2001 From: Mikhail Musin Date: Mon, 7 Sep 2026 17:55:45 +0300 Subject: [PATCH 6/7] ci: drop temporary diagnostic step The publish path is confirmed working end to end, so the step that dumped the repository and package origin configuration is no longer needed. Keeps the finding as a comment: both package names need publish=ALLOW set once, because the feed has a public nuget.org external connection and CodeArtifact defaults such packages to publish=BLOCK. Co-Authored-By: Claude Opus 5 (1M context) --- .../publish-prerelease-codeartifact.yml | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/.github/workflows/publish-prerelease-codeartifact.yml b/.github/workflows/publish-prerelease-codeartifact.yml index b84f4c9..9a08f19 100644 --- a/.github/workflows/publish-prerelease-codeartifact.yml +++ b/.github/workflows/publish-prerelease-codeartifact.yml @@ -65,24 +65,11 @@ jobs: dotnet pack src/SqsPoller.Extensions.Publisher/SqsPoller.Extensions.Publisher.csproj \ -c Release -o ./artifacts -p:GeneratePackageOnBuild=false --version-suffix "$SUFFIX" - # TEMPORARY. `dotnet nuget push` reports only the status code, not the - # CodeArtifact error body. This prints the repository upstreams and the - # package origin configuration, which is the usual reason a push of a name - # that also exists on nuget.org is rejected with 400. - - name: Diagnose feed configuration - continue-on-error: true - run: | - echo "--- repository" - aws codeartifact describe-repository \ - --domain "$CODEARTIFACT_DOMAIN" --domain-owner "$CODEARTIFACT_DOMAIN_OWNER" \ - --repository "$CODEARTIFACT_REPO" || true - echo "--- package SqsPoller" - aws codeartifact describe-package \ - --domain "$CODEARTIFACT_DOMAIN" --domain-owner "$CODEARTIFACT_DOMAIN_OWNER" \ - --repository "$CODEARTIFACT_REPO" --format nuget --package SqsPoller || true - echo "--- caller identity" - aws sts get-caller-identity || true - + # Both package names are also reachable through the feed's public nuget.org + # external connection, so CodeArtifact defaults them to publish=BLOCK. Each + # needs publish=ALLOW,upstream=BLOCK set once via + # `aws codeartifact put-package-origin-configuration`; otherwise the push + # below returns a bare 400. - name: Push to CodeArtifact run: | dotnet nuget push "./artifacts/*.nupkg" \ From 13b217b30703b830f61f4f0c8e62301f554a405b Mon Sep 17 00:00:00 2001 From: Mikhail Musin Date: Mon, 7 Sep 2026 18:04:04 +0300 Subject: [PATCH 7/7] ci: take the released version from the tag The release workflow now passes -p:Version derived from the tag, so v2.1.0 always publishes 2.1.0. Previously the csproj decided the version and the tag only triggered the run: tagging without bumping the csproj republished the old version, which --skip-duplicate turned into a silently green no-op. A tag that does not parse as MAJOR.MINOR.PATCH[-suffix] fails the run instead of publishing something unintended. workflow_dispatch runs from a branch, where the ref is not a version, and there the csproj value is used unchanged. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/publish-codeartifact.yml | 32 +++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-codeartifact.yml b/.github/workflows/publish-codeartifact.yml index 20aab90..cffb574 100644 --- a/.github/workflows/publish-codeartifact.yml +++ b/.github/workflows/publish-codeartifact.yml @@ -50,16 +50,40 @@ jobs: --domain-owner ${{ env.CODEARTIFACT_DOMAIN_OWNER }} \ --repository ${{ env.CODEARTIFACT_REPO }} + # The tag is the source of truth for the released version: `-p:Version` overrides + # the csproj, so v2.1.0 always produces 2.1.0. Without this the csproj decides, + # and tagging without bumping it republishes the old version, which + # --skip-duplicate then turns into a silently green no-op. + # + # workflow_dispatch runs from a branch, where GITHUB_REF_NAME is not a version; + # there the csproj value is used unchanged. + # # -p:GeneratePackageOnBuild=false: both csproj set GeneratePackageOnBuild=true, # which wires packing into build. On SDK 10 `dotnet pack` then does not rebuild # and fails with NU5026 (dll not found on disk); SDK 8 tolerated it. - # Pack the two library projects explicitly. `dotnet pack` on the solution also - # packs sample/SqsPoller.Sample.Publisher and sample/SqsPoller.Sample.Subscriber, + # + # The two library projects are packed explicitly. `dotnet pack` on the solution + # also packs sample/SqsPoller.Sample.Publisher and sample/SqsPoller.Sample.Subscriber, # which are not products and would be pushed to the feed as 1.0.0. - name: Pack run: | - dotnet pack src/SqsPoller/SqsPoller.csproj -c Release -o ./artifacts -p:GeneratePackageOnBuild=false - dotnet pack src/SqsPoller.Extensions.Publisher/SqsPoller.Extensions.Publisher.csproj -c Release -o ./artifacts -p:GeneratePackageOnBuild=false + VERSION_ARG="" + if [ "${GITHUB_REF_TYPE:-}" = "tag" ]; then + VERSION="${GITHUB_REF_NAME#v}" + if ! printf '%s' "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then + echo "::error::Tag '$GITHUB_REF_NAME' does not yield a valid version ('$VERSION'). Expected vMAJOR.MINOR.PATCH[-suffix]." + exit 1 + fi + VERSION_ARG="-p:Version=$VERSION" + echo "Releasing version $VERSION from tag $GITHUB_REF_NAME" + else + echo "Not a tag ref; using the version declared in the csproj." + fi + + dotnet pack src/SqsPoller/SqsPoller.csproj \ + -c Release -o ./artifacts -p:GeneratePackageOnBuild=false $VERSION_ARG + dotnet pack src/SqsPoller.Extensions.Publisher/SqsPoller.Extensions.Publisher.csproj \ + -c Release -o ./artifacts -p:GeneratePackageOnBuild=false $VERSION_ARG # --skip-duplicate makes a re-run of the same tag a no-op instead of a # failure. CodeArtifact rejects overwriting an existing version.