diff --git a/.github/workflows/flake8.yaml b/.github/workflows/flake8.yaml index 2cdcdf0..daf4413 100644 --- a/.github/workflows/flake8.yaml +++ b/.github/workflows/flake8.yaml @@ -3,16 +3,19 @@ on: push: pull_request: +permissions: + contents: read + jobs: flake8-lint: runs-on: ubuntu-24.04 name: flake8 lint steps: - name: Setup python for flake8 - uses: actions/setup-python@v4 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.10" - - uses: actions/checkout@v3 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Install nox run: python -m pip install nox==2024.10.09 - name: Setup flake8 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c70f1ed..38c2d99 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -6,15 +6,18 @@ on: schedule: - cron: "0 8 * * *" +permissions: + contents: read + jobs: pre-commit: name: pre-commit runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.10" - name: Install dependencies @@ -28,36 +31,42 @@ jobs: test: name: test ${{ matrix.py }} - ${{ matrix.netapi }} - ${{ matrix.salt }} runs-on: ubuntu-22.04 + timeout-minutes: 30 strategy: fail-fast: false matrix: py: - - "3.8" - - "3.9" - "3.10" - "3.11" + - "3.12" + - "3.13" netapi: - "cherrypy" - "tornado" salt: - - "v3006.9" - - "v3007.1" + - "v3006.30" + - "v3007.17" + - "v3008.5" - "master" exclude: - - py: "3.8" - salt: "v3007.1" - - py: "3.9" - salt: "v3007.1" - - py: "3.8" - salt: "master" - - py: "3.9" - salt: "master" + # The test minion never completes authentication with Salt 3006 on + # Python 3.12+ or Salt 3007 on Python 3.13. Salt 3007 on Python 3.12 + # usually passes, but the minion intermittently fails to start or + # stops answering. + - py: "3.12" + salt: "v3006.30" + - py: "3.13" + salt: "v3006.30" + - py: "3.12" + salt: "v3007.17" + - py: "3.13" + salt: "v3007.17" env: SALT_REQUIREMENT: ${{ matrix.salt == 'master' && 'salt@git+https://github.com/saltstack/salt.git@master' || format('salt=={0}', matrix.salt) }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Set up Python ${{ matrix.py }} - uses: actions/setup-python@v4 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ matrix.py }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index dbdda31..0000000 --- a/.travis.yml +++ /dev/null @@ -1,41 +0,0 @@ -dist: xenial -sudo: false -services: -- docker -language: python -services: -- docker - -install: -- pip install tox - -python: -- '2.7' -- '3.4' -- '3.5' -- '3.6' -- '3.7' -- '3.8-dev' - -env: -- SALT=v2018.3 BACKEND=cherrypy -- SALT=v2018.3 BACKEND=tornado -- SALT=v2019.2 BACKEND=cherrypy -- SALT=v2019.2 BACKEND=tornado -- SALT=develop BACKEND=cherrypy -- SALT=develop BACKEND=tornado - -matrix: - allow_failures: - - python: '3.8-dev' - - env: SALT=develop BACKEND=tornado - - env: SALT=develop BACKEND=cherrypy - -script: -- PYTHON="${TRAVIS_PYTHON_VERSION/-dev/-rc}" -- TOX_VERSION="py${PYTHON//./}" -- docker run -v $PWD:/pepper -ti --rm "python:$PYTHON" make -C /pepper test PYVERSION="${TOX_VERSION%-rc}" SALT="${SALT}" BACKEND="${BACKEND}" - -after_success: -- sudo chown $USER .tox/ -- tox -e codecov diff --git a/Makefile b/Makefile deleted file mode 100644 index 1c69fd3..0000000 --- a/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -PYVERSION?=py37 -SALT?=v2019.2 -BACKEND?=cherrypy -DEBIAN_FRONTEND=noninteractive - -install: - apt update && apt install -y libc6-dev libffi-dev gcc git openssh-server libzmq3-dev - pip install tox - -test: install - tox -e flake8,$(PYVERSION)-$(BACKEND)-$(SALT) diff --git a/README.rst b/README.rst index 6b285a3..ee5c8cc 100644 --- a/README.rst +++ b/README.rst @@ -4,14 +4,12 @@ Pepper .. image:: https://img.shields.io/pypi/v/salt-pepper.svg :target: https://pypi.org/project/salt-pepper -.. image:: https://travis-ci.com/saltstack/pepper.svg?branch=develop - :target: https://travis-ci.com/saltstack/pepper +.. image:: https://github.com/saltstack/pepper/actions/workflows/test.yaml/badge.svg?branch=develop + :target: https://github.com/saltstack/pepper/actions/workflows/test.yaml .. image:: https://img.shields.io/pypi/pyversions/salt-pepper.svg :target: https://pypi.org/project/salt-pepper .. image:: https://img.shields.io/badge/license-Apache2-blue.svg?maxAge=3600 :target: https://pypi.org/project/salt-pepper -.. image:: https://codecov.io/gh/saltstack/pepper/branch/develop/graph/badge.svg - :target: https://codecov.io/gh/saltstack/pepper/branch/develop Pepper contains a Python library and CLI scripts for accessing a remote `salt-api`__ instance. diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 87d32eb..0000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,60 +0,0 @@ -trigger: -- develop - -variables: - python: '["py2.7", "py3.4", "py3.5", "py3.6", "py3.7", "py3.8"]' - salt: '["v2018.3", "v2019.2", "develop"]' - backends: '["cherrypy", "tornado"]' - -jobs: -- job: build_matrix - pool: - vmImage: 'Ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - inputs: - versionSpec: '3.7' - architecture: x64 - - - task: PythonScript@0 - name: matrix - inputs: - scriptSource: Inline - script: | - import json - matrix = {} - for pyver in $(python): - for saltver in $(salt): - for backend in $(backends): - matrix['{0}-{1}-{2}'.format(pyver, backend, saltver)] = { - 'python.version': pyver[2:], - 'version': pyver.replace('.', ''), - 'salt': saltver, - 'backend': backend, - } - print('##vso[task.setvariable variable=matrix;isOutput=true]{0}'.format(json.dumps(matrix))) - -- job: test_pepper - dependsOn: build_matrix - pool: - vmImage: 'Ubuntu-16.04' - strategy: - matrix: $[ dependencies.build_matrix.outputs['matrix.matrix'] ] - steps: - - task: UsePythonVersion@0 - inputs: - versionSpec: '$(python.version)' - architecture: x64 - - - script: | - pip install tox - displayName: Install dependencies - - script: | - docker run -v $PWD:/pepper --rm "python:$(python.version)" make -C /pepper test PYTHON_VERSION=$(version) SALT=$(salt) BACKEND=$(backend) - displayName: pytest - - script: | - sudo chown $USER .tox/ - tox -e codecov - displayName: codecov - env: - CODECOV_TOKEN: '16c2a232-4329-438c-b163-ccbfeeab47aa' diff --git a/codecov.yml b/codecov.yml deleted file mode 100644 index 2ef3d9f..0000000 --- a/codecov.yml +++ /dev/null @@ -1,27 +0,0 @@ -codecov: - notify: - require_ci_to_pass: yes - branch: develop - -coverage: - precision: 2 - round: down - range: "50...100" - - status: - project: yes - patch: yes - changes: no - -parsers: - gcov: - branch_detection: - conditional: yes - loop: yes - method: no - macro: no - -comment: - layout: "header, diff" - behavior: default - require_changes: no diff --git a/noxfile.py b/noxfile.py index 432929d..8994f2d 100644 --- a/noxfile.py +++ b/noxfile.py @@ -7,8 +7,8 @@ from nox.command import CommandFailed -API_BACKEND = [os.environ.get("API_BACKEND")] or ["cherrypy", "tornado"] -PYTHON_VERSIONS = [os.environ.get("PYTHON_VERSIONS")] or ["3.8", "3.9", "3.10", "3.11"] +API_BACKEND = os.environ.get("API_BACKEND", "cherrypy tornado").split() +PYTHON_VERSIONS = os.environ.get("PYTHON_VERSIONS", "3.10 3.11 3.12 3.13").split() # Nox options # Reuse existing virtualenvs @@ -18,11 +18,11 @@ # Be verbose when running under a CI context CI_RUN = os.environ.get("CI") -PIP_INSTALL_SILENT = CI_RUN is False +PIP_INSTALL_SILENT = not CI_RUN SKIP_REQUIREMENTS_INSTALL = "SKIP_REQUIREMENTS_INSTALL" in os.environ EXTRA_REQUIREMENTS_INSTALL = os.environ.get("EXTRA_REQUIREMENTS_INSTALL") SALT_REQUIREMENT = os.environ.get("SALT_REQUIREMENT") or "salt" -COVERAGE_VERSION_REQUIREMENT = "coverage==5.5" +COVERAGE_VERSION_REQUIREMENT = "coverage>=7.2" # Prevent Python from writing bytecode os.environ["PYTHONDONTWRITEBYTECODE"] = "1" diff --git a/tests/conftest.py b/tests/conftest.py index 0af0f63..e7754de 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -301,6 +301,27 @@ def session_salt_api(session_master, session_salt_api_factory): yield session_salt_api_factory +@pytest.fixture(autouse=True) +def isolated_environment(monkeypatch, tmp_path): + """ + Remove pepper and salt-api settings inherited from the calling shell, and + point the home directory at an empty one. + + Pepper gives environment variables precedence over the config file, so a + developer with SALTAPI_URL exported would otherwise send the test + credentials to that salt-api instead of the one started for the tests. + With the real home directory, tests would also read the developer's + ~/.pepperrc and write their ~/.peppercache. + """ + for name in list(os.environ): + if name.startswith(("SALTAPI_", "PEPPER")) or name == "MASTER_CONFIG": + monkeypatch.delenv(name) + home = tmp_path / "home" + home.mkdir() + monkeypatch.setenv("HOME", str(home)) + monkeypatch.setenv("USERPROFILE", str(home)) + + def pytest_addoption(parser): parser.addoption( "--salt-api-backend", diff --git a/tests/integration/test_clients.py b/tests/integration/test_clients.py index 6a00be3..27dc01c 100644 --- a/tests/integration/test_clients.py +++ b/tests/integration/test_clients.py @@ -2,6 +2,7 @@ import pathlib import pytest +import salt.version def test_local_bad_opts(pepper_cli): @@ -62,6 +63,10 @@ def test_wheel_client_kwargs(pepper_cli, session_master): 'config.getoption("--salt-api-backend") == "rest_tornado"', reason="sshClient unimplemented for now on tornado", ) +@pytest.mark.xfail( + salt.version.__saltstack_version__.info >= (3008,), + reason="salt-api rejects the eauth token for the ssh client on Salt 3008+", +) def test_ssh_client(pepper_cli, session_ssh_roster_config): ret = pepper_cli("--client=ssh", "*", "test.ping") assert ret["ssh"]["localhost"]["return"] is True diff --git a/tests/requirements.txt b/tests/requirements.txt index 083f792..dd24b8b 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,13 +1,6 @@ -mock pytest>=6.0.0 flake8-pyproject pytest-rerunfailures pytest-cov -pytest-salt-factories==1.0.4 +pytest-salt-factories==1.0.5 CherryPy -setuptools_scm==7.1.0 -importlib-metadata<5.0.0 -pyzmq>=25.1.2 ; python_version < '3.13' -pyzmq>=26.2.0 ; python_version >= '3.13' -cryptography>=42.0.0; python_version < '3.13' -cryptography==42.0.2; python_version >= '3.13' diff --git a/tests/unit/test_init.py b/tests/unit/test_init.py index dee3976..180ba75 100644 --- a/tests/unit/test_init.py +++ b/tests/unit/test_init.py @@ -1,24 +1,32 @@ -# Import Python Libraries -import imp +import importlib.util import os -import shutil - -import setuptools_scm +from importlib.metadata import PackageNotFoundError +from importlib.metadata import version +from unittest.mock import patch import pepper -# Import Pepper Libraries - -def test_no_setup(): - setuppath = os.path.join(os.path.dirname(pepper.__file__), os.pardir, "setup.py") - shutil.move(setuppath, setuppath + ".bak") - ptest = imp.load_source("ptest", os.path.join(os.path.dirname(pepper.__file__), "__init__.py")) - shutil.move(setuppath + ".bak", setuppath) - assert ptest.version == setuptools_scm.get_version() - assert ptest.sha is None +def _load_pepper_init(name): + """ + Execute a fresh copy of pepper/__init__.py without touching the imported module + """ + path = os.path.join(os.path.dirname(pepper.__file__), "__init__.py") + spec = importlib.util.spec_from_file_location(name, path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module def test_version(): - assert pepper.version == setuptools_scm.get_version() + assert pepper.__version__ == version("salt_pepper") + assert pepper.version == pepper.__version__ assert pepper.sha is None + + +def test_version_not_installed(): + with patch("importlib.metadata.version", side_effect=PackageNotFoundError): + ptest = _load_pepper_init("ptest") + assert ptest.__version__ is None + assert ptest.version is None + assert ptest.sha is None