diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 45433d0..eb93077 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,10 +22,10 @@ jobs: steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Setup uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v7 with: cache-dependency-glob: "**/pyproject.toml" @@ -43,10 +43,10 @@ jobs: shell: bash steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Setup uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v7 with: enable-cache: false @@ -73,10 +73,10 @@ jobs: shell: bash steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Setup uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v7 with: cache-dependency-glob: "**/pyproject.toml" python-version: ${{ matrix.python-version }} @@ -85,6 +85,17 @@ jobs: run: uv sync --all-extras - name: Install modflow executables + id: install_modflow + continue-on-error: true + uses: modflowpy/install-modflow-action@v1 + with: + path: ${{ github.workspace }}/autotest + repo: modflow6-nightly-build + + # the download reaches out to github and occasionally has its + # connection reset, failing the job before any test runs + - name: Install modflow executables (retry) + if: steps.install_modflow.outcome == 'failure' uses: modflowpy/install-modflow-action@v1 with: path: ${{ github.workspace }}/autotest @@ -113,10 +124,10 @@ jobs: shell: bash steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Setup uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v7 with: cache-dependency-glob: "**/pyproject.toml" python-version: ${{ matrix.python-version }} @@ -125,6 +136,18 @@ jobs: run: uv sync --all-extras - name: Install modflow executables + id: install_modflow + continue-on-error: true + uses: modflowpy/install-modflow-action@v1 + with: + path: ${{ github.workspace }}/autotest + repo: executables + tag: "14.0" + + # the download reaches out to github and occasionally has its + # connection reset, failing the job before any test runs + - name: Install modflow executables (retry) + if: steps.install_modflow.outcome == 'failure' uses: modflowpy/install-modflow-action@v1 with: path: ${{ github.workspace }}/autotest @@ -138,7 +161,7 @@ jobs: - name: Run autotests working-directory: ./autotest shell: bash -l {0} - run: pytest -v -n auto -m "not mf6" + run: uv run pytest -v -n auto -m "not mf6" autotest_mf6_examples: name: modflowapi mf6 examples autotests @@ -154,10 +177,10 @@ jobs: shell: bash steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Setup uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v7 with: cache-dependency-glob: "**/pyproject.toml" python-version: ${{ matrix.python-version }} @@ -166,6 +189,17 @@ jobs: run: uv sync --all-extras - name: Install modflow6 nightly build + id: install_modflow + continue-on-error: true + uses: modflowpy/install-modflow-action@v1 + with: + path: ${{ github.workspace }}/autotest + repo: modflow6-nightly-build + + # the download reaches out to github and occasionally has its + # connection reset, failing the job before any test runs + - name: Install modflow6 nightly build (retry) + if: steps.install_modflow.outcome == 'failure' uses: modflowpy/install-modflow-action@v1 with: path: ${{ github.workspace }}/autotest diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..54368a2 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,43 @@ +name: pull request + +on: + pull_request: + types: [opened, edited, reopened, synchronize] + branches: [develop] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + + title: + name: check title + # the release and reset pull requests are opened by a bot and are not + # squash merged, so their titles do not reach the changelog + if: github.event.pull_request.user.type != 'Bot' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + + - name: Check conventional commit format + env: + TITLE: ${{ github.event.pull_request.title }} + run: | + # pull requests are squash merged, so the title becomes the commit + # message in develop, and the changelog is generated from those + # messages. a title that is not a conventional commit is dropped + # from the release notes without warning. + types="build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test" + if [[ ! "$TITLE" =~ ^($types)(\([^\)]+\))?!?:\ .+ ]]; then + echo "::error::'$TITLE' is not a conventional commit header." + echo "" + echo "Use '(): ', for example:" + echo " feat(runner): support adaptive time step retries" + echo "" + echo "Type is one of: ${types//|/, }." + echo "Only feat, fix, perf and refactor reach the release notes;" + echo "see cliff.toml. A user facing change needs one of those." + exit 1 + fi + echo "'$TITLE' is a conventional commit header" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d34cfd4..9701e71 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,13 +65,13 @@ jobs: fi - name: Checkout source branch - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: ref: ${{ github.event_name == 'workflow_dispatch' && inputs.branch || github.ref_name }} fetch-depth: 0 - name: Setup uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v7 with: cache-dependency-glob: "**/pyproject.toml" @@ -104,14 +104,25 @@ jobs: uv run scripts/update_version.py -v "${{ steps.version.outputs.version }}" uv run python -c "import modflowapi; print('Version: ', modflowapi.__version__)" - - name: Lint and format + - name: Check style run: | - uvx ruff check --fix . - uvx ruff format . + uvx ruff check . + uvx ruff format --check . uvx codespell - name: Install modflow executables if: ${{ github.event_name != 'workflow_dispatch' || inputs.run_tests }} + id: install_modflow + continue-on-error: true + uses: modflowpy/install-modflow-action@v1 + with: + path: ${{ github.workspace }}/autotest + repo: modflow6-nightly-build + + # the download reaches out to github and occasionally has its + # connection reset, failing the job before any test runs + - name: Install modflow executables (retry) + if: ${{ (github.event_name != 'workflow_dispatch' || inputs.run_tests) && steps.install_modflow.outcome == 'failure' }} uses: modflowpy/install-modflow-action@v1 with: path: ${{ github.workspace }}/autotest @@ -167,7 +178,7 @@ jobs: git config core.sharedRepository true git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A + git add version.txt modflowapi/version.py CITATION.cff HISTORY.md git commit -m "ci(release): set version to $ver, update changelog" git push origin "v$ver" @@ -200,7 +211,7 @@ jobs: steps: - name: Checkout main branch - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: ref: main fetch-depth: 0 @@ -251,12 +262,12 @@ jobs: steps: - name: Checkout main branch - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: ref: main - name: Setup uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v7 with: enable-cache: false @@ -267,7 +278,7 @@ jobs: run: uvx twine check --strict dist/* - name: Upload package - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: dist path: dist @@ -290,13 +301,13 @@ jobs: steps: - name: Checkout main branch - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: ref: main fetch-depth: 0 - name: Setup uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v7 with: cache-dependency-glob: "**/pyproject.toml" @@ -317,7 +328,7 @@ jobs: git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git switch -c "$branch" - git add -A + git add version.txt modflowapi/version.py CITATION.cff git commit -m "ci(release): update version to $next" git push origin "$branch" diff --git a/.gitignore b/.gitignore index 3bc7727..7d0274a 100644 --- a/.gitignore +++ b/.gitignore @@ -142,6 +142,15 @@ uv.lock # temporary test folders autotest/temp/** +# modflow executables installed for testing +autotest/mf6 +autotest/mf5to6 +autotest/zbud6 +autotest/libmf6.* +autotest/mf6.exe +autotest/mf5to6.exe +autotest/zbud6.exe + # notebooks docs/examples/notebooks/*.ipynb diff --git a/CITATION.cff b/CITATION.cff index 89ae30a..147e7bf 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -3,8 +3,8 @@ message: If you use this software, please cite both the article from preferred-c and the software itself. type: software title: MODFLOW API -version: 1.0.0 -date-released: '2026-09-05' +version: 1.0.1 +date-released: '2026-09-06' abstract: An extension to xmipy for the MODFLOW API. repository-artifact: https://pypi.org/project/modflowapi repository-code: https://github.com/MODFLOW-ORG/modflowapi diff --git a/HISTORY.md b/HISTORY.md index 65c762e..10b71ff 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,4 +1,10 @@ # Changelog +### Version 1.0.1 + +#### Bug fixes + +* [fix(dependencies)](https://github.com/MODFLOW-ORG/modflowapi/commit/adbfd151b14861360fbb9fb67f48bcff87f7d43f): Require a pandas that supports numpy 2 (#118). Committed by Joseph Hughes on 2026-09-06. + ### Version 1.0.0 This is the first stable release. modflowapi now follows semantic versioning, so a breaking change to the `modflowapi` or `modflowapi.extensions` interface will increment the major version. The Python interface is unchanged from 0.2.0, but Python 3.9 and 3.10 are no longer supported; Python 3.11 or later is required. diff --git a/autotest/mf5to6 b/autotest/mf5to6 deleted file mode 100755 index 1e394e7..0000000 Binary files a/autotest/mf5to6 and /dev/null differ diff --git a/autotest/mf6 b/autotest/mf6 deleted file mode 100755 index 0cd4524..0000000 Binary files a/autotest/mf6 and /dev/null differ diff --git a/autotest/zbud6 b/autotest/zbud6 deleted file mode 100755 index c37c1b1..0000000 Binary files a/autotest/zbud6 and /dev/null differ diff --git a/guide-to-publish.md b/guide-to-publish.md index e6b70bc..70a9a34 100644 --- a/guide-to-publish.md +++ b/guide-to-publish.md @@ -4,6 +4,14 @@ Releases are automated by [`.github/workflows/release.yml`](.github/workflows/re Publishing to PyPI uses [trusted publishing](https://docs.pypi.org/trusted-publishers/), so no API token is needed, but the repository must have a `release` environment configured. +> [!IMPORTANT] +> PyPI matches a trusted publisher on the organisation name, the repository name, the workflow +> filename and the environment name. Renaming any of them silently invalidates the publisher, and +> nothing reports it until the next release fails with `invalid-publisher`. This happened when the +> organisation was renamed from `MODFLOW-USGS` to `MODFLOW-ORG`, and went unnoticed for the +> eighteen months until the next release. After any such rename, update the publisher at +> https://pypi.org/manage/project/modflowapi/settings/publishing/ to match. + ## 1. Start the release From the [Actions tab](https://github.com/MODFLOW-ORG/modflowapi/actions/workflows/release.yml), @@ -46,7 +54,16 @@ Merge the reset pull request to finish the release. ## Changelog conventions -Release notes are generated from commit messages, so commits merged to `develop` should follow the +Release notes are generated from commit messages, so commits merged to `develop` must follow the [conventional commits](https://www.conventionalcommits.org/) format (`feat:`, `fix:`, `refactor:`, -etc.). Commits that do not follow the convention are omitted from the changelog. See -[`cliff.toml`](cliff.toml) for the commit groups and which ones are skipped. +etc.). Commits that do not follow the convention are omitted from the changelog without warning. +See [`cliff.toml`](cliff.toml) for the commit groups and which ones are skipped. + +Pull requests are squash merged, so the title becomes the commit message the notes are generated +from. [`.github/workflows/pull_request.yml`](.github/workflows/pull_request.yml) rejects a title +that is not a conventional commit header, but it cannot tell whether the type is the right one: a +user facing change titled `chore:` still passes the check and is still dropped from the notes. + +Read the generated changelog on the release pull request before merging it. Anything missing is +added there, into the section for the version being cut, not to `develop`; the section does not +exist until the release workflow generates it. diff --git a/modflowapi/version.py b/modflowapi/version.py index 0272270..f229cbb 100644 --- a/modflowapi/version.py +++ b/modflowapi/version.py @@ -1,3 +1,3 @@ # modflowapi version file automatically created using...update_version.py -# created on...September 05, 2026 12:54:22 -__version__ = "1.0.0" +# created on...September 06, 2026 12:36:39 +__version__ = "1.0.1" diff --git a/pyproject.toml b/pyproject.toml index 1714cf1..054124b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ classifiers = [ requires-python = ">=3.11" dependencies = [ "numpy>=1.23", - "pandas>=1.5", + "pandas>=2.2.2", "xmipy>=1.5.0", ] diff --git a/version.txt b/version.txt index afaf360..7f20734 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.0 \ No newline at end of file +1.0.1 \ No newline at end of file