Skip to content

Commit bdf9328

Browse files
nanotaboadaclaude
andcommitted
ci(cd): normalize and align CD pipeline (#465)
- Extract test job from release so tests run before any publish step - Add linux/arm64 to build platforms - Add id-token: write and attestations: write to release permissions - Set provenance: mode=max - Add id: push and actions/attest-build-provenance@v4.1.0 - Add --no-merges to changelog git log command - Add empty changelog guard - Normalize first-release message to "No changes (first release)" - Remove changelog.txt write step - Add ## Changes section to release body Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 4a81db3 commit bdf9328

File tree

2 files changed

+57
-26
lines changed

2 files changed

+57
-26
lines changed

.github/workflows/dotnet-cd.yml

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,40 @@ env:
1313
PACKAGE_NAME: nanotaboada/dotnet-samples-aspnetcore-webapi
1414

1515
jobs:
16+
test:
17+
runs-on: ubuntu-latest
18+
permissions:
19+
contents: read
20+
steps:
21+
- name: Checkout repository
22+
uses: actions/checkout@v6
23+
24+
- name: Set up .NET ${{ env.DOTNET_VERSION }}
25+
uses: actions/setup-dotnet@v5.2.0
26+
with:
27+
dotnet-version: ${{ env.DOTNET_VERSION }}
28+
cache: true
29+
cache-dependency-path: |
30+
src/Dotnet.Samples.AspNetCore.WebApi/packages.lock.json
31+
test/Dotnet.Samples.AspNetCore.WebApi.Tests/packages.lock.json
32+
33+
- name: Restore dependencies
34+
run: dotnet restore
35+
36+
- name: Build projects (Release configuration)
37+
run: dotnet build --configuration Release --no-restore
38+
39+
- name: Run tests
40+
run: dotnet test --configuration Release --no-build --verbosity normal
41+
1642
release:
43+
needs: test
1744
runs-on: ubuntu-latest
1845
permissions:
1946
contents: write
2047
packages: write
48+
id-token: write
49+
attestations: write
2150

2251
steps:
2352
- name: Checkout repository
@@ -77,24 +106,6 @@ jobs:
77106
echo "📦 Release version: $SEMVER"
78107
echo "🏟️ Stadium name: $STADIUM"
79108
80-
- name: Set up .NET ${{ env.DOTNET_VERSION }}
81-
uses: actions/setup-dotnet@v5.2.0
82-
with:
83-
dotnet-version: ${{ env.DOTNET_VERSION }}
84-
cache: true
85-
cache-dependency-path: |
86-
src/Dotnet.Samples.AspNetCore.WebApi/packages.lock.json
87-
test/Dotnet.Samples.AspNetCore.WebApi.Tests/packages.lock.json
88-
89-
- name: Restore dependencies
90-
run: dotnet restore
91-
92-
- name: Build projects (Release configuration)
93-
run: dotnet build --configuration Release --no-restore
94-
95-
- name: Run tests
96-
run: dotnet test --configuration Release --no-build --verbosity normal
97-
98109
- name: Log in to GitHub Container Registry
99110
uses: docker/login-action@v4.1.0
100111
with:
@@ -106,19 +117,27 @@ jobs:
106117
uses: docker/setup-buildx-action@v4.0.0
107118

108119
- name: Build and push Docker image to GitHub Container Registry
120+
id: push
109121
uses: docker/build-push-action@v7.0.0
110122
with:
111123
context: .
112124
push: true
113-
platforms: linux/amd64
114-
provenance: false
125+
platforms: linux/amd64,linux/arm64
126+
provenance: mode=max
115127
cache-from: type=gha
116128
cache-to: type=gha,mode=max
117129
tags: |
118130
ghcr.io/${{ env.PACKAGE_NAME }}:latest
119131
ghcr.io/${{ env.PACKAGE_NAME }}:${{ steps.version.outputs.semver }}
120132
ghcr.io/${{ env.PACKAGE_NAME }}:${{ steps.version.outputs.stadium }}
121133
134+
- name: Attest build provenance
135+
uses: actions/attest-build-provenance@v4.1.0
136+
with:
137+
subject-name: ghcr.io/${{ env.PACKAGE_NAME }}
138+
subject-digest: ${{ steps.push.outputs.digest }}
139+
push-to-registry: true
140+
122141
- name: Generate changelog
123142
id: changelog
124143
run: |
@@ -127,15 +146,15 @@ jobs:
127146
128147
if [ -z "$PREVIOUS_TAG" ]; then
129148
echo "📝 First release - no previous tag found"
130-
CHANGELOG="Initial release"
149+
CHANGELOG="No changes (first release)"
131150
else
132151
echo "📝 Generating changelog from $PREVIOUS_TAG to ${{ steps.version.outputs.tag_name }}"
133-
CHANGELOG=$(git log --pretty=format:"- %s (%h)" ${PREVIOUS_TAG}..${{ steps.version.outputs.tag_name }})
134-
fi
152+
CHANGELOG=$(git log --pretty=format:"- %s (%h)" --no-merges ${PREVIOUS_TAG}..${{ steps.version.outputs.tag_name }})
135153
136-
# Write changelog to file
137-
echo "$CHANGELOG" > changelog.txt
138-
cat changelog.txt
154+
if [ -z "$CHANGELOG" ]; then
155+
CHANGELOG="No new changes since $PREVIOUS_TAG"
156+
fi
157+
fi
139158
140159
# Set output for use in release body
141160
{
@@ -167,6 +186,10 @@ jobs:
167186
docker pull ghcr.io/${{ env.PACKAGE_NAME }}:latest
168187
```
169188
189+
## Changes
190+
191+
${{ steps.changelog.outputs.changelog }}
192+
170193
---
171194
172195
📦 **Package:** [ghcr.io/${{ env.PACKAGE_NAME }}](https://github.com/${{ github.repository }}/pkgs/container/dotnet-samples-aspnetcore-webapi)

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ This project uses famous football stadiums (A-Z) that hosted FIFA World Cup matc
4444

4545
### Added
4646

47+
- Extract `test` job from `release` in CD pipeline so tests run in isolation
48+
before any publish step; add `linux/arm64` to build platforms; add
49+
`id-token: write` and `attestations: write` permissions to `release`; set
50+
`provenance: mode=max` and attest the image digest with
51+
`actions/attest-build-provenance@v4.1.0` (`push-to-registry: true`); add
52+
`--no-merges` to the changelog `git log` command; add empty changelog guard;
53+
normalize first-release message to `"No changes (first release)"` (#465)
54+
4755
- Add `adr/0013-testing-strategy.md` documenting the decision to implement the full test pyramid as a deliberate educational choice (#421)
4856
- Add `test/.../Integration/PlayerWebApplicationTests.cs` with 14 HTTP-layer integration tests covering all player endpoints and `/health` via `WebApplicationFactory<Program>` backed by in-memory SQLite; includes `Utilities/TestAuthHandler.cs` to bypass `[Authorize]` on `GET /players/{id:Guid}`; expose `Program` to the test project via `public partial class Program {}` in `Program.cs`; add `Microsoft.AspNetCore.Mvc.Testing` to the test project (#421)
4957
- Add `test/.../Integration/PlayerRepositoryTests.cs` with 9 integration tests covering `Repository<T>` (`GetAllAsync`, `FindByIdAsync`, `RemoveAsync`) and `PlayerRepository` (`FindBySquadNumberAsync`, `SquadNumberExistsAsync`); all tests use `DatabaseFakes.MigrateAsync()` on in-memory SQLite and are tagged `[Trait("Category", "Integration")]` (#461)

0 commit comments

Comments
 (0)