Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 3 additions & 14 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,8 @@ on:
required: true
type: string
default: 'develop'
bump:
description: 'Version increment relative to the latest release tag. Ignored if a version number is given below.'
required: true
type: choice
default: 'minor'
options:
- minor
- patch
- major
- dev
version:
description: 'Version number to release, e.g. 0.3.0. Overrides the increment selected above.'
description: "Version number to release, e.g. 0.3.0. Defaults to version.txt with its development suffix removed."
required: false
type: string
run_tests:
Expand Down Expand Up @@ -86,7 +76,7 @@ jobs:
if [[ -n "${{ inputs.version }}" ]]; then
ver="${{ inputs.version }}"
else
ver=$(uv run scripts/update_version.py --get --bump "${{ inputs.bump }}")
ver=$(uv run scripts/update_version.py --release --dry-run)
fi
else
# release branch name is the version number, prefixed with 'v'
Expand Down Expand Up @@ -332,8 +322,7 @@ jobs:
ver="${{ needs.release.outputs.version }}"
branch="post-release-$ver-reset"

next=$(uv run scripts/update_version.py --get --next-dev)
uv run scripts/update_version.py -v "$next"
next=$(uv run scripts/update_version.py --post-release)

git config core.sharedRepository true
git config user.name "github-actions[bot]"
Expand Down
177 changes: 177 additions & 0 deletions DEVELOPER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# Developing `modflowapi`

This document explains how to set up a development environment, run the tests, and cut a release.
Conventions used in the project are noted along the way.

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->


- [Requirements](#requirements)
- [Installation](#installation)
- [Linting](#linting)
- [Testing](#testing)
- [MODFLOW executables and example models](#modflow-executables-and-example-models)
- [Running the tests](#running-the-tests)
- [Releasing](#releasing)
- [1. Start the release](#1-start-the-release)
- [2. Review and approve](#2-review-and-approve)
- [3. Automatic steps](#3-automatic-steps)
- [4. conda-forge](#4-conda-forge)
- [Changelog conventions](#changelog-conventions)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Requirements

Python 3.11+. Like the other MODFLOW Python projects, `modflowapi` aims to support recent Python
versions, loosely following [SPEC 0](https://scientific-python.org/specs/spec-0000/#support-window).

## Installation

Fork and clone the repository, then install the project in editable mode with the development
dependencies:

```shell
pip install -e . --group dev
```

Developers who use `uv` can sync the project instead:

```shell
uv sync --all-extras
```

The `dev` group includes the `test` and `lint` groups.

## Linting

Linting and formatting use [`ruff`](https://docs.astral.sh/ruff/), and spelling is checked with
[`codespell`](https://github.com/codespell-project/codespell):

```shell
ruff check .
ruff format .
codespell
```

These are also run in CI and must pass.

## Testing

The tests use [`pytest`](https://docs.pytest.org/) with
[`pytest-xdist`](https://pytest-xdist.readthedocs.io/) and fixtures from
[`modflow-devtools`](https://github.com/MODFLOW-ORG/modflow-devtools). They live in `autotest/` and
are run from that directory.

### MODFLOW executables and example models

The tests need the MODFLOW 6 executables, including the `libmf6` shared library, either on the
`PATH` or installed into `autotest/`. They also need the MODFLOW 6 example models. Both can be
fetched with the `mf` command from `modflow-devtools`:

```shell
mf programs install libmf6 --bindir autotest
mf sync
```

FloPy's [`get-modflow`](https://github.com/modflowpy/flopy) utility is an alternative way to install
the executables. See [`.github/workflows/ci.yml`](.github/workflows/ci.yml) for exactly what CI
installs, including the nightly build used for the example-model tests.

### Running the tests

From `autotest/`, run in parallel with verbose output:

```shell
pytest -v -n auto
```

Two markers select subsets of the suite (see [`autotest/pytest.ini`](autotest/pytest.ini)):

- `mf6`: tests that run the MODFLOW 6 example models
- `extensions`: tests for the `modflowapi` extensions

For instance, to skip the example-model tests: `pytest -v -n auto -m "not mf6"`.

## Releasing

Releases are automated by [`.github/workflows/release.yml`](.github/workflows/release.yml).
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`. 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),
select **Run workflow** and fill in the form:

| Input | Description |
|:--|:--|
| `branch` | Branch to release from. Defaults to `develop`. |
| `version` | Explicit version number, e.g. `0.3.0`. Defaults to the version in `version.txt` with its `.dev` suffix removed. |
| `run_tests` | Run the test suite before drafting the release. Defaults to true. |

This can also be done from the command line, for instance:

```shell
gh workflow run release.yml -f branch=develop
```

The release version is normally the development version already set in `version.txt` (e.g.
`1.2.0.dev0` releases as `1.2.0`); pass `version` only to release something else. The workflow
creates a `v<version>` release branch, updates the version number, regenerates the changelog with
[git-cliff](https://git-cliff.org/), runs the tests, and opens a draft pull request into `main`.

A release can alternatively be started by pushing a release branch named `v<major>.<minor>.<patch>`.

### 2. Review and approve

Review the release pull request, in particular `HISTORY.md`. Mark it ready for review and merge it
into `main`. Merge rather than squash, to preserve the commit history.

### 3. Automatic steps

Merging the release pull request into `main` triggers jobs that:

1. tag the release and create a GitHub release, with notes taken from `HISTORY.md`
2. build the package and publish it to [PyPI](https://pypi.org/project/modflowapi)
3. open a follow-up pull request resetting `develop` from `main`, with the version number
incremented to the next development version

Merge the reset pull request to finish the release.

### 4. conda-forge

A few hours after the upload to PyPI, a bot opens a version pull request on the
[feedstock](https://github.com/conda-forge/modflowapi-feedstock). To start it immediately instead,
open an issue there titled `@conda-forge-admin, please update version`.

> [!IMPORTANT]
> The bot updates the version number and the checksum, and nothing else. **Check the recipe's
> `host` and `run` requirements against the dependencies the release actually declares**, which are
> the `Requires-Dist` lines of the sdist on PyPI. A maintainer can push corrections to the bot's branch.

Merging the feedstock pull request builds and uploads the package. It does not appear to a solver
until the channel index is regenerated, which takes up to about an hour; the package is visible on
anaconda.org before then.

### Changelog conventions

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 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, and make any necessary
edits to the section for the version being cut.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ An extension to [xmipy](https://pypi.org/project/xmipy/) for the [MODFLOW API](h
- [Introduction](#introduction)
- [Installation](#installation)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [Citation](#citation)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
Expand Down Expand Up @@ -61,6 +62,11 @@ Examples using `modflowapi` and its extensions can be found in the [Quickstart](

For more info on MODFLOW 6 see [the USGS overview](https://water.usgs.gov/ogw/modflow/).

## Contributing

See [DEVELOPER.md](DEVELOPER.md) for how to set up a development environment, run the tests, and
cut a release.

## Citation

Hughes, Joseph D., Russcher, M. J., Langevin, C. D., Morway, E. D. and McDonald, R. R., 2022, The MODFLOW Application Programming Interface for simulationcontrol and software interoperability: Environmental Modelling & Software, v. 148, p. 105257, [doi:10.1016/j.envsoft.2021.105257](https://doi.org/10.1016/j.envsoft.2021.105257).
Expand Down
86 changes: 0 additions & 86 deletions guide-to-publish.md

This file was deleted.

Loading