Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Release

on:
workflow_dispatch:
inputs:
bump_type:
description: 'Version part to bump'
required: true
default: 'patch'
type: choice
options:
- patch
- minor
- major

jobs:
release:
runs-on: ubuntu-latest
environment: release
permissions:
contents: write
id-token: write

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Configure git identity
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'

- name: Install build and release tooling
run: pip install -e ".[test]" bumpversion build

- name: Run tests
run: pytest

- name: Bump version
run: bumpversion "${{ github.event.inputs.bump_type }}"

- name: Push version bump commit and tag
run: git push --follow-tags

- name: Build distributions
run: python -m build

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
tag=$(git describe --tags --abbrev=0)
gh release create "$tag" dist/* --title "$tag" --generate-notes
133 changes: 1 addition & 132 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
# See setup.py for humans: https://github.com/navdeep-G/setup.py

import io
import os
import sys
import shutil
from setuptools import setup, find_packages, Command

# Python 2/3 compat.
try:
from configparser import RawConfigParser
except ImportError:
from ConfigParser import RawConfigParser
from setuptools import setup, find_packages

import versioneer

Expand All @@ -24,9 +15,6 @@
VERSION = versioneer.get_version()


here = os.path.abspath(os.path.dirname(__file__))


def read_requirements(extension=None):
ext = '' if extension is None else '-{}'.format(extension)
filename = 'requirements{}.txt'.format(ext)
Expand All @@ -35,126 +23,7 @@ def read_requirements(extension=None):
return requirements


def read_current_version():
"""Read the current_version string in .bumpversion.cfg"""
config = RawConfigParser()
config.add_section('bumpversion')
config.read_file(io.open('.bumpversion.cfg', 'rt', encoding='utf-8'))
items = dict(config.items('bumpversion'))
current_version = items.get('current_version')
return current_version


class UploadCommand(Command):
"""Support setup.py upload."""

description = 'Build and publish the package.'
user_options = [
('release', 'r', 'Upload to PyPI release instance. (Default: test instance)'),
('skip-tests', None, 'Upload without running test first. (Default: run tests)')
]

def initialize_options(self):
self.release = False
self.skip_tests = False
self.upload_cmd = 'twine upload --repository-url https://test.pypi.org/legacy/ dist/*'
self.install_cmd = 'pip install --index-url https://test.pypi.org/simple/ {0}'.format(NAME)

def finalize_options(self):
if self.release:
self.upload_cmd = 'twine upload dist/*'
self.install_cmd = 'pip install {0}'.format(NAME)

@staticmethod
def status(s):
"""Prints things in bold."""
print('\033[1m{0}\033[0m'.format(s))

def abort(self):
self.status('Upload aborted.')
sys.exit(1)

def validate_deps(self):
"""Validates required packages are installed."""
_error = False

try:
import twine
except ImportError:
self.status('Please `pip install twine` to use upload command.')
_error = True

try:
import bumpversion
except ImportError:
self.status('Please `pip install bumpversion` to use upload command.')
_error = True

if _error:
self.abort()

def validate_dirty(self):
"""Aborts upload if there are uncommitted changes."""
if 'dirty' in VERSION:
self.status('Uncommitted changes detected in branch.')
self.abort()


def run(self):
self.validate_deps()
self.validate_dirty()

if not self.skip_tests:
self.status('Testing build...')
res = os.system('{0} -m pytest'.format(sys.executable))

if res != 0:
self.abort()

current_version = read_current_version()
if VERSION != current_version:
self.status('Existing version: {0}'.format(current_version))
self.status('New patch detected: {0}'.format(VERSION))

self.status('Bumping version...')
res = os.system('bumpversion patch')

if res != 0:
self.abort()

new_version = read_current_version()
self.status('New version: {0}'.format(new_version))
os.system('git push --tags')

self.status('Cleaning build...')
os.system('{0} setup.py clean --all'.format(sys.executable))

try:
self.status('Removing previous builds...')
shutil.rmtree(os.path.join(here, 'dist'))
except OSError:
pass

self.status('Building Source and Wheel (universal) distribution...')
res = os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable))

if res != 0:
self.abort()

self.status('Uploading the package to PyPI via Twine...')
res = os.system(self.upload_cmd)

if res != 0:
self.abort()

self.status('Upload success!')
self.status('Installation command: {0}'.format(self.install_cmd))

sys.exit(0)


cmdclass = versioneer.get_cmdclass()
cmdclass.update({'upload': UploadCommand})


setup(
Expand Down
Loading