diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 0000000..f9f2e82 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,25 @@ +--- +coverage: + status: + project: + default: false + app: + informational: true + paths: + - src/ + tests: + informational: true + paths: + - tests/ + patch: + default: false + app: + informational: true + paths: + - src/ + tests: + informational: true + paths: + - tests/ +github_checks: + annotations: false diff --git a/.copier-answers.yml b/.copier-answers.yml index d0b81f2..dc6c0ac 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,6 +1,6 @@ # Autogenerated. Do not edit this by hand, use `copier update`. --- -_commit: 0.4.5 +_commit: 0.5.0 _src_path: https://github.com/lkubb/salt-extension-copier author: EITR Technologies, LLC author_email: devops@eitr.tech @@ -18,15 +18,18 @@ loaders: - state max_salt_version: '3007' no_saltext_namespace: false +os_support: + - Linux + - macOS + - Windows package_name: consul project_name: consul python_requires: '3.8' relax_pylint: true -salt_version: '3005' +salt_version: '3006' source_url: https://github.com/salt-extensions/saltext-consul ssh_fixtures: false summary: Salt Extension for interacting with HashiCorp Consul test_containers: true tracker_url: https://github.com/salt-extensions/saltext-consul/issues url: https://github.com/salt-extensions/saltext-consul -workflows: org diff --git a/.coveragerc b/.coveragerc index 811f136..51fa72d 100644 --- a/.coveragerc +++ b/.coveragerc @@ -11,10 +11,7 @@ omit = [report] # Regexes for lines to exclude from consideration -exclude_lines = - # Have to re-enable the standard pragma - pragma: no cover - +exclude_also = # Don't complain about missing debug-only code: def __repr__ @@ -26,12 +23,17 @@ exclude_lines = if 0: if False: if __name__ == .__main__.: + if TYPE_CHECKING: + @(abc\.)?abstractmethod + + # Add markers which exclude statements in between. + # Requires coverage>=7.6.0. + no cover: start(?s:.)*?no cover: stop omit = .nox/* setup.py - ignore_errors = True [paths] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..7b529c1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,135 @@ +--- +name: CI + +on: + workflow_call: + inputs: + deploy-docs: + required: false + type: boolean + default: false + release: + required: false + type: boolean + default: false + version: + required: false + type: string + secrets: + PYPI_API_TOKEN: + required: false + TEST_PYPI_API_TOKEN: + required: false + + +jobs: + get-changed-files: + name: Get Changed Files + uses: ./.github/workflows/get-changed-files.yml + + pre-commit: + name: Pre-Commit + uses: ./.github/workflows/pre-commit-action.yml + needs: + - get-changed-files + with: + changed-files: ${{ needs.get-changed-files.outputs.changed-files }} + + test: + name: Test + needs: + - pre-commit + uses: ./.github/workflows/test-action.yml + + docs: + name: Docs + needs: + - pre-commit + uses: ./.github/workflows/docs-action.yml + + deploy-docs: + name: Deploy Docs + uses: ./.github/workflows/deploy-docs-action.yml + # Only build doc deployments from the default branch of the repo and never for PRs. + if: >- + github.event_name != 'pull_request' && + inputs.deploy-docs && + github.ref == format('refs/heads/{0}', github.event.repository.default_branch) + needs: + - docs + - test + + build-python-package: + name: Python Package + if: ${{ inputs.release && success() }} + uses: ./.github/workflows/package-action.yml + needs: + - pre-commit + with: + version: "${{ inputs.version }}" + + deploy-python-package-test-pypi: + name: Deploy Python Package (Test PyPI) + uses: ./.github/workflows/deploy-package-action.yml + if: ${{ inputs.release && success() }} + needs: + - test + - docs + - build-python-package + secrets: + TEST_PYPI_API_TOKEN: "${{ secrets.TEST_PYPI_API_TOKEN }}" + with: + version: "${{ inputs.version }}" + + deploy-python-package: + name: Deploy Python Package (PyPI) + uses: ./.github/workflows/deploy-package-action.yml + if: ${{ inputs.release && success() }} + needs: + - deploy-python-package-test-pypi + secrets: + PYPI_API_TOKEN: "${{ secrets.PYPI_API_TOKEN }}" + with: + test: false + version: "${{ inputs.version }}" + + set-pipeline-exit-status: + # This step is just so we can make github require this step, to pass checks + # on a pull request instead of requiring all + name: Set the CI Pipeline Exit Status + runs-on: ubuntu-24.04 + if: always() + needs: + - test + - docs + - deploy-docs + - build-python-package + - deploy-python-package-test-pypi + - deploy-python-package + + steps: + - name: Download Exit Status Files + if: always() + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + path: exitstatus + pattern: exitstatus-* + merge-multiple: true + + - name: Delete Exit Status Artifacts + if: always() + uses: geekyeggo/delete-artifact@7ee91e82b4a7f3339cd8b14beace3d826a2aac39 # v5.1.0 + with: + name: exitstatus-* + useGlob: true + failOnError: false + + - name: Set Pipeline Exit Status + run: | + tree exitstatus + grep -RE 'failure|cancelled' exitstatus/ && exit 1 || exit 0 + + - name: Done + if: always() + run: + echo "All workflows finished" diff --git a/.github/workflows/deploy-docs-action.yml b/.github/workflows/deploy-docs-action.yml new file mode 100644 index 0000000..d4bf10d --- /dev/null +++ b/.github/workflows/deploy-docs-action.yml @@ -0,0 +1,78 @@ +--- +name: Publish Documentation + +on: + workflow_call: + inputs: + # This is the name of the regular artifact that should + # be transformed into a GitHub Pages deployment. + artifact-name: + type: string + required: false + default: html-docs + +jobs: + + # The released docs are not versioned currently, only the latest ones are deployed. + # + # Versioning support would require either (better): + # * Rebuilding docs for all versions when a new release is made + # * Version selector support in `furo`: https://github.com/pradyunsg/furo/pull/500 + # + # or (more basic): + # * using the `gh-pages` branch and peaceiris/actions-gh-pages + # to be able to deploy to subdirectories. The implementation via + # actions/deploy-pages always replaces the directory root. + + Deploy-Docs-GH-Pages: + name: Publish Docs to GitHub Pages + + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + permissions: + pages: write + id-token: write + + runs-on: ubuntu-24.04 + + steps: + - name: Download built docs + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: ${{ inputs.artifact-name }} + path: html-docs + + - name: Upload GitHub Pages artifact + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1 + with: + name: html-docs-pages + path: html-docs + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 + with: + artifact_name: html-docs-pages + + - name: Delete GitHub Pages artifact + if: always() + uses: geekyeggo/delete-artifact@7ee91e82b4a7f3339cd8b14beace3d826a2aac39 # v5.1.0 + with: + name: html-docs-pages + failOnError: false + + - name: Set Exit Status + if: always() + run: | + mkdir exitstatus + echo "${{ job.status }}" > exitstatus/${{ github.job }} + + - name: Upload Exit Status + if: always() + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: exitstatus-${{ github.job }} + path: exitstatus + if-no-files-found: error diff --git a/.github/workflows/deploy-package-action.yml b/.github/workflows/deploy-package-action.yml new file mode 100644 index 0000000..9f1d6ba --- /dev/null +++ b/.github/workflows/deploy-package-action.yml @@ -0,0 +1,54 @@ +--- +name: Deploy Salt Extension Python Package + +on: + workflow_call: + inputs: + test: + type: boolean + required: false + default: true + version: + type: string + required: true + secrets: + PYPI_API_TOKEN: + required: false + TEST_PYPI_API_TOKEN: + required: false + +jobs: + build: + name: Publish Python Package to ${{ fromJSON('["PyPI", "Test PyPI"]')[inputs.test] }} + runs-on: ubuntu-24.04 + + steps: + - name: Download Python Package Artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: salt-extension-${{ inputs.version }}-packages + path: dist + + - name: Publish distribution to Test PyPI + uses: pypa/gh-action-pypi-publish@c44d2f0e52f028349e3ecafbf7f32561da677277 # v1.10.3 + if: ${{ inputs.test }} + with: + password: ${{ secrets.TEST_PYPI_API_TOKEN }} + repository-url: https://test.pypi.org/legacy/ + + - name: Create GitHub Release + if: ${{ !inputs.test }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release create "$GITHUB_REF_NAME" \ + --repo="$GITHUB_REPOSITORY" \ + --title="${GITHUB_REPOSITORY#*/} ${{ inputs.version }}" \ + --generate-notes \ + dist/* + + - name: Publish distribution to PyPI + uses: pypa/gh-action-pypi-publish@c44d2f0e52f028349e3ecafbf7f32561da677277 # v1.10.3 + if: ${{ !inputs.test }} + with: + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/docs-action.yml b/.github/workflows/docs-action.yml new file mode 100644 index 0000000..8a5c751 --- /dev/null +++ b/.github/workflows/docs-action.yml @@ -0,0 +1,55 @@ +--- +name: Build Documentation + +on: + workflow_call: + +jobs: + Docs: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + + steps: + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + fetch-depth: 0 + + - name: Set up Python 3.10 For Nox + uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + with: + python-version: "3.10" + + - name: Install Nox + run: | + python -m pip install --upgrade pip + pip install nox + + - name: Install Doc Requirements + run: | + nox --force-color -e docs --install-only + + - name: Build Docs + env: + SKIP_REQUIREMENTS_INSTALL: true + run: | + nox --force-color -e docs + + - name: Upload built docs as artifact + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: html-docs + path: docs/_build/html + + - name: Set Exit Status + if: always() + run: | + mkdir exitstatus + echo "${{ job.status }}" > exitstatus/${{ github.job }} + + - name: Upload Exit Status + if: always() + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: exitstatus-${{ github.job }} + path: exitstatus + if-no-files-found: error diff --git a/.github/workflows/get-changed-files.yml b/.github/workflows/get-changed-files.yml new file mode 100644 index 0000000..3e568c0 --- /dev/null +++ b/.github/workflows/get-changed-files.yml @@ -0,0 +1,43 @@ +--- +on: + workflow_call: + outputs: + changed-files: + description: "Changed file JSON output from dorny/paths-filter" + value: ${{ jobs.get-changed-files.outputs.changed-files }} + +jobs: + get-changed-files: + name: Get Changed Files + runs-on: ubuntu-24.04 + permissions: + contents: read # for dorny/paths-filter to fetch a list of changed files + pull-requests: read # for dorny/paths-filter to read pull requests + outputs: + changed-files: ${{ toJSON(steps.changed-files.outputs) }} + + steps: + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - name: Get Changed Files + id: changed-files + uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 + with: + token: ${{ github.token }} + list-files: escape + filters: | + repo: + - added|modified: + - '**' + deleted: + - deleted: + - '**' + pre-commit: + - added|modified|deleted: + - .pre-commit-hooks/** + - .pre-commit-config.y?(a)ml + - .pylintrc + - pyproject.toml + + - name: Echo Changed Files Output + run: echo "${{ toJSON(steps.changed-files.outputs) }}" diff --git a/.github/workflows/package-action.yml b/.github/workflows/package-action.yml new file mode 100644 index 0000000..818b1aa --- /dev/null +++ b/.github/workflows/package-action.yml @@ -0,0 +1,60 @@ +--- +name: Salt Extension Python Package + +on: + workflow_call: + inputs: + version: + required: true + type: string + +jobs: + build: + name: Build Python Packages (wheel and sdist) + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + fetch-depth: 0 + + - name: Set up Python 3.10 + uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + with: + python-version: "3.10" + + - name: Install build tools + run: >- + python -m + pip install + build + setuptools_scm + --user + + - name: Echo Version + run: echo "${{ inputs.version }}" + + - name: Build Wheel + run: python -m build --outdir dist/ + + - name: Upload build artifacts + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + if: always() + with: + name: salt-extension-${{ inputs.version }}-packages + path: dist/* + retention-days: 5 + + - name: Set Exit Status + if: always() + run: | + mkdir exitstatus + echo "${{ job.status }}" > exitstatus/${{ github.job }} + + - name: Upload Exit Status + if: always() + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: exitstatus-${{ github.job }} + path: exitstatus + if-no-files-found: error diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index fc650b6..403a722 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -12,7 +12,7 @@ on: jobs: call_central_workflow: name: CI - uses: salt-extensions/central-artifacts/.github/workflows/ci.yml@main + uses: ./.github/workflows/ci.yml with: deploy-docs: true permissions: diff --git a/.github/workflows/pre-commit-action.yml b/.github/workflows/pre-commit-action.yml new file mode 100644 index 0000000..ebf639a --- /dev/null +++ b/.github/workflows/pre-commit-action.yml @@ -0,0 +1,56 @@ +--- +name: Pre-Commit + +on: + workflow_call: + inputs: + changed-files: + required: true + type: string + description: JSON string containing information about changed files + +jobs: + Pre-Commit: + name: Pre-Commit + runs-on: ubuntu-24.04 + container: + image: docker.io/library/python:3.10.15-slim-bookworm@sha256:1eb5d76bf3e9e612176ebf5eadf8f27ec300b7b4b9a99f5856f8232fd33aa16e + + steps: + - name: Install System Deps + run: | + apt-get update + apt-get install -y enchant-2 git gcc make zlib1g-dev libc-dev libffi-dev g++ libxml2 libxml2-dev libxslt-dev libcurl4-openssl-dev libssl-dev libgnutls28-dev + git config --global --add safe.directory "$(pwd)" + + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - name: Install Pre-Commit + run: | + python -m pip install --upgrade pip + pip install pre-commit + pre-commit install --install-hooks + + - name: Check ALL Files On Branch + if: github.event_name != 'pull_request' || fromJSON(inputs.changed-files)['pre-commit'] == 'true' + run: | + pre-commit run --show-diff-on-failure --color=always --all-files + + - name: Check Changed Files On PR + if: github.event_name == 'pull_request' && fromJSON(inputs.changed-files)['repo'] == 'true' + run: | + pre-commit run --show-diff-on-failure --color=always --files ${{ fromJSON(inputs.changed-files)['repo_files'] }} + + - name: Set Exit Status + if: always() + run: | + mkdir exitstatus + echo "${{ job.status }}" > exitstatus/${{ github.job }} + + - name: Upload Exit Status + if: always() + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: exitstatus-${{ github.job }} + path: exitstatus + if-no-files-found: error diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index 016aeea..33eded8 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -8,12 +8,12 @@ on: jobs: get_tag_version: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: version: ${{ steps.get_version.outputs.version }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Extract tag name id: get_version @@ -21,7 +21,7 @@ jobs: call_central_workflow: needs: get_tag_version - uses: salt-extensions/central-artifacts/.github/workflows/ci.yml@main + uses: ./.github/workflows/ci.yml with: deploy-docs: true release: true diff --git a/.github/workflows/test-action.yml b/.github/workflows/test-action.yml new file mode 100644 index 0000000..88242f3 --- /dev/null +++ b/.github/workflows/test-action.yml @@ -0,0 +1,293 @@ +--- +name: Testing + +on: + workflow_call: + +jobs: + + Linux: + runs-on: ubuntu-24.04 + timeout-minutes: 30 + + strategy: + fail-fast: false + max-parallel: 4 + matrix: + include: + - {salt-version: "3006.9", python-version: "3.8"} + - {salt-version: "3006.9", python-version: "3.9"} + - {salt-version: "3006.9", python-version: "3.10"} + - {salt-version: "3007.1", python-version: "3.10"} + + steps: + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + fetch-depth: 2 # coverage: Issue detecting commit SHA + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + with: + python-version: ${{ matrix.python-version }} + + - name: Install Nox + run: | + python -m pip install --upgrade pip + pip install nox + + - name: Install Test Requirements + env: + SALT_REQUIREMENT: salt==${{ matrix.salt-version }} + run: | + nox --force-color -e tests-3 --install-only + + - name: Test + env: + SALT_REQUIREMENT: salt==${{ matrix.salt-version }} + SKIP_REQUIREMENTS_INSTALL: true + run: | + nox --force-color -e tests-3 -- -vv tests/ + + - name: Create CodeCov Flags + if: always() + id: codecov-flags + run: | + echo "flags=$(python -c "import sys; print('{},{},salt_{}'.format('${{ runner.os }}'.replace('-latest', ''), 'py{}{}'.format(*sys.version_info), '_'.join(str(v) for v in '${{ matrix.salt-version }}'.replace('==', '_').split('.'))))")" >> "$GITHUB_OUTPUT" + + - name: Upload Project Code Coverage + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 + with: + file: artifacts/coverage-project.xml + disable_search: true + fail_ci_if_error: false + flags: ${{ steps.codecov-flags.outputs.flags }},project + name: ${{ runner.os }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}-project + use_oidc: true + version: v0.7.5 + + - name: Upload Tests Code Coverage + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 + with: + file: artifacts/coverage-tests.xml + disable_search: true + fail_ci_if_error: false + flags: ${{ steps.codecov-flags.outputs.flags }},tests + name: ${{ runner.os }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}-tests + use_oidc: true + version: v0.7.5 + + - name: Upload Logs + if: always() + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: runtests-${{ runner.os }}-py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}.log + path: artifacts/runtests-*.log + + - name: Set Exit Status + if: always() + run: | + mkdir exitstatus + echo "${{ job.status }}" > exitstatus/${{ github.job }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }} + + - name: Upload Exit Status + if: always() + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: exitstatus-${{ github.job }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }} + path: exitstatus + if-no-files-found: error + + Windows: + runs-on: windows-2022 + timeout-minutes: 40 + + strategy: + fail-fast: false + max-parallel: 2 + matrix: + include: + - {salt-version: "3006.9", python-version: "3.8"} + - {salt-version: "3007.1", python-version: "3.8"} + + steps: + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + fetch-depth: 2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + with: + python-version: ${{ matrix.python-version }} + + - name: Download libeay32.dll + run: | + PY_LOC="$(which python.exe)" + export PY_LOC + echo "${PY_LOC}" + PY_DIR="$(dirname "${PY_LOC}")" + export PY_DIR + echo "${PY_DIR}" + curl https://repo.saltproject.io/windows/dependencies/64/libeay32.dll --output "${PY_DIR}/libeay32.dll" + ls -l "${PY_DIR}" + shell: bash + + - name: Install Nox + run: | + python -m pip install --upgrade pip + pip install nox + + - name: Install Test Requirements + shell: bash + env: + SALT_REQUIREMENT: salt==${{ matrix.salt-version }} + # EXTRA_REQUIREMENTS_INSTALL: Cython + run: | + export PATH="/C/Program Files (x86)/Windows Kits/10/bin/10.0.18362.0/x64;$PATH" + nox --force-color -e tests-3 --install-only + + - name: Test + shell: bash + env: + SALT_REQUIREMENT: salt==${{ matrix.salt-version }} + SKIP_REQUIREMENTS_INSTALL: true + run: | + export PATH="/C/Program Files (x86)/Windows Kits/10/bin/10.0.18362.0/x64;$PATH" + nox --force-color -e tests-3 -- -vv tests/ + + - name: Create CodeCov Flags + if: always() + id: codecov-flags + run: | + echo "flags=$(python -c "import sys; print('{},{},salt_{}'.format('${{ runner.os }}'.replace('-latest', ''), 'py{}{}'.format(*sys.version_info), '_'.join(str(v) for v in '${{ matrix.salt-version }}'.replace('==', '_').split('.'))))")" >> "$GITHUB_OUTPUT" + + - name: Upload Project Code Coverage + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 + with: + file: artifacts/coverage-project.xml + disable_search: true + fail_ci_if_error: false + flags: ${{ steps.codecov-flags.outputs.flags }},project + name: ${{ runner.os }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}-project + use_oidc: true + version: v0.7.5 + + - name: Upload Tests Code Coverage + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 + with: + file: artifacts/coverage-tests.xml + disable_search: true + fail_ci_if_error: false + flags: ${{ steps.codecov-flags.outputs.flags }},tests + name: ${{ runner.os }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}-tests + use_oidc: true + version: v0.7.5 + + - name: Upload Logs + if: always() + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: runtests-${{ runner.os }}-py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}.log + path: artifacts/runtests-*.log + + - name: Set Exit Status + if: always() + run: | + mkdir exitstatus + echo "${{ job.status }}" > exitstatus/${{ github.job }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }} + + - name: Upload Exit Status + if: always() + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: exitstatus-${{ github.job }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }} + path: exitstatus + if-no-files-found: error + + macOS: + runs-on: macos-14 + timeout-minutes: 40 + + strategy: + fail-fast: false + max-parallel: 2 + matrix: + include: + - {salt-version: "3006.9", python-version: "3.9"} + - {salt-version: "3007.1", python-version: "3.10"} + + steps: + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + fetch-depth: 2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + with: + python-version: ${{ matrix.python-version }} + + - name: Install Nox + run: | + python -m pip install --upgrade pip + pip install nox + + - name: Install Test Requirements + env: + SALT_REQUIREMENT: salt==${{ matrix.salt-version }} + run: | + nox --force-color -e tests-3 --install-only + + - name: Test + env: + SALT_REQUIREMENT: salt==${{ matrix.salt-version }} + SKIP_REQUIREMENTS_INSTALL: true + run: | + nox --force-color -e tests-3 -- -vv tests/ + + - name: Create CodeCov Flags + if: always() + id: codecov-flags + run: | + echo "flags=$(python -c "import sys; print('{},{},salt_{}'.format('${{ runner.os }}'.replace('-latest', ''), 'py{}{}'.format(*sys.version_info), '_'.join(str(v) for v in '${{ matrix.salt-version }}'.replace('==', '_').split('.'))))")" >> "$GITHUB_OUTPUT" + + - name: Upload Project Code Coverage + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 + with: + file: artifacts/coverage-project.xml + disable_search: true + fail_ci_if_error: false + flags: ${{ steps.codecov-flags.outputs.flags }},project + name: ${{ runner.os }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}-project + use_oidc: true + version: v0.7.5 + + - name: Upload Tests Code Coverage + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 + with: + file: artifacts/coverage-tests.xml + disable_search: true + fail_ci_if_error: false + flags: ${{ steps.codecov-flags.outputs.flags }},tests + name: ${{ runner.os }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}-tests + use_oidc: true + version: v0.7.5 + + - name: Upload Logs + if: always() + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: runtests-${{ runner.os }}-py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}.log + path: artifacts/runtests-*.log + + - name: Set Exit Status + if: always() + run: | + mkdir exitstatus + echo "${{ job.status }}" > exitstatus/${{ github.job }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }} + + - name: Upload Exit Status + if: always() + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: exitstatus-${{ github.job }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }} + path: exitstatus + if-no-files-found: error diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 66ce305..8a05cb4 100755 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ minimum_pre_commit_version: 2.4.0 repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # v5.0.0 hooks: - id: check-merge-conflict # Check for files that contain merge conflict strings. args: [--assume-in-merge] @@ -15,7 +15,7 @@ repos: # ----- Formatting ----------------------------------------------------------------------------> - repo: https://github.com/saltstack/pre-commit-remove-import-headers - rev: 1.1.0 + rev: 209beff8e11fed83f3f0863ccfd95aa663fffaf6 # 1.1.0 hooks: - id: remove-import-headers @@ -37,7 +37,7 @@ repos: - repo: https://github.com/saltstack/salt-rewrite # Automatically rewrite code with known rules - rev: 2.5.2 + rev: 8079cfb7f601e5dbad58b8449d85bb24f1e52082 # 2.5.2 hooks: - id: salt-rewrite alias: rewrite-docstrings @@ -47,7 +47,7 @@ repos: - repo: https://github.com/saltstack/salt-rewrite # Automatically rewrite code with known rules - rev: 2.5.2 + rev: 8079cfb7f601e5dbad58b8449d85bb24f1e52082 # 2.5.2 hooks: - id: salt-rewrite alias: rewrite-tests @@ -56,17 +56,17 @@ repos: args: [--silent, -E, fix_docstrings] - repo: https://github.com/asottile/pyupgrade - rev: v3.16.0 + rev: 32151ac97cbfd7f9dcd22e49516fb32266db45b4 # v3.16.0 hooks: - id: pyupgrade name: Rewrite Code to be Py3.8+ args: [ - --py38-plus + --py38-plus, ] exclude: src/saltext/consul/version.py - repo: https://github.com/PyCQA/isort - rev: 5.13.2 + rev: c235f5e450b4b84e58d114ed4c589cbf454175a3 # 5.13.2 hooks: - id: isort args: [ @@ -75,33 +75,34 @@ repos: exclude: src/saltext/consul/(__init__|version).py - repo: https://github.com/psf/black - rev: 24.8.0 + rev: b965c2a5026f8ba399283ba3e01898b012853c79 # 24.8.0 hooks: - id: black args: [-l 100] exclude: src/saltext/consul/version.py - repo: https://github.com/adamchainz/blacken-docs - rev: 1.18.0 + rev: 4c97c4a0d921007af6fefae92d8447cfbf63720b # 1.18.0 hooks: - id: blacken-docs args: [--skip-errors] files: ^(docs/.*\.rst|src/saltext/consul/.*\.py)$ additional_dependencies: - - black==24.2.0 + - black==24.8.0 # <---- Formatting ----------------------------------------------------------------------------- # ----- Security ------------------------------------------------------------------------------> - repo: https://github.com/PyCQA/bandit - rev: 1.7.9 + rev: 36fd65054fc8864b4037d0918904f9331512feb5 # 1.7.10 hooks: - id: bandit alias: bandit-salt name: Run bandit against the code base args: [--silent, -lll, --skip, B701] exclude: src/saltext/consul/version.py + - repo: https://github.com/PyCQA/bandit - rev: 1.7.9 + rev: 36fd65054fc8864b4037d0918904f9331512feb5 # 1.7.10 hooks: - id: bandit alias: bandit-tests @@ -123,7 +124,7 @@ repos: require_serial: true additional_dependencies: - nox==2024.4.15 - - uv==0.4.0 # Makes this hook much faster + - uv==0.4.18 # Makes this hook much faster - id: nox alias: lint-tests @@ -134,12 +135,12 @@ repos: require_serial: true additional_dependencies: - nox==2024.4.15 - - uv==0.4.0 # Makes this hook much faster + - uv==0.4.18 # Makes this hook much faster - repo: https://github.com/Mateusz-Grzelinski/actionlint-py - rev: 1ca29a1b5d949b3586800190ad6cc98317cb43b8 # v1.7.1.15 + rev: 27445053da613c660ed5895d9616662059a53ca7 # v1.7.3.17 hooks: - id: actionlint additional_dependencies: - - shellcheck-py>=0.9.0.5 + - shellcheck-py==0.10.0.1 # <---- Code Analysis -------------------------------------------------------------------------- diff --git a/docs/index.rst b/docs/index.rst index ba2a10b..09e6e80 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,5 +1,5 @@ -``saltext-consul``: Integrate Salt with Consul -============================================== +``saltext-consul``: Integrate Salt with HashiCorp Consul +======================================================== Salt Extension for interacting with HashiCorp Consul diff --git a/noxfile.py b/noxfile.py index 79a3c1d..acddd9c 100755 --- a/noxfile.py +++ b/noxfile.py @@ -21,7 +21,7 @@ nox.options.default_venv_backend = "uv|virtualenv" # Python versions to test against -PYTHON_VERSIONS = ("3", "3.8", "3.9", "3.10", "3.11", "3.12") +PYTHON_VERSIONS = ("3", "3.8", "3.9", "3.10") # Be verbose when running under a CI context CI_RUN = ( os.environ.get("JENKINS_URL") or os.environ.get("CI") or os.environ.get("DRONE") is not None @@ -30,8 +30,8 @@ SKIP_REQUIREMENTS_INSTALL = os.environ.get("SKIP_REQUIREMENTS_INSTALL", "0") == "1" EXTRA_REQUIREMENTS_INSTALL = os.environ.get("EXTRA_REQUIREMENTS_INSTALL") -COVERAGE_REQUIREMENT = os.environ.get("COVERAGE_REQUIREMENT") or "coverage==7.5.1" -SALT_REQUIREMENT = os.environ.get("SALT_REQUIREMENT") or "salt>=3005" +COVERAGE_REQUIREMENT = os.environ.get("COVERAGE_REQUIREMENT") or "coverage==7.6.1" +SALT_REQUIREMENT = os.environ.get("SALT_REQUIREMENT") or "salt>=3006" if SALT_REQUIREMENT == "salt==master": SALT_REQUIREMENT = "git+https://github.com/saltstack/salt.git@master" diff --git a/pyproject.toml b/pyproject.toml index 0b603d8..16d1c13 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,8 +28,6 @@ classifiers = [ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", @@ -37,8 +35,12 @@ classifiers = [ requires-python = ">= 3.8" dynamic = ["version"] dependencies = [ +<<<<<<< before updating "salt>=3005", "python-consul>=0.4.7", +======= + "salt>=3006", +>>>>>>> after updating ] [project.readme] diff --git a/tests/conftest.py b/tests/conftest.py index 2445fc5..c87f7d4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -12,13 +12,13 @@ # This swallows all logging to stdout. # To show select logs, set --log-cli-level= -for handler in logging.root.handlers[:]: +for handler in logging.root.handlers[:]: # pragma: no cover logging.root.removeHandler(handler) handler.close() @pytest.fixture(scope="session") -def salt_factories_config(): +def salt_factories_config(): # pragma: no cover """ Return a dictionary with the keyword arguments for FactoriesManager """ @@ -30,7 +30,7 @@ def salt_factories_config(): @pytest.fixture(scope="package") -def master_config(): +def master_config(): # pragma: no cover """ Salt master configuration overrides for integration tests. """ @@ -38,12 +38,12 @@ def master_config(): @pytest.fixture(scope="package") -def master(salt_factories, master_config): +def master(salt_factories, master_config): # pragma: no cover return salt_factories.salt_master_daemon(random_string("master-"), overrides=master_config) @pytest.fixture(scope="package") -def minion_config(): +def minion_config(): # pragma: no cover """ Salt minion configuration overrides for integration tests. """ @@ -51,5 +51,5 @@ def minion_config(): @pytest.fixture(scope="package") -def minion(master, minion_config): +def minion(master, minion_config): # pragma: no cover return master.salt_minion_daemon(random_string("minion-"), overrides=minion_config) diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index 2c7c84a..0a4757c 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -8,12 +8,12 @@ @pytest.fixture(scope="package") -def minion_id(): +def minion_id(): # pragma: no cover return "func-tests-minion-opts" @pytest.fixture(scope="module") -def state_tree(tmp_path_factory): +def state_tree(tmp_path_factory): # pragma: no cover state_tree_path = tmp_path_factory.mktemp("state-tree-base") try: yield state_tree_path @@ -22,7 +22,7 @@ def state_tree(tmp_path_factory): @pytest.fixture(scope="module") -def state_tree_prod(tmp_path_factory): +def state_tree_prod(tmp_path_factory): # pragma: no cover state_tree_path = tmp_path_factory.mktemp("state-tree-prod") try: yield state_tree_path @@ -31,7 +31,7 @@ def state_tree_prod(tmp_path_factory): @pytest.fixture(scope="module") -def minion_config_defaults(): +def minion_config_defaults(): # pragma: no cover """ Functional test modules can provide this fixture to tweak the default configuration dictionary passed to the minion factory @@ -40,7 +40,7 @@ def minion_config_defaults(): @pytest.fixture(scope="module") -def minion_config_overrides(): +def minion_config_overrides(): # pragma: no cover """ Functional test modules can provide this fixture to tweak the configuration overrides dictionary passed to the minion factory @@ -56,7 +56,7 @@ def minion_opts( state_tree_prod, minion_config_defaults, minion_config_overrides, -): +): # pragma: no cover minion_config_overrides.update( { "file_client": "local", @@ -79,7 +79,7 @@ def minion_opts( @pytest.fixture(scope="module") -def master_config_defaults(): +def master_config_defaults(): # pragma: no cover """ Functional test modules can provide this fixture to tweak the default configuration dictionary passed to the master factory @@ -88,7 +88,7 @@ def master_config_defaults(): @pytest.fixture(scope="module") -def master_config_overrides(): +def master_config_overrides(): # pragma: no cover """ Functional test modules can provide this fixture to tweak the configuration overrides dictionary passed to the master factory @@ -103,7 +103,7 @@ def master_opts( state_tree_prod, master_config_defaults, master_config_overrides, -): +): # pragma: no cover master_config_overrides.update( { "file_client": "local", @@ -126,12 +126,12 @@ def master_opts( @pytest.fixture(scope="module") -def loaders(minion_opts): +def loaders(minion_opts): # pragma: no cover return Loaders(minion_opts, loaded_base_name=f"{__name__}.loaded") @pytest.fixture(autouse=True) -def reset_loaders_state(loaders): +def reset_loaders_state(loaders): # pragma: no cover try: # Run the tests yield @@ -141,10 +141,10 @@ def reset_loaders_state(loaders): @pytest.fixture(scope="module") -def modules(loaders): +def modules(loaders): # pragma: no cover return loaders.modules @pytest.fixture(scope="module") -def states(loaders): +def states(loaders): # pragma: no cover return loaders.states diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 9bd9458..b9c5954 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -2,27 +2,27 @@ @pytest.fixture(scope="package") -def master(master): +def master(master): # pragma: no cover with master.started(): yield master @pytest.fixture(scope="package") -def minion(minion): +def minion(minion): # pragma: no cover with minion.started(): yield minion @pytest.fixture -def salt_run_cli(master): +def salt_run_cli(master): # pragma: no cover return master.salt_run_cli() @pytest.fixture -def salt_cli(master): +def salt_cli(master): # pragma: no cover return master.salt_cli() @pytest.fixture -def salt_call_cli(minion): +def salt_call_cli(minion): # pragma: no cover return minion.salt_call_cli() diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index b3b6ced..4e1e4b2 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -5,7 +5,7 @@ @pytest.fixture -def minion_opts(tmp_path): +def minion_opts(tmp_path): # pragma: no cover """ Default minion configuration with relative temporary paths to not require root permissions. @@ -24,7 +24,7 @@ def minion_opts(tmp_path): @pytest.fixture -def master_opts(tmp_path): +def master_opts(tmp_path): # pragma: no cover """ Default master configuration with relative temporary paths to not require root permissions. @@ -43,7 +43,7 @@ def master_opts(tmp_path): @pytest.fixture -def syndic_opts(tmp_path): +def syndic_opts(tmp_path): # pragma: no cover """ Default master configuration with relative temporary paths to not require root permissions.