-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #216 from EC-USGS/v0.2.0
Release 0.2.0
- Loading branch information
Showing
205 changed files
with
246,287 additions
and
9,496 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,3 @@ | ||
[metadata] | ||
name = pywatershed | ||
version = attr: pywatershed.version.__version__ | ||
description = pywatershed is a hydrologic model | ||
long_description = pywatershed is a Python package for hydrologic modeling | ||
long_description_content_type = text/markdown | ||
author = USGS Enterprise Capacity Team | ||
author_email = [email protected] | ||
maintainer = James McCreight | ||
maintainer_email = [email protected] | ||
license = CC0 | ||
license_files = LICENSE, LICENSE.md | ||
platform = Mac OS-X, Linux | ||
keywords = PRMS, hydrology | ||
classifiers = | ||
Development Status :: 5 - Production/Stable | ||
Intended Audience :: Science/Research | ||
License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication | ||
Programming Language :: Python | ||
Programming Language :: Python :: 3 :: Only | ||
Topic :: Scientific/Engineering :: Hydrology | ||
url = https://github.com/EC-USGS/prmsNHMpy | ||
download_url = https://pypi.org/project/pywatershed | ||
project_urls = | ||
Bug Tracker = https://github.com/EC-USGS/pywatershed/issues | ||
Source Code = https://github.com/EC-USGS/pywatershed | ||
|
||
[options] | ||
include_package_data = True # includes files listed in MANIFEST.in | ||
zip_safe = False | ||
packages = find: | ||
python_requires = >=3.7 | ||
install_requires = | ||
epiweeks | ||
netCDF4 | ||
networkx | ||
numpy | ||
numba | ||
pandas | ||
pyyaml | ||
xarray | ||
|
||
[options.package_data] | ||
pywatershed = | ||
static/metadata/*.yaml | ||
|
||
[sdist] | ||
formats = zip | ||
|
||
[flake8] | ||
exclude = | ||
.git | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<!-- Feel free to remove check-list items aren't relevant to your change --> | ||
|
||
- [ ] Closes #xxxx | ||
- [ ] Tests and/or performance benchmarks added | ||
- [ ] User visible changes (including notable bug fixes) are documented in `whats-new.rst` | ||
- [ ] New functions/methods are listed in `api.rst` or it's sub rsts? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
# Release guide This document describes release procedures, conventions, and | ||
utilities for `pywatershed`. | ||
|
||
<!-- START doctoc generated TOC please keep comment here to allow auto update --> | ||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> | ||
**Contents** | ||
|
||
- [Conventions](#conventions) | ||
- [Releasing `pywatershed`](#releasing-pywatershed) | ||
- [Utility scripts](#utility-scripts) | ||
- [Updating version numbers](#updating-version-numbers) | ||
|
||
<!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
|
||
## Conventions | ||
|
||
- Releases follow the [git | ||
flow](https://nvie.com/posts/a-successful-git-branching-model/). - Release | ||
numbers follow [semantic version](https://semver.org/) conventions. - Minor | ||
and major releases branch from `develop`. Patches branch from `main`. | ||
|
||
## Releasing `pywatershed` | ||
|
||
The release procedure is mostly automated. The workflow is defined in | ||
`.github/workflows/release.yaml` and triggers when a release or patch branch is | ||
pushed to this repo. | ||
|
||
To release a new version: | ||
|
||
1. Test asv benchmarking with the `-q` flag to ensure it is working (multiple | ||
platformas a bonus). | ||
|
||
1. On your local machine, create a release branch from `develop` or a patch | ||
branch from `main`. The branch's name must follow format | ||
`v{major}.{minor}.{patch}` ([semantic version](https://semver.org/) number | ||
with a leading 'v'). For instance, for a minor release, if this repo is an | ||
`upstream` remote and one's local `develop` is up to date with upstream | ||
`develop`, then from `develop` run `git switch -c vx.y.z`. | ||
|
||
1. If this is a patch release, make changes/fixes locally. If this is a major or | ||
minor release, no changes are needed. | ||
|
||
In either case, add the release version and date to the top of | ||
`doc/whats-new.rst`. If a patch, put it below the pending minor release. | ||
|
||
1. Push the branch to this repo. For instance, if this repo is an `upstream` | ||
remote: `git push -u upstream vx.y.z`. This starts a job to: | ||
|
||
- Check out the release branch Update version number in `version.txt` and | ||
- `pywatershed/version.py` to match the version in the branch name Build and | ||
- check the Python package Generate a changelog since the last release | ||
- Prepend the changelog to the cumulative `HISTORY.md` Upload the package | ||
- and changelog as artifacts Draft a PR against `main` with the updated | ||
- version files and cumulative changelog. The cumulative `HISTORY.md` is | ||
- version-controlled, release changelogs are not. | ||
|
||
1. On all platforms, pull the release from upstream and perform ASV performance | ||
benchmarks against previous release , e.g., ``` asv continuous --verbose | ||
--show-stderr --factor 1.3 previous_release this_release ``` Collect | ||
performance reports from various machines into a single report and use `asv | ||
publish` to generate the static webpages to be included with the release as | ||
artifacts in that step below. | ||
|
||
1. Inspect the package and changelog. If they look good, merge the PR to `main`. | ||
|
||
**Note**: it is critical to *merge* the PR to `main`, not squash as is | ||
conventional for development PRs. Squashing causes `develop` and `main` to | ||
diverge. Merging to `main` preserves commit history and ensures `develop` | ||
and `main` don't diverge. | ||
|
||
Merging the PR to `main` will trigger another job to draft a [GitHub | ||
release](https://github.com/EC-USGS/pywatershed/releases). The release is | ||
not yet publicly visible at this point. The release notes are autofilled as | ||
the changelog since the last release. | ||
|
||
1. Inspect the GitHub release. If needed, make any manual edits to the release | ||
notes. If the release looks good, publish it via GitHub UI or CLI. Manually | ||
add the asv static web pages and frozen conda dependencies for each platform. | ||
|
||
Publishing the release on GitHub automatically tags the head of `main` with | ||
the release version number (**Note**: release tags, unlike branches, don't | ||
include an initial `v`, as is common in some projects) and triggers jobs to: | ||
|
||
- Publish the package to PyPI | ||
- Check out `main` | ||
- Run `.github/scripts/update_version.py -v x.y+1.0.dev0` to update | ||
`version.txt` and `pywatershed/version.py` with the minor version number | ||
incremented. The `.dev0` suffix indicates preliminary development status. | ||
- Draft a PR against `develop` with the updated version files and the | ||
updates previously merged to `main`. | ||
|
||
1. In the case of a minor or major release, a couple of manual steps: | ||
- Update the PR against `develop` to add a new minor or major release to | ||
the top of `doc/whats-new.rst` | ||
- Update `main` image on WholeTale to have the current release. | ||
|
||
1. Merge the PR to `develop`. As above, it is important to *merge* the PR, not | ||
squash, to preserve history and keep `develop` and `main` from diverging. | ||
|
||
|
||
## Utility scripts | ||
|
||
The automated release procedure uses a few scripts, located in | ||
`.github/scripts`. | ||
|
||
### Updating version numbers | ||
|
||
The `update_version.py` script can be used to update version numbers embedded in | ||
the repository. The script acquires a file lock to make sure only one process | ||
edits version files at a given time. If the script is run with no arguments, | ||
updated timestamp comments are written but the version number is not changed. To | ||
set the version number, use the `--version` (short `-v`) option. | ||
|
||
For instance, to set the version number before a release: | ||
|
||
```shell python .github/scripts/update_version.py -a -v 0.1.3 ``` | ||
|
||
Or to set the version number on `develop` following a release: | ||
|
||
```shell python .github/scripts/update_version.py -a -v 0.2.0.dev0 ``` | ||
|
||
To get the current version number without writing any changes to the | ||
repository's files, use the `--get` (short `-g`) flag: | ||
|
||
```shell python .github/scripts/update_version.py -g ``` | ||
|
||
**Note**: this script should not need to be run manually, as it is run automatically in the release automation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#!/usr/bin/env bash | ||
|
||
# get full gfortran version string | ||
# assumes installed via brew as by | ||
# https://github.com/awvwgk/setup-fortran | ||
# | ||
# sed not head for first line, avoid ruby broken pipe issues | ||
# (https://stackoverflow.com/a/2845541/6514033) | ||
full_version=$(brew info gfortran | sed -n 1p | cut -d' ' -f 4) | ||
|
||
# get major version | ||
version=$(echo "$full_version" | cut -d'.' -f 1) | ||
|
||
# symlink gfortran libraries | ||
old_libdir="/usr/local/opt/gcc/lib/gcc/${version}" | ||
new_libdir="/usr/local/lib/" | ||
mkdir -p "$new_libdir" | ||
if [ -d "$old_libdir" ] | ||
then | ||
sudo ln -fs "$old_libdir/libgfortran.5.dylib" "$new_libdir/libgfortran.5.dylib" | ||
sudo ln -fs "$old_libdir/libquadmath.0.dylib" "$new_libdir/libquadmath.0.dylib" | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import argparse | ||
import textwrap | ||
import yaml | ||
from datetime import datetime | ||
from pathlib import Path | ||
|
||
from filelock import FileLock | ||
from packaging.version import Version | ||
|
||
|
||
_project_name = "pywatershed" | ||
_project_root_path = Path(__file__).parent.parent.parent | ||
_version_txt_path = _project_root_path / "version.txt" | ||
_citation_cff_path = _project_root_path / "CITATION.cff" | ||
_version_py_path = _project_root_path / _project_name / "version.py" | ||
_initial_version = Version("0.0.1") | ||
_current_version = Version(_version_txt_path.read_text().strip()) | ||
|
||
|
||
def update_version_txt(version: Version): | ||
with open(_version_txt_path, "w") as f: | ||
f.write(str(version)) | ||
print(f"Updated {_version_txt_path} to version {version}") | ||
|
||
|
||
def get_authors(): | ||
citation = yaml.safe_load(_citation_cff_path.read_text()) | ||
return citation["authors"] | ||
|
||
|
||
def update_version_py(timestamp: datetime, version: Version): | ||
lines = open(_version_py_path, "r").readlines() if _version_py_path.exists() else [] | ||
authors = get_authors() | ||
with open(_version_py_path, "w") as f: | ||
f.write( | ||
f"# {_project_name} version file automatically created using " | ||
f"{Path(__file__).name} on {timestamp:%B %d, %Y %H:%M:%S}\n\n" | ||
) | ||
f.write(f'__version__ = "{version}"\n') | ||
f.writelines( | ||
[ | ||
f"__pakname__ = \"{_project_name}\"\n", | ||
"\n", | ||
"author_dict = {\n", | ||
] + [f" \"{a['given-names']} {a['family-names']}\": \"{a['email']}\",\n" for a in authors] + [ | ||
"}\n", | ||
"__author__ = \", \".join(author_dict.keys())\n", | ||
"__author_email__ = \", \".join(s for _, s in author_dict.items())\n", | ||
] | ||
) | ||
f.close() | ||
print(f"Updated {_version_py_path} to version {version}") | ||
|
||
|
||
def update_version( | ||
timestamp: datetime = datetime.now(), | ||
version: Version = None, | ||
): | ||
lock_path = Path(_version_txt_path.name + ".lock") | ||
try: | ||
lock = FileLock(lock_path) | ||
previous = Version(_version_txt_path.read_text().strip()) | ||
version = ( | ||
version | ||
if version | ||
else Version(previous.major, previous.minor, previous.micro) | ||
) | ||
|
||
with lock: | ||
update_version_txt(version) | ||
update_version_py(timestamp, version) | ||
finally: | ||
try: | ||
lock_path.unlink() | ||
except: | ||
pass | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser( | ||
prog=f"Update {_project_name} version", | ||
formatter_class=argparse.RawDescriptionHelpFormatter, | ||
epilog=textwrap.dedent( | ||
"""\ | ||
Update version information stored in version.txt in the project root, | ||
as well as several other files in the repository. If --version is not | ||
provided, the version number will not be changed. A file lock is held | ||
to synchronize file access. The version tag must comply with standard | ||
'<major>.<minor>.<patch>' format conventions for semantic versioning. | ||
""" | ||
), | ||
) | ||
parser.add_argument( | ||
"-v", | ||
"--version", | ||
required=False, | ||
help="Specify the release version", | ||
) | ||
parser.add_argument( | ||
"-g", | ||
"--get", | ||
required=False, | ||
action="store_true", | ||
help="Just get the current version number, don't update anything (defaults to false)", | ||
) | ||
args = parser.parse_args() | ||
|
||
if args.get: | ||
print( | ||
Version((_project_root_path / "version.txt").read_text().strip()) | ||
) | ||
else: | ||
update_version( | ||
timestamp=datetime.now(), | ||
version=Version(args.version) | ||
if args.version | ||
else _current_version, | ||
) |
Oops, something went wrong.