Skip to content

FIX (releases): Fix version generation #2

FIX (releases): Fix version generation

FIX (releases): Fix version generation #2

Workflow file for this run

name: Automated Release
on:
push:
branches: [main]
workflow_dispatch:
jobs:
release:
runs-on: ubuntu-latest
if: ${{ !contains(github.event.head_commit.message, '[skip-release]') }}
steps:
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: |
npm install -g conventional-changelog-cli
npm install -g semver
- name: Get current version
id: current_version
run: |
# Get the latest tag, default to 0.0.0 if no tags exist
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
echo "current_version=${LATEST_TAG#v}" >> $GITHUB_OUTPUT
echo "Current version: ${LATEST_TAG#v}"
- name: Analyze commits and determine version bump
id: version_bump
run: |
CURRENT_VERSION="${{ steps.current_version.outputs.current_version }}"
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
# Get commits since last tag
if [ "$LATEST_TAG" = "v0.0.0" ]; then
COMMITS=$(git log --pretty=format:"%s" --no-merges)
else
COMMITS=$(git log ${LATEST_TAG}..HEAD --pretty=format:"%s" --no-merges)
fi
echo "Analyzing commits:"
echo "$COMMITS"
# Initialize flags
HAS_FEATURE=false
HAS_FIX=false
HAS_BREAKING=false
# Analyze each commit
while IFS= read -r commit; do
if [[ "$commit" =~ ^FEATURE ]]; then
HAS_FEATURE=true
echo "Found FEATURE commit: $commit"
elif [[ "$commit" =~ ^FIX ]]; then
HAS_FIX=true
echo "Found FIX commit: $commit"
elif [[ "$commit" =~ ^REFACTOR ]]; then
HAS_FIX=true # Treat refactor as patch
echo "Found REFACTOR commit: $commit"
fi
# Check for breaking changes
if [[ "$commit" =~ BREAKING[[:space:]]CHANGE ]] || [[ "$commit" =~ "!" ]]; then
HAS_BREAKING=true
echo "Found BREAKING CHANGE: $commit"
fi
done <<< "$COMMITS"
# Determine version bump
if [ "$HAS_BREAKING" = true ]; then
BUMP_TYPE="major"
elif [ "$HAS_FEATURE" = true ]; then
BUMP_TYPE="minor"
elif [ "$HAS_FIX" = true ]; then
BUMP_TYPE="patch"
else
BUMP_TYPE="none"
fi
echo "bump_type=$BUMP_TYPE" >> $GITHUB_OUTPUT
if [ "$BUMP_TYPE" != "none" ]; then
NEW_VERSION=$(npx semver -i $BUMP_TYPE $CURRENT_VERSION)
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "should_release=true" >> $GITHUB_OUTPUT
echo "New version will be: $NEW_VERSION"
else
echo "should_release=false" >> $GITHUB_OUTPUT
echo "No version bump needed"
fi
- name: Generate changelog
id: changelog
if: steps.version_bump.outputs.should_release == 'true'
run: |
CURRENT_VERSION="${{ steps.current_version.outputs.current_version }}"
NEW_VERSION="${{ steps.version_bump.outputs.new_version }}"
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
# Get commits since last tag
if [ "$LATEST_TAG" = "v0.0.0" ]; then
COMMITS=$(git log --pretty=format:"%s|||%H|||%an|||%ad" --date=short --no-merges)
else
COMMITS=$(git log ${LATEST_TAG}..HEAD --pretty=format:"%s|||%H|||%an|||%ad" --date=short --no-merges)
fi
# Create changelog
CHANGELOG="# Changelog\n\n## [${NEW_VERSION}] - $(date +%Y-%m-%d)\n\n"
# Group commits by type and area
FEATURES=""
FIXES=""
REFACTORS=""
while IFS= read -r line; do
if [ -n "$line" ]; then
COMMIT_MSG=$(echo "$line" | cut -d'|||' -f1)
COMMIT_HASH=$(echo "$line" | cut -d'|||' -f2)
COMMIT_AUTHOR=$(echo "$line" | cut -d'|||' -f3)
COMMIT_DATE=$(echo "$line" | cut -d'|||' -f4)
SHORT_HASH=${COMMIT_HASH:0:7}
# Parse commit message format: TYPE (area): description
if [[ "$COMMIT_MSG" == FEATURE* ]]; then
# Extract area and description
TEMP="${COMMIT_MSG#FEATURE}"
TEMP="${TEMP#"${TEMP%%[![:space:]]*}"}" # trim leading spaces
if [[ "$TEMP" == \(* ]]; then
AREA=$(echo "$TEMP" | sed 's/^(\([^)]*\)).*/\1/')
DESC=$(echo "$TEMP" | sed 's/^([^)]*):[[:space:]]*//')
FEATURES="${FEATURES}- **${AREA}**: ${DESC} ([${SHORT_HASH}](https://github.com/${{ github.repository }}/commit/${COMMIT_HASH}))\n"
fi
elif [[ "$COMMIT_MSG" == FIX* ]]; then
# Extract area and description
TEMP="${COMMIT_MSG#FIX}"
TEMP="${TEMP#"${TEMP%%[![:space:]]*}"}" # trim leading spaces
if [[ "$TEMP" == \(* ]]; then
AREA=$(echo "$TEMP" | sed 's/^(\([^)]*\)).*/\1/')
DESC=$(echo "$TEMP" | sed 's/^([^)]*):[[:space:]]*//')
FIXES="${FIXES}- **${AREA}**: ${DESC} ([${SHORT_HASH}](https://github.com/${{ github.repository }}/commit/${COMMIT_HASH}))\n"
fi
elif [[ "$COMMIT_MSG" == REFACTOR* ]]; then
# Extract area and description
TEMP="${COMMIT_MSG#REFACTOR}"
TEMP="${TEMP#"${TEMP%%[![:space:]]*}"}" # trim leading spaces
if [[ "$TEMP" == \(* ]]; then
AREA=$(echo "$TEMP" | sed 's/^(\([^)]*\)).*/\1/')
DESC=$(echo "$TEMP" | sed 's/^([^)]*):[[:space:]]*//')
REFACTORS="${REFACTORS}- **${AREA}**: ${DESC} ([${SHORT_HASH}](https://github.com/${{ github.repository }}/commit/${COMMIT_HASH}))\n"
fi
fi
fi
done <<< "$COMMITS"
# Build changelog sections
if [ -n "$FEATURES" ]; then
CHANGELOG="${CHANGELOG}### ✨ Features\n${FEATURES}\n"
fi
if [ -n "$FIXES" ]; then
CHANGELOG="${CHANGELOG}### 🐛 Bug Fixes\n${FIXES}\n"
fi
if [ -n "$REFACTORS" ]; then
CHANGELOG="${CHANGELOG}### 🔨 Refactoring\n${REFACTORS}\n"
fi
# Save changelog to file
echo -e "$CHANGELOG" > RELEASE_CHANGELOG.md
# Update main CHANGELOG.md
if [ -f "CHANGELOG.md" ]; then
# Create new changelog content
echo -e "$CHANGELOG" > NEW_CHANGELOG.md
# Get existing changelog content after the [Unreleased] section
sed -n '/## \[Unreleased\]/,$p' CHANGELOG.md | tail -n +3 >> NEW_CHANGELOG.md
# Replace the original file
mv NEW_CHANGELOG.md CHANGELOG.md
else
echo -e "$CHANGELOG" > CHANGELOG.md
fi
# Set output for GitHub release (escape newlines)
{
echo 'changelog<<EOF'
echo -e "$CHANGELOG"
echo EOF
} >> $GITHUB_OUTPUT
- name: Create Git tag
if: steps.version_bump.outputs.should_release == 'true'
run: |
NEW_VERSION="${{ steps.version_bump.outputs.new_version }}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "v${NEW_VERSION}" -m "Release v${NEW_VERSION}"
git push origin "v${NEW_VERSION}"
- name: Create GitHub Release
if: steps.version_bump.outputs.should_release == 'true'
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ steps.version_bump.outputs.new_version }}
release_name: Release v${{ steps.version_bump.outputs.new_version }}
body: ${{ steps.changelog.outputs.changelog }}
draft: false
prerelease: false
- name: Update version files and changelog
if: steps.version_bump.outputs.should_release == 'true'
run: |
NEW_VERSION="${{ steps.version_bump.outputs.new_version }}"
cd frontend
npm version $NEW_VERSION --no-git-tag-version
cd ..
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add frontend/package.json frontend/package-lock.json CHANGELOG.md
git commit -m "chore: bump version to ${NEW_VERSION} [skip-release]" || true
git push origin main || true