Skip to content

Commit a8dc43e

Browse files
committed
feat: implement tag-based deployment with stadium release names (#356)
- Rename dotnet.yml to dotnet-ci.yml and remove container publishing - Create dotnet-cd.yml workflow triggered by version tags (v*.*.*-*) - Add CHANGELOG.md with A-Z stadium list and release template - Update README.md with release instructions and docker pull examples - Separate CI (build/test) from CD (publish packages on tags only)
1 parent 66b2e52 commit a8dc43e

4 files changed

Lines changed: 272 additions & 38 deletions

File tree

.github/workflows/dotnet-cd.yml

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Building, testing, and publishing .NET releases
2+
# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
3+
4+
name: .NET CD
5+
6+
on:
7+
push:
8+
tags:
9+
- 'v*.*.*-*'
10+
11+
env:
12+
DOTNET_VERSION: 8.0.x
13+
PACKAGE_NAME: nanotaboada/dotnet-samples-aspnetcore-webapi
14+
15+
jobs:
16+
release:
17+
runs-on: ubuntu-latest
18+
permissions:
19+
contents: write
20+
packages: write
21+
22+
steps:
23+
- name: Checkout repository
24+
uses: actions/checkout@v6.0.1
25+
with:
26+
fetch-depth: 0
27+
28+
- name: Extract version from tag
29+
id: version
30+
run: |
31+
TAG_NAME=${GITHUB_REF#refs/tags/}
32+
echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT
33+
34+
# Extract semver (e.g., v1.0.0-azteca -> 1.0.0)
35+
SEMVER=$(echo $TAG_NAME | sed -E 's/^v([0-9]+\.[0-9]+\.[0-9]+)-.*/\1/')
36+
echo "semver=$SEMVER" >> $GITHUB_OUTPUT
37+
38+
# Extract stadium name (e.g., v1.0.0-azteca -> azteca)
39+
STADIUM=$(echo $TAG_NAME | sed -E 's/^v[0-9]+\.[0-9]+\.[0-9]+-//')
40+
echo "stadium=$STADIUM" >> $GITHUB_OUTPUT
41+
42+
echo "📦 Release version: $SEMVER"
43+
echo "🏟️ Stadium name: $STADIUM"
44+
45+
- name: Set up .NET ${{ env.DOTNET_VERSION }}
46+
uses: actions/setup-dotnet@v5.1.0
47+
with:
48+
dotnet-version: ${{ env.DOTNET_VERSION }}
49+
cache: true
50+
cache-dependency-path: |
51+
src/Dotnet.Samples.AspNetCore.WebApi/packages.lock.json
52+
test/Dotnet.Samples.AspNetCore.WebApi.Tests/packages.lock.json
53+
54+
- name: Restore dependencies
55+
run: dotnet restore
56+
57+
- name: Build projects (Release configuration)
58+
run: dotnet build --configuration Release --no-restore
59+
60+
- name: Run tests
61+
run: dotnet test --configuration Release --no-build --verbosity normal
62+
63+
- name: Log in to GitHub Container Registry
64+
uses: docker/login-action@v3.6.0
65+
with:
66+
registry: ghcr.io
67+
username: ${{ github.actor }}
68+
password: ${{ secrets.GITHUB_TOKEN }}
69+
70+
- name: Set up Docker Buildx
71+
uses: docker/setup-buildx-action@v3.12.0
72+
73+
- name: Build and push Docker image to GitHub Container Registry
74+
uses: docker/build-push-action@v6.18.0
75+
with:
76+
context: .
77+
push: true
78+
platforms: linux/amd64
79+
provenance: false
80+
cache-from: type=gha
81+
cache-to: type=gha,mode=max
82+
tags: |
83+
ghcr.io/${{ env.PACKAGE_NAME }}:latest
84+
ghcr.io/${{ env.PACKAGE_NAME }}:${{ steps.version.outputs.semver }}
85+
ghcr.io/${{ env.PACKAGE_NAME }}:${{ steps.version.outputs.stadium }}
86+
87+
- name: Generate changelog
88+
id: changelog
89+
run: |
90+
# Get previous tag
91+
PREVIOUS_TAG=$(git tag --sort=-version:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+-' | sed -n '2p')
92+
93+
if [ -z "$PREVIOUS_TAG" ]; then
94+
echo "📝 First release - no previous tag found"
95+
CHANGELOG="Initial release"
96+
else
97+
echo "📝 Generating changelog from $PREVIOUS_TAG to ${{ steps.version.outputs.tag_name }}"
98+
CHANGELOG=$(git log --pretty=format:"- %s (%h)" ${PREVIOUS_TAG}..${{ steps.version.outputs.tag_name }})
99+
fi
100+
101+
# Write changelog to file
102+
echo "$CHANGELOG" > changelog.txt
103+
cat changelog.txt
104+
105+
- name: Create GitHub Release
106+
uses: softprops/action-gh-release@v2.2.0
107+
with:
108+
name: "v${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }}"
109+
tag_name: ${{ steps.version.outputs.tag_name }}
110+
body: |
111+
# 🏟️ Release ${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }}
112+
113+
## Docker Images
114+
115+
Pull this release using any of the following tags:
116+
117+
```bash
118+
# By semantic version (recommended)
119+
docker pull ghcr.io/${{ env.PACKAGE_NAME }}:${{ steps.version.outputs.semver }}
120+
121+
# By stadium name
122+
docker pull ghcr.io/${{ env.PACKAGE_NAME }}:${{ steps.version.outputs.stadium }}
123+
124+
# Latest
125+
docker pull ghcr.io/${{ env.PACKAGE_NAME }}:latest
126+
```
127+
128+
## Changes
129+
130+
${{ steps.changelog.outputs.changelog }}
131+
132+
---
133+
134+
📦 **Package:** [ghcr.io/${{ env.PACKAGE_NAME }}](https://github.com/${{ github.repository }}/pkgs/container/dotnet-samples-aspnetcore-webapi)
135+
draft: false
136+
prerelease: false
137+
generate_release_notes: true
Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ on:
1111

1212
env:
1313
DOTNET_VERSION: 8.0.x
14-
PACKAGE_NAME: nanotaboada/dotnet-samples-aspnetcore-webapi
1514

1615
jobs:
1716
build:
@@ -108,39 +107,3 @@ jobs:
108107
with:
109108
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
110109
coverage-reports: cobertura.xml
111-
112-
container:
113-
needs: coverage
114-
runs-on: ubuntu-latest
115-
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
116-
117-
permissions:
118-
contents: read
119-
packages: write
120-
121-
steps:
122-
- name: Checkout repository
123-
uses: actions/checkout@v6.0.1
124-
125-
- name: Log in to GitHub Container Registry
126-
uses: docker/login-action@v3.6.0
127-
with:
128-
registry: ghcr.io
129-
username: ${{ github.actor }}
130-
password: ${{ secrets.GITHUB_TOKEN }}
131-
132-
- name: Set up Docker Buildx
133-
uses: docker/setup-buildx-action@v3.12.0
134-
135-
- name: Build and push Docker image to GitHub Container Registry
136-
uses: docker/build-push-action@v6.18.0
137-
with:
138-
context: .
139-
push: true
140-
platforms: linux/amd64
141-
provenance: false
142-
cache-from: type=gha
143-
cache-to: type=gha,mode=max
144-
tags: |
145-
ghcr.io/${{ env.PACKAGE_NAME }}:latest
146-
ghcr.io/${{ env.PACKAGE_NAME }}:sha-${{ github.sha }}

CHANGELOG.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## Stadium Release Names
9+
10+
This project uses famous football stadiums (A-Z) that hosted FIFA World Cup matches:
11+
12+
| Letter | Stadium Name | Location | Tag Name |
13+
| ------ | ----------- | -------- | -------- |
14+
| A | Azteca | Mexico (1970, 1986, 2026) | `azteca` |
15+
| B | Bernabéu | Spain (1982) | `bernabeu` |
16+
| C | Centenario | Uruguay (1930) | `centenario` |
17+
| D | Düsseldorf (Merkur Spiel-Arena) | Germany (2006) | `dusseldorf` |
18+
| E | Ekaterinburg Arena | Russia (2018) | `ekaterinburg` |
19+
| F | Frankfurt Waldstadion | Germany (1974, 2006) | `frankfurt` |
20+
| G | Gelsenkirchen | Germany (2006) | `gelsenkirchen` |
21+
| H | Hard Rock Stadium | USA (2026) | `hardrock` |
22+
| I | Ibn Batouta Stadium | Morocco (2030) | `ibnbatouta` |
23+
| J | Johannesburg Soccer City | South Africa (2010) | `johannesburg` |
24+
| K | Kazan Arena | Russia (2018) | `kazan` |
25+
| L | Lusail | Qatar (2022) | `lusail` |
26+
| M | Maracanã | Brazil (1950, 2014) | `maracana` |
27+
| N | Nantes Beaujoire | France (1998) | `nantes` |
28+
| O | Olympiastadion Berlin | Germany (1974, 2006) | `olympiastadion` |
29+
| P | Parc des Princes | France (1938, 1998) | `parcdesprince` |
30+
| Q | Qatar 974 | Qatar (2022) | `qatar974` |
31+
| R | Rose Bowl | USA (1994) | `rosebowl` |
32+
| S | San Siro | Italy (1934, 1990) | `sansiro` |
33+
| T | Toronto BMO Field | Canada (2026) | `toronto` |
34+
| U | Ullevi | Sweden (1958) | `ullevi` |
35+
| V | Volgograd Arena | Russia (2018) | `volgograd` |
36+
| W | Wembley | England (1966) | `wembley` |
37+
| X | Xiamen Egret Stadium | (famous fallback) | `xiamen` |
38+
| Y | Yokohama International Stadium | Japan (2002) | `yokohama` |
39+
| Z | Zentralstadion Leipzig | Germany (1974, 2006) | `zentralstadion` |
40+
41+
---
42+
43+
## [Unreleased]
44+
45+
### Added
46+
47+
### Changed
48+
49+
### Fixed
50+
51+
### Removed
52+
53+
---
54+
55+
## How to Release
56+
57+
To create a new release:
58+
59+
1. Update this CHANGELOG with release notes under the appropriate version heading
60+
2. Create and push a version tag with stadium name:
61+
62+
```bash
63+
git tag -a v1.0.0-azteca -m "Release 1.0.0 - Azteca"
64+
git push origin v1.0.0-azteca
65+
```
66+
67+
3. The CD workflow will automatically:
68+
- Build and test the project
69+
- Publish Docker images to GHCR with three tags (`:1.0.0`, `:azteca`, `:latest`)
70+
- Create a GitHub Release with auto-generated notes
71+
72+
---
73+
74+
<!-- Template for new releases:
75+
76+
## [X.Y.Z - STADIUM_NAME] - YYYY-MM-DD
77+
78+
### Added
79+
- New features
80+
81+
### Changed
82+
- Changes in existing functionality
83+
84+
### Fixed
85+
- Bug fixes
86+
87+
### Removed
88+
- Removed features
89+
90+
-->

README.md

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 🧪 RESTful API with .NET and ASP.NET Core
22

3-
[![.NET CI](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/actions/workflows/dotnet.yml/badge.svg)](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/actions/workflows/dotnet.yml)
3+
[![.NET CI](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/actions/workflows/dotnet-ci.yml/badge.svg)](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/actions/workflows/dotnet-ci.yml)
44
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=nanotaboada_Dotnet.Samples.AspNetCore.WebApi&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=nanotaboada_Dotnet.Samples.AspNetCore.WebApi)
55
[![Build Status](https://dev.azure.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/_apis/build/status%2FDotnet.Samples.AspNetCore.WebApi?branchName=master)](https://dev.azure.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/_build/latest?definitionId=14&branchName=master)
66
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/ac7b7e22f1cd4d9d9233b36982b0d6a9)](https://app.codacy.com/gh/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
@@ -21,6 +21,7 @@ Proof of Concept for a RESTful API built with .NET 8 (LTS) and ASP.NET Core. Man
2121
- [Quick Start](#quick-start)
2222
- [Testing](#testing)
2323
- [Docker](#docker)
24+
- [Releases](#releases)
2425
- [Environment Variables](#environment-variables)
2526
- [Command Summary](#command-summary)
2627
- [Contributing](#contributing)
@@ -289,6 +290,49 @@ docker compose down -v
289290

290291
The containerized application runs on port 9000 and includes health checks that monitor the `/health` endpoint.
291292

293+
## Releases
294+
295+
This project uses **stadium-themed release names** inspired by famous football stadiums that hosted FIFA World Cup matches. Each release is named after a stadium (A-Z alphabetically), making versions memorable and fun.
296+
297+
### Release Naming Convention
298+
299+
Releases follow the pattern: `v{SEMVER}-{STADIUM}` (e.g., `v1.0.0-azteca`)
300+
301+
- **Semantic Version**: Standard versioning (MAJOR.MINOR.PATCH)
302+
- **Stadium Name**: Alphabetically ordered codename from the [stadium list](CHANGELOG.md#stadium-release-names)
303+
304+
### Create a Release
305+
306+
To create a new release, tag a commit and push the tag:
307+
308+
```bash
309+
git tag -a v1.0.0-azteca -m "Release 1.0.0 - Azteca"
310+
git push origin v1.0.0-azteca
311+
```
312+
313+
This triggers the CD workflow which automatically:
314+
315+
1. Builds and tests the project in Release configuration
316+
2. Publishes Docker images to GitHub Container Registry with three tags
317+
3. Creates a GitHub Release with auto-generated changelog
318+
319+
### Pull Docker Images
320+
321+
Each release publishes multiple tags for flexibility:
322+
323+
```bash
324+
# By semantic version (recommended for production)
325+
docker pull ghcr.io/nanotaboada/dotnet-samples-aspnetcore-webapi:1.0.0
326+
327+
# By stadium name (memorable alternative)
328+
docker pull ghcr.io/nanotaboada/dotnet-samples-aspnetcore-webapi:azteca
329+
330+
# Latest release
331+
docker pull ghcr.io/nanotaboada/dotnet-samples-aspnetcore-webapi:latest
332+
```
333+
334+
> 💡 **Note:** See [CHANGELOG.md](CHANGELOG.md) for the complete stadium list (A-Z) and release history.
335+
292336
## Environment Variables
293337

294338
The application can be configured using environment variables for different scenarios:

0 commit comments

Comments
 (0)