Skip to content

Manual Release

Manual Release #73

name: Manual Release
on:
workflow_dispatch:
inputs:
bump_type:
description: "Select semantic version bump type"
required: true
default: patch
type: choice
options:
- major
- minor
- patch
permissions:
contents: write
actions: write
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.next_version }}
last_tag: ${{ steps.version.outputs.last_tag }}
notes_file: ${{ steps.notes.outputs.file }}
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Determine next version
id: version
run: |
set -eo pipefail
git fetch --tags --force
LAST_TAG=$(git describe --tags --abbrev=0 --match "v*" 2>/dev/null || true)
if [ -z "$LAST_TAG" ]; then
# First release: always start at 1.0.0 regardless of bump type
NEXT_VERSION="1.0.0"
echo "last_tag=" >> "$GITHUB_OUTPUT"
echo "next_version=$NEXT_VERSION" >> "$GITHUB_OUTPUT"
exit 0
else
CURRENT=${LAST_TAG#v}
fi
IFS='.' read -r MAJOR MINOR PATCH <<<"$CURRENT"
case "${{ github.event.inputs.bump_type }}" in
major)
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
;;
minor)
MINOR=$((MINOR + 1))
PATCH=0
;;
*)
PATCH=$((PATCH + 1))
;;
esac
NEXT_VERSION="$MAJOR.$MINOR.$PATCH"
echo "last_tag=$LAST_TAG" >> "$GITHUB_OUTPUT"
echo "next_version=$NEXT_VERSION" >> "$GITHUB_OUTPUT"
- name: Build release notes
id: notes
run: |
set -eo pipefail
NOTES_FILE="release-notes.md"
LAST_TAG="${{ steps.version.outputs.last_tag }}"
NEXT_VERSION="${{ steps.version.outputs.next_version }}"
if [ -z "$LAST_TAG" ]; then
RANGE="HEAD"
else
RANGE="$LAST_TAG..HEAD"
fi
# Collect commits grouped by type (hash and subject)
declare -a FEATURES FIXES REFACTORS CHORES DOCS PERFS OTHERS
PATTERN='^(feat|fix|perf|refactor|docs|chore)(\([^)]+\))?:\ (.+)$'
while IFS= read -r LINE; do
HASH="${LINE:0:7}"
SUBJECT="${LINE:8}"
# Skip merge commits
if [[ "$SUBJECT" == Merge\ * ]]; then
continue
fi
if [[ $SUBJECT =~ $PATTERN ]]; then
TYPE="${BASH_REMATCH[1]}"
MSG="${BASH_REMATCH[3]}"
case "$TYPE" in
feat) FEATURES+=("- $MSG ($HASH)");;
fix) FIXES+=("- $MSG ($HASH)");;
perf) PERFS+=("- $MSG ($HASH)");;
refactor) REFACTORS+=("- $MSG ($HASH)");;
docs) DOCS+=("- $MSG ($HASH)");;
chore) CHORES+=("- $MSG ($HASH)");;
esac
else
OTHERS+=("- $SUBJECT ($HASH)")
fi
done < <(git log $RANGE --pretty=format:"%h %s")
# Write release notes
echo "## What's Changed" > "$NOTES_FILE"
echo "" >> "$NOTES_FILE"
if [ ${#FEATURES[@]} -gt 0 ]; then
echo "### Features" >> "$NOTES_FILE"
printf '%s\n' "${FEATURES[@]}" >> "$NOTES_FILE"
echo "" >> "$NOTES_FILE"
fi
if [ ${#FIXES[@]} -gt 0 ]; then
echo "### Fixes" >> "$NOTES_FILE"
printf '%s\n' "${FIXES[@]}" >> "$NOTES_FILE"
echo "" >> "$NOTES_FILE"
fi
if [ ${#PERFS[@]} -gt 0 ]; then
echo "### Performance" >> "$NOTES_FILE"
printf '%s\n' "${PERFS[@]}" >> "$NOTES_FILE"
echo "" >> "$NOTES_FILE"
fi
if [ ${#REFACTORS[@]} -gt 0 ]; then
echo "### Refactors" >> "$NOTES_FILE"
printf '%s\n' "${REFACTORS[@]}" >> "$NOTES_FILE"
echo "" >> "$NOTES_FILE"
fi
if [ ${#DOCS[@]} -gt 0 ]; then
echo "### Documentation" >> "$NOTES_FILE"
printf '%s\n' "${DOCS[@]}" >> "$NOTES_FILE"
echo "" >> "$NOTES_FILE"
fi
if [ ${#CHORES[@]} -gt 0 ]; then
echo "### Chores" >> "$NOTES_FILE"
printf '%s\n' "${CHORES[@]}" >> "$NOTES_FILE"
echo "" >> "$NOTES_FILE"
fi
if [ ${#OTHERS[@]} -gt 0 ]; then
echo "### Other" >> "$NOTES_FILE"
printf '%s\n' "${OTHERS[@]}" >> "$NOTES_FILE"
echo "" >> "$NOTES_FILE"
fi
# Add full changelog link
if [ -n "$LAST_TAG" ]; then
echo "**Full Changelog**: https://github.com/$GITHUB_REPOSITORY/compare/$LAST_TAG...v$NEXT_VERSION" >> "$NOTES_FILE"
fi
echo "file=$NOTES_FILE" >> "$GITHUB_OUTPUT"
- name: Prepare common release files and models
run: |
./scripts/prepare-common.sh "${{ steps.version.outputs.next_version }}"
- name: Upload common files artifact
id: upload
uses: actions/upload-artifact@v4
with:
name: release-common-${{ steps.version.outputs.next_version }}
path: release_common.tar
retention-days: 1
- name: Upload release notes
uses: actions/upload-artifact@v4
with:
name: release-notes-${{ steps.version.outputs.next_version }}
path: ${{ steps.notes.outputs.file }}
retention-days: 1
package_manylinux_2_34:
needs: prepare
runs-on: ubuntu-latest
container: registry.access.redhat.com/ubi9/ubi:9.7
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Download common files artifact
uses: actions/download-artifact@v4
with:
name: release-common-${{ needs.prepare.outputs.version }}
- name: Extract common files (preserves file permissions)
run: |
mkdir -p release_common
tar -xvf release_common.tar -C release_common
- name: Build manylinux package
id: build_package
run: |
chmod +x scripts/package-manylinux-2_34.sh
scripts/package-manylinux-2_34.sh "${{ needs.prepare.outputs.version }}"
- name: Upload manylinux package artifact
uses: actions/upload-artifact@v4
with:
name: package-manylinux-2_34-${{ needs.prepare.outputs.version }}
path: ${{ steps.build_package.outputs.asset_path }}
retention-days: 1
release:
needs: [prepare, package_manylinux_2_34]
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Download manylinux_2_34 package
uses: actions/download-artifact@v4
with:
name: package-manylinux-2_34-${{ needs.prepare.outputs.version }}
path: packages
- name: Download release notes
uses: actions/download-artifact@v4
with:
name: release-notes-${{ needs.prepare.outputs.version }}
path: .
- name: Create GitHub Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -eo pipefail
gh release create "v${{ needs.prepare.outputs.version }}" \
--title "v${{ needs.prepare.outputs.version }}" \
--notes-file release-notes.md \
packages/*.tar.gz
publish_pypi:
needs: [prepare, release]
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Set package version
run: |
VERSION="${{ needs.prepare.outputs.version }}"
sed -i "s/^version = .*/version = \"$VERSION\"/" pyproject.toml
sed -i "s/^__version__ = .*/__version__ = \"$VERSION\"/" src/chunksilo/__init__.py
- name: Build package
run: |
pip install build
python -m build
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
update_version:
needs: [prepare, publish_pypi]
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 1
- name: Update version in source files
run: |
VERSION="${{ needs.prepare.outputs.version }}"
sed -i "s/^version = .*/version = \"$VERSION\"/" pyproject.toml
sed -i "s/^__version__ = .*/__version__ = \"$VERSION\"/" src/chunksilo/__init__.py
- name: Commit and push version update
run: |
VERSION="${{ needs.prepare.outputs.version }}"
if git diff --quiet; then
echo "No version changes detected, skipping commit"
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add pyproject.toml src/chunksilo/__init__.py
git commit -m "chore: bump version to $VERSION [skip ci]"
git push origin main