Skip to content

Python package test #325

Python package test

Python package test #325

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.10", "3.11", "3.12", "3.13"]
container: ghcr.io/osgeo/gdal:ubuntu-small-latest
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 }} [${{ matrix.split }}/4]"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
split: [1, 2, 3, 4]
container: ghcr.io/osgeo/gdal:ubuntu-small-latest
steps:
- name: ⚡ Prepare Container
run: |
apt-get update
apt-get install -y curl git gpg
# Fix "Dubious Ownership" error (Required for containerized Git)
git config --global --add safe.directory '*'
- uses: actions/checkout@v4
- name: 📥 Download Requirements
uses: actions/download-artifact@v4
with:
name: frozen-reqs-${{ matrix.python-version }}
- name: ⚡ Install uv
run: |
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 (Split ${{ matrix.split }}/4)
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 }}
CDSE_S3_ACCESS_KEY: ${{ secrets.CDSE_S3_ACCESS_KEY }}
CDSE_S3_ACCESS_SECRET: ${{ secrets.CDSE_S3_ACCESS_SECRET }}
CURL_CA_BUNDLE: /etc/ssl/certs/ca-certificates.crt
COVERAGE_FILE: .coverage.python.${{ matrix.python-version }}.test.split.${{ matrix.split }}
run: |
uv run pytest -v \
--splits 4 \
--group ${{ matrix.split }} \
--cov=mapchete_eo \
--cov-report=xml:coverage.xml \
--junitxml="pytest-${{ matrix.python-version }}-${{ matrix.split }}.xml"
- name: 📊 Upload to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
flags: py${{ matrix.python-version }}-split${{ matrix.split }}
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-chunk-${{ matrix.split }}
path: .coverage.python.${{ matrix.python-version }}.test.split.${{ matrix.split }}
include-hidden-files: true
retention-days: 1
- name: 📤 Archive JUnit Results
if: always()
uses: actions/upload-artifact@v4
with:
name: results-${{ matrix.python-version }}-${{ matrix.split }}
path: pytest-${{ matrix.python-version }}-${{ matrix.split }}.xml
retention-days: 1
summary:
name: "📊 Final Summary & Coverage"
needs: test
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
if [[ "${{ needs.test.result }}" != "success" ]]; then
echo "❌ **Test Suite Failed**" >> $GITHUB_STEP_SUMMARY
exit 1
fi
uv tool install coverage
if ls all-results/.coverage* 1> /dev/null 2>&1; then
mv all-results/.coverage* .
fi
cat <<EOF > .coveragerc
[run]
relative_files = True
[paths]
source =
.
/__w/mapchete-eo/mapchete-eo/
EOF
echo "Merging coverage files with path remapping..."
# 2️⃣ COMBINE & REPORT
# We use the rcfile to ensure the mapping is applied during the merge
uv tool run coverage combine --append --rcfile=.coveragerc || echo "No extra coverage files to combine."
# ENFORCE 85% (or your chosen threshold)
REPORT_OUTPUT=$(uv tool run coverage report --show-missing --fail-under=85 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 85%." >> $GITHUB_STEP_SUMMARY
exit $EXIT_CODE
else
echo "✅ **Coverage Passed:** 85% coverage achieved (Py3.13)." >> $GITHUB_STEP_SUMMARY
fi