Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions .github/release-drafter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Release Drafter Configuration
# Documentation: https://github.com/release-drafter/release-drafter

name-template: 'Version $RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'

# Categories for organizing release notes
categories:
- title: '🚀 Features'
labels:
- 'feature'
- 'enhancement'
- title: '🐛 Bug Fixes'
labels:
- 'bug'
- 'fix'
- title: '🔧 Maintenance'
labels:
- 'maintenance'
- 'chore'
- 'refactor'
- 'dependencies'
- title: '📚 Documentation'
labels:
- 'documentation'
- 'docs'
- title: '⚡ Performance'
labels:
- 'performance'
- title: '🔒 Security'
labels:
- 'security'

# Exclude certain labels from release notes
exclude-labels:
- 'skip-changelog'
- 'wip'

# Change template (how each PR is listed)
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
change-title-escapes: '\<*_&' # Escape special markdown characters

# Template for the release body
template: |
## What's Changed

$CHANGES

## 📦 NuGet Packages

The following packages are included in this release:

- `MyCSharp.HttpUserAgentParser`
- `MyCSharp.HttpUserAgentParser.AspNetCore`
- `MyCSharp.HttpUserAgentParser.MemoryCache`

### Installation

```bash
dotnet add package MyCSharp.HttpUserAgentParser
dotnet add package MyCSharp.HttpUserAgentParser.AspNetCore
dotnet add package MyCSharp.HttpUserAgentParser.MemoryCache
```

## Contributors

$CONTRIBUTORS

---

**Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION

# Automatically label PRs based on modified files
autolabeler:
- label: 'documentation'
files:
- '*.md'
- 'docs/**/*'
- label: 'bug'
branch:
- '/fix\/.+/'
title:
- '/fix/i'
- label: 'feature'
branch:
- '/feature\/.+/'
title:
- '/feature/i'
- label: 'dependencies'
files:
- '**/packages.lock.json'
- '**/*.csproj'
- 'Directory.Packages.props'
- 'Directory.Build.props'
- label: 'github-actions'
files:
- '.github/workflows/**/*'
- label: 'tests'
files:
- 'tests/**/*'
- '**/*Tests.cs'
- '**/*Test.cs'
- label: 'performance'
files:
- 'perf/**/*'
- '**/*Benchmark*.cs'

# Version resolver (uses version from workflow input)
version-resolver:
default: patch
89 changes: 89 additions & 0 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Build and Test (Reusable)

on:
workflow_call:
inputs:
dotnet-version:
description: '.NET version to use (can be multi-line for multiple versions)'
required: false
type: string
default: |
8.0.x
9.0.x
10.0.x
configuration:
description: 'Build configuration'
required: false
type: string
default: 'Release'
upload-test-results:
description: 'Whether to upload test results as artifacts'
required: false
type: boolean
default: false
create-pack:
description: 'Whether to pack NuGet packages'
required: false
type: boolean
default: false
outputs:
version:
description: 'The calculated version from NBGV'
value: ${{ jobs.build.outputs.version }}

jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
outputs:
version: ${{ steps.nbgv.outputs.version }}

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Required for GitVersion

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ inputs.dotnet-version }}

- name: Install Nerdbank.GitVersioning
run: dotnet tool install -g nbgv

- name: Set version with NBGV
id: nbgv
run: |
nbgv get-version --format json > version.json
VERSION=$(nbgv get-version -v NuGetPackageVersion)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Calculated version: $VERSION"

- name: Restore dependencies
run: dotnet restore

- name: Build
run: dotnet build --configuration ${{ inputs.configuration }} --no-restore

- name: Test
run: dotnet test --configuration ${{ inputs.configuration }} --no-build --verbosity normal --logger "trx;LogFileName=test-results.trx"

- name: Upload test results
if: always() && inputs.upload-test-results
uses: actions/upload-artifact@v4
with:
name: test-results-${{ inputs.dotnet-version }}
path: '**/TestResults/**/*.trx'

- name: Pack NuGet packages
if: inputs.create-pack
run: dotnet pack --configuration ${{ inputs.configuration }} --no-build --output ./artifacts

