From 5370b16b58927a51a2c3dd225537818c54cc2fcf Mon Sep 17 00:00:00 2001 From: Nano Taboada <87288+nanotaboada@users.noreply.github.com> Date: Sun, 8 Feb 2026 10:58:51 -0300 Subject: [PATCH 1/2] docs: standardize release workflow and improve documentation quality - Add comprehensive Release Management section to AGENTS.md - Document CHANGELOG-first release workflow (3-step process) - Add XML documentation comments to all model properties - Reframe Features section to highlight reference project value - Reorder features by development lifecycle importance --- .github/workflows/dotnet-cd.yml | 4 +- AGENTS.md | 71 +++++++++++++- CHANGELOG.md | 96 ++++++++++++++++--- README.md | 58 +++++++---- .../Models/Player.cs | 33 +++++++ .../Models/PlayerRequestModel.cs | 24 +++++ .../Models/PlayerResponseModel.cs | 21 ++++ 7 files changed, 266 insertions(+), 41 deletions(-) diff --git a/.github/workflows/dotnet-cd.yml b/.github/workflows/dotnet-cd.yml index 52cb801..2aaf160 100644 --- a/.github/workflows/dotnet-cd.yml +++ b/.github/workflows/dotnet-cd.yml @@ -138,10 +138,10 @@ jobs: - name: Create GitHub Release uses: softprops/action-gh-release@v2.5.0 with: - name: "v${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }}" + name: "v${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }} 🏟️" tag_name: ${{ steps.version.outputs.tag_name }} body: | - # 🏟️ Release ${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }} + #Release ${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }} 🏟️ ## Docker Images diff --git a/AGENTS.md b/AGENTS.md index 0100e7e..bd6f3ce 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -81,9 +81,11 @@ dotnet build && dotnet test **Pre-commit checklist**: -1. Run `dotnet build --configuration Release` - must build successfully -2. Run `dotnet test` - all tests must pass -3. Check code formatting and style +1. Update CHANGELOG.md `[Unreleased]` section with your changes (Added/Changed/Fixed/Removed) +2. Run `dotnet build --configuration Release` - must build successfully +3. Run `dotnet test` - all tests must pass +4. Check code formatting and style +5. Follow conventional commit format (enforced by commitlint) ### Running the Application @@ -153,6 +155,66 @@ curl http://localhost:5000/health **First run behavior**: Container initializes SQLite database with seed data. Volume persists data between runs. +## Release Management + +### CHANGELOG Maintenance + +**Important**: Update CHANGELOG.md continuously as you work, not just before releases. + +**For every meaningful commit**: + +1. Add your changes to the `[Unreleased]` section in CHANGELOG.md +2. Categorize under the appropriate heading: + - **Added**: New features + - **Changed**: Changes in existing functionality + - **Deprecated**: Soon-to-be removed features + - **Removed**: Removed features + - **Fixed**: Bug fixes + - **Security**: Security vulnerability fixes +3. Use clear, user-facing descriptions (not just commit messages) +4. Include PR/issue numbers when relevant (#123) + +**Example**: + +```markdown +## [Unreleased] + +### Added +- User authentication with JWT tokens (#145) +- Rate limiting middleware for API endpoints + +### Deprecated +- Legacy authentication endpoint /api/v1/auth (use /api/v2/auth instead) + +### Fixed +- Null reference exception in player service (#147) + +### Security +- Fix SQL injection vulnerability in search endpoint (#148) +``` + +### Creating a Release + +When ready to release: + +1. **Update CHANGELOG.md**: Move items from `[Unreleased]` to a new versioned section: + + ```markdown + ## [1.1.0 - bernabeu] - 2026-02-15 + ``` + +2. **Commit and push** CHANGELOG changes +3. **Create and push tag**: + + ```bash + git tag -a v1.1.0-bernabeu -m "Release 1.1.0 - BernabΓ©u" + git push origin v1.1.0-bernabeu + ``` + +4. **CD workflow runs automatically** to publish Docker images and create GitHub Release + +See [CHANGELOG.md](CHANGELOG.md#how-to-release) for complete release instructions and stadium naming convention. + ## CI/CD Pipeline ### Continuous Integration (dotnet.yml) @@ -165,7 +227,7 @@ curl http://localhost:5000/health 2. **Restore**: `dotnet restore` with dependency caching 3. **Build**: `dotnet build --no-restore --configuration Release` 4. **Test**: `dotnet test --no-build --verbosity normal --settings .runsettings` -5. **Coverage**: Upload coverage reports to Codecov and Codacy +5. **Coverage**: Upload coverage reports to Codecov **Local validation** (run this before pushing): @@ -384,6 +446,7 @@ curl -X DELETE https://localhost:9000/players/1 -k ## Important Notes +- **CHANGELOG maintenance**: Update CHANGELOG.md `[Unreleased]` section with every meaningful change - **Never commit secrets**: No API keys, tokens, or credentials in code - **Test coverage**: Maintain high coverage with xUnit tests - **Commit messages**: Follow conventional commits (enforced by commitlint in CI) diff --git a/CHANGELOG.md b/CHANGELOG.md index b66de58..2a7c3b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,30 +44,87 @@ This project uses famous football stadiums (A-Z) that hosted FIFA World Cup matc ### Added +- Token efficiency strategy for Copilot/AI agents with optimized instruction loading and improved token counting script (#364) + ### Changed -### Fixed +- Bump Swashbuckle.AspNetCore from 10.1.0 to 10.1.2 +- Bump docker/login-action from 3.6.0 to 3.7.0 +- Bump softprops/action-gh-release from 2.2.0 to 2.5.0 +- Bump actions/checkout from 6.0.1 to 6.0.2 + +### Deprecated ### Removed +### Fixed + +### Security + +--- + +## [1.0.0 - azteca] - 2026-01-22 + +Initial release. See [README.md](README.md) for complete feature list and documentation. + --- ## How to Release -To create a new release: +To create a new release, follow these steps in order: + +### 1. Update CHANGELOG.md + +Move items from the `[Unreleased]` section to a new release section: + +```markdown +## [X.Y.Z - STADIUM_NAME] - YYYY-MM-DD + +### Added +- New features here + +### Changed +- Changes here + +### Fixed +- Bug fixes here + +### Removed +- Removed features here +``` + +**Important:** Commit and push this change before creating the tag. + +### 2. Create and Push Version Tag + +```bash +git tag -a vX.Y.Z-stadium -m "Release X.Y.Z - Stadium" +git push origin vX.Y.Z-stadium +``` + +Example: + +```bash +git tag -a v1.0.0-azteca -m "Release 1.0.0 - Azteca" +git push origin v1.0.0-azteca +``` + +### 3. Automated CD Workflow + +The CD workflow automatically: -1. Update this CHANGELOG with release notes under the appropriate version heading -2. Create and push a version tag with stadium name: +- βœ… Validates the stadium name against the A-Z list +- βœ… Builds and tests the project in Release configuration +- βœ… Publishes Docker images to GHCR with three tags (`:X.Y.Z`, `:stadium`, `:latest`) +- βœ… Creates a GitHub Release with auto-generated notes from commits - ```bash - git tag -a v1.0.0-azteca -m "Release 1.0.0 - Azteca" - git push origin v1.0.0-azteca - ``` +### Pre-Release Checklist -3. The CD workflow will automatically: - - Build and test the project - - Publish Docker images to GHCR with three tags (`:1.0.0`, `:azteca`, `:latest`) - - Create a GitHub Release with auto-generated notes +- [ ] CHANGELOG.md updated with release notes +- [ ] CHANGELOG.md changes committed and pushed +- [ ] Tag created with correct format: `vX.Y.Z-stadium` +- [ ] Stadium name is valid (A-Z from table above) +- [ ] Tag pushed to trigger CD workflow --- @@ -81,10 +138,21 @@ To create a new release: ### Changed - Changes in existing functionality -### Fixed -- Bug fixes +### Deprecated +- Soon-to-be removed features ### Removed - Removed features +### Fixed +- Bug fixes + +### Security +- Security vulnerability fixes + --> + +--- + +[unreleased]: https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/compare/v1.0.0-azteca...HEAD +[1.0.0 - azteca]: https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/releases/tag/v1.0.0-azteca diff --git a/README.md b/README.md index a95ec06..680ae43 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ [![.NET CD](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/actions/workflows/dotnet-cd.yml/badge.svg)](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/actions/workflows/dotnet-cd.yml) [![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) [![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) -[![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) [![codecov](https://codecov.io/gh/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/graph/badge.svg?token=hgJc1rStJ9)](https://codecov.io/gh/nanotaboada/Dotnet.Samples.AspNetCore.WebApi) [![CodeFactor](https://www.codefactor.io/repository/github/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/badge)](https://www.codefactor.io/repository/github/nanotaboada/Dotnet.Samples.AspNetCore.WebApi) [![License: MIT](https://img.shields.io/badge/License-MIT-white.svg)](https://opensource.org/licenses/MIT) @@ -30,18 +29,14 @@ Proof of Concept for a RESTful API built with .NET 8 (LTS) and ASP.NET Core. Man ## Features -- πŸ”Œ RESTful CRUD operations for football player data -- πŸ“š Interactive API documentation -- 🚦 Fixed window rate limiting -- ⌨️ Input validation -- ⚑ In-memory caching (1-hour TTL) -- πŸ’Ώ Relational database with ORM -- πŸ—οΈ Layered architecture pattern -- βŒ› Asynchronous operations throughout -- πŸ“ Structured logging to console and file -- 🩺 Health check endpoint for monitoring -- 🐳 Full containerization support -- βœ… Comprehensive unit tests +- πŸ—οΈ **Clean layered architecture** - Repository pattern, dependency injection, and async operations throughout +- πŸ“š **Interactive API exploration** - Swagger UI documentation with health monitoring endpoints +- ⚑ **Performance optimizations** - In-memory caching, rate limiting, and efficient database queries +- πŸ§ͺ **High test coverage** - xUnit tests with automated reporting to Codecov and SonarCloud +- πŸ“– **Token-efficient documentation** - AGENTS.md + auto-loaded Copilot instructions for AI-assisted development +- 🐳 **Full containerization** - Multi-stage Docker builds with Docker Compose orchestration +- πŸ”„ **Complete CI/CD pipeline** - Automated testing, code quality checks, Docker publishing, and GitHub releases +- 🏟️ **Stadium-themed semantic versioning** - Memorable, alphabetical release names from World Cup venues ## Tech Stack @@ -190,7 +185,7 @@ graph TB Interactive API documentation is available via Swagger UI at `https://localhost:9000/swagger/index.html` when the server is running. -> πŸ’‘ **Note:** Swagger documentation is only available in development mode for security reasons. +> πŸ’‘ Swagger documentation is only available in development mode for security reasons. **Quick Reference:** @@ -273,7 +268,7 @@ docker compose build docker compose up ``` -> πŸ’‘ **Note:** On first run, the container copies a pre-seeded SQLite database into a persistent volume. On subsequent runs, that volume is reused and the data is preserved. +> πŸ’‘ On first run, the container copies a pre-seeded SQLite database into a persistent volume. On subsequent runs, that volume is reused and the data is preserved. ### Stop the application @@ -304,18 +299,39 @@ Releases follow the pattern: `v{SEMVER}-{STADIUM}` (e.g., `v1.0.0-azteca`) ### Create a Release -To create a new release, tag a commit and push the tag: +To create a new release, follow this workflow: + +#### 1. Update CHANGELOG.md + +First, document your changes in [CHANGELOG.md](CHANGELOG.md): + +```bash +# Move items from [Unreleased] to new release section +# Example: [1.0.0 - azteca] - 2026-01-22 +git add CHANGELOG.md +git commit -m "docs: prepare changelog for v1.0.0-azteca release" +git push +``` + +#### 2. Create and Push Tag + +Then create and push the version tag: ```bash git tag -a v1.0.0-azteca -m "Release 1.0.0 - Azteca" git push origin v1.0.0-azteca ``` +#### 3. Automated CD Workflow + This triggers the CD workflow which automatically: -1. Builds and tests the project in Release configuration -2. Publishes Docker images to GitHub Container Registry with three tags -3. Creates a GitHub Release with auto-generated changelog +1. Validates the stadium name +2. Builds and tests the project in Release configuration +3. Publishes Docker images to GitHub Container Registry with three tags +4. Creates a GitHub Release with auto-generated changelog from commits + +> πŸ’‘ Always update CHANGELOG.md before creating the tag. See [CHANGELOG.md](CHANGELOG.md#how-to-release) for detailed release instructions. ### Pull Docker Images @@ -332,7 +348,7 @@ docker pull ghcr.io/nanotaboada/dotnet-samples-aspnetcore-webapi:azteca docker pull ghcr.io/nanotaboada/dotnet-samples-aspnetcore-webapi:latest ``` -> πŸ’‘ **Note:** See [CHANGELOG.md](CHANGELOG.md) for the complete stadium list (A-Z) and release history. +> πŸ’‘ See [CHANGELOG.md](CHANGELOG.md) for the complete stadium list (A-Z) and release history. ## Environment Variables @@ -366,7 +382,7 @@ For containerized production deployment: STORAGE_PATH=/storage/players-sqlite3.db ``` -> πŸ’‘ **Note:** Additional environment variables (`ASPNETCORE_ENVIRONMENT=Production` and `ASPNETCORE_URLS=http://+:9000`) are set in the `Dockerfile`. +> πŸ’‘ Additional environment variables (`ASPNETCORE_ENVIRONMENT=Production` and `ASPNETCORE_URLS=http://+:9000`) are set in the `Dockerfile`. ## Command Summary diff --git a/src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs b/src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs index 2cb144c..32257d8 100644 --- a/src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs +++ b/src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs @@ -10,25 +10,58 @@ namespace Dotnet.Samples.AspNetCore.WebApi.Models; /// public class Player { + /// + /// The unique identifier for the Player. + /// public Guid Id { get; set; } = Guid.NewGuid(); + /// + /// The first name of the Player. + /// public string? FirstName { get; set; } + /// + /// The middle name of the Player, if any. + /// public string? MiddleName { get; set; } + /// + /// The last name of the Player. + /// public string? LastName { get; set; } + /// + /// The date of birth of the Player. + /// public DateTime? DateOfBirth { get; set; } + /// + /// The squad number assigned to the Player. + /// public int SquadNumber { get; set; } + /// + /// The playing position of the Player. + /// public string? Position { get; set; } + /// + /// The abbreviated form of the Player's position. + /// public string? AbbrPosition { get; set; } + /// + /// The team to which the Player belongs. + /// public string? Team { get; set; } + /// + /// The league where the team plays. + /// public string? League { get; set; } + /// + /// Indicates whether the Player is in the starting 11. + /// public bool Starting11 { get; set; } } diff --git a/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerRequestModel.cs b/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerRequestModel.cs index cdc6928..3046dd5 100644 --- a/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerRequestModel.cs +++ b/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerRequestModel.cs @@ -12,19 +12,43 @@ namespace Dotnet.Samples.AspNetCore.WebApi.Models; /// public class PlayerRequestModel { + /// + /// The first name of the Player. + /// public string? FirstName { get; set; } + /// + /// The middle name of the Player, if any. + /// public string? MiddleName { get; set; } + /// + /// The last name of the Player. + /// public string? LastName { get; set; } + /// + /// The date of birth of the Player. + /// public DateTime? DateOfBirth { get; set; } + /// + /// The squad number assigned to the Player (required). + /// public required int SquadNumber { get; set; } + /// + /// The abbreviated form of the Player's position. + /// public string? AbbrPosition { get; set; } + /// + /// The team to which the Player belongs. + /// public string? Team { get; set; } + /// + /// The league where the team plays. + /// public string? League { get; set; } } diff --git a/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs b/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs index a285228..3f3c4bf 100644 --- a/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs +++ b/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs @@ -10,17 +10,38 @@ namespace Dotnet.Samples.AspNetCore.WebApi.Models; /// public class PlayerResponseModel { + /// + /// The full name of the Player (combined first, middle, and last names). + /// public string? FullName { get; set; } + /// + /// The formatted birth date of the Player. + /// public string? Birth { get; set; } + /// + /// The squad number (dorsal) of the Player. + /// public int Dorsal { get; set; } + /// + /// The playing position of the Player. + /// public string? Position { get; set; } + /// + /// The club (team) to which the Player belongs. + /// public string? Club { get; set; } + /// + /// The league where the club plays. + /// public string? League { get; set; } + /// + /// Indicates whether the Player is in the starting 11 (formatted as string). + /// public string? Starting11 { get; set; } } From 5ad6131c462ee155d2c85530d579c1aa0d02b3ec Mon Sep 17 00:00:00 2001 From: Nano Taboada <87288+nanotaboada@users.noreply.github.com> Date: Sun, 8 Feb 2026 11:06:17 -0300 Subject: [PATCH 2/2] fix(cd): add space after # in release heading for valid Markdown --- .github/workflows/dotnet-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet-cd.yml b/.github/workflows/dotnet-cd.yml index 2aaf160..08f72c9 100644 --- a/.github/workflows/dotnet-cd.yml +++ b/.github/workflows/dotnet-cd.yml @@ -141,7 +141,7 @@ jobs: name: "v${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }} 🏟️" tag_name: ${{ steps.version.outputs.tag_name }} body: | - #Release ${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }} 🏟️ + # Release ${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }} 🏟️ ## Docker Images