# Releasing a new version of sourmash

These are adapted from the khmer release docs, originally written by
Michael Crusoe.

## Checklist

Here's a checklist to copy/paste into an issue:

```

Release candidate testing:
- [ ] Command line tests pass for a release candidate
- [ ] All eight release candidate wheels are built

Releasing to PyPI:

- [ ] RC tag(s)s deleted on github
- [ ] Release tag cut
- [ ] Release notes written
- [ ] All eight release wheels built
- [ ] Release wheels uploaded to pypi
- [ ] tar.gz distribution uploaded to pypi

After release to PyPI and conda-forge/bioconda packages built:

- [ ] [PyPI page](https://pypi.org/project/sourmash/) updated
- [ ] Zenodo DOI successfully minted upon new github release - [see search results](https://zenodo.org/search?page=1&size=20&q=sourmash&sort=mostrecent)
- [ ] `pip install sourmash` installs the correct version
- [ ] [conda-forge sourmash-minimal-feedstock](https://github.com/conda-forge/sourmash-minimal-feedstock) has updated `sourmash-minimal` to the correct version 
- [ ] `mamba create -n smash-release -y sourmash` installs the correct version

Optional but recommended:

- [ ] PR submitted to update pyodide version
- [ ] PR submitted to update spack version
```

## Creating the build environment with conda

You can most easily set up your build environment with conda.

Your conda version will need to be at least `v4.9.0`. You can check your
conda version with `conda --version` and update with `conda update conda`.

Create the basic build environment:

```
mamba create -y -n sourmash-rc python=3.10 pip \
    cxx-compiler make twine tox tox-conda rust
```

Then activate it with `conda activate sourmash-rc`.

## Writing release notes

Draft release notes can be created with `git log --oneline
v4.6.1..latest`, but should then be edited manually. We suggest
putting PRs in the following categories:

```
Major new features:

Minor new features:

Bug fixes:

Cleanup and documentation updates:

Developer updates:

Dependabot updates:
```

A convenient way to edit release notes is to put them in a [hackmd.io](https://hackmd.io) document and edit/display them there; then, create a "draft release notes for v..." issue and paste the markdown into the release PR.

## Testing a release

0\. First things first: check if Read the Docs is building properly for `latest`.
The build for the `latest` branch on [Read the Docs] should be passing,
and also the [rendered docs] should be up to date.

[Read the Docs]: https://readthedocs.org/projects/sourmash/builds/
[rendered docs]: https://sourmash.readthedocs.io/en/latest/

1\. The below should be done in a clean checkout:
```
cd $(mktemp -d)
git clone https://github.com/sourmash-bio/sourmash
cd sourmash
```

2\. Set your new version number and release candidate.
You might want to check [the releases page] for next version number,
or you can run `make last-tag` and check the output.
```
new_version=4.X.X
rc=rc1
```

Next create a new branch to work on release candidates and the version bump:
```
git switch -c release/v${new_version}
```
and update the version number in `pyproject.toml` and `flake.nix`:
```
sed -i -e "s|version = .*$|version = \"${new_version}\"|g" pyproject.toml
sed -i -e "s|version = .*$|version = \"${new_version}\";|g" flake.nix
```

Commit the changes and push the branch:
```
git add pyproject.toml flake.nix
git commit -m "${new_version} release branch"
git push -u origin release/v${new_version}
```
and then open a PR for the new branch by following the link printed by
```
echo "https://github.com/sourmash-bio/sourmash/pull/new/release/v${new_version}"
```

[the releases page]: https://github.com/sourmash-bio/sourmash/releases

Once the checks for the PR work, let's trigger the automatic wheel building
by creating a tag:

```
git tag -a v${new_version}${rc} -m "${new_version} release candidate ${rc}"
git push origin refs/tags/v${new_version}${rc}
```

3\. Test the release candidate. Bonus: repeat on macOS:
```
python -m pip install -U pip

cd ..
python -m venv testenv1
python -m venv testenv2
python -m venv testenv3

# First we test the tag

cd testenv1
source bin/activate
git clone --depth 1 --branch release/v${new_version} https://github.com/sourmash-bio/sourmash.git
cd sourmash
python -m pip install -r requirements.txt
pytest && cargo test

# Secondly we test via pip

cd ../../testenv2
deactivate
source bin/activate
python -m pip install build
python -m pip install -e git+https://github.com/sourmash-bio/sourmash.git@release/v${new_version}#egg=sourmash[test]
cd src/sourmash
pytest && cargo test
make dist
cp dist/sourmash*tar.gz ../../../testenv3/

# Is the distribution in testenv2 complete enough to build another
# functional distribution?

cd ../../../testenv3/
deactivate
source bin/activate
python -m pip install sourmash*tar.gz
tar xzf sourmash-${new_version}.tar.gz
cd sourmash-${new_version}
python -m pip install -r requirements.txt
pytest && cargo test
```

4\. Do any final testing:

 * check that the binder demo notebook is up to date

5\. Wait for GitHub Actions to finish running on the release candidate tag.

Wait for the
[various cibuildwheel actions](https://github.com/sourmash-bio/sourmash/actions)
to finish and upload; the
[latest release](https://github.com/sourmash-bio/sourmash/releases)
should have nine wheel files attached to it.

6\. Remove release candidate tags

NOTE: If you delete the rc tag before the rc wheels are done building, they
may get added to the wrong release.

```
cd ../../sourmash
git tag -d v${new_version}${rc}
git push --delete origin v${new_version}${rc}
```

## How to make a final release

When you've got a thoroughly tested release candidate,
cut a release like so:

1\. Merge the pull request bumping the version. Once the PR is merged,
change back to the `latest` branch and pull the new commit:

```
git checkout latest
git pull --rebase
```

2\. Create the final tag and push to GitHub:

```
git tag -a v${new_version} -m "${new_version} release tag"
git push --tags origin
```

(make sure to be in the `latest` branch when creating the final tag!)

3\. Upload wheels from GitHub Releases to PyPI

[GitHub Actions will automatically build wheels and upload them to GitHub Releases](https://github.com/sourmash-bio/sourmash/actions?query=workflow%3Acibuildwheel).
This will take about 45 minutes, or more. After they're built, they must be
copied over to PyPI manually.

You can do this in two ways: you can manually download all the files
from [the releases page], or, if you have the
[`GitHub CLI`](https://cli.github.com/), you can use that to download the
packages.

Download the wheels with the `GitHub CLI`:
```
mkdir -p wheel && cd wheel
gh release download v${new_version}
```
or download them manually.

Once you have them downloaded, upload them to PyPI like so:
```
twine upload *.whl
```
twine will correctly determine the version from the filenames.

4\. Once the wheels are uploaded, publish the new release on PyPI (requires an authorized account).
```
cd ..
make dist
twine upload dist/sourmash-${new_version}.tar.gz
```

(This must be done *after* the wheels are available, because some of
the conda package build steps require the source dist and are automatically
triggered when a new version shows up on PyPI.)

5\. Edit the release on GitHub; there will already be one associated
with the tag you pushed. Copy and paste in the release notes.

Note that there will also be releases associated with the Rust `core`
package, which is versioned differently than `sourmash`.  These will
be of the form `rXX.YY.ZZ`, e.g. `r0.9.0`. Please just ignore them :)

## Conda-forge

The [sourmash-minimal feedstock](https://github.com/conda-forge/sourmash-minimal-feedstock/)
in [conda-forge](https://conda-forge.org/) picks up new versions from
PyPI (need the sdist to be published) and opens a new PR.

Check if there are any dependency changes,
with special attention to the minimum supported Rust version.

After tests pass,
merge it and wait for the `sourmash-minimal` package to show up in conda-forge:
```
conda search sourmash-minimal={new_version}
```

[An example conda-forge PR for `4.6.0`](https://github.com/conda-forge/sourmash-minimal-feedstock/pull/37).

[An example bioconda PR for `4.6.0`](https://github.com/bioconda/bioconda-recipes/pull/38205).

## Bioconda

The BiocondaBot has an `autobump` feature that should pick up new releases from PyPI,
and open a PR in Bioconda. Review any changes
(especially dependency versions, since these don't get picked up).

Note that you need to wait for the `sourmash-minimal` package
prepared in the previous section to be available for installation,
and tests are going to fail in Bioconda before that.

An example PR for [`3.4.0`](https://github.com/bioconda/bioconda-recipes/pull/23171).

## Pyodide

You will need to open a PR on pyodide manually, e.g. [pyodide#4075 for 4.8.3](https://github.com/pyodide/pyodide/pull/4075).

## Spack

You will need to open a PR on spack manually, e.g. [spack#40062 for 4.8.4](https://github.com/spack/spack/pull/40062).

## Announce it!

If a bioinformatics software is released and no one tweets, is it really released?

Examples:

- [3.4.1](https://twitter.com/ctitusbrown/status/1286652952828993537)
- [3.4.0](https://twitter.com/luizirber/status/1283157954598858752)
- [3.0.0](https://twitter.com/luizirber/status/1213588144458649600)

## After release

Update version to next minor version + `-dev`, e.g. [4.8.3-dev as in this PR](https://github.com/sourmash-bio/sourmash/pull/2584), per [sourmash#2517](https://github.com/sourmash-bio/sourmash/issues/2517).
