Created
July 8, 2025 16:25
-
-
Save freehuntx/ce14609040ccaaabae170dc8e20164e8 to your computer and use it in GitHub Desktop.
Release workflow bash file
This file contains hidden or 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
#!/bin/bash | |
set -euo pipefail | |
IFS=$'\n\t' | |
# Get the latest tag | |
LAST_TAG="$(git describe --tags --abbrev=0 2>/dev/null || true)" | |
# Get commits since the last tag, or all commits if no tag exists | |
if [[ -z "$LAST_TAG" ]]; then | |
COMMITS=$(git log --pretty=format:"%s") | |
else | |
COMMITS=$(git log "$LAST_TAG"..HEAD --pretty=format:"%s") | |
fi | |
# Check if there are any new commits | |
if [ -z "$COMMITS" ]; then | |
echo "No new commits since ${LAST_TAG:-beginning of history}. Exiting." | |
exit 0 | |
fi | |
CURRENT_VERSION=0.0.0 | |
if [ -n "$LAST_TAG" ]; then | |
CURRENT_VERSION=${LAST_TAG#v} | |
CURRENT_VERSION=${CURRENT_VERSION%%+*} | |
CURRENT_VERSION=${CURRENT_VERSION%%-*} | |
fi | |
IFS='.' read -r MAJOR MINOR PATCH <<<"$CURRENT_VERSION" | |
MAJOR=$((10#$MAJOR)) | |
MINOR=$((10#$MINOR)) | |
PATCH=$((10#$PATCH)) | |
# Check for breaking changes (type! or type(scope)!: ...) | |
if echo "$COMMITS" | grep -Eq "^(feat|fix|chore|docs|style|refactor|perf|test|build|ci)(\([^)]+\))?!:"; then | |
MAJOR=$((MAJOR + 1)) | |
MINOR=0 | |
PATCH=0 | |
elif echo "$COMMITS" | grep -q "^feat"; then | |
MINOR=$((MINOR + 1)) | |
PATCH=0 | |
else | |
PATCH=$((PATCH + 1)) | |
fi | |
NEXT_VERSION="v$MAJOR.$MINOR.$PATCH" | |
CURRENT_DATE=$(date +%Y-%m-%d) | |
# Generate categorized changelog for this release | |
NEW_CHANGELOG=$(echo "$COMMITS" | \ | |
grep -E "^(feat|fix|chore|docs|style|refactor|perf|test|build|ci)(\([^)]+\))?!?:" | \ | |
awk -v ver="$NEXT_VERSION" -v date="$CURRENT_DATE" ' | |
BEGIN { print "## " ver " - " date "\n" } | |
/^feat/ { feats = feats $0 "\n" } | |
/^fix/ { fixes = fixes $0 "\n" } | |
/^chore/ { chores = chores $0 "\n" } | |
/^docs/ { docs = docs $0 "\n" } | |
/^style/ { styles = styles $0 "\n" } | |
/^refactor/ { refactors = refactors $0 "\n" } | |
/^perf/ { perfs = perfs $0 "\n" } | |
/^test/ { tests = tests $0 "\n" } | |
/^build/ { builds = builds $0 "\n" } | |
/^ci/ { cis = cis $0 "\n" } | |
END { | |
if (feats) print "### Features\n" feats | |
if (fixes) print "### Fixes\n" fixes | |
if (chores) print "### Chores\n" chores | |
if (docs) print "### Documentation\n" docs | |
if (styles) print "### Styles\n" styles | |
if (refactors) print "### Refactoring\n" refactors | |
if (perfs) print "### Performance\n" perfs | |
if (tests) print "### Tests\n" tests | |
if (builds) print "### Build\n" builds | |
if (cis) print "### CI\n" cis | |
print "---\n" | |
} | |
') | |
# Confirmation before pushing changelog commit and tag | |
read -p "$(echo -e "$NEW_CHANGELOG\n\nAbout to push the changelog commit and tag $NEXT_VERSION (prev. $CURRENT_VERSION).\nContinue? [y/N]: ")" CONFIRM | |
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then | |
echo "Aborted by user." | |
exit 0 | |
fi | |
# If there's no CHANGELOG.md then create one with a placeholder | |
CHANGELOG="CHANGELOG.md" | |
PLACEHOLDER="<!-- changelog-placeholder -->" | |
if [ ! -f "$CHANGELOG" ]; then | |
cat <<EOF >"$CHANGELOG" | |
# Changelog | |
$PLACEHOLDER | |
EOF | |
fi | |
# Insert new changelog entry after the placeholder | |
awk -v entry="$NEW_CHANGELOG" -v ph="$PLACEHOLDER" ' | |
BEGIN { done=0 } | |
{ | |
if (!done && index($0, ph)) { | |
print entry | |
done=1 | |
} | |
} | |
' "$CHANGELOG" > "$CHANGELOG.tmp" && mv "$CHANGELOG.tmp" "$CHANGELOG" | |
# Create a commit with the updated changelog and push it | |
git add "$CHANGELOG" | |
git commit -m "docs(changelog): $NEXT_VERSION" | |
git push | |
# Create a new tag with the next version and changelog as description | |
git tag -a "$NEXT_VERSION" -m "$NEW_CHANGELOG" | |
# Push the new tag | |
git push origin "$NEXT_VERSION" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment