Skip to content

Refactor(pyavd)!: Make sort_key mandatory in natural_sort when sortin… #944

Refactor(pyavd)!: Make sort_key mandatory in natural_sort when sortin…

Refactor(pyavd)!: Make sort_key mandatory in natural_sort when sortin… #944

---
name: "Collection code testing"
"on":
pull_request:
merge_group:
types: [checks_requested]
push:
branches:
- devel
concurrency:
# For PRs the head_ref will be used. For Merge Queues (merge_group) we fallback to run_id.
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
# Set -vvv is ACTIONS_STEP_DEBUG is set
# Apparently it is set in secrets when running with debug
ANSIBLE_VERBOSITY: ${{ secrets.ACTIONS_STEP_DEBUG && 3 || 0 }}
AVD_NEVER_RUN_FROM_SOURCE: 1
PY_COLORS: 1 # allows molecule colors to be passed to GitHub Actions
ANSIBLE_FORCE_COLOR: 1 # allows ansible colors to be passed to GitHub Actions
jobs:
required-checks: # Added in github settings as a required check before merge. This ensures that CI finishes before merge queue is merged.
needs:
- python_type_checking
- python_requirements
- molecule_eos_cli_config_gen
- molecule_eos_designs
- molecule_eos_designs_minimum_requirements
- molecule_anta_runner
- ansible_test_sanity
- ansible_test_units
- ansible_test_integration
- galaxy_importer
- ansible_lint
- test_pyavd
if: always()
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: echo '${{ toJSON(needs) }}' | jq -e 'to_entries | all(.value.result == "success" or .value.result == "skipped")'
file-changes:
runs-on: ubuntu-latest
outputs:
eos_design: ${{ steps.filter.outputs.eos_design }}
config_gen: ${{ steps.filter.outputs.config_gen }}
pyavd: ${{ steps.filter.outputs.pyavd }}
requirements: ${{ steps.filter.outputs.requirements }}
anta_runner: ${{ steps.filter.outputs.anta_runner }}
steps:
- uses: actions/checkout@v6
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
eos_design:
- 'ansible_collections/arista/avd/roles/eos_designs/*'
- 'ansible_collections/arista/avd/roles/eos_designs/**/*'
- '.github/workflows/pull-request-management.yml'
- 'ansible_collections/arista/avd/extensions/molecule/*'
- 'ansible_collections/arista/avd/extensions/molecule/**/*'
- 'python-avd/pyavd/_eos_designs/*'
- 'python-avd/pyavd/_eos_designs/**/*'
config_gen:
- 'ansible_collections/arista/avd/roles/eos_cli_config_gen/*'
- 'ansible_collections/arista/avd/roles/eos_cli_config_gen/**/*'
- '.github/workflows/pull-request-management.yml'
- 'ansible_collections/arista/avd/extensions/molecule/eos_cli_config_gen*/*'
- 'ansible_collections/arista/avd/extensions/molecule/eos_cli_config_gen*/**/*'
- 'python-avd/pyavd/_eos_cli_config_gen/*'
- 'python-avd/pyavd/_eos_cli_config_gen/**/*'
plugins:
- 'ansible_collections/arista/avd/plugins/filter/**'
- 'ansible_collections/arista/avd/plugins/test/**'
requirements:
- 'ansible_collections/arista/avd/requirements.txt'
- 'ansible_collections/arista/avd/meta/runtime.yml'
- 'ansible_collections/arista/avd/requirements.yml'
- '.github/workflows/pull-request-management.yml'
- 'sonar-project.properties'
- '.pre-commit-config.yaml'
pyavd:
- 'python-avd/**/*'
anta_runner:
- 'ansible_collections/arista/avd/roles/anta_runner/*'
- 'ansible_collections/arista/avd/roles/anta_runner/**/*'
- 'python-avd/pyavd/_anta/*'
- 'python-avd/pyavd/_anta/**/*'
- 'python-avd/pyavd/api/_anta/*'
- 'python-avd/pyavd/api/_anta/**/*'
- 'python-avd/pyavd/get_device_anta_catalog.py'
# -------------------------------------- #
# Build PyAVD wheel and upload artifact
# -------------------------------------- #
build_pyavd:
name: Build pyavd
runs-on: ubuntu-latest
outputs:
wheel_file: ${{ steps.build_step.outputs.wheel_file }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: |
3.12
- name: Create pyavd wheel and output wheel path
id: build_step
working-directory: ./python-avd
run: |
pip install build
python -m build --wheel
WHEEL_FILE=$(find ./dist/*.whl -print0 -type f | xargs -0 -n 1 basename)
echo "wheel_file=/tmp/pyavd/$WHEEL_FILE" >> "$GITHUB_OUTPUT"
- name: Upload pyavd artifact
uses: actions/upload-artifact@v6
with:
name: pyavd
path: ./python-avd/dist/*.whl
# -------------------------------------------- #
# Python type checking not covered in pre-commit
# -------------------------------------------- #
python_type_checking:
name: Python Linting not covered in pre-commit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install pyavd and Ansible requirements
run: |
pip install --group dev --upgrade
- name: PyRight static type checker
# Specific SHA as allowed by github org admins
uses: jakebailey/pyright-action@6cabc0f01c4994be48fd45cd9dbacdd6e1ee6e5e
# ----------------------------------- #
# Test Requirements
# ----------------------------------- #
python_requirements:
name: Test Python requirements installation
runs-on: ubuntu-latest
needs: [build_pyavd, file-changes]
if: needs.file-changes.outputs.requirements == 'true'
strategy:
fail-fast: true
matrix:
python_version:
- "3.10"
- "3.11"
- "3.12"
- "3.13"
steps:
- uses: actions/checkout@v6
- name: Set up Python 3
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python_version }}
- name: Download pyavd Artifact
uses: actions/download-artifact@v7
with:
name: pyavd
path: /tmp/pyavd/
- name: "Install Python requirements"
run: |
pip install "${{ needs.build_pyavd.outputs.wheel_file }}" --group dev --upgrade
# ----------------------------------- #
# EOS CLI CONFIG GEN MOLECULE
# ----------------------------------- #
molecule_eos_cli_config_gen:
name: Validate eos_cli_config_gen
runs-on: ubuntu-latest
needs: [build_pyavd, file-changes]
if: |
needs.file-changes.outputs.config_gen == 'true' ||
needs.file-changes.outputs.requirements == 'true' ||
github.event_name == 'merge_group'
strategy:
fail-fast: true
matrix:
avd_scenario:
- "eos_cli_config_gen"
- "eos_cli_config_gen_deprecated_vars"
- "eos_cli_config_gen_negative_unit_tests"
ansible_version:
- "ansible-core<2.20.0"
# Also test minimum ansible version for one scenario.
include:
- avd_scenario: "eos_cli_config_gen"
ansible_version: "ansible-core==2.16.0"
steps:
- uses: actions/checkout@v6
- name: Download pyavd Artifact
uses: actions/download-artifact@v7
with:
name: pyavd
path: /tmp/pyavd/
- name: Set up Python 3.11
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install pyavd and Ansible requirements
run: |
python -m pip install "${{ matrix.ansible_version}}" "${{ needs.build_pyavd.outputs.wheel_file }}[ansible-collection]" --group molecule
- name: Run molecule test
working-directory: ansible_collections/arista/avd
run: |
molecule test --scenario-name ${{ matrix.avd_scenario }}
- name: Check GIT status
run: |
sh .github/check-git-status.sh
# ----------------------------------- #
# EOS Design MOLECULE
# ----------------------------------- #
molecule_eos_designs:
name: Validate eos_designs
runs-on: ubuntu-latest
needs: [build_pyavd, file-changes]
if: |
needs.file-changes.outputs.eos_design == 'true' ||
needs.file-changes.outputs.config_gen == 'true' ||
needs.file-changes.outputs.requirements == 'true' ||
github.event_name == 'merge_group'
strategy:
fail-fast: true
matrix:
avd_scenario:
- "ansible_only"
- "digital_twin"
- "eos_designs_deprecated_vars"
- "eos_designs-l2ls"
- "eos_designs-mpls-isis-sr-ldp"
- "eos_designs-twodc-5stage-clos"
- "eos_designs_unit_tests"
- "evpn_underlay_ebgp_overlay_ebgp"
- "evpn_underlay_isis_overlay_ibgp"
- "evpn_underlay_ospf_overlay_ebgp"
- "evpn_underlay_rfc5549_overlay_ebgp"
- "example-campus-fabric"
- "example-dual-dc-l3ls"
- "example-isis-ldp-ipvpn"
- "example-l2ls-fabric"
- "example-single-dc-l3ls"
- "example-single-dc-l3ls-ipv6"
- "example-cv-pathfinder"
ansible_version:
- "ansible-core>=2.16.0,<2.20.0"
include:
- avd_scenario: "eos_designs_negative_unit_tests"
# Testing with 2.16.x, due to bug with in 2.17.0 with and the way we test eos_designs_negative_unit_tests https://github.com/ansible/ansible/issues/83292
ansible_version: "ansible-core<2.17.0"
- avd_scenario: "eos_designs_unit_tests"
ansible_version: "ansible-core<2.17.0"
- avd_scenario: "eos_designs_unit_tests"
ansible_version: "ansible-core<2.18.0"
- avd_scenario: "eos_designs_unit_tests"
ansible_version: "ansible-core<2.19.0"
steps:
- uses: actions/checkout@v6
- name: Download pyavd Artifact
uses: actions/download-artifact@v7
with:
name: pyavd
path: /tmp/pyavd/
- name: Set up Python 3.11
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install pyavd and Ansible requirements
run: |
python -m pip install "${{ matrix.ansible_version}}" "${{ needs.build_pyavd.outputs.wheel_file }}[ansible-collection]" --group molecule
- name: Run molecule test
working-directory: ansible_collections/arista/avd
run: |
molecule test --scenario-name ${{ matrix.avd_scenario }}
- name: Check GIT status
run: |
sh .github/check-git-status.sh
molecule_eos_designs_minimum_requirements:
name: Validate eos_designs with minimum requirements
runs-on: ubuntu-latest
needs: [build_pyavd, file-changes]
if: needs.file-changes.outputs.eos_design == 'true' || needs.file-changes.outputs.config_gen == 'true' || needs.file-changes.outputs.requirements == 'true' ||
github.event_name == 'merge_group'
steps:
- uses: actions/checkout@v6
- name: Download pyavd Artifact
uses: actions/download-artifact@v7
with:
name: pyavd
path: /tmp/pyavd/
- name: Use Python 3.10 for minimum requirements
uses: actions/setup-python@v6
with:
python-version: |
3.10
- name: Install pyavd and Ansible minimum requirements
# Installing molecule and requirements in different pip command because of jsonschema>=3.2.0 in AVD is incompatible
# with jsonschema>=4.9.1 in molecule when using pip compile with lowest
# Need to delete min_requirements afterwards otherwise git status is sad
# pip upgrade to get dependency groups
run: |
pip install uv
uv pip compile python-avd/pyproject.toml --extra ansible-collection --resolution lowest-direct > /tmp/pyavd/min_requirements.txt
cat /tmp/pyavd/min_requirements.txt
pip install pip --upgrade
python -m pip install --group molecule
python -m pip install "ansible-core==2.16.0" "${{ needs.build_pyavd.outputs.wheel_file }}[ansible-collection]" -r /tmp/pyavd/min_requirements.txt
- name: Run molecule test
working-directory: ansible_collections/arista/avd
run: |
molecule test --scenario-name eos_designs_unit_tests
- name: Check GIT status
run: |
sh .github/check-git-status.sh
# ----------------------------------- #
# ANTA Runner MOLECULE
# ----------------------------------- #
molecule_anta_runner:
name: Validate anta_runner
runs-on: ubuntu-latest
needs: [build_pyavd, file-changes]
if: |
needs.file-changes.outputs.eos_design == 'true' ||
needs.file-changes.outputs.anta_runner == 'true' ||
needs.file-changes.outputs.requirements == 'true' ||
github.event_name == 'merge_group'
strategy:
fail-fast: true
matrix:
avd_scenario:
- "anta_runner"
ansible_version:
- "ansible-core<2.20.0"
include:
- avd_scenario: "anta_runner"
ansible_version: "ansible-core==2.16.0"
steps:
- uses: actions/checkout@v6
- name: Download pyavd Artifact
uses: actions/download-artifact@v7
with:
name: pyavd
path: /tmp/pyavd/
- name: Set up Python 3.11
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install pyavd and Ansible requirements
run: |
python -m pip install "${{ matrix.ansible_version}}" "${{ needs.build_pyavd.outputs.wheel_file }}[ansible-collection]" --group molecule
- name: Run molecule test
working-directory: ansible_collections/arista/avd
run: |
molecule test --scenario-name ${{ matrix.avd_scenario }}
- name: Check GIT status
run: |
sh .github/check-git-status.sh
# ----------------------------------- #
# Ansible tests
# ----------------------------------- #
ansible_test_sanity:
name: Run ansible-test sanity validation
runs-on: ubuntu-latest
needs: [build_pyavd, file-changes]
strategy:
fail-fast: true
matrix:
ansible_version: [stable, devel]
include:
- ansibe_version: stable
pip_installation: "ansible-core<2.20.0"
- ansibe_version: devel
pip_installation: "--user https://github.com/ansible/ansible/archive/devel.tar.gz"
skip_test: "--skip-test ansible-doc"
steps:
- uses: actions/checkout@v6
- name: Set up Python 3
uses: actions/setup-python@v6
with:
python-version: |
3.10
3.11
3.12
3.13
- name: Download pyavd Artifact
uses: actions/download-artifact@v7
with:
name: pyavd
path: /tmp/pyavd/
- name: Install pyavd and Ansible requirements
run: |
pip install ${{ matrix.pip_installation }} "${{ needs.build_pyavd.outputs.wheel_file }}[ansible-collection]"
- name: Run ansible-test sanity
working-directory: ansible_collections/arista/avd
# Skip ansible-doc due to testing with ansible-core @ devel and raising error on supported Ansible version
run: |
ansible-test sanity --color yes -v ${{ matrix.skip_test }}
ansible_test_units:
name: Run ansible-test units test cases
runs-on: ubuntu-latest
needs: [file-changes, build_pyavd]
steps:
- uses: actions/checkout@v6
- name: Set up Python 3
uses: actions/setup-python@v6
with:
python-version: |
3.12
- name: Download pyavd Artifact
uses: actions/download-artifact@v7
with:
name: pyavd
path: /tmp/pyavd/
- name: Install pyavd and ansible requirements
run: |
pip install "ansible-core<2.20.0" "${{ needs.build_pyavd.outputs.wheel_file }}[ansible-collection]"
- name: Run ansible-test units
working-directory: ansible_collections/arista/avd
run: |
ansible-test units --coverage --requirements -vv
ansible-test coverage xml
mv tests/output/reports/coverage.xml ./units-coverage.xml
- name: Upload coverage from ansible-test units
uses: actions/upload-artifact@v6
with:
name: ansible-test-units-coverage
path: ansible_collections/arista/avd/units-coverage.xml
ansible_test_integration:
name: Run ansible-test integration test cases
runs-on: ubuntu-latest
needs: [file-changes]
steps:
- uses: actions/checkout@v6
- name: Set up Python 3
uses: actions/setup-python@v6
with:
# Testing 3.10 to ensure ansible-core < 2.19 still works.
python-version: |
3.10
3.12
3.13
- name: Install Python requirements
run: |
pip install "ansible-core<2.20.0" "./python-avd[ansible-collection]" --upgrade
- name: Run ansible-test integration test cases
working-directory: ansible_collections/arista/avd
run: |
ansible-test integration --coverage --requirements -vv
ansible-test coverage xml
mv tests/output/reports/coverage.xml ./integration-coverage.xml
- name: Upload coverage from ansible-test integration
uses: actions/upload-artifact@v6
with:
name: ansible-test-integration-coverage
path: ansible_collections/arista/avd/integration-coverage.xml
# ----------------------------------- #
# Build Collection
# ----------------------------------- #
build_collection:
name: Build Ansible collection
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v6
with:
python-version: |
3.12
- uses: actions/checkout@v6
- name: Install Python & Ansible requirements
run: |
# distlib is required when using manifest
pip install "ansible-core<2.20.0" distlib --upgrade
- name: Build Ansible collection
run: |
ansible-galaxy collection build -vvv --force ansible_collections/arista/avd
- name: Upload collection
uses: actions/upload-artifact@v6
with:
name: avd-collection
path: ./arista-avd-*.tar.gz
# ----------------------------------- #
# Galaxy Importer
# ----------------------------------- #
galaxy_importer:
name: Test galaxy-importer
runs-on: ubuntu-latest
needs: [build_collection]
steps:
- uses: actions/setup-python@v6
with:
python-version: |
3.11
- uses: actions/checkout@v6
- name: Install Python & Ansible requirements
run: |
pip install "ansible-core==2.16.0"
- name: Download collection
uses: actions/download-artifact@v7
with:
name: avd-collection
- name: Install galaxy-importer
# Install the specific version of galaxy-importer used on galaxy.ansible.com
# The version conflicts with our requirements,
# so we let the galaxy-importer version resolve remaining requirements.
run: |
pip install "galaxy-importer==0.4.31"
- name: Run galaxy-importer checks
run: python -m galaxy_importer.main *.tar.gz
- uses: actions/upload-artifact@v6
with:
name: importer-logs
path: ./importer_result.json
# ----------------------------------- #
# Ansible Lint
# Run on the built collection from Galaxy importer
# ----------------------------------- #
ansible_lint:
name: Run ansible-lint test case
runs-on: ubuntu-latest
needs: [file-changes, build_pyavd]
env:
ANSIBLE_COLLECTIONS_PATH: ${{ github.workspace }}
steps:
- uses: actions/checkout@v6
- name: Set up Python 3
uses: actions/setup-python@v6
with:
python-version: |
3.10
3.11
3.12
3.13
- name: Download pyavd Artifact
uses: actions/download-artifact@v7
with:
name: pyavd
path: /tmp/pyavd/
- name: Install Python & Ansible requirements
run: |
pip install "${{ needs.build_pyavd.outputs.wheel_file }}[ansible-collection]" --group dev --upgrade
- name: Download collection
uses: actions/download-artifact@v7
with:
name: avd-collection
- name: Extract collection
run: |
mkdir collections
tar xvzf arista-avd-*.tar.gz -C collections
- name: Run ansible-lint
working-directory: collections
run: |
ansible-lint --force-color --strict -v
# ----------------------------------- #
# Test of pyavd
# ----------------------------------- #
test_pyavd:
name: Test pyavd (Python ${{ matrix.python }}, Suite ${{ matrix.suite.name }})
runs-on: ubuntu-latest
needs: [file-changes]
if: |
needs.file-changes.outputs.eos_design == 'true' ||
needs.file-changes.outputs.config_gen == 'true' ||
needs.file-changes.outputs.pyavd == 'true' ||
needs.file-changes.outputs.requirements == 'true' ||
github.event_name == 'merge_group'
strategy:
fail-fast: false
matrix:
python: ["3.10", "3.11", "3.12", "3.13"]
suite:
- name: "Main-Tests"
id: Main-Tests
pytest_args: >-
--ignore=python-avd/tests/pyavd/molecule_scenarios/test_get_device_config.py
--ignore=python-avd/tests/pyavd/molecule_scenarios/test_negative_eos_designs.py
--ignore=python-avd/tests/schema_tools/metaschema/test_meta_schema_model.py
upload_compiled_templates: true
- name: "Excluded-Tests (test_get_device_config and test_meta_schema_model)"
id: Excluded-test_get_device_config-and-test_meta_schema_model
pytest_args: >-
python-avd/tests/pyavd/molecule_scenarios/test_get_device_config.py
python-avd/tests/schema_tools/metaschema/test_meta_schema_model.py
- name: "Excluded-Tests (test_negative_eos_designs)"
id: Excluded-test_negative_eos_designs
pytest_args: >-
python-avd/tests/pyavd/molecule_scenarios/test_negative_eos_designs.py
steps:
- uses: actions/checkout@v6
- name: Set up Python 3
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
- name: Install tox
run: |
pip install tox tox-gh-actions --upgrade
- name: Run pytest via tox for ${{ matrix.python }}
run: |
tox run -- ${{ matrix.suite.pytest_args }}
- name: Rename the coverage file
if: matrix.python == '3.11'
run: |
mv .coverage coverage-${{ matrix.suite.id }}.dat
- name: Upload pytest coverage data
if: matrix.python == '3.11'
uses: actions/upload-artifact@v6
with:
name: coverage-data-${{ matrix.suite.id }}
path: coverage-${{ matrix.suite.id }}.dat
- name: Upload eos_designs compiled templates from pytest
if: matrix.suite.upload_compiled_templates == true && matrix.python == '3.11'
uses: actions/upload-artifact@v6
with:
name: pytest-eos-designs-compiled-templates
path: python-avd/pyavd/_eos_designs/j2templates/compiled_templates/
- name: Upload eos_cli_config_gen compiled templates from pytest
if: matrix.suite.upload_compiled_templates == true && matrix.python == '3.11'
uses: actions/upload-artifact@v6
with:
name: pytest-eos-cli-config-gen-compiled-templates
path: python-avd/pyavd/_eos_cli_config_gen/j2templates/compiled_templates/
generate_pyavd_coverage_report:
name: Test pyavd python 3.11 coverage report
runs-on: ubuntu-latest
needs: [test_pyavd]
steps:
- uses: actions/checkout@v6
- name: Set up Python 3.11
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install coverage
run: pip install --group coverage
- name: Download coverage artifacts
uses: actions/download-artifact@v7
with:
pattern: coverage-data-*
merge-multiple: true
- name: Download eos_designs compiled templates artifact
uses: actions/download-artifact@v7
with:
name: pytest-eos-designs-compiled-templates
path: python-avd/pyavd/_eos_designs/j2templates/compiled_templates/
- name: Download eos_cli_config_gen compiled templates artifact
uses: actions/download-artifact@v7
with:
name: pytest-eos-cli-config-gen-compiled-templates
path: python-avd/pyavd/_eos_cli_config_gen/j2templates/compiled_templates/
- name: Combine and report test coverage
run: |
set -ex
coverage combine coverage-*.dat
coverage report
coverage xml
- name: Upload pytest coverage report
uses: actions/upload-artifact@v6
with:
name: pytest-coverage
path: coverage.xml