Skip to content

anomius/uv-semantic-release

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

UV Semantic Release Action

GitHub Marketplace GitHub release License: MIT

πŸš€ Automatic version bumping, changelog generation, and releases for UV Python projects using conventional commits.

graph LR
    A[1. Push<br/>feat: new feature<br/>fix: bug fix] --> B[2. Analyze<br/>Parse commits<br/>Determine bump]
    B --> C[3. Version<br/>Update pyproject.toml<br/>0.1.0 β†’ 0.2.0]
    C --> D[4. Changelog<br/>Generate notes<br/>CHANGELOG.md]
    D --> E[5. Tag<br/>Create git tag<br/>v0.2.0]
    E --> F[6. Release<br/>GitHub Release<br/>+ Artifacts]
    F --> G[7. Build<br/>uv build<br/>.whl + .tar.gz]
    G -.-> H[8. Publish<br/>PyPI optional<br/>uv publish]

    style A fill:#e94560,stroke:#e94560,color:#fff
    style B fill:#0ea5e9,stroke:#0ea5e9,color:#fff
    style C fill:#22c55e,stroke:#22c55e,color:#fff
    style D fill:#f59e0b,stroke:#f59e0b,color:#fff
    style E fill:#a855f7,stroke:#a855f7,color:#fff
    style F fill:#ec4899,stroke:#ec4899,color:#fff
    style G fill:#14b8a6,stroke:#14b8a6,color:#fff
    style H fill:#6366f1,stroke:#6366f1,stroke-dasharray: 5 5,color:#fff
Loading

✨ Features

  • πŸ”„ Automatic Semantic Versioning - Version bumps based on conventional commits
  • πŸ“ Auto-generated Changelog - Beautiful CHANGELOG.md from commit history
  • 🏷️ Git Tags - Automatic tag creation (e.g., v1.2.3)
  • πŸ“¦ GitHub Releases - Full releases with notes and artifacts
  • 🐍 UV Native - Built specifically for UV Python projects
  • πŸ“€ PyPI Publishing - Optional automatic PyPI deployment
  • ⚑ Zero Config - Sensible defaults, works out of the box
  • πŸ”§ Highly Configurable - Customize every aspect of the release process

πŸ“‹ Table of Contents

πŸš€ Quick Start

1. Add the workflow to your repository

Create .github/workflows/release.yml:

name: Release

on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: UV Semantic Release
        uses: anomius/uv-semantic-release@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}

2. Add semantic-release config to pyproject.toml

[tool.semantic_release]
version_toml = ["pyproject.toml:project.version"]
branch = "main"
commit_parser = "conventional_commits"
tag_format = "v{version}"

[tool.semantic_release.changelog]
changelog_file = "CHANGELOG.md"

3. Use Conventional Commits

git commit -m "feat: add user authentication"
git commit -m "fix: resolve login timeout issue"
git push origin main

That's it! πŸŽ‰ The action will automatically create releases when you push to main.

πŸ“– Usage

Basic Usage

- uses: anomius/uv-semantic-release@v1
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}

With PyPI Publishing

- uses: anomius/uv-semantic-release@v1
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}
    publish_to_pypi: 'true'
    pypi_token: ${{ secrets.PYPI_TOKEN }}

Full Configuration

- uses: anomius/uv-semantic-release@v1
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}
    python_version: '3.12'
    uv_version: 'latest'
    semantic_release_version: '9.14.0'
    changelog: 'true'
    push: 'true'
    vcs_release: 'true'
    build: 'true'
    upload_to_release: 'true'
    publish_to_pypi: 'false'
    working_directory: '.'
    git_committer_name: 'github-actions[bot]'
    git_committer_email: 'github-actions[bot]@users.noreply.github.com'

πŸ“₯ Inputs

Input Description Required Default
github_token GitHub token for releases and pushing Yes ${{ github.token }}
pypi_token PyPI token for publishing No ''
python_version Python version to use No '3.12'
uv_version UV version to use No 'latest'
semantic_release_version python-semantic-release version No '9.14.0'
root_options Additional semantic-release options No ''
changelog Generate changelog No 'true'
push Push changes to remote No 'true'
vcs_release Create GitHub release No 'true'
build Build the package No 'true'
publish_to_pypi Publish to PyPI No 'false'
upload_to_release Upload artifacts to release No 'true'
working_directory Working directory No '.'
git_committer_name Git committer name No 'github-actions[bot]'
git_committer_email Git committer email No '...[bot]@users.noreply.github.com'

πŸ“€ Outputs

Output Description
released Whether a new release was created ('true' or 'false')
version The new version number (e.g., '1.2.3')
previous_version The previous version number
tag The git tag for the release (e.g., 'v1.2.3')

Using Outputs

- name: UV Semantic Release
  id: release
  uses: anomius/uv-semantic-release@v1
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}

- name: Post-release actions
  if: steps.release.outputs.released == 'true'
  run: |
    echo "Released version ${{ steps.release.outputs.version }}"
    echo "Tag: ${{ steps.release.outputs.tag }}"

βš™οΈ Configuration

pyproject.toml Configuration

Add this to your pyproject.toml:

[project]
name = "your-package"
version = "0.1.0"  # This will be auto-updated

[tool.semantic_release]
# Version location(s)
version_toml = ["pyproject.toml:project.version"]

# Branch configuration
branch = "main"

