diff --git a/.github/workflows/test-geotiff-corpus.yml b/.github/workflows/test-geotiff-corpus.yml new file mode 100644 index 000000000..8451ce3a7 --- /dev/null +++ b/.github/workflows/test-geotiff-corpus.yml @@ -0,0 +1,89 @@ +name: pytest-geotiff-corpus +on: + push: + branches: + - main + pull_request: + branches: + - '*' + # Nightly cron so the full corpus (slow lane included) runs at + # least once a day against rasterio from conda-forge. PR runs stay + # on the fast lane via `-m "not slow"`. See issue #2289 for why + # this workflow exists separately from `test.yml`: the geotiff + # golden_corpus tests all start with `pytest.importorskip("rasterio")`, + # and the pip-based job in `test.yml` cannot install rasterio + # reliably across the OS matrix because of the GDAL build chain. + # GitHub Actions only fires `schedule` triggers on the workflow + # file in the default branch -- use `workflow_dispatch` for an + # on-demand run from a feature branch. + schedule: + # 03:30 UTC daily. Offset from `test.yml` (03:00) so the two + # nightlies do not contend for runner capacity at the same time. + - cron: '30 3 * * *' + workflow_dispatch: + +jobs: + run: + runs-on: ${{ matrix.os }} + # PR runs stick to ubuntu only to keep CI cost down; the nightly + # / push-to-main runs widen to macos + windows so the parity + # oracle exercises the full OS matrix against rasterio. + strategy: + fail-fast: false + matrix: + os: ${{ github.event_name == 'pull_request' && fromJson('["ubuntu-latest"]') || fromJson('["ubuntu-latest", "macos-latest", "windows-latest"]') }} + python: ${{ github.event_name == 'pull_request' && fromJson('["3.14"]') || fromJson('["3.12", "3.14"]') }} + defaults: + run: + # `-el` so micromamba's activation hooks fire and `rasterio` + # resolves to the conda-forge env in every step. + shell: bash -el {0} + steps: + - uses: actions/checkout@v4 + - name: Set up micromamba env (conda-forge rasterio + GDAL) + uses: mamba-org/setup-micromamba@v1 + with: + environment-name: xrspatial-geotiff + create-args: >- + python=${{ matrix.python }} + rasterio + gdal + pyyaml + tifffile + condarc: | + channels: + - conda-forge + channel_priority: strict + cache-environment: true + - name: Install xrspatial (test extras) + run: | + python -m pip install --upgrade pip + pip install -e .[tests] + - name: Verify rasterio still imports after pip step + # `pip install -e .[tests]` can pull PyPI wheels (pyproj, numpy) on + # top of the conda-forge env and shadow the GDAL/proj stack that + # rasterio links against. Re-import here so a broken env fails + # this step with a clear message instead of mid-pytest. + run: | + python -c "import sys, rasterio, numpy; print('python', sys.version.split()[0]); print('rasterio', rasterio.__version__); print('gdal', rasterio.__gdal_version__); print('numpy', numpy.__version__)" + - name: Run geotiff golden_corpus tests (fast lane) + # PR triggers run the fast lane: `-m "not slow"` deselects the + # heavier corpus cells tagged via `_marks.fast_slow_marks_for`. + # push-to-main and the nightly schedule run the full set. + # Target is scoped to `golden_corpus/` to match the issue (#2289); + # broader geotiff integration tests stay on the `test.yml` job. + # + # `test_corpus_determinism.py` is deselected here: it asserts md5 + # equality between committed fixtures and bytes regenerated by + # `generate.py`, which depends on the exact GDAL / libjpeg the + # corpus was produced against. Conda-forge ships different + # versions than the developer machine that originally built the + # fixtures (today: COG-with-overview and JPEG-YCbCr drift), so + # this check is fundamentally toolchain-coupled. Tracking the + # cleanup in a follow-up issue; the oracle and nodata tests -- + # which compare semantic output, not byte exactness -- still run. + if: github.event_name == 'pull_request' + run: pytest xrspatial/geotiff/tests/golden_corpus/ -m "not slow" --ignore=xrspatial/geotiff/tests/golden_corpus/test_corpus_determinism.py + - name: Run geotiff golden_corpus tests (full) + if: github.event_name != 'pull_request' + run: pytest xrspatial/geotiff/tests/golden_corpus/ --ignore=xrspatial/geotiff/tests/golden_corpus/test_corpus_determinism.py