- name: Upload NuGet packages
if: inputs.create-pack
uses: actions/upload-artifact@v4
with:
name: nuget-packages
path: ./artifacts/*.nupkg
retention-days: 30
152 changes: 58 additions & 94 deletions .github/workflows/main-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,118 +10,82 @@ permissions:
packages: write

jobs:
build-and-pack:
name: Build, Pack and Create Draft Release
build-and-test:
name: Build, Test and Pack
uses: ./.github/workflows/build-and-test.yml
with:
create-pack: true

create-draft-release:
name: Create Draft Release
needs: build-and-test
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Required for GitVersion

- name: Setup .NET
uses: actions/setup-dotnet@v4
- name: Download NuGet packages
uses: actions/download-artifact@v4
with:
dotnet-version: |
8.0.x
9.0.x
10.0.x

- name: Restore dependencies
run: dotnet restore

- name: Build
run: dotnet build --configuration Release --no-restore

- name: Test
run: dotnet test --configuration Release --no-build --verbosity normal

- name: Pack NuGet packages
run: dotnet pack --configuration Release --no-build --output ./artifacts
name: nuget-packages
path: ./artifacts

- name: Get version from packages
id: get-version
- name: Check if tag exists
id: check-tag
run: |
# Extract version from the first package
VERSION=$(ls ./artifacts/*.nupkg | head -1 | sed -n 's/.*\.MyCSharp\.HttpUserAgentParser\.\([0-9]\+\.[0-9]\+\.[0-9]\+.*\)\.nupkg/\1/p')
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Version: $VERSION"

- name: Check for existing draft release
id: check-draft
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
DRAFT_RELEASE=$(gh release list --limit 100 --json isDraft,name,tagName | jq -r '.[] | select(.isDraft == true) | .tagName' | head -1)
if [ -n "$DRAFT_RELEASE" ]; then
TAG="v${{ needs.build-and-test.outputs.version }}"
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "tag=$DRAFT_RELEASE" >> $GITHUB_OUTPUT
echo "Found existing draft release: $DRAFT_RELEASE"
echo "⚠️ Tag $TAG already exists"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "No existing draft release found"
echo "✅ Tag $TAG does not exist yet"
fi

- name: Delete existing draft release
if: steps.check-draft.outputs.exists == 'true'
- name: Create/Update Draft Release
if: steps.check-tag.outputs.exists == 'false'
uses: release-drafter/release-drafter@v6
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Deleting existing draft release: ${{ steps.check-draft.outputs.tag }}"
gh release delete ${{ steps.check-draft.outputs.tag }} --yes --cleanup-tag || true

- name: Create draft release
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
config-name: release-drafter.yml
version: v${{ needs.build-and-test.outputs.version }}
tag: v${{ needs.build-and-test.outputs.version }}
name: Version ${{ needs.build-and-test.outputs.version }}
publish: false
prerelease: false

- name: Upload packages to draft release
if: steps.check-tag.outputs.exists == 'false'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ steps.get-version.outputs.version }}"
TAG="v${VERSION}"

# Create release notes
cat > release-notes.md << 'EOF'
## What's Changed

This is an automated draft release created from the main branch.

### Packages

The following NuGet packages are included in this release:

EOF

# List all packages
TAG="v${{ needs.build-and-test.outputs.version }}"
# Wait a moment for the release to be created
sleep 2
# Upload artifacts to the draft release
for file in ./artifacts/*.nupkg; do
filename=$(basename "$file")
echo "- \`$filename\`" >> release-notes.md
gh release upload "$TAG" "$file" --clobber
done
echo "✅ Uploaded NuGet packages to draft release"

cat >> release-notes.md << 'EOF'

### Installation

```bash
dotnet add package MyCSharp.HttpUserAgentParser
dotnet add package MyCSharp.HttpUserAgentParser.AspNetCore
dotnet add package MyCSharp.HttpUserAgentParser.MemoryCache
```

**Full Changelog**: https://github.com/${{ github.repository }}/commits/${{ github.sha }}
EOF

# Create draft release
gh release create "$TAG" \
./artifacts/*.nupkg \
--draft \
--title "Release $VERSION" \
--notes-file release-notes.md \
--target ${{ github.sha }}

echo "Created draft release: $TAG"

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: nuget-packages
path: ./artifacts/*.nupkg
retention-days: 30
- name: Summary
if: steps.check-tag.outputs.exists == 'false'
run: |
echo "✅ Draft release created/updated" >> $GITHUB_STEP_SUMMARY
echo "Version: v${{ needs.build-and-test.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Next steps:" >> $GITHUB_STEP_SUMMARY
echo "1. Go to [Releases](../../releases)" >> $GITHUB_STEP_SUMMARY
echo "2. Review the draft release" >> $GITHUB_STEP_SUMMARY
echo "3. Edit release notes if needed" >> $GITHUB_STEP_SUMMARY
echo "4. Publish release to trigger production deployment" >> $GITHUB_STEP_SUMMARY

- name: Release already exists
if: steps.check-tag.outputs.exists == 'true'
run: |
echo "ℹ️ Release v${{ needs.build-and-test.outputs.version }} already exists" >> $GITHUB_STEP_SUMMARY
echo "No action taken" >> $GITHUB_STEP_SUMMARY
Loading