diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..a1321ca --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,132 @@ +name: publish + +on: + push: + tags: '\d+.\d+.\d+' + +env: + POETRY_VERSION: 1.6 + +jobs: + on-main-branch-check: + runs-on: ubuntu-latest + outputs: + on_main: ${{ steps.contains_tag.outputs.retval }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: rickstaa/action-contains-tag@v1 + id: contains_tag + with: + reference: "main" + tag: "${{ github.ref_name }}" + + tests: + name: tests + needs: on-main-branch-check + if: ${{ needs.on-main-branch-check.outputs.on_main == 'true' }} + uses: "./.github/workflows/tests.yml" + + build-wheels: + name: build wheels + needs: tests + uses: "./.github/workflows/wheels.yml" + + build-sdist: + name: build source distribution + needs: tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: true + + - uses: actions/setup-python@v5 + with: + python-version: 3.12 + + - name: Install poetry + run: | + python -m pip install --upgrade pip + python -m pip install poetry==${{env.POETRY_VERSION}} + + - name: Configure poetry + shell: bash + run: poetry config virtualenvs.in-project true + + - name: Install dependencies + run: poetry install --no-interaction --no-root --without=dev + + - name: Install project + run: poetry install --no-interaction --without=dev + + - name: Build package + run: poetry build --format=sdist + + - uses: actions/upload-artifact@v4 + with: + name: pybedlite-sdist + path: dist/*.tar.gz + + publish-to-pypi: + runs-on: ubuntu-latest + needs: [build-wheels, build-sdist] + environment: pypi + permissions: + id-token: write + steps: + - uses: actions/download-artifact@v4 + with: + path: packages + pattern: 'pybedlite-*' + merge-multiple: true + + - uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: packages/ + skip-existing: true + verbose: true + + make-changelog: + runs-on: ubuntu-latest + needs: publish-to-pypi + outputs: + release_body: ${{ steps.git-cliff.outputs.content }} + steps: + - name: Checkout the Repository at the Tagged Commit + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.ref_name }} + + - name: Generate a Changelog + uses: orhun/git-cliff-action@v3 + id: git-cliff + with: + config: pyproject.toml + args: --latest --verbose + env: + GITHUB_REPO: ${{ github.repository }} + + make-github-release: + runs-on: ubuntu-latest + environment: github + permissions: + contents: write + pull-requests: read + needs: make-changelog + steps: + - name: Create Draft Release + id: create_release + uses: softprops/action-gh-release@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + name: ${{ github.ref_name }} + body: | + ${{ needs.draft-changelog.outputs.release_body }} + draft: false + prerelease: false diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml deleted file mode 100644 index fe3b9cc..0000000 --- a/.github/workflows/pythonpackage.yml +++ /dev/null @@ -1,93 +0,0 @@ -name: Python package - -on: [push] -env: - POETRY_VERSION: 1.6.1 - -jobs: - testing: - runs-on: ubuntu-20.04 - environment: github-action-ci - strategy: - matrix: - PYTHON_VERSION: ["3.8", "3.9", "3.10", "3.11"] - steps: - - uses: actions/checkout@v2 - with: - submodules: 'true' - - - name: Set up Python ${{matrix.PYTHON_VERSION}} - uses: actions/setup-python@v4 - with: - python-version: ${{matrix.PYTHON_VERSION}} - - - name: Get full Python version - id: full-python-version - shell: bash - run: echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))") - - - name: Install poetry - shell: bash - run: | - pip install poetry==${{env.POETRY_VERSION}} - - - name: Configure poetry - shell: bash - run: poetry config virtualenvs.in-project true - - - name: Set up cache - uses: actions/cache@v2 - id: cache - with: - path: .venv - key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }} - - - name: Ensure cache is healthy - if: steps.cache.outputs.cache-hit == 'true' - shell: bash - run: poetry run pip --version >/dev/null 2>&1 || rm -rf .venv - - - name: Install deps - shell: bash - run: | - poetry install --only dev - poetry build - poetry install --extras docs - - - name: Run pytest - shell: bash - run: | - poetry run python -m pytest --cov=pybedlite --cov-report=xml --cov-branch - - - name: Style checking - shell: bash - run: | - poetry run black --line-length 99 --check pybedlite - - - name: Import sorting - shell: bash - run: | - poetry run isort --force-single-line-imports --profile black --check pybedlite - - - name: Run lint - shell: bash - run: | - poetry run flake8 --config=ci/flake8.cfg pybedlite - - - name: Run mypy - shell: bash - run: | - poetry run mypy -p pybedlite --config=ci/mypy.ini - - - name: Run docs - shell: bash - run: | - set -euo pipefail - pushd docs - poetry run make html - popd - - - name: Upload code coverage - uses: codecov/codecov-action@v4.5.0 - with: - token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..425e112 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,104 @@ +name: tests + +on: + push: + branches: + - "**" + tags: + - "!**" + workflow_call: + +env: + POETRY_VERSION: 1.6 + +jobs: + unit-tests: + runs-on: ubuntu-latest + environment: github-action-ci + strategy: + matrix: + PYTHON_VERSION: ["3.8", "3.9", "3.10", "3.11"] + + steps: + - uses: actions/checkout@v4 + with: + submodules: "true" + + - name: Set up Python ${{ matrix.PYTHON_VERSION }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.PYTHON_VERSION }} + + - name: Get full Python version + id: full-python-version + shell: bash + run: echo "version=$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))")" >> $GITHUB_OUTPUT + + - name: Install poetry + run: | + python -m pip install --upgrade pip + python -m pip install poetry==${{env.POETRY_VERSION}} + + - name: Configure poetry + shell: bash + run: poetry config virtualenvs.in-project true + + - name: Set up cache + uses: actions/cache@v4 + id: cache + with: + path: .venv + key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }} + + - name: Ensure cache is healthy + if: steps.cache.outputs.cache-hit == 'true' + shell: bash + run: poetry run pip --version >/dev/null 2>&1 || rm -rf .venv + + - name: Test the lock file is up to date + run: python -m poetry check --lock + + - name: Install dependencies and package + shell: bash + run: | + poetry install --only dev + poetry build + poetry install --extras docs + + - name: Run pytest + shell: bash + run: | + poetry run python -m pytest --cov=pybedlite --cov-report=xml --cov-branch + + - name: Style checking + shell: bash + run: | + poetry run black --line-length 99 --check pybedlite + + - name: Import sorting + shell: bash + run: | + poetry run isort --force-single-line-imports --profile black --check pybedlite + + - name: Run lint + shell: bash + run: | + poetry run flake8 --config=ci/flake8.cfg pybedlite + + - name: Run mypy + shell: bash + run: | + poetry run mypy -p pybedlite --config=ci/mypy.ini + + - name: Run docs + shell: bash + run: | + set -euo pipefail + pushd docs + poetry run make html + popd + + - name: Upload code coverage + uses: codecov/codecov-action@v4.5.0 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index f555d6c..3cfa839 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -1,12 +1,12 @@ -name: Build wheels for multiple platforms +name: build wheels on: - push: - branches: [main] + pull_request: + workflow_call: workflow_dispatch: jobs: - build_wheels: + build-wheels: name: Build wheels for ${{ matrix.python }}-${{ matrix.platform.target }}_${{ matrix.platform.arch }} on ${{ matrix.platform.os }} runs-on: ${{ matrix.platform.os }} strategy: @@ -22,12 +22,12 @@ jobs: # These don't work right now - they just hang while pulling the build image from quay. # If this doesn't resolve itself, we could try to configure different images: # https://cibuildwheel.readthedocs.io/en/stable/options/. - #- os: ubuntu-latest - # target: manylinux - # arch: aarch64 - #- os: ubuntu-latest - # target: musllinux - # arch: aarch64 + # - os: ubuntu-latest + # target: manylinux + # arch: aarch64 + # - os: ubuntu-latest + # target: musllinux + # arch: aarch64 - os: macos-latest target: macosx arch: x86_64 @@ -40,13 +40,12 @@ jobs: with: submodules: "true" - # Used to host cibuildwheel - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: - python-version: 3.8 + python-version: 3.12 - name: Install cibuildwheel - run: python -m pip install cibuildwheel==2.15.0 + run: python -m pip install cibuildwheel==2.20.0 - name: Build wheels run: python -m cibuildwheel --output-dir wheelhouse @@ -55,8 +54,8 @@ jobs: CIBW_BUILD: ${{ matrix.python }}-${{ matrix.platform.target }}_${{ matrix.platform.arch }} CIBW_BUILD_VERBOSITY: 1 - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: - name: wheels + name: pybedlite-wheels-${{ matrix.python }}-${{ matrix.platform.target }}_${{ matrix.platform.arch }} path: ./wheelhouse/*.whl if-no-files-found: error diff --git a/pyproject.toml b/pyproject.toml index 06402b2..cb5ec11 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,3 +50,33 @@ generate-setup-file = true [build-system] requires = ["poetry-core", "setuptools", "cython"] build-backend = "poetry.core.masonry.api" + +[tool.git-cliff.changelog] +header = "" +trim = true +body = """ +{% for group, commits in commits | group_by(attribute="group") %} + ## {{ group | upper_first }} + {% for commit in commits %} + - {{ commit.message | upper_first }} ({{ commit.id | truncate(length=8, end="") }})\ + {% endfor %} +{% endfor %}\n +""" + +[tool.git-cliff.git] +conventional_commits = true +commit_parsers = [ + { message = "^.+!:*", group = "Breaking"}, + { message = "^feat*", group = "Features"}, + { message = "^fix*", group = "Bug Fixes"}, + { message = "^[cC]i*", group = "CI/CD"}, + { message = "^docs*", group = "Documentation"}, + { message = "^perf*", group = "Performance"}, + { message = "^refactor*", group = "Refactor"}, + { message = "^style*", group = "Styling"}, + { message = "^test*", group = "Testing"}, + { message = "^chore\\(release\\):*", skip = true}, + { message = "^chore*", group = "Miscellaneous Tasks"}, + { body = ".*security", group = "Security"} +] +filter_commits = false