From e6f1895de4ad498780ad87ea7fc712b78e4e62fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Tue, 17 Sep 2024 16:56:51 -0700 Subject: [PATCH] Improve the CI and allow to set major.minor upfront (#134) --- .github/workflows/{check.yml => check.yaml} | 29 ++++++++----- .github/workflows/release.yaml | 48 +++++++++++++++++++++ .github/workflows/release.yml | 32 -------------- README.md | 42 ++++++++++++------ pyproject.toml | 3 +- src/tox_gh/plugin.py | 3 ++ tests/test_tox_gh.py | 14 +++++- tox.ini | 48 ++++++++++----------- 8 files changed, 139 insertions(+), 80 deletions(-) rename .github/workflows/{check.yml => check.yaml} (51%) create mode 100644 .github/workflows/release.yaml delete mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/check.yml b/.github/workflows/check.yaml similarity index 51% rename from .github/workflows/check.yml rename to .github/workflows/check.yaml index bf7b8f8..a887b12 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yaml @@ -14,12 +14,12 @@ concurrency: jobs: test: - name: test with ${{ matrix.py }} on ${{ matrix.os }} + name: test with ${{ matrix.env }} on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - py: + env: - "3.13" - "3.12" - "3.11" @@ -34,19 +34,28 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Setup python for test ${{ matrix.py }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.py }} - allow-prereleases: true - name: Install the latest version of uv uses: astral-sh/setup-uv@v3 with: enable-cache: true + cache-dependency-glob: "pyproject.toml" github-token: ${{ secrets.GITHUB_TOKEN }} - - name: install self with tox-uv - run: uv pip install tox-uv tox-gh@. --system --python ${{ matrix.py }} + - name: Add .local/bin to Windows PATH + if: runner.os == 'Windows' + shell: bash + run: echo "$USERPROFILE/.local/bin" >> $GITHUB_PATH + - name: Install tox + run: uv tool install --python-preference only-managed --python 3.13 tox --with tox-uv --with tox-gh@. + - name: Install Python + if: matrix.env != '3.13' + run: uv python install --python-preference only-managed ${{ matrix.env }} - name: Setup test suite - run: tox run -vv --skip-missing-interpreters false --notest + run: tox run -vv --notest --skip-missing-interpreters false + env: + TOX_GH_MAJOR_MINOR: ${{ matrix.env }} - name: Run test suite run: tox run --skip-pkg-install + env: + PYTEST_ADDOPTS: "-vv --durations=20" + DIFF_AGAINST: HEAD + TOX_GH_MAJOR_MINOR: ${{ matrix.env }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..0b4c92b --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,48 @@ +name: Release to PyPI +on: + push: + tags: ["*"] + +env: + dists-artifact-name: python-package-distributions + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install the latest version of uv + uses: astral-sh/setup-uv@v3 + with: + enable-cache: true + cache-dependency-glob: "pyproject.toml" + github-token: ${{ secrets.GITHUB_TOKEN }} + - name: Build package + run: uv build --python 3.13 --python-preference only-managed --sdist --wheel . --out-dir dist + - name: Store the distribution packages + uses: actions/upload-artifact@v4 + with: + name: ${{ env.dists-artifact-name }} + path: dist/* + + release: + needs: + - build + runs-on: ubuntu-latest + environment: + name: release + url: https://pypi.org/project/tox-gh/${{ github.ref_name }} + permissions: + id-token: write + steps: + - name: Download all the dists + uses: actions/download-artifact@v4 + with: + name: ${{ env.dists-artifact-name }} + path: dist/ + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@v1.10.1 + with: + attestations: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 1dc5e3b..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Release to PyPI -on: - push: - tags: ["*"] - -jobs: - release: - runs-on: ubuntu-latest - environment: - name: release - url: https://pypi.org/p/tox-gh - permissions: - id-token: write - steps: - - name: Setup python to build package - uses: actions/setup-python@v5 - with: - python-version: "3.12" - - name: Install the latest version of uv - uses: astral-sh/setup-uv@v3 - with: - enable-cache: true - github-token: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Build package - run: uv build --sdist --wheel . --out-dir dist - - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@v1.10.1 - with: - attestations: true diff --git a/README.md b/README.md index 67f88f1..1c62d81 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![PyPI version](https://badge.fury.io/py/tox-gh.svg)](https://badge.fury.io/py/tox-gh) [![PyPI Supported Python Versions](https://img.shields.io/pypi/pyversions/tox-gh.svg)](https://pypi.python.org/pypi/tox-gh/) -[![check](https://github.com/tox-dev/tox-gh/actions/workflows/check.yml/badge.svg)](https://github.com/tox-dev/tox-gh/actions/workflows/check.yml) +[![check](https://github.com/tox-dev/tox-gh/actions/workflows/check.yaml/badge.svg)](https://github.com/tox-dev/tox-gh/actions/workflows/check.yaml) [![Downloads](https://static.pepy.tech/badge/tox-gh/month)](https://pepy.tech/project/tox-gh) **tox-gh** is a tox plugin which helps running tox on GitHub Actions with multiple different Python versions on multiple @@ -12,7 +12,8 @@ workers in parallel. When running tox on GitHub Actions, tox-gh -- detects which environment to run based on configurations and +- detects which environment to run based on configurations (or bypass detection and set it explicitly via the + `TOX_GH_MAJOR_MINOR` environment variable) and - provides utilities such as [grouping log lines](https://github.com/actions/toolkit/blob/main/docs/commands.md#group-and-ungroup-log-lines). @@ -47,12 +48,15 @@ This will run different set of tox environments on different python versions set #### Workflow Configuration -`.github/workflows/check.yml`: +`.github/workflows/check.yaml`: ```yaml name: check on: + workflow_dispatch: push: + branches: ["main"] + tags-ignore: ["**"] pull_request: schedule: - cron: "0 8 * * *" @@ -63,12 +67,13 @@ concurrency: jobs: test: - name: test with ${{ matrix.py }} on ${{ matrix.os }} + name: test with ${{ matrix.env }} on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - py: + env: + - "3.13" - "3.12" - "3.11" - "3.10" @@ -79,19 +84,32 @@ jobs: - macos-latest - windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Setup python for test ${{ matrix.py }} - uses: actions/setup-python@v4 + - name: Install the latest version of uv + uses: astral-sh/setup-uv@v3 with: - python-version: ${{ matrix.py }} + enable-cache: true + cache-dependency-glob: "pyproject.toml" + github-token: ${{ secrets.GITHUB_TOKEN }} + - name: Add .local/bin to Windows PATH + if: runner.os == 'Windows' + shell: bash + run: echo "$USERPROFILE/.local/bin" >> $GITHUB_PATH - name: Install tox - run: python -m pip install tox-gh>=1.2 + run: uv tool install --python-preference only-managed --python 3.13 tox --with tox-uv --with tox-gh + - name: Install Python + if: matrix.env != '3.13' + run: uv python install --python-preference only-managed ${{ matrix.env }} - name: Setup test suite - run: tox -vv --notest + run: tox run -vv --notest --skip-missing-interpreters false + env: + TOX_GH_MAJOR_MINOR: ${{ matrix.env }} - name: Run test suite - run: tox --skip-pkg-install + run: tox run --skip-pkg-install + env: + TOX_GH_MAJOR_MINOR: ${{ matrix.env }} ``` ## FAQ diff --git a/pyproject.toml b/pyproject.toml index 5db65d9..3268940 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,9 +43,10 @@ dynamic = [ dependencies = [ "tox>=4.18.1", ] -optional-dependencies.test = [ +optional-dependencies.testing = [ "covdefaults>=2.3", "devpi-process>=1", + "diff-cover>=9.2", "pytest>=8.3.2", "pytest-cov>=5", "pytest-mock>=3.14", diff --git a/src/tox_gh/plugin.py b/src/tox_gh/plugin.py index 836bb79..3920f4b 100644 --- a/src/tox_gh/plugin.py +++ b/src/tox_gh/plugin.py @@ -33,6 +33,9 @@ def is_running_on_actions() -> bool: def get_python_version_keys() -> list[str]: """:return: python spec for the python interpreter""" + if os.environ.get("TOX_GH_MAJOR_MINOR"): + major_minor_version = os.environ["TOX_GH_MAJOR_MINOR"] + return [major_minor_version, major_minor_version.split(".")[0]] python_exe = shutil.which("python") or sys.executable info = PythonInfo.from_exe(exe=python_exe) major_version = str(info.version_info[0]) diff --git a/tests/test_tox_gh.py b/tests/test_tox_gh.py index 4459f08..fe5de40 100644 --- a/tests/test_tox_gh.py +++ b/tests/test_tox_gh.py @@ -4,6 +4,8 @@ from typing import TYPE_CHECKING from unittest.mock import ANY +import pytest + from tox_gh import plugin if TYPE_CHECKING: @@ -12,6 +14,11 @@ from tox.pytest import MonkeyPatch, ToxProjectCreator +@pytest.fixture(autouse=True) +def _clear_env_var(monkeypatch: MonkeyPatch) -> None: + monkeypatch.delenv("TOX_GH_MAJOR_MINOR", raising=False) + + def test_gh_not_in_actions(monkeypatch: MonkeyPatch, tox_project: ToxProjectCreator) -> None: monkeypatch.delenv("GITHUB_ACTIONS", raising=False) project = tox_project({"tox.ini": "[testenv]\npackage=skip"}) @@ -46,7 +53,12 @@ def test_gh_toxenv_set(monkeypatch: MonkeyPatch, tox_project: ToxProjectCreator) assert "tox-gh won't override envlist because envlist is explicitly given via TOXENV" in result.out -def test_gh_ok(monkeypatch: MonkeyPatch, tox_project: ToxProjectCreator, tmp_path: Path) -> None: +@pytest.mark.parametrize("via_env", [True, False]) +def test_gh_ok(monkeypatch: MonkeyPatch, tox_project: ToxProjectCreator, tmp_path: Path, via_env: bool) -> None: + if via_env: + monkeypatch.setenv("TOX_GH_MAJOR_MINOR", f"{sys.version_info.major}.{sys.version_info.minor}") + else: + monkeypatch.setenv("PATH", "") step_output_file = tmp_path / "gh_out" step_output_file.touch() empty_requirements = tmp_path / "empty.txt" diff --git a/tox.ini b/tox.ini index 8245f5b..9027956 100644 --- a/tox.ini +++ b/tox.ini @@ -11,33 +11,35 @@ env_list = 3.9 3.8 type - readme + pkg_meta skip_missing_interpreters = true [testenv] -description = run the unit tests with pytest under {basepython} +description = run the unit tests with pytest under {base_python} package = wheel wheel_build_env = .pkg extras = - test + testing +pass_env = + DIFF_AGAINST + PYTEST_* + TOX_GH_MAJOR_MINOR set_env = - COVERAGE_FILE = {toxworkdir}{/}.coverage.{envname} + COVERAGE_FILE = {work_dir}/.coverage.{env_name} commands = - pytest {tty:--color=yes} {posargs: \ - --cov {envsitepackagesdir}{/}tox_gh --cov {toxinidir}{/}tests --cov-context=test \ - --no-cov-on-fail --cov-config {toxinidir}{/}pyproject.toml \ - --cov-report term-missing:skip-covered --junitxml {toxworkdir}{/}junit.{envname}.xml \ - --cov-report html:{envtmpdir}{/}htmlcov \ + python -m pytest {tty:--color=yes} {posargs: \ + --cov {env_site_packages_dir}{/}tox_gh --cov {tox_root}{/}tests \ + --cov-config=pyproject.toml --no-cov-on-fail --cov-report term-missing:skip-covered --cov-context=test \ + --cov-report html:{env_tmp_dir}{/}htmlcov --cov-report xml:{work_dir}{/}coverage.{env_name}.xml \ + --junitxml {work_dir}{/}junit.{env_name}.xml \ tests} + diff-cover --compare-branch {env:DIFF_AGAINST:origin/main} {work_dir}{/}coverage.{env_name}.xml --fail-under 100 [testenv:fix] -description = run static analysis and style check using flake8 +description = format the code base to adhere to our styles, and complain about what we cannot do automatically skip_install = true deps = - pre-commit>=3.8 -pass_env = - HOMEPATH - PROGRAMDATA + pre-commit-uv>=4.1.1 commands = pre-commit run --all-files --show-diff-on-failure @@ -46,26 +48,24 @@ description = run type check on code base deps = mypy==1.11.2 commands = - mypy src {posargs} - mypy tests {posargs} + mypy src + mypy tests -[testenv:readme] +[testenv:pkg_meta] description = check that the long description is valid skip_install = true deps = - build[uv]>=1.2.2 check-wheel-contents>=0.6 twine>=5.1.1 + uv>=0.4.10 commands = - pyproject-build --installer uv --outdir {envtmpdir} --sdist --wheel . - twine check {envtmpdir}{/}* - check-wheel-contents --no-config {envtmpdir} + uv build --sdist --wheel --out-dir {env_tmp_dir} . + twine check {env_tmp_dir}{/}* + check-wheel-contents --no-config {env_tmp_dir} [testenv:dev] description = generate a DEV environment package = editable -extras = - test commands = uv pip tree python -c 'import sys; print(sys.executable)' @@ -77,4 +77,4 @@ python = 3.10 = 3.10 3.11 = 3.11 3.12 = 3.12 - 3.13 = type, dev, readme + 3.13 = 3.13, type, dev, pkg_meta