Create Release and Publish to NuGet #10
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Create Release and Publish to NuGet | |
on: | |
workflow_dispatch: | |
inputs: | |
release_type: | |
description: 'Release type' | |
required: true | |
default: 'patch' | |
type: choice | |
options: | |
- patch | |
- minor | |
- major | |
jobs: | |
build-and-release: | |
runs-on: ubuntu-latest | |
steps: | |
# Checkout repository with full history | |
- uses: actions/checkout@v3 | |
with: | |
fetch-depth: 0 | |
# Setup .NET SDK | |
- name: Setup .NET | |
uses: actions/setup-dotnet@v3 | |
with: | |
dotnet-version: '8.0.x' | |
# Check which projects changed and calculate their new versions | |
- name: Check Changes and Calculate Versions | |
id: version_check | |
run: | | |
SHOULD_RELEASE="false" | |
CHANGED_PROJECTS="" | |
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") | |
NEW_VERSION="" | |
# Function to compare version numbers | |
version_gt() { | |
test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1" | |
} | |
# Check each project for changes and update versions | |
for proj in $(find . -name "*.csproj"); do | |
PROJECT_NAME=$(basename "$proj") | |
PROJECT_DIR=$(dirname "$proj") | |
# Get current version from csproj | |
CURRENT_VERSION=$(grep -oP '(?<=<Version>).*(?=</Version>)' "$proj" || echo "0.0.0") | |
if [ -z "$CURRENT_VERSION" ]; then | |
echo "Warning: Could not find version in $proj" | |
continue | |
fi | |
# Split version into parts | |
IFS='.' read -r -a VERSION_PARTS <<< "$CURRENT_VERSION" | |
MAJOR="${VERSION_PARTS[0]}" | |
MINOR="${VERSION_PARTS[1]}" | |
PATCH="${VERSION_PARTS[2]}" | |
# Check if project has changes since last tag | |
if [ -z "$LATEST_TAG" ] || ! git diff --quiet $LATEST_TAG HEAD -- "$PROJECT_DIR"; then | |
# Calculate new version based on release type | |
case "${{ github.event.inputs.release_type }}" in | |
"major") | |
PROJECT_NEW_VERSION="$((MAJOR + 1)).0.0" | |
;; | |
"minor") | |
PROJECT_NEW_VERSION="${MAJOR}.$((MINOR + 1)).0" | |
;; | |
"patch") | |
PROJECT_NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" | |
;; | |
esac | |
# Update version in csproj | |
sed -i "s/<Version>.*<\/Version>/<Version>${PROJECT_NEW_VERSION}<\/Version>/g" "$proj" | |
CHANGED_PROJECTS="$CHANGED_PROJECTS$PROJECT_NAME -> $PROJECT_NEW_VERSION\n" | |
SHOULD_RELEASE="true" | |
# Update NEW_VERSION if this project's version is higher | |
if [ -z "$NEW_VERSION" ] || version_gt "$PROJECT_NEW_VERSION" "$NEW_VERSION"; then | |
NEW_VERSION="$PROJECT_NEW_VERSION" | |
echo "New highest version: $NEW_VERSION from $PROJECT_NAME" | |
fi | |
fi | |
done | |
if [ -z "$NEW_VERSION" ]; then | |
echo "No version changes detected" | |
exit 0 | |
fi | |
echo "Final highest version will be: v$NEW_VERSION" | |
# Set environment variables for next steps | |
echo "CHANGED_PROJECTS<<EOF" >> $GITHUB_ENV | |
echo -e "$CHANGED_PROJECTS" >> $GITHUB_ENV | |
echo "EOF" >> $GITHUB_ENV | |
echo "SHOULD_RELEASE=$SHOULD_RELEASE" >> $GITHUB_ENV | |
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV | |
# Generate release notes with commits and changed projects | |
- name: Generate Release Notes | |
if: env.SHOULD_RELEASE == 'true' | |
id: release_notes | |
run: | | |
PREVIOUS_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") | |
if [ -z "$PREVIOUS_TAG" ]; then | |
COMMITS=$(git log --pretty=format:"- %s" --no-merges) | |
else | |
COMMITS=$(git log ${PREVIOUS_TAG}..HEAD --pretty=format:"- %s" --no-merges) | |
fi | |
echo "RELEASE_NOTES<<EOF" >> $GITHUB_ENV | |
echo "## What's Changed" >> $GITHUB_ENV | |
echo "$COMMITS" >> $GITHUB_ENV | |
echo -e "\n## Updated Projects" >> $GITHUB_ENV | |
echo "${{ env.CHANGED_PROJECTS }}" >> $GITHUB_ENV | |
echo "EOF" >> $GITHUB_ENV | |
# Restore project dependencies | |
- name: Restore dependencies | |
if: env.SHOULD_RELEASE == 'true' | |
run: dotnet restore | |
# Build solution | |
- name: Build | |
if: env.SHOULD_RELEASE == 'true' | |
run: dotnet build --configuration Release --no-restore | |
# Create NuGet packages | |
- name: Pack | |
if: env.SHOULD_RELEASE == 'true' | |
run: dotnet pack --configuration Release --no-build --output nupkgs | |
# Create GitHub release | |
- name: Create Release | |
if: env.SHOULD_RELEASE == 'true' | |
id: create_release | |
uses: actions/create-release@v1 | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
with: | |
tag_name: v${{ env.NEW_VERSION }} | |
release_name: Release v${{ env.NEW_VERSION }} | |
body: ${{ env.RELEASE_NOTES }} | |
draft: false | |
prerelease: false | |
# Upload NuGet packages as release assets | |
- name: Upload Release Assets | |
if: env.SHOULD_RELEASE == 'true' | |
uses: softprops/action-gh-release@v1 | |
with: | |
files: ./nupkgs/*.nupkg | |
tag_name: v${{ env.NEW_VERSION }} | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
# Publish packages to NuGet.org | |
- name: Push to NuGet | |
if: env.SHOULD_RELEASE == 'true' | |
run: dotnet nuget push "./nupkgs/*.nupkg" --source "https://api.nuget.org/v3/index.json" --api-key ${{secrets.NUGET_API_KEY}} --skip-duplicate | |
# Commit version updates and create tag | |
- name: Commit version updates | |
if: env.SHOULD_RELEASE == 'true' && env.NEW_VERSION != '' | |
run: | | |
if [ -z "${{ env.NEW_VERSION }}" ]; then | |
echo "Error: NEW_VERSION is not set" | |
exit 1 | |
fi | |
echo "Creating release for version v${{ env.NEW_VERSION }}" | |
git config --local user.email "[email protected]" | |
git config --local user.name "GitHub Action" | |
git add . | |
git commit -m "Update project versions to v${{ env.NEW_VERSION }}" | |
git tag -a "v${{ env.NEW_VERSION }}" -m "Release v${{ env.NEW_VERSION }}" | |
git push --follow-tags |