Python package test #193
This file contains hidden or 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: Python package test | |
| on: | |
| schedule: | |
| - cron: '0 8 * * 1,4' | |
| push: | |
| branches: [main] | |
| tags: ['*'] | |
| pull_request: | |
| branches: ['**'] | |
| workflow_call: | |
| inputs: | |
| override-deps-artifact: | |
| description: "Name of artifact containing updated lockfiles" | |
| required: false | |
| type: string | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| lint: | |
| name: "📝 Pre-commit / Code Quality" | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: ⚡ Install uv | |
| run: curl -LsSf https://astral.sh/uv/install.sh | sh | |
| - name: 🏃 Run Pre-commit | |
| run: | | |
| uv tool install pre-commit | |
| uv tool run pre-commit run --show-diff-on-failure --all-files | |
| setup: | |
| name: "🏗️ Build Py${{ matrix.python-version }}" | |
| needs: lint | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python-version: ["3.11", "3.12", "3.13"] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: 📥 Apply Dependency Overrides | |
| if: "${{ inputs.override-deps-artifact != '' && inputs.override-deps-artifact != 'null' }}" | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ${{ inputs.override-deps-artifact }} | |
| - name: ⚡ Install uv | |
| run: | | |
| apt-get update && apt-get install -y curl | |
| curl -LsSf https://astral.sh/uv/install.sh | BINDIR=/usr/local/bin sh | |
| - name: 📝 Export Locked Requirements | |
| run: | | |
| uv export --frozen --all-extras --format requirements-txt > requirements.txt | |
| - name: 📤 Upload Requirements | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: frozen-reqs-${{ matrix.python-version }} | |
| path: requirements.txt | |
| retention-days: 1 | |
| test: | |
| needs: setup | |
| name: "🧪 py${{ matrix.python-version }}" | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ["3.11", "3.12", "3.13"] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: 📥 Download Requirements | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: frozen-reqs-${{ matrix.python-version }} | |
| - name: ⚡ Install uv, git & GIS Dependencies | |
| run: | | |
| sudo apt-add-repository -y ppa:ubuntugis/ubuntugis-unstable | |
| sudo apt-get update | |
| sudo apt-get install -y curl git gpg gdal-bin libgdal-dev libproj-dev libgeos-dev g++ | |
| curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR="/usr/local/bin" sh | |
| uv --version | |
| - name: 🏗️ Restore Native Env | |
| run: | | |
| uv venv --python ${{ matrix.python-version }} | |
| uv pip install -r requirements.txt | |
| uv pip install -e ".[test]" --no-deps | |
| - name: 🧪 Run Tests | |
| env: | |
| AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| AWS_REQUEST_PAYER: ${{ vars.AWS_REQUEST_PAYER }} | |
| AWS_DEFAULT_REGION: ${{ vars.AWS_DEFAULT_REGION }} | |
| CURL_CA_BUNDLE: /etc/ssl/certs/ca-certificates.crt | |
| COVERAGE_FILE: .coverage.python.${{ matrix.python-version }} | |
| run: | | |
| uv run pytest -v \ | |
| --cov=mapchete_hub \ | |
| --cov-report=xml:coverage.xml \ | |
| --junitxml="pytest-${{ matrix.python-version }}.xml" | |
| - name: 📊 Upload to Codecov | |
| uses: codecov/codecov-action@v5 | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| files: ./coverage.xml | |
| flags: py${{ matrix.python-version }} | |
| fail_ci_if_error: true | |
| - name: 📤 Upload Coverage Chunk (Latest Only) | |
| if: matrix.python-version == '3.13' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-all | |
| path: .coverage.python.${{ matrix.python-version }} | |
| include-hidden-files: true | |
| retention-days: 1 | |
| - name: 📤 Archive JUnit Results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: results-${{ matrix.python-version }} | |
| path: pytest-${{ matrix.python-version }}.xml | |
| retention-days: 1 | |
| integration-tests: | |
| name: "🚀 Integration Tests" | |
| needs: setup | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: 🏃 Run Integration Tests | |
| run: | | |
| chmod +x ./run_integration_tests.sh | |
| ./run_integration_tests.sh | |
| build-docker-image: | |
| name: "🐳 Docker Build & CLI Check" | |
| if: github.event_name == 'pull_request' | |
| needs: setup | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: ⚡ Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: 🏗️ Build image for validation | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| push: false | |
| load: true | |
| tags: mapchete-hub:test | |
| - name: 🏃 Run CLI checks | |
| run: | | |
| docker run --rm mapchete-hub:test mhub-server --help | |
| docker run --rm mapchete-hub:test mhub-manager --help | |
| docker run --rm mapchete-hub:test mhub-worker --help | |
| summary: | |
| name: "📊 Final Summary & Coverage" | |
| needs: [test, integration-tests, build-docker-image] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 # Needed for coverage to see source files | |
| - name: ⚡ Install uv | |
| run: curl -LsSf https://astral.sh/uv/install.sh | sh | |
| - name: 📥 Download Artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: all-results | |
| pattern: "*-*" | |
| merge-multiple: true | |
| - name: 📊 Check Tests & Coverage | |
| run: | | |
| echo "### 🧪 Test & Coverage Summary" >> $GITHUB_STEP_SUMMARY | |
| # 1. CHECK OVERALL TEST STATUS | |
| if [[ "${{ needs.test.result }}" != "success" || "${{ needs.integration-tests.result }}" != "success" || ( "${{ github.event_name }}" == "pull_request" && "${{ needs.build-docker-image.result }}" != "success" ) ]]; then | |
| echo "❌ **Test Suite Failed**" >> $GITHUB_STEP_SUMMARY | |
| echo "- Unit/Doc Tests: ${{ needs.test.result }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- Integration Tests: ${{ needs.integration-tests.result }}" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ github.event_name }}" == "pull_request" ]]; then | |
| echo "- Docker Build: ${{ needs.build-docker-image.result }}" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "Coverage check skipped because tests failed." >> $GITHUB_STEP_SUMMARY | |
| exit 1 | |
| fi | |
| echo "✅ **Test Suite Passed**" >> $GITHUB_STEP_SUMMARY | |
| echo "- Unit/Doc Tests: Passed" >> $GITHUB_STEP_SUMMARY | |
| echo "- Integration Tests: Passed" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ github.event_name }}" == "pull_request" ]]; then | |
| echo "- Docker Build: Passed" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "- Docker Build: Skipped (Not a PR)" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # 2. PREPARE COVERAGE DATA | |
| uv tool install coverage | |
| if ls all-results/.coverage* 1> /dev/null 2>&1; then | |
| mv all-results/.coverage* . | |
| fi | |
| echo "Merging/Preparing coverage data..." | |
| # combine will merge .coverage.* into .coverage | |
| uv tool run coverage combine --append || echo "No extra coverage files to combine." | |
| # 3. ENFORCE 70% | |
| REPORT_OUTPUT=$(uv tool run coverage report --show-missing --fail-under=70 2>&1) | |
| EXIT_CODE=$? | |
| echo "$REPORT_OUTPUT" | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| echo "$REPORT_OUTPUT" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| if [ $EXIT_CODE -ne 0 ]; then | |
| echo "❌ **Coverage Failed:** Python 3.13 coverage is below 70%." >> $GITHUB_STEP_SUMMARY | |
| exit $EXIT_CODE | |
| else | |
| echo "✅ **Coverage Passed:** 70% coverage achieved (Py3.13)." >> $GITHUB_STEP_SUMMARY | |
| fi |