Add Tox to manage dynamic options with pytest
.
#397
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: CICD | |
on: | |
push: | |
branches: | |
- main | |
pull_request: | |
branches: | |
- "**" | |
workflow_dispatch: | |
inputs: | |
rewrite_dependencies: | |
description: | |
If "true" or empty CICD will rewrite BL_Python dependencies, | |
during the build only, to use the local filesystem checkout rather than PyPI. | |
If "false" CICD will not rewrite the BL_Python dependencies. | |
type: choice | |
options: | |
- true | |
- false | |
default: "true" | |
required: true | |
use_dependency_cache: | |
description: | |
If "true", the workflow will use the dependency cache if the associated | |
cache key has a hit. If "false," any existing dependency cache will be ignored. | |
The workflow will save a new dependency cache with the same cache key regardless | |
of `use_dependency_cache` if there was not a cache hit. | |
type: choice | |
options: | |
- true | |
- false | |
default: "true" | |
required: false | |
jobs: | |
Checkout: | |
name: Checkout and Setup | |
runs-on: ubuntu-latest | |
outputs: | |
cache-key-dependencies: ${{ steps.generate-cache-keys.outputs.cache_key }} | |
cache-key-run: ${{ steps.generate-cache-keys.outputs.cache_key_run }} | |
python-version: ${{ steps.install-python.outputs.python-version }} | |
env: | |
PYTHON_VERSION: "3.10" | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Generate cache keys | |
id: generate-cache-keys | |
# Use separate cache keys for dependencies and for run workspace. | |
# The dependencies can be restored between runs, | |
# while the workspace is restored between jobs in the same run. | |
run: | | |
rand=$(( (1000+$RANDOM)%$RANDOM*$RANDOM )) | |
run_attempt=$([ -n "${{ github.run_attempt }}" ] && printf ${{ github.run_attempt }} || printf $rand) | |
cache_key_dependencies='${{ runner.os }}-dependencies-${{ hashFiles('pyproject.toml', 'src/*/pyproject.toml') }}' | |
cache_key_run='${{ runner.os }}-run-${{ hashFiles('pyproject.toml', 'src/*/pyproject.toml') }}-run-id_${{ github.run_id }}-number_${{ github.run_number }}-attempt_'"$run_attempt" | |
echo "cache_key_dependencies=$cache_key_dependencies" >> $GITHUB_OUTPUT | |
echo "cache_key_run=$cache_key_run" >> $GITHUB_OUTPUT | |
- name: Set up Python ${{ steps.generate-cache-keys.outputs.python-version }} | |
#if: ${{ success() && (inputs.use_dependency_cache == 'false' || !steps.restore-dependency-cache.outputs.cache-hit) }} | |
uses: actions/setup-python@v5 | |
id: install-python | |
with: | |
python-version: ${{ env.PYTHON_VERSION }} | |
- name: Install dependencies | |
#if: ${{ success() && (inputs.use_dependency_cache == 'false' || !steps.restore-dependency-cache.outputs.cache-hit) }} | |
run: | | |
echo Setting up dependencies | |
VENV=.github-venv \ | |
REWRITE_DEPENDENCIES=${{ inputs.rewrite_dependencies }} \ | |
make cicd | |
echo 'prefix=${{ github.workspace }}/node_modules' >> ~/.npmrc | |
. .github-venv/bin/activate && \ | |
npm install -g "pyright@`pyright --version | awk '/^pyright [0-9]/{print $2}'`" | |
- name: Save run cache | |
uses: actions/cache/save@v4 | |
id: save-run-cache | |
with: | |
path: ${{ github.workspace }} | |
key: ${{ steps.generate-cache-keys.outputs.cache_key_run }} | |
Pyright: | |
name: Static type checking | |
runs-on: ubuntu-latest | |
needs: | |
- Checkout | |
env: | |
PYTHON_VERSION: ${{ needs.Checkout.outputs.python-version }} | |
if: ${{( success() && !cancelled() ) }} | |
steps: | |
- name: Set up Python ${{ env.PYTHON_VERSION }} | |
uses: actions/setup-python@v5 | |
id: install-python | |
with: | |
python-version: ${{ env.PYTHON_VERSION }} | |
- uses: actions/cache/restore@v4 | |
name: Restore run cache | |
id: restore-run-cache | |
with: | |
key: ${{ needs.Checkout.outputs.cache-key-run }} | |
path: ${{ github.workspace }} | |
fail-on-cache-miss: true | |
- name: Test with pyright | |
run: | | |
echo Running pyright | |
VENV=.github-venv \ | |
PYRIGHT_MODE=npm \ | |
DEFAULT_TARGET=cicd \ | |
make test-pyright | |
Pytest: | |
name: Automated testing | |
runs-on: ubuntu-latest | |
needs: | |
- Checkout | |
env: | |
PYTHON_VERSION: ${{ needs.Checkout.outputs.python-version }} | |
if: ${{( success() && !cancelled() ) }} | |
steps: | |
- name: Set up Python ${{ env.PYTHON_VERSION }} | |
uses: actions/setup-python@v5 | |
id: install-python | |
with: | |
python-version: ${{ env.PYTHON_VERSION }} | |
- uses: actions/cache/restore@v4 | |
name: Restore run cache | |
id: restore-run-cache | |
with: | |
key: ${{ needs.Checkout.outputs.cache-key-run }} | |
path: ${{ github.workspace }} | |
fail-on-cache-miss: true | |
- name: Test with pytest and generate reports | |
run: | | |
echo Running pytest | |
VENV=.github-venv \ | |
PYTEST_FLAGS="-k 'not acceptance'" \ | |
DEFAULT_TARGET=cicd \ | |
make test-pytest | |
- name: Output pytest report | |
uses: actions/upload-artifact@v4 | |
if: ${{ always() }} | |
with: | |
name: pytest-and-coverage-report | |
path: | | |
reports/pytest/ | |
retention-days: 1 | |
if-no-files-found: error | |
Bandit: | |
name: SAST scanning | |
runs-on: ubuntu-latest | |
needs: | |
- Checkout | |
env: | |
PYTHON_VERSION: ${{ needs.Checkout.outputs.python-version }} | |
if: ${{( success() && !cancelled() ) }} | |
# FIXME Ignore errors while testing Bandit | |
continue-on-error: true | |
steps: | |
- name: Set up Python ${{ env.PYTHON_VERSION }} | |
uses: actions/setup-python@v5 | |
id: install-python | |
with: | |
python-version: ${{ env.PYTHON_VERSION }} | |
- uses: actions/cache/restore@v4 | |
name: Restore run cache | |
id: restore-run-cache | |
with: | |
key: ${{ needs.Checkout.outputs.cache-key-run }} | |
path: ${{ github.workspace }} | |
fail-on-cache-miss: true | |
- name: Run bandit scan and generate reports | |
run: | | |
echo Running bandit | |
VENV=.github-venv \ | |
DEFAULT_TARGET=cicd \ | |
make test-bandit || BANDIT_EXIT_CODE=$? | |
echo "Bandit exit code: $BANDIT_EXIT_CODE" | |
if [ $BANDIT_EXIT_CODE -ne 0 ]; then | |
echo "::warning title=Bandit::Bandit exit code: $BANDIT_EXIT_CODE" | |
fi | |
- name: Output bandit report artifact | |
uses: actions/upload-artifact@v4 | |
if: ${{ always() }} | |
with: | |
name: bandit-sast-report | |
path: | | |
reports/bandit.sarif | |
retention-days: 1 | |
if-no-files-found: error | |
- name: Upload bandit report to CodeQL | |
uses: github/codeql-action/upload-sarif@v3 | |
with: | |
sarif_file: reports/bandit.sarif | |
Style: | |
name: Style and formatting | |
runs-on: ubuntu-latest | |
needs: | |
- Checkout | |
env: | |
PYTHON_VERSION: ${{ needs.Checkout.outputs.python-version }} | |
if: ${{( success() && !cancelled() ) }} | |
steps: | |
- name: Set up Python ${{ env.PYTHON_VERSION }} | |
uses: actions/setup-python@v5 | |
id: install-python | |
with: | |
python-version: ${{ env.PYTHON_VERSION }} | |
- uses: actions/cache/restore@v4 | |
name: Restore run cache | |
id: restore-run-cache | |
with: | |
key: ${{ needs.Checkout.outputs.cache-key-run }} | |
path: ${{ github.workspace }} | |
fail-on-cache-miss: true | |
- name: Check code style | |
run: | | |
VENV=.github-venv \ | |
DEFAULT_TARGET=cicd \ | |
make test-ruff | |
- name: Check import order | |
run: | | |
VENV=.github-venv \ | |
DEFAULT_TARGET=cicd \ | |
make test-isort | |
Final-status-check: | |
name: Check workflow success | |
runs-on: ubuntu-latest | |
needs: | |
- Checkout | |
- Pyright | |
- Pytest | |
- Bandit | |
- Style | |
# this job should run regardless of success, failure, or skips, | |
# but not if the workflow is cancelled. `always()` ignores cancelled, | |
# and so we check for the cancelled state. | |
if: ${{( always() && !cancelled() ) }} | |
steps: | |
- name: Failure | |
# once the "needs" jobs have completed, if any of them | |
# failed, then the entire workflow is considered failed. | |
if: | | |
contains(toJSON(needs), '"result": "failure"') | |
env: | |
RANDOM_EOF: | | |
EOF`echo $RANDOM` | |
run: | | |
echo One or more required jobs did not complete successfully; | |
jq -r 'keys[] as $job | "Job ID: \($job)'"\n"' \(.[$job] | .result)"' <<${{ env.RANDOM_EOF }} | |
${{ toJSON(needs) }} | |
${{ env.RANDOM_EOF }} | |
exit 1; | |
# TODO consider uploading the repository so errors can be more easily resolved. | |
#- name: Upload repository build | |
# uses: actions/upload-artifact@v3 | |
# with: | |
# name: repository-build | |
# path: ${{ github.workspace }} | |
# retention-days: 1 | |
# if-no-files-found: error | |
- name: Success | |
run: echo Workflow succeeded; exit 0; |