diff --git a/.github/workflows/build-manylinux-wheels.sh b/.github/workflows/build-manylinux-wheels.sh new file mode 100755 index 000000000..53ed6d330 --- /dev/null +++ b/.github/workflows/build-manylinux-wheels.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -e -x + +PY_MAJOR=${PYTHON_VERSION%%.*} +PY_MINOR=${PYTHON_VERSION#*.} + +ML_PYTHON_VERSION="cp${PY_MAJOR}${PY_MINOR}-cp${PY_MAJOR}${PY_MINOR}" +if [ "${PY_MAJOR}" -lt "4" -a "${PY_MINOR}" -lt "8" ]; then + ML_PYTHON_VERSION+="m" +fi + +# Compile wheels +PYTHON="/opt/python/${ML_PYTHON_VERSION}/bin/python" +PIP="/opt/python/${ML_PYTHON_VERSION}/bin/pip" +"${PIP}" install --upgrade setuptools pip wheel +cd "${GITHUB_WORKSPACE}" +make clean +"${PYTHON}" setup.py bdist_wheel + +# Bundle external shared libraries into the wheels. +for whl in "${GITHUB_WORKSPACE}"/dist/*.whl; do + auditwheel repair $whl -w "${GITHUB_WORKSPACE}"/dist/ + rm "${GITHUB_WORKSPACE}"/dist/*-linux_*.whl +done diff --git a/.github/workflows/release-trigger.yml b/.github/workflows/release-trigger.yml new file mode 100644 index 000000000..101406a74 --- /dev/null +++ b/.github/workflows/release-trigger.yml @@ -0,0 +1,25 @@ +name: Trigger Release + +on: + pull_request_review: + types: [submitted] + +jobs: + check-review: + runs-on: ubuntu-latest + steps: + - name: Validate release PR + uses: edgedb/action-release/validate-pr@master + id: release + continue-on-error: true + with: + github_token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }} + version_file: immutables/_version.py + version_line_pattern: | + __version__\s*=\s*(?:['"])([[:PEP440:]])(?:['"]) + - name: Trigger release + uses: edgedb/action-release/trigger@master + if: steps.release.outputs.version != 0 + with: + github_token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }} + release_validation_check: "validate-release-request" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..c992bda9d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,179 @@ +name: Release + +on: + pull_request: + branches: + - "master" + - "ci" + - "[0-9]+.[0-9x]+*" + paths: + - "immutables/_version.py" + +jobs: + validate-release-request: + runs-on: ubuntu-latest + steps: + - name: Validate release PR + uses: edgedb/action-release/validate-pr@master + id: checkver + with: + github_token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }} + version_file: immutables/_version.py + version_line_pattern: | + __version__\s*=\s*(?:['"])([[:PEP440:]])(?:['"]) + + - name: Stop if not approved + if: steps.checkver.outputs.approved != 'true' + run: | + echo ::error::PR is not approved yet. + exit 1 + + - name: Store release version for later use + env: + VERSION: ${{ steps.checkver.outputs.version }} + run: | + mkdir -p dist/ + echo "${VERSION}" > dist/VERSION + + - uses: actions/upload-artifact@v1 + with: + name: dist + path: dist/ + + build-sdist: + needs: validate-release-request + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + with: + fetch-depth: 50 + submodules: true + + - name: Set up Python 3.7 + uses: actions/setup-python@v1 + with: + python-version: 3.7 + + - name: Build source distribution + run: | + pip install -U setuptools wheel pip + python setup.py sdist + + - uses: actions/upload-artifact@v1 + with: + name: dist + path: dist/ + + build-wheels: + needs: validate-release-request + runs-on: ${{ matrix.os }} + strategy: + matrix: + python-version: [3.5, 3.6, 3.7, 3.8] + os: [ubuntu-16.04, macos-latest, windows-latest] + exclude: + # Python 3.5 is unable to properly + # find the recent VS tooling + # https://bugs.python.org/issue30389 + - os: windows-latest + python-version: 3.5 + + steps: + - uses: actions/checkout@v1 + with: + fetch-depth: 50 + submodules: true + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + + - name: Install Python Deps + run: | + python -m pip install --upgrade setuptools pip wheel + + - name: Test + run: | + make debug && make test + + - name: Build Wheels (linux) + if: startsWith(matrix.os, 'ubuntu') + uses: docker://quay.io/pypa/manylinux1_x86_64 + env: + PYTHON_VERSION: ${{ matrix.python-version }} + with: + entrypoint: /github/workspace/.github/workflows/build-manylinux-wheels.sh + + - name: Build Wheels (non-linux) + if: "!startsWith(matrix.os, 'ubuntu')" + run: | + make clean + python setup.py bdist_wheel + + - name: Test Wheels + shell: bash + if: | + !contains(github.event.pull_request.labels.*.name, 'skip wheel tests') + run: | + pip install --pre immutables -f "file:///${GITHUB_WORKSPACE}/dist" + make -C "${GITHUB_WORKSPACE}" testinstalled + + - uses: actions/upload-artifact@v1 + with: + name: dist + path: dist/ + + publish: + needs: [build-sdist, build-wheels] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + with: + fetch-depth: 5 + submodules: false + + - uses: actions/download-artifact@v1 + with: + name: dist + path: dist/ + + - name: Extract Release Version + id: relver + run: | + set -e + echo ::set-output name=version::$(cat dist/VERSION) + rm dist/VERSION + + - name: Merge and tag the PR + uses: edgedb/action-release/merge@master + with: + github_token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }} + ssh_key: ${{ secrets.RELEASE_BOT_SSH_KEY }} + gpg_key: ${{ secrets.RELEASE_BOT_GPG_KEY }} + gpg_key_id: "5C468778062D87BF!" + tag_name: v${{ steps.relver.outputs.version }} + + - name: Publish Github Release + uses: elprans/gh-action-create-release@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ steps.relver.outputs.version }} + release_name: v${{ steps.relver.outputs.version }} + target: ${{ github.event.pull_request.base.ref }} + body: ${{ github.event.pull_request.body }} + draft: false + + - run: | + ls -al dist/ + + - name: Upload to PyPI + uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.PYPI_TOKEN }} + # password: ${{ secrets.TEST_PYPI_TOKEN }} + # repository_url: https://test.pypi.org/legacy/ diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..27a9ae7da --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,53 @@ +name: Tests + +on: + push: + branches: + - master + - ci + pull_request: + branches: + - master + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + max-parallel: 4 + matrix: + python-version: [3.6, 3.7, 3.8] + os: [ubuntu-latest, macos-latest] + + steps: + - uses: actions/checkout@v1 + with: + fetch-depth: 50 + submodules: true + + - name: Check if release PR. + uses: edgedb/action-release/validate-pr@master + continue-on-error: true + id: release + with: + github_token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }} + version_file: immutables/_version.py + version_line_pattern: | + __version__\s*=\s*(?:['"])([[:PEP440:]])(?:['"]) + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + if: steps.release.outputs.version == 0 + with: + python-version: ${{ matrix.python-version }} + + - name: Install Python Deps + if: steps.release.outputs.version == 0 + run: | + pip install --upgrade setuptools pip wheel + pip download --dest=/tmp/deps .[test] + pip install -U --no-index --find-links=/tmp/deps /tmp/deps/* + + - name: Test + if: steps.release.outputs.version == 0 + run: | + make debug && make test diff --git a/.gitignore b/.gitignore index 4b713b291..4975f937b 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,4 @@ __pycache__/ /.cache /.pytest_cache /.coverage - +/.mypy_cache diff --git a/Makefile b/Makefile index a625f5cdc..d22a85951 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,20 @@ -.PHONY: rtest build test clean +.PHONY: rtest build test clean all +PYTHON ?= python +ROOT = $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + + +all: build + build: - python setup.py build_ext --inplace + $(PYTHON) setup.py build_ext --inplace + +debug: + DEBUG_IMMUTABLES=1 $(PYTHON) setup.py build_ext --inplace test: - python setup.py test -v + $(PYTHON) setup.py test -v rtest: ~/dev/venvs/36-debug/bin/python setup.py build_ext --inplace @@ -14,8 +23,11 @@ rtest: ~/dev/venvs/36-debug/bin/python -m test.regrtest -R3:3 --testdir tests/ clean: - find . -name '*.pyc' | xargs rm - find . -name '*.so' | xargs rm + find . -name '*.pyc' | xargs rm -f + find . -name '*.so' | xargs rm -f rm -rf ./build rm -rf ./dist rm -rf ./*.egg-info + +testinstalled: + cd /tmp && $(PYTHON) $(ROOT)/tests/__init__.py diff --git a/immutables/__init__.py b/immutables/__init__.py index 655d318cd..eaf02303b 100644 --- a/immutables/__init__.py +++ b/immutables/__init__.py @@ -1,3 +1,5 @@ +# flake8: noqa + try: from ._map import Map except ImportError: @@ -6,6 +8,6 @@ import collections.abc as _abc _abc.Mapping.register(Map) +from ._version import __version__ __all__ = 'Map', -__version__ = '0.12' diff --git a/immutables/_version.py b/immutables/_version.py new file mode 100644 index 000000000..2296fca54 --- /dev/null +++ b/immutables/_version.py @@ -0,0 +1,13 @@ +# This file MUST NOT contain anything but the __version__ assignment. +# +# When making a release, change the value of __version__ +# to an appropriate value, and open a pull request against +# the correct branch (master if making a new feature release). +# The commit message MUST contain a properly formatted release +# log, and the commit must be signed. +# +# The release automation will: build and test the packages for the +# supported platforms, publish the packages on PyPI, merge the PR +# to the target branch, create a Git tag pointing to the commit. + +__version__ = '0.12' diff --git a/setup.py b/setup.py index a30fc5d89..0a02ab91e 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ with open(os.path.join( - os.path.dirname(__file__), 'immutables', '__init__.py')) as f: + os.path.dirname(__file__), 'immutables', '_version.py')) as f: for line in f: if line.startswith('__version__ ='): _, _, version = line.partition('=')