From 2c512127d498d40f2dcc6abfffdc797f2a0e7964 Mon Sep 17 00:00:00 2001 From: Charles Coggins Date: Tue, 4 Apr 2023 12:49:40 -0500 Subject: [PATCH] chore: add QA checks to `Test` workflow This change adds a new `QA` job to the existing `Test` workflow. It is done in a way that the `Test rollup` job can continue to be an enforced status check, but with the addition of this job. A new optional `tox` test environment named `qa` was added and is called by the `QA` job. The environment can also be called by users locally. It relies on simply running `pre-commit` on the existing hooks defined in the repository: * trim trailing whitespace * fix end of files * check yaml * check for added large files * `black` * `pyupgrade` * analyze lockfile with `phylum-ci` The `pre-commit` package was added as a dependency in the `qa` group and can therefore be kept under configuration control and used by `poetry`. Documentation was updated to make all the new usage patterns explicit. Additional QA checks and `pre-commit` hooks will be added separatetely. --- .github/workflows/test.yml | 56 +++++++++++++++++++------- CONTRIBUTING.md | 26 +++++++------ poetry.lock | 80 +++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + src/phylum/ci/constants.py | 2 +- tox.ini | 14 +++++++ 6 files changed, 151 insertions(+), 28 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8ef166d0..b7602c49 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,43 @@ on: branches: - main +defaults: + run: + shell: bash + jobs: + QA: + name: Quality Assurance + runs-on: ubuntu-latest + strategy: + matrix: + # It's only one Python version specified in a "matrix", but on purpose to stay DRY + python-version: ["3.11"] + steps: + - name: Checkout the repo + uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 + + - name: Install poetry + run: pipx install poetry + + - name: Configure poetry + run: poetry config virtualenvs.in-project true + + - name: Set up Python + uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0 + with: + python-version: ${{ matrix.python-version }} + cache: 'poetry' + + - name: Install the project with poetry + run: | + poetry env use python${{ matrix.python-version }} + poetry lock --check + poetry install --verbose --no-root --sync --with qa + + - name: Run tox via poetry + run: poetry run tox run -e qa + test-matrix: name: Test on Python ${{ matrix.python-version }} runs-on: ubuntu-latest @@ -18,9 +54,6 @@ jobs: fail-fast: false matrix: python-version: ["3.8", "3.9", "3.10", "3.11"] - defaults: - run: - shell: bash steps: - name: Checkout the repo uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 @@ -55,9 +88,6 @@ jobs: matrix: # It's only one Python version specified in a "matrix", but on purpose to stay DRY python-version: ["3.11"] - defaults: - run: - shell: bash env: DOCKER_BUILDKIT: 1 steps: @@ -123,18 +153,16 @@ jobs: # the repo settings without needing to update those settings everytime the test jobs are updated. test-rollup: name: Test rollup - if: always() - needs: [test-matrix, docker] runs-on: ubuntu-latest + if: always() + needs: [QA, test-matrix, docker] steps: - name: Check for test jobs failure - if: (needs.test-matrix.result != 'success') || (needs.docker.result != 'success') - shell: bash + if: (needs.QA.result != 'success') || (needs.test-matrix.result != 'success') || (needs.docker.result != 'success') run: | - echo "One or more test matrix jobs was/were not successful" + echo "At least one test job was not successful" exit 1 - name: Confirm test jobs success - if: (needs.test-matrix.result == 'success') && (needs.docker.result == 'success') - shell: bash - run: echo "All test matrix jobs were successful" + if: (needs.QA.result == 'success') && (needs.test-matrix.result == 'success') && (needs.docker.result == 'success') + run: echo "All test jobs were successful" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ed24d286..8dbcaa5c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -140,9 +140,10 @@ Here's how to set up `phylum-ci` for local development. # Install the main dependencies only: poetry install --sync - # Alternatively, specific dependency groups can be installed at the same time. - # It makes sense to add the "test" group now if new code is going to be added and tested: - poetry install --sync --with test + # Alternatively, specific dependency groups can be installed at the + # same time. It makes sense to add the "test" and "qa" groups now + # if new code is going to be added and tested: + poetry install --sync --with test,qa ``` 6. Create a branch for local development: @@ -180,12 +181,13 @@ Here's how to set up `phylum-ci` for local development. phylum analyze poetry.lock ``` -8. When you're done making changes, check that your changes pass the tests: +8. When you're done making changes, check that your changes pass QA and the tests: ```sh - # Ensure the "test" dependency group is installed, if not done previously - poetry install --sync --with test - poetry run tox + # Ensure the "test" and "qa" dependency groups are installed, if not done previously + poetry install --sync --with test,qa + poetry run tox run -e qa + poetry run tox run-parallel ``` 9. Commit your changes and push your branch to GitHub: @@ -232,16 +234,16 @@ interact with `pytest` by passing additional positional arguments: ```sh # passing additional options to pytest requires using the double dash # escape twice, once for escaping `poetry` and again for escaping `tox` -poetry run -- tox -e py310 -- --help +poetry run -- tox run -e py310 -- --help -# run a specific test module across all test environments -poetry run -- tox -- tests/unit/test_package_metadata.py +# run a specific test module across all test environments in parallel +poetry run -- tox run-parallel -- tests/unit/test_package_metadata.py # run a specific test module across a specific test environment -poetry run -- tox -e py39 -- tests/unit/test_package_metadata.py +poetry run -- tox run -e py39 -- tests/unit/test_package_metadata.py # run a specific test function within a test module, in a specific test environment -poetry run -- tox -e py310 -- tests/unit/test_package_metadata.py::test_python_version +poetry run -- tox run -e py310 -- tests/unit/test_package_metadata.py::test_python_version ``` To run a script entry point with the local checkout of the code (in develop mode), use `poetry`: diff --git a/poetry.lock b/poetry.lock index 09ed91c3..aeee4278 100644 --- a/poetry.lock +++ b/poetry.lock @@ -139,6 +139,18 @@ files = [ [package.dependencies] pycparser = "*" +[[package]] +name = "cfgv" +version = "3.3.1" +description = "Validate configuration and produce human readable error messages." +category = "dev" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, +] + [[package]] name = "chardet" version = "5.1.0" @@ -523,6 +535,21 @@ files = [ [package.dependencies] gitdb = ">=4.0.1,<5" +[[package]] +name = "identify" +version = "2.5.22" +description = "File identification library for Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "identify-2.5.22-py2.py3-none-any.whl", hash = "sha256:f0faad595a4687053669c112004178149f6c326db71ee999ae4636685753ad2f"}, + {file = "identify-2.5.22.tar.gz", hash = "sha256:f7a93d6cf98e29bd07663c60728e7a4057615068d7a639d132dc883b2d54d31e"}, +] + +[package.extras] +license = ["ukkonen"] + [[package]] name = "idna" version = "3.4" @@ -844,6 +871,21 @@ files = [ {file = "more_itertools-9.1.0-py3-none-any.whl", hash = "sha256:d2bc7f02446e86a68911e58ded76d6561eea00cddfb2a91e7019bbb586c799f3"}, ] +[[package]] +name = "nodeenv" +version = "1.7.0" +description = "Node.js virtual environment builder" +category = "dev" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, + {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, +] + +[package.dependencies] +setuptools = "*" + [[package]] name = "packaging" version = "23.0" @@ -927,6 +969,25 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "pre-commit" +version = "3.2.1" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pre_commit-3.2.1-py2.py3-none-any.whl", hash = "sha256:a06a7fcce7f420047a71213c175714216498b49ebc81fe106f7716ca265f5bb6"}, + {file = "pre_commit-3.2.1.tar.gz", hash = "sha256:b5aee7d75dbba21ee161ba641b01e7ae10c5b91967ebf7b2ab0dfae12d07e1f1"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + [[package]] name = "pycparser" version = "2.21" @@ -1529,6 +1590,23 @@ files = [ {file = "semver-2.13.0.tar.gz", hash = "sha256:fa0fe2722ee1c3f57eac478820c3a5ae2f624af8264cbdf9000c980ff7f75e3f"}, ] +[[package]] +name = "setuptools" +version = "67.6.1" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setuptools-67.6.1-py3-none-any.whl", hash = "sha256:e728ca814a823bf7bf60162daf9db95b93d532948c4c0bea762ce62f60189078"}, + {file = "setuptools-67.6.1.tar.gz", hash = "sha256:257de92a9d50a60b8e22abfcbb771571fde0dbf3ec234463212027a4eeecbe9a"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + [[package]] name = "six" version = "1.16.0" @@ -1807,4 +1885,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.8,<3.12" -content-hash = "07266d395f60d5aede8b129bdf22f065538367fbb8b617f52523a8a167a7907d" +content-hash = "256b1e36f50551160988c3487f9938c65163bc2b032d999aa6e573fe04a81560" diff --git a/pyproject.toml b/pyproject.toml index 300ec0dd..25392de9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,6 +76,7 @@ optional = true [tool.poetry.group.qa.dependencies] types-requests = "*" +pre-commit = "*" [tool.black] line-length = 120 diff --git a/src/phylum/ci/constants.py b/src/phylum/ci/constants.py index d6fbf8c9..c67daa14 100644 --- a/src/phylum/ci/constants.py +++ b/src/phylum/ci/constants.py @@ -12,7 +12,7 @@ SUCCESS_DETAILS = "The Phylum risk analysis is complete and did not identify any issues." -# Expandable HTML providing information on why there was a failure +# Background text providing information on why there was a failure FAILURE_DETAILS = """ This repository analyzes risk of new dependencies with Phylum. An administrator of this repository has set score requirements for Phylum's five risk domains. diff --git a/tox.ini b/tox.ini index 90c3d45b..4557431a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,4 +1,6 @@ [tox] +# Sub-commands were introduced in v4. These are used in workflows and docs. +min_version = 4 envlist = py38, py39, py310, py311 isolated_build = true @@ -10,10 +12,22 @@ python = 3.11: py311 [testenv] +description = Test environment for minor Python version passenv = * +# Skip the local package install so that `poetry` can handle installing +# all of the dependencies and do so only from the `poetry.lock` lockfile. +skip_install = true allowlist_externals = poetry commands = poetry lock --check poetry install --verbose --sync --with test poetry run python -m pip list poetry run pytest {posargs} + +[testenv:qa] +description = Quality Assurance (QA) checks +commands = + poetry lock --check + poetry install --verbose --sync --with qa + poetry run python -m pip list + poetry run pre-commit run --all-files --verbose