From de29047e9013f4c62492f1837b578a7f06ccf5db Mon Sep 17 00:00:00 2001 From: Romulo Quidute Filho <116586593+rquidute@users.noreply.github.com> Date: Tue, 9 Jun 2026 17:36:37 -0300 Subject: [PATCH 1/2] Add CI workflow to run pytest on every PR (#95) * Add CI workflow to run pytest on every PR Adds .github/workflows/python-tests.yml which: - Triggers on all pull requests (any target branch) - Sets up Python 3.10 and installs dependencies via Poetry (with venv cache) - Runs ./scripts/run_pytest.py (existing test runner) - Fails if coverage drops below 85% (enforced by pyproject.toml) - Uploads coverage.xml and htmlcov/ as artifacts on every run Tracks: https://github.com/project-chip/certification-tool/issues/1020 Co-Authored-By: Claude Opus 4.8 * Fix CI: bump action versions to v4/v5 actions/upload-artifact@v3 was deprecated and disabled by GitHub in November 2024, causing the job setup to fail before any steps ran. Bump all actions to their current major versions: - actions/checkout: v3 -> v4 - actions/setup-python: v4 -> v5 - actions/cache: v3 -> v4 - actions/upload-artifact: v3 -> v4 Co-Authored-By: Claude Opus 4.8 * Fix CI: correct test runner script name (run_pytest.sh not .py) Co-Authored-By: Claude Opus 4.8 * Fix failing test and align coverage threshold with actual coverage - Fix test_test_run_execution_log_whitespace_content: Click prepends a DeprecationWarning line when invoking a deprecated option (--log). Strip DeprecationWarning lines before asserting on output content. - Lower --cov-fail-under from 85 to 65 to match the actual coverage achieved by the current test suite (65.54%). The 85% target was aspirational and not yet reached; using it as a hard gate would permanently block CI on every PR. Co-Authored-By: Claude Opus 4.8 * Fix CI: use Python 3.12 to match development environment Python 3.10's unittest.mock._dot_lookup resolves dotted patch paths differently from 3.12: it walks the path with getattr, finds the imported Click Command object at 'th_cli.commands.abort_testing' (due to 'from .abort_testing import abort_testing' in __init__.py), and then fails trying to get 'get_client' off the Command object. Python 3.12 correctly resolves the patch target via sys.modules, finding the module rather than the imported name. All tests pass locally on 3.12; switching CI to match eliminates the AttributeError failures across all command modules. Co-Authored-By: Claude Opus 4.8 * Revert coverage threshold back to 85% Co-Authored-By: Claude Opus 4.8 --------- Co-authored-by: Claude Opus 4.8 --- .github/workflows/python-tests.yml | 48 ++++++++++++++++++++++++++++++ tests/test_test_run_execution.py | 6 +++- 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/python-tests.yml diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml new file mode 100644 index 0000000..7c9d550 --- /dev/null +++ b/.github/workflows/python-tests.yml @@ -0,0 +1,48 @@ +name: Python Tests + +on: + pull_request: + +jobs: + run-tests: + name: Run unit tests + runs-on: ubuntu-latest + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-create: true + virtualenvs-in-project: true + installer-parallel: true + + - name: Load cached venv + id: cached-poetry-dependencies + uses: actions/cache@v4 + with: + path: .venv + key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} + + - name: Install dependencies + if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' + run: poetry install --no-interaction --no-root + + - name: Run tests + run: ./scripts/run_pytest.sh + + - name: Upload coverage report + uses: actions/upload-artifact@v4 + if: always() + with: + name: coverage-report + path: | + coverage.xml + htmlcov/ diff --git a/tests/test_test_run_execution.py b/tests/test_test_run_execution.py index f66c251..3b6141b 100644 --- a/tests/test_test_run_execution.py +++ b/tests/test_test_run_execution.py @@ -693,8 +693,12 @@ def test_test_run_execution_log_whitespace_content( # Assert assert result.exit_code == 0 + # Click prepends a DeprecationWarning line for deprecated options; strip it before comparing + output_without_warning = "\n".join( + line for line in result.output.splitlines() if not line.startswith("DeprecationWarning:") + ) # Should still output the whitespace content as-is - assert result.output.strip() == log_content.rstrip() + assert output_without_warning.strip() == log_content.rstrip() def test_test_run_execution_log_generic_exception( self, From a8102a028a7064f32b72764a0f00b04edbf4d1da Mon Sep 17 00:00:00 2001 From: Steven Green Date: Fri, 21 Aug 2026 10:18:08 -0700 Subject: [PATCH 2/2] Re-enable linting action (#102) * Re-enable linting action Also changes install script to exclude dev dependencies. * update action versions * remove accidentally included changes --- .github/workflows/python-lint.yml | 16 ++++----------- .github/workflows/python-tests.yml | 3 ++- .github/workflows/upload-test-results.yml | 20 +++++++++++++++++++ scripts/th_cli_install.sh | 2 +- .../camera/test_two_way_talk_handler.py | 1 - th_cli/commands/run_tests.py | 9 ++++++++- 6 files changed, 35 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/upload-test-results.yml diff --git a/.github/workflows/python-lint.yml b/.github/workflows/python-lint.yml index c133224..2ef93db 100644 --- a/.github/workflows/python-lint.yml +++ b/.github/workflows/python-lint.yml @@ -2,11 +2,6 @@ name: Python Linting on: pull_request: - branches: - - develop - push: - branches: - - develop jobs: run-linters: @@ -15,16 +10,13 @@ jobs: steps: - name: Check out Git repository - uses: actions/checkout@v3 + uses: actions/checkout@v7 - name: Set up Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v6 with: python-version: "3.10" - - name: Install Python dependencies - run: pip install black flake8 mypy pydantic types-requests - - name: Install Poetry uses: snok/install-poetry@v1 with: @@ -34,7 +26,7 @@ jobs: - name: Load cached venv id: cached-poetry-dependencies - uses: actions/cache@v2 + uses: actions/cache@v6 with: path: .venv key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} @@ -44,7 +36,7 @@ jobs: run: poetry install --no-interaction --no-root - name: Run linters - uses: wearerequired/lint-action@v1 + uses: wearerequired/lint-action@v2 with: github_token: ${{ secrets.github_token }} # Enable linters diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 7c9d550..c68bc82 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -36,7 +36,7 @@ jobs: run: poetry install --no-interaction --no-root - name: Run tests - run: ./scripts/run_pytest.sh + run: ./scripts/run_pytest.sh --junitxml=report.xml - name: Upload coverage report uses: actions/upload-artifact@v4 @@ -45,4 +45,5 @@ jobs: name: coverage-report path: | coverage.xml + report.xml htmlcov/ diff --git a/.github/workflows/upload-test-results.yml b/.github/workflows/upload-test-results.yml new file mode 100644 index 0000000..f9ce2e7 --- /dev/null +++ b/.github/workflows/upload-test-results.yml @@ -0,0 +1,20 @@ +name: 'Test Report' +on: + workflow_run: + workflows: ['Python Tests'] + types: + - completed +permissions: + contents: read + actions: read + checks: write +jobs: + report: + runs-on: ubuntu-latest + steps: + - uses: dorny/test-reporter@v3 + with: + artifact: coverage-report + name: Python Tests + path: 'report.xml' + reporter: python-xunit \ No newline at end of file diff --git a/scripts/th_cli_install.sh b/scripts/th_cli_install.sh index c8568a7..30d0d0b 100755 --- a/scripts/th_cli_install.sh +++ b/scripts/th_cli_install.sh @@ -70,7 +70,7 @@ if ! command -v poetry &> /dev/null; then exit 1 fi poetry self update -poetry --project="$PROJECT_ROOT" install +poetry --project="$PROJECT_ROOT" install --without dev # Build the package echo "Building package..." diff --git a/tests/test_run/camera/test_two_way_talk_handler.py b/tests/test_run/camera/test_two_way_talk_handler.py index 2b610e5..d7009e3 100644 --- a/tests/test_run/camera/test_two_way_talk_handler.py +++ b/tests/test_run/camera/test_two_way_talk_handler.py @@ -25,7 +25,6 @@ import pytest -import th_cli.test_run.camera.two_way_talk_handler as _module from th_cli.test_run.camera.two_way_talk_handler import TwoWayTalkHandler, TwoWayTalkHTTPHandler # --------------------------------------------------------------------------- diff --git a/th_cli/commands/run_tests.py b/th_cli/commands/run_tests.py index 1ba7405..918ac7c 100644 --- a/th_cli/commands/run_tests.py +++ b/th_cli/commands/run_tests.py @@ -42,7 +42,14 @@ from th_cli.exceptions import CLIError, handle_api_error from th_cli.test_run.camera.two_way_talk_handler import TwoWayTalkHandler from th_cli.test_run.websocket import TestRunSocket -from th_cli.utils import DEFAULT_CLI_PROJECT_NAME, build_test_selection, convert_nested_to_dict, load_json_config, merge_configs, read_pics_config +from th_cli.utils import ( + DEFAULT_CLI_PROJECT_NAME, + build_test_selection, + convert_nested_to_dict, + load_json_config, + merge_configs, + read_pics_config, +) from th_cli.validation import validate_directory_path, validate_file_path, validate_test_ids # Constants