Skip to content

build(deps-dev): bump ruff from 0.15.6 to 0.15.7 #2618

build(deps-dev): bump ruff from 0.15.6 to 0.15.7

build(deps-dev): bump ruff from 0.15.6 to 0.15.7 #2618

Workflow file for this run

name: Pytest
# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#packaging-workflow-data-as-artifacts
on:
pull_request:
paths:
- '**/*.py' # Watch for changes in any Python files
- 'pyproject.toml' # Watch for changes in the pyproject.toml file
- '.github/workflows/pytest.yml'
push:
branches:
- master # Only run on push to master branch
paths:
- '**/*.py' # Watch for changes in any Python files
- 'pyproject.toml' # Watch for changes in the pyproject.toml file
- '.github/workflows/pytest.yml'
workflow_dispatch:
permissions:
contents: read
jobs:
pytest:
if: github.event_name == 'pull_request' || (github.event_name == 'push' && !github.event.pull_request) || github.event_name == 'workflow_dispatch'
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.14"] # to make sure the latest AMC supported python version does not break
include:
- os: ubuntu-latest
python-version: "3.9" # to make sure the minimum AMC supported python version does not break
# this is also the version used to report test coverage, other versions do not report coverage
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
with:
egress-policy: audit
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# https://docs.astral.sh/uv/guides/integration/github/
- name: Install uv and set the Python version
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
with:
python-version: ${{ matrix.python-version }}
activate-environment: true
enable-cache: true
cache-dependency-glob: "pyproject.toml"
- name: Cache apt packages (Linux)
if: matrix.os == 'ubuntu-latest'
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: /var/cache/apt/archives
key: apt-${{ runner.os }}-py${{ matrix.python-version }}-${{ hashFiles('.github/workflows/pytest.yml') }}
restore-keys: |
apt-${{ runner.os }}-py${{ matrix.python-version }}-
apt-${{ runner.os }}-
- name: Install system dependencies for GUI testing on linux
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
# Only install system Tcl/Tk for Python < 3.13 (newer versions bundle their own)
if [[ "${{ matrix.python-version }}" < "3.13" ]]; then
echo "Installing system Tcl/Tk 8.6 for Python ${{ matrix.python-version }}"
sudo apt-get install -y python3-tk tcl8.6 tk8.6 libtcl8.6 libtk8.6
else
echo "Python ${{ matrix.python-version }} uses bundled Tcl/Tk, skipping system packages"
# Only install tools, not Tcl/Tk libraries
sudo apt-get install -y scrot xdotool x11-utils gnome-screenshot
fi
python3 --version && python3 -c "import tkinter; print(tkinter.TclVersion, tkinter.TkVersion)"
- name: Cache Homebrew packages (macOS)
if: matrix.os == 'macos-latest'
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: ~/Library/Caches/Homebrew
key: brew-${{ runner.os }}-python-tk-${{ hashFiles('.github/workflows/pytest.yml') }}
restore-keys: |
brew-${{ runner.os }}-python-tk-
- name: Install system dependencies for GUI testing on macOS
if: matrix.os == 'macos-latest'
run: brew list python-tk &>/dev/null || brew install python-tk
- name: Ensure Tcl/Tk search paths
if: matrix.os == 'ubuntu-latest'
run: |
# Only set Tcl/Tk paths for Python < 3.13
if [[ "${{ matrix.python-version }}" < "3.13" ]]; then
echo "Setting Tcl/Tk paths for Python ${{ matrix.python-version }}"
echo "TCL_LIBRARY=/usr/share/tcltk/tcl8.6" >> $GITHUB_ENV
echo "TK_LIBRARY=/usr/share/tcltk/tk8.6" >> $GITHUB_ENV
else
echo "Python ${{ matrix.python-version }} uses bundled Tcl/Tk, no custom paths needed"
fi
- name: Check Tcl and Tk installed versions
shell: bash
run: |
python --version
python -c "import tkinter; print('Tcl version:', tkinter.TclVersion, 'Tk version:', tkinter.TkVersion)"
- name: Install dependencies (without project)
# Installs all deps from uv.lock into the venv - this layer is cached by setup-uv
shell: bash
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
uv sync --no-install-project --extra dev --extra ci_headless_tests
else
uv sync --no-install-project --extra dev
fi
- name: Install project in editable mode
# Installs only the project itself (no deps) - always runs, but is fast
# without --editable, the coverage report is not generated correctly
run: uv pip install --editable "." --no-deps
- name: Compute SITL cache key
if: matrix.os == 'ubuntu-latest'
run: |
YEAR=$(date +%Y)
MONTH=$(date +%m)
QUARTER=$(( (MONTH-1)/3 + 1 ))
echo "SITL_CACHE_KEY=sitl-cache-ubuntu-${YEAR}-Q${QUARTER}" >> $GITHUB_ENV
- name: Cache SITL files
if: matrix.os == 'ubuntu-latest'
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: sitl/
key: ${{ env.SITL_CACHE_KEY }}
restore-keys: |
sitl-cache-ubuntu-
- name: Download ArduCopter SITL (if available)
if: matrix.os == 'ubuntu-latest'
run: |
# Skip download if the cache was restored (exact or partial hit)
if [ -f "sitl/arducopter" ]; then
echo "Using cached SITL binary"
else
echo "Downloading fresh SITL files"
mkdir -p sitl/
# Download latest ArduCopter SITL from official firmware server
curl -L -o sitl/arducopter https://firmware.ardupilot.org/Copter/latest/SITL_x86_64_linux_gnu/arducopter
curl -L -o sitl/firmware-version.txt https://firmware.ardupilot.org/Copter/latest/SITL_x86_64_linux_gnu/firmware-version.txt
curl -L -o sitl/git-version.txt https://firmware.ardupilot.org/Copter/latest/SITL_x86_64_linux_gnu/git-version.txt
fi
# Make executable and verify
chmod +x sitl/arducopter
ls -la sitl/
# Set environment variables
echo "SITL_BINARY=$(pwd)/sitl/arducopter" >> $GITHUB_ENV
echo "SITL_AVAILABLE=true" >> $GITHUB_ENV
echo "SITL version: $(cat sitl/git-version.txt)"
echo "Firmware version: $(cat sitl/firmware-version.txt)"
continue-on-error: true
- name: Test with pytest
id: pytest
continue-on-error: false
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
export LIBGL_ALWAYS_SOFTWARE=1
export DISPLAY=:99
# disable X authentication
export XAUTHORITY=/dev/null
# disable access control restrictions
Xvfb :99 -screen 0 1024x768x16 -ac &
# ensure Xvfb is fully started before running tests
sleep 2
fi
if [ "$SITL_AVAILABLE" = "true" ]; then
echo "Running tests with SITL support"
uv run pytest --cov=ardupilot_methodic_configurator --cov-report=xml:tests/coverage.xml --md=tests/results-${{ matrix.python-version }}.md --junit-xml=tests/results-junit.xml -m "sitl or not sitl"
else
echo "Running tests without SITL (mocked tests only)"
uv run pytest --cov=ardupilot_methodic_configurator --cov-report=xml:tests/coverage.xml --md=tests/results-${{ matrix.python-version }}.md --junit-xml=tests/results-junit.xml -m "not sitl"
fi
- name: Fix coverage paths
shell: python
run: |
import re, pathlib
p = pathlib.Path("tests/coverage.xml")
content = p.read_text(encoding="utf-8")
# Normalise package name
content = content.replace('<package name="." ', '<package name="ardupilot_methodic_configurator" ')
# Normalise source element
content = re.sub(r"<source>.*?</source>", "<source>.</source>", content, flags=re.DOTALL)
# Normalise filenames: strip any OS-specific absolute/relative prefix
# before the package directory so all legs emit the same relative path
# (e.g. ardupilot_methodic_configurator/foo.py).
# If the marker is absent the filename is left unchanged.
marker = "ardupilot_methodic_configurator/"
def fix_filename(m):
raw = m.group(1).replace("\\", "/")
# Find the LAST occurrence so repeated markers are collapsed too
idx = raw.rfind(marker)
if idx != -1:
raw = raw[idx:]
return f'filename="{raw}"'
content = re.sub(r'filename="([^"]+)"', fix_filename, content)
p.write_text(content, encoding="utf-8")
- name: Display test results as GitHub job summary
run: cat tests/results-${{ matrix.python-version }}.md >> $GITHUB_STEP_SUMMARY
shell: bash
# Use always() to always run this step to publish test results when there are test failures
if: ${{ always() }}
- name: Upload coverage xml report
# Use always() to always run this step to publish test results when there are test failures
if: always()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: coverage-${{ matrix.os }}-${{ matrix.python-version }}-xml
path: tests/*.xml
retention-days: 1
- name: Upload coverage report
# Use always() to always run this step to publish test results when there are test failures
if: always()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: coverage-${{ matrix.os }}-${{ matrix.python-version }}
path: .coverage
include-hidden-files: true
retention-days: 1
- name: Upload coverage to Coveralls (parallel)
# https://docs.coveralls.io/parallel-builds
if: always() && github.repository == 'ArduPilot/MethodicConfigurator'
uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2.3.7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel: true
flag-name: run-${{ matrix.os }}-py${{ matrix.python-version }}
files: tests/coverage.xml
upload_coverage_to_coveralls:
if: always() && github.repository == 'ArduPilot/MethodicConfigurator'
runs-on: ubuntu-latest
needs: pytest
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
with:
egress-policy: audit
- name: Close Coveralls parallel build
# https://docs.coveralls.io/parallel-builds
uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2.3.7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel-finished: true
carryforward: "run-ubuntu-latest-py3.9,run-ubuntu-latest-py3.14,run-windows-latest-py3.14,run-macos-latest-py3.14"
# TODO: create a badge that presents the result of the Upload coverage xml report step
publish-test-results:
if: always()
name: "Publish Tests Results"
runs-on: ubuntu-latest
needs: pytest # This will ensure this job runs after 'pytest'
permissions:
checks: write
# only needed unless run with comment_mode: off
pull-requests: write
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Download Artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: artifacts
- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action@c950f6fb443cb5af20a377fd0dfaa78838901040 # v2.23.0
if: always()
id: test-results
with:
files: "artifacts/**/results-junit.xml"
- name: Set badge color
if: always()
shell: bash
run: |
case ${{ fromJSON( steps.test-results.outputs.json ).conclusion }} in
success)
echo "BADGE_COLOR=31c653" >> $GITHUB_ENV
;;
failure)
echo "BADGE_COLOR=800000" >> $GITHUB_ENV
;;
neutral)
echo "BADGE_COLOR=696969" >> $GITHUB_ENV
;;
esac
- name: Create badge
if: always()
uses: emibcn/badge-action@808173dd03e2f30c980d03ee49e181626088eee8
with:
label: Tests
status: '${{ fromJSON( steps.test-results.outputs.json ).formatted.stats.tests }} tests, ${{ fromJSON( steps.test-results.outputs.json ).formatted.stats.runs }} runs: ${{ fromJSON( steps.test-results.outputs.json ).conclusion }}'
color: ${{ env.BADGE_COLOR }}
path: badge.svg
- name: Upload badge to Gist
# Upload only for master branch
if: >
always() && (github.event_name == 'workflow_run' && github.event.workflow_run.head_branch == 'master' ||
github.event_name != 'workflow_run' && github.ref == 'refs/heads/master')
uses: andymckay/append-gist-action@ab30bf28df67017c7ad696500b218558c7c04db3
with:
token: ${{ secrets.GIST_TOKEN }}
gistURL: https://gist.githubusercontent.com/amilcarlucas/81b511dc0ff92b8072613d1cd100832e
file: badge.svg
- name: Download coverage report
if: needs.pytest.result != 'skipped'
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: coverage-ubuntu-latest-3.9
# https://docs.astral.sh/uv/guides/integration/github/
- name: Install uv and set the Python version
if: needs.pytest.result != 'skipped'
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
with:
python-version: '3.9' # Match with the coverage report Python version
activate-environment: true
enable-cache: true
cache-dependency-glob: "pyproject.toml"
- name: Install coverage
if: needs.pytest.result != 'skipped'
run: uv pip install "coverage==7.10.7"
- name: Check coverage
if: needs.pytest.result != 'skipped'
shell: bash
run: |
# Check if pytest job failed
if [ "${{ needs.pytest.result }}" == "failure" ]; then
echo "Pytest failed - failing coverage check"
exit 1
fi
coverage report --fail-under=89
add_coverage_to_pullrequest:
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && (success() || failure())
runs-on: ubuntu-latest
needs: pytest # This will ensure this job runs after 'pytest'
permissions:
contents: read
pull-requests: write
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
with:
egress-policy: audit
- name: Download coverage xml report
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: coverage-ubuntu-latest-3.9-xml
- name: Get Cover
uses: orgoro/coverage@3f13a558c5af7376496aa4848bf0224aead366ac # v3.2
with:
coverageFile: coverage.xml
token: ${{ secrets.GITHUB_TOKEN }}
thresholdAll: 0.89