Create Release #6
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
| name: Create Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version number (e.g., 0.6.0)' | |
| required: true | |
| type: string | |
| permissions: | |
| contents: write | |
| jobs: | |
| release: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| # Use PAT with bypass permissions for pushing to protected branch | |
| token: ${{ secrets.RELEASE_TOKEN }} | |
| - name: Validate version format | |
| run: | | |
| if ! echo "${{ inputs.version }}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then | |
| echo "Error: Version must be in format X.Y.Z (e.g., 0.6.0)" | |
| exit 1 | |
| fi | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Update CHANGELOG.md | |
| id: changelog | |
| env: | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| run: | | |
| VERSION="${{ inputs.version }}" | |
| DATE=$(date +%Y-%m-%d) | |
| # Create the new Unreleased section template | |
| UNRELEASED_TEMPLATE=$(printf '%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n' \ | |
| '## [Unreleased]' \ | |
| '### Added' \ | |
| '### Changed' \ | |
| '### Fixed' \ | |
| '### Removed') | |
| # Read the current changelog | |
| CHANGELOG=$(cat CHANGELOG.md) | |
| # Check if there's an existing Unreleased section | |
| if grep -q "^## \[Unreleased\]" CHANGELOG.md; then | |
| # Replace [Unreleased] with the new version and date | |
| # First, extract everything after the Unreleased header until the next ## section | |
| # Then insert the new Unreleased section at the top | |
| # Use awk to do the replacement | |
| awk -v version="$VERSION" -v date="$DATE" -v template="$UNRELEASED_TEMPLATE" ' | |
| /^## \[Unreleased\]/ { | |
| print template | |
| print "## [" version "] - " date | |
| next | |
| } | |
| { print } | |
| ' CHANGELOG.md > CHANGELOG.md.tmp | |
| mv CHANGELOG.md.tmp CHANGELOG.md | |
| else | |
| # No Unreleased section exists - insert new version after the header | |
| # Find the first ## line and insert before it | |
| awk -v version="$VERSION" -v date="$DATE" -v template="$UNRELEASED_TEMPLATE" ' | |
| BEGIN { inserted = 0 } | |
| /^## \[/ && !inserted { | |
| print template | |
| print "## [" version "] - " date | |
| print "" | |
| inserted = 1 | |
| } | |
| { print } | |
| ' CHANGELOG.md > CHANGELOG.md.tmp | |
| mv CHANGELOG.md.tmp CHANGELOG.md | |
| fi | |
| # Update the version links at the bottom of the CHANGELOG | |
| # Update the Unreleased link to compare from the new version | |
| sed -i "s|\[Unreleased\]: https://github.com/.*/compare/.*\.\.\.HEAD|[Unreleased]: https://github.com/${GITHUB_REPOSITORY}/compare/${VERSION}...HEAD|" CHANGELOG.md | |
| # Add the new version link if it doesn't exist (insert after Unreleased link) | |
| if ! grep -q "^\[${VERSION}\]:" CHANGELOG.md; then | |
| # Find the previous version from the changelog (first version after Unreleased) | |
| PREV_VERSION=$(grep -oP '^\[[\d.]+\]:' CHANGELOG.md | head -1 | tr -d '[]:' || echo "") | |
| if [ -n "$PREV_VERSION" ]; then | |
| VERSION_LINK="[${VERSION}]: https://github.com/${GITHUB_REPOSITORY}/releases/tag/${VERSION}" | |
| sed -i "/^\[Unreleased\]:/a ${VERSION_LINK}" CHANGELOG.md | |
| fi | |
| fi | |
| # Extract the changelog content for this version (for the release notes) | |
| # Get everything between the version header and the next version header | |
| RELEASE_NOTES=$(awk -v version="$VERSION" ' | |
| BEGIN { capture = 0; found = 0 } | |
| /^## \[/ { | |
| if (capture) exit | |
| if ($0 ~ "\\[" version "\\]") { | |
| capture = 1 | |
| found = 1 | |
| next | |
| } | |
| } | |
| capture { print } | |
| ' CHANGELOG.md) | |
| # Save release notes to a file for the release step | |
| echo "$RELEASE_NOTES" > release_notes.md | |
| # Output for debugging | |
| echo "Release notes extracted:" | |
| cat release_notes.md | |
| - name: Update pyproject.toml version | |
| run: | | |
| VERSION="${{ inputs.version }}" | |
| sed -i "s/^version = \".*\"/version = \"$VERSION\"/" pyproject.toml | |
| # Verify the change | |
| grep "^version = " pyproject.toml | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| with: | |
| version: "latest" | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - name: Update lock file | |
| run: uv sync | |
| - name: Commit changes | |
| run: | | |
| VERSION="${{ inputs.version }}" | |
| git add CHANGELOG.md pyproject.toml uv.lock | |
| git commit -m "Release v${VERSION}" | |
| git push origin main | |
| - name: Create and push tag | |
| run: | | |
| VERSION="${{ inputs.version }}" | |
| git tag -a "$VERSION" -m "Release $VERSION" | |
| git push origin "$VERSION" | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ inputs.version }} | |
| name: ${{ inputs.version }} | |
| body_path: release_notes.md | |
| draft: false | |
| prerelease: false |