# Commit parser
commit_parser = "conventional_commits"

# Tag format
tag_format = "v{version}"

# Build command
build_command = "uv build"

# Release settings
upload_to_vcs_release = true
upload_to_pypi = false

# Commit message for version bumps
commit_message = "chore(release): bump version to {version} [skip ci]"

# Allow 0.x versions
allow_zero_version = true
major_on_zero = false

[tool.semantic_release.changelog]
changelog_file = "CHANGELOG.md"
exclude_commit_patterns = [
    '''chore\(deps.*\):.*''',
    '''chore\(release\):.*''',
    '''Merge.*''',
]

[tool.semantic_release.branches.main]
match = "^(main|master)$"
prerelease = false

[tool.semantic_release.branches.develop]
match = "^(dev|develop)$"
prerelease = true
prerelease_token = "dev"

[tool.semantic_release.commit_parser_options]
allowed_tags = ["feat", "fix", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore"]
minor_tags = ["feat"]
patch_tags = ["fix", "perf"]

Multiple Version Locations

If you have version in multiple places:

[tool.semantic_release]
version_toml = ["pyproject.toml:project.version"]
version_variables = ["src/mypackage/__init__.py:__version__"]

πŸ“ Conventional Commits

This action uses Conventional Commits to determine version bumps.

Commit Format

<type>(<scope>): <description>

[optional body]

[optional footer(s)]

Version Bump Rules

Commit Type Example Version Bump
fix: fix: resolve null pointer PATCH (0.0.X)
perf: perf: optimize queries PATCH (0.0.X)
feat: feat: add dark mode MINOR (0.X.0)
feat!: feat!: redesign API MAJOR (X.0.0)
BREAKING CHANGE: See below MAJOR (X.0.0)

Breaking Changes

# Option 1: ! after type
git commit -m "feat!: remove deprecated endpoints"

# Option 2: Footer
git commit -m "refactor: update database schema

BREAKING CHANGE: requires database migration"

Non-Releasing Types

These types don't trigger a release:

  • docs: - Documentation changes
  • style: - Code style changes
  • refactor: - Code refactoring
  • test: - Test changes
  • build: - Build system changes
  • ci: - CI configuration
  • chore: - Maintenance tasks

πŸ“š Examples

Basic Release Workflow

name: Release

on:
  push:
    branches: [main]

permissions:
  contents: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: anomius/uv-semantic-release@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}

Release with PyPI Publishing

name: Release and Publish

on:
  push:
    branches: [main]

permissions:
  contents: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Release
        id: release
        uses: anomius/uv-semantic-release@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_to_pypi: 'true'
          pypi_token: ${{ secrets.PYPI_TOKEN }}

      - name: Announce Release
        if: steps.release.outputs.released == 'true'
        run: |
          echo "πŸŽ‰ Released v${{ steps.release.outputs.version }}!"

Monorepo Setup

name: Release Package A

on:
  push:
    branches: [main]
    paths:
      - 'packages/package-a/**'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: anomius/uv-semantic-release@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          working_directory: 'packages/package-a'

Manual Release with Dry Run

name: Manual Release

on:
  workflow_dispatch:
    inputs:
      dry_run:
        description: 'Dry run (no actual release)'
        required: false
        default: 'false'
        type: boolean

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: anomius/uv-semantic-release@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          root_options: ${{ inputs.dry_run == 'true' && '--noop' || '' }}

Pre-release from Feature Branches

name: Pre-release

on:
  push:
    branches:
      - 'develop'
      - 'beta'

jobs:
  prerelease:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: anomius/uv-semantic-release@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          root_options: '--prerelease'

πŸ”§ Troubleshooting

No release created

Problem: Commits are pushed but no release is created.

Solutions:

  1. Ensure commits follow conventional commit format
  2. Check that commits include feat:, fix:, or perf: types
  3. Verify fetch-depth: 0 in checkout step
  4. Check workflow has contents: write permission

Permission denied

Problem: Push or release creation fails with permission error.

Solutions:

  1. For protected branches, use a Personal Access Token (PAT):

    - uses: actions/checkout@v4
      with:
        token: ${{ secrets.PAT_TOKEN }}
        fetch-depth: 0
    
    - uses: anomius/uv-semantic-release@v1
      with:
        github_token: ${{ secrets.PAT_TOKEN }}
  2. Ensure the token has repo scope

Version not updating

Problem: Release created but pyproject.toml version unchanged.

Solutions:

  1. Check version_toml path is correct:
    • PEP 621: ["pyproject.toml:project.version"]
    • Poetry: ["pyproject.toml:tool.poetry.version"]
  2. Ensure pyproject.toml has a version field

Changelog not generated

Problem: CHANGELOG.md not created or updated.

Solutions:

  1. Ensure changelog: 'true' in action inputs
  2. Check [tool.semantic_release.changelog] config exists
  3. Verify file permissions in repository

PyPI publishing fails

Problem: Release succeeds but PyPI upload fails.

Solutions:

  1. Verify PYPI_TOKEN secret is set correctly
  2. Check token has upload permissions
  3. Ensure package name is available on PyPI
  4. Verify pyproject.toml has valid metadata

🀝 Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

Development Setup

# Clone the repository
git clone https://github.com/anomius/uv-semantic-release.git
cd uv-semantic-release

# Install UV
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install dependencies
uv sync --dev

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments


Made with ❀️ for the Python community

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors