diff --git a/.github/workflows/upstream-dev-ci.yml b/.github/workflows/upstream-dev-ci.yml new file mode 100644 index 00000000..326f1377 --- /dev/null +++ b/.github/workflows/upstream-dev-ci.yml @@ -0,0 +1,111 @@ +# Test VirtualShip against the unreleased `main` branch of Parcels, to catch breaking changes. +# Environment is defined in `ci/upstream/pixi.toml`. On scheduled runs, failures open (or update) a GitHub issue. +name: CI (for upstream Parcels main) + +on: + schedule: + - cron: "0 0 * * 1" # 00:00 UTC every Monday + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -el {0} + +env: + FORCE_COLOR: 3 + +permissions: {} + +jobs: + cache-pixi-lock: + if: github.repository == 'Parcels-code/virtualship' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + cache-key: ${{ steps.pixi-lock.outputs.cache-key }} + pixi-version: ${{ steps.pixi-lock.outputs.pixi-version }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: Parcels-code/pixi-lock/create-and-cache@1fab4c17af8243f6ca1321bc941cf2325f46c05d # v0.1.1 + id: pixi-lock + with: + manifest-path: ci/upstream/pixi.toml + hash-files: | + ci/upstream/pixi.toml + pyproject.toml + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: pixi-lock-upstream + path: ci/upstream/pixi.lock + + upstream-dev: + name: "Upstream tests: pixi run --manifest-path ci/upstream/pixi.toml tests-upstream" + runs-on: ubuntu-latest + needs: cache-pixi-lock + permissions: + contents: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 # setuptools_scm needs the git history to version the editable install + persist-credentials: false + - uses: Parcels-code/pixi-lock/restore@1fab4c17af8243f6ca1321bc941cf2325f46c05d # v0.1.1 + with: + cache-key: ${{ needs.cache-pixi-lock.outputs.cache-key }} + manifest-path: ci/upstream/pixi.toml + - uses: prefix-dev/setup-pixi@d3f436a425481402e6a95a1d1fc10331c708cd9e # v0.10.2 + with: + manifest-path: ci/upstream/pixi.toml + cache: false + pixi-version: ${{ needs.cache-pixi-lock.outputs.pixi-version }} + + - name: Version info + run: | + pixi list --manifest-path ci/upstream/pixi.toml parcels + pixi run --manifest-path ci/upstream/pixi.toml python -c 'import parcels; print(f"parcels {parcels.__version__}")' + + - name: Run tests + id: status + if: ${{ !cancelled() }} # run even if the import check fails, so a report log is produced for the issue + run: >- + pixi run --manifest-path ci/upstream/pixi.toml tests-upstream + --timeout=120 + --report-log output-upstream-dev-log.jsonl + + - name: Upload test results + if: ${{ failure() && steps.status.outcome == 'failure' }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: output-upstream-dev-log + path: output-upstream-dev-log.jsonl + retention-days: 5 + + create-issue: + name: Create issue on failure + needs: upstream-dev + if: | + always() + && needs.upstream-dev.result == 'failure' + && github.event_name == 'schedule' + && github.repository == 'Parcels-code/virtualship' + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: output-upstream-dev-log + - name: Generate and publish the report + uses: scientific-python/issue-from-pytest-log-action@35b4e0a9e06f8e7e261778289cf4b968b722662d # v1.6.2 + with: + log-path: output-upstream-dev-log.jsonl + issue-title: "⚠️ CI against Parcels main failed ⚠️" + issue-label: automated + assignees: erikvansebille diff --git a/.gitignore b/.gitignore index 7a3285aa..79bc8fbb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ .pixi/* !.pixi/config.toml pixi.lock +ci/upstream/.pixi/ +output-upstream-dev-log.jsonl # Byte-compiled / optimized / DLL files diff --git a/ci/upstream/pixi.toml b/ci/upstream/pixi.toml new file mode 100644 index 00000000..7c4b4f7a --- /dev/null +++ b/ci/upstream/pixi.toml @@ -0,0 +1,64 @@ +# Environment for testing VirtualShip against the unreleased `main` branch of Parcels (weekly) + +[workspace] +name = "VirtualShip upstream" +channels = ["conda-forge"] +platforms = ["linux-64", "osx-arm64"] +exclude-newer = "5d" # security pre-caution against compromised packages (does not apply to the git override) +requires-pixi = ">=0.82.1" + +[dependencies] +python = "3.14.*" +# VirtualShip run dependencies, pre-installed as conda packages (keep in sync with `pyproject.toml`) +click = "*" +pyproj = ">=3,<4" +sortedcontainers = "==2.4.0" +opensimplex = "==0.4.5" +numpy = ">=2.1.0" +pydantic = ">=2,<3" +pyyaml = "*" +copernicusmarine = ">=2.2.2" +yaspin = "*" +textual = "*" +# Parcels run dependencies, pre-installed as conda packages to avoid PyPI source builds +# If Parcels `main` adds a dependency that isn't listed here, it is installed from PyPI +cf_xarray = "*" +cftime = "*" +dask = "*" +netcdf4 = "*" +pandas = "*" +polars = "*" +pooch = "*" +pyarrow = "*" +tabulate = "*" +tqdm = "*" +uxarray = "*" +xarray = "*" +zarr = ">=3.0.0" +# downstream uxarray deps (see root `pixi.toml`) +numba = ">=0.59.0" +healpix = "*" +cartopy = "*" +shapely = "*" +geopandas = "*" +scipy = "*" + +[pypi-dependencies] +virtualship = { path = "../..", editable = true } + +[pypi-options.dependency-overrides] +parcels = { git = "https://github.com/Parcels-code/Parcels", branch = "main" } + +[feature.test.dependencies] +pytest = "*" +pytest-asyncio = "*" +pytest-reportlog = "*" # required: issue-from-pytest-log-action consumes the pytest report log +pytest-timeout = "*" +seabird = "*" +openpyxl = "*" + +[feature.test.tasks] +tests-upstream = { cmd = "pytest -m 'not network'", cwd = "../..", description = "Run the test suite (excluding tests that call external services) against Parcels main" } + +[environments] +default = { features = ["test"] }