.. _development:
Development
***********
To get the source code from GitHub, you can do
.. code-block:: console
git clone git@github.com:yatiml/yatiml.git
cd yatiml
Run tests (including coverage and type checking) with:
.. code-block:: console
pip install tox
tox
Error message evaluation mode can be enable by
.. code-block:: console
tox -e show-errors
This will disable pytest.raises, causing all the expected exceptions raised by
the tests to actually be raised and their tests to fail. As a result, you can
see the error messages generated by YAtiML and see if they're easy to
understand.
A local copy of the documentation can be generated using:
.. code-block:: console
tox -e docs
Contributing
------------
If you want to contribute some improvements to YAtiML, please use the following
process:
#. (**important**) Announce your plan to the rest of the community *before you
start working*. This announcement should be in the form of a (new) issue.
#. (**important**) wait until some kind of consensus is reached about your idea
being a good idea.
#. If needed, fork the repository to your own Github profile and create your
own feature branch off of the latest ``develop`` commit. While working on
your feature branch, make sure to stay up to date with the ``develop``
branch by pulling in changes, possibly from the 'upstream' repository
(follow the instructions `here
`__ and
`here `__).
#. Make sure the existing tests still work by running ``python setup.py test``.
#. Add your own tests (if necessary).
#. Update or expand the documentation.
#. Use ``yapf`` to fix the readability of your code style and ``isort``
to format and group your imports.
#. `Push `_ your feature branch to
(your fork of) the YAtiML repository on GitHub.
#. create the pull request,
e.g. following the instructions `here
`_.
In case you feel like you've made a valuable contribution, but you don't know
how to write or run tests for it, or how to generate the documentation: don't
let this discourage you from making the pull request; we can help you! Just go
ahead and submit the pull request, but keep in mind that you might be asked to
append additional commits to your pull request.
Making a release
----------------
YAtiML uses Git on GitHub for version management, using the `Git Flow`_
branching model. Making a release involves quite a few steps, so they're listed
here to help make the process more reliable; this information is really only
useful for the maintainers.
Check metadata
..............
- Check the metadata in ``setup.py``, and update as necessary.
- Check the copyright date and owners in README.rst and docs/conf.py and update
as necessary.
Update the changelog
....................
Each release should have an entry in the CHANGELOG.rst describing the new
features and fixed problems. Since we'll want to carry these entries forward,
we'll make them first, on the develop branch. Use the git log to get a list of
the changes, and switch to the development branch:
.. code-block:: bash
git log
git switch develop
and then edit CHANGELOG.rst and commit.
.. code-block:: bash
git add CHANGELOG.rst
git commit -m 'Add version x.y.z to the change log'
Make release branch
...................
To start the release process, make a release branch
.. code-block:: bash
git switch -c release-x.y.z develop
YAtiML uses `Semantic Versioning`_, so name the new version accordingly.
Update version
..............
Next, the version should be updated. There is a version tag in ``setup.py`` and
two for the documentation in ``docs/conf.py`` (search for ``version`` and
``release``). There is also an ``__version__`` in ``__init__.py``. On the
development branch, these should be set to ``x.y.z.dev0``, where ``x.y.z`` is
the expected next version. On the release branch, they should be set to
``x.y.z`` (with here the actual number of this release of course).
Check documentation
...................
Since we've just changed the documentation build configuration, the build should
be run locally to test:
.. code-block:: bash
tox -e docs
Next, point your web browser to ``docs/_build/index.html`` and verify that the
documentation built correctly. In particular, the new version number should be
in the browser's title bar as well as in the blue box on the top left of the
page.
Run tests
.........
Before we make a commit, the tests should be run, and this is a good idea anyway
if we're making a release. So run ``tox`` and check that everything is in order.
Commit the version update
.........................
This is the usual Git poem:
.. code-block:: bash
git add setup.py docs/conf.py yatiml/__init__.py
git commit -m 'Set release version to x.y.z'
git push --set-upstream origin release-x.y.z
This will trigger the Continuous Integration, so check that that's not giving
any errors while we're at it.
Fix badges
..........
The badges in the README.rst normally point to the development branch versions
of everything. For the master branch, they should point to the master version.
Note that for the ReadTheDocs badge, ``develop`` should be changed to
``latest``, and that for Codacy there is only one badge, so no change is needed.
.. code-block:: bash
# edit README.rst
git add README.rst
git commit -m 'Update badges to point to master'
git push
Merge into the master branch
............................
If all seems to be well, then we can merge the release branch into the master
branch and tag it, thus making a release, at least as far as Git Flow is
concerned. We use the ``-X theirs`` option here to resolve the merge conflict
caused by the version update that was done for the previous release, which we
don't have on this branch. The last command is to push the tag, which is
important for GitHub and GitHub integrations.
.. code-block:: bash
git switch master
git merge --no-ff -X theirs release-x.y.z
git tag -a x.y.z -m 'Release x.y.z'
git push
git push origin x.y.z
Build and release to PyPI
.........................
Finally, the new version needs to be built and uploaded to PyPI, so that people
can start using it. To build, use:
.. code-block:: bash
python3 setup.py sdist bdist_wheel
Then, we can upload to the test instance of PyPI:
.. code-block:: bash
twine upload --repository-url https://test.pypi.org/legacy/ dist/yatiml-x.y.z*
To test that we can install it, run this in a fresh virtualenv. Note that the
PyPI test server doesn't have the dependencies, so we need to install those from
the production server first.
.. code-block:: bash
pip install PyYAML typing_extensions
pip install --index-url https://test.pypi.org/simple/ yatiml
And if all seems well, we can upload to the real PyPI:
.. code-block:: bash
twine upload dist/yatiml-x.y.z*
Update conda-forge feedstock
............................
(Note: we're skipping a local rerender here in favour of letting the conda-forge
bot handle it on GitHub. If that becomes an issue we'll change it, but this way
we don't need to have conda installed locally.)
First, we need a fork of https://github.com/conda-forge/yatiml-feedstock, so
create one if you don't have one yet, and clone it locally.
If you are reusing an existing clone of an existing fork, then it may need some
updates first. First, add the conda-forge remote if it's not there yet:
.. code-block:: bash
git remote add conda-forge https://github.com/conda-forge/yatiml-feedstock.git
Now that our clone is connected to both the fork (origin) and the original
repository (conda-forge), we can synchronise them:
.. code-block:: bash
git switch release-w.x.y # previous release
git pull # get changes made by conda in the fork
git switch main
git pull conda-forge main # get the previous merge
git push origin # update the fork
This should make it so that conda-forge, the fork, and the clone all agree on
which commits we have.
Then we can create a branch to work on:
.. code-block:: bash
git switch main
git pull
git switch -c release-x.y.z
Next, we need to get a checksum for the package we uploaded to PyPI. In the main
yatiml directory, run:
.. code-block:: bash
sha256sum dist/yatiml-x.y.z.tar.gz
Next, in ``yatiml-feedstock``, edit ``recipe/meta.yaml``:
- Update to the new version at the top
- Replace the checksum with the one for the new release
We can then test the new build by running ``python3 build-locally.py``. This
will build the package inside of a Docker container, so you need to have Docker
installed and have a couple GB of free disk space.
If it all works, then we can commit the changes to the local branch:
.. code-block:: bash
git add recipe/meta.yaml
git commit -m 'Update to version x.y.z'
git push --set-upstream origin release-x.y.z
Note that this pushes to the fork, not to ``conda-forge/yatiml-feedstock``,
which is exactly what we want. Pushing to upstream directly will break the
automation.
Instead, go to the fork, and make a pull request for merging the changes into
``conda-forge/yatiml-feedstock:main``. Run through the checklist in the
template. To check whether the license file is included, in the yatiml
directory do:
.. code-block:: bash
tar tf dist/yatiml-x.y.z.tar.gz
and check that LICENSE and NOTICE are both there.
Add a ``@conda-forge-admin, please rerender`` to the text to rerender the
feedstock. This will upgrade the auto-generated parts of ``meta.yaml`` to the
latest configuration, so it adds another commit to the branch.
So, wait for the ``conda-forge-linter`` to lint, and for ``conda-forge-admin``
to rerender, and then merge the PR using the GitHub GUI. The new package will
now be staged and built and copied over to the Anaconda repository. This may
take a couple of hours, so don't worry if it doesn't appear immediately.
As a final test, you can do:
.. code-block:: bash
docker run -ti conda/miniconda3
# conda install -c conda-forge yatiml
which should install the new version.
Finally, we need to re-sync the fork and clone with the original repository,
because changes have been made in the cloud. By doing this, we avoid having to
do it next time (see above) if we reuse this fork and/or clone.
.. code-block:: bash
git switch release-x.y.z
git pull # get changes made by conda in the fork
git switch main
git pull conda-forge main # get the merge we just made
git push origin # update the fork for next time
Make a GitHub Release
.....................
Go to Releases on the GitHub page and make a new release from the tag. For the
release notes, use this template and copy-paste the content from the CHANGELOG:
.. code-block:: markdown
# YAtiML
YAML-based file formats can be very handy, as YAML is easy to write by humans, and parsing support for it is widely available. Just read your YAML file into a document structure (a tree of nested dicts and lists), and manipulate that in your code.
As long as that YAML file contains exactly what you expect, that works fine. But if it contains a mistake, then you're likely to crash the program with a cryptic error message, or worse (especially if the YAML file was loaded from the Internet) it may do something unexpected.
To avoid that, you can validate your YAML using various schema checkers. You write a description of what your YAML file must look like, then feed that to a library which checks the incoming file against the description. That gives you a better error message, but it's a lot of work.
YAtiML takes a different approach. Instead of a schema, you write a Python class. You probably already know how to do that, so no need to learn anything. YAtiML then generates loading and dumping functions for you, which convert between YAML and Python objects. If needed, you can add some extra code to make the YAML look nicer or implement special features.
#
## Incompatible changes
*
## New functionality
*
## Fixes
*
## Removed
*
The preamble is there because this text ends up on the Zenodo page, and people
who end up there will probably want to know what it is before learning about the
latest changes.
There's no need to upload binaries, GitHub will create tar files with snapshots
for Zenodo automatically, and we've already put things on PyPI and Conda.
Merge release branch back into develop
......................................
To continue developing, merge the release branch back into develop
.. code-block:: bash
git switch develop
git merge --no-commit release-x.y.z
Make sure that the badges are set to develop, and that the version number is
set to the next expected version x.y.{z+1}.dev0 (it's fine if x.{y+1}.0 is what
ends up being released eventually). Then you can commit and continue developing:
.. code-block:: bash
git commit
git push
Update issues
.............
Go through the issues on GitHub and close the ones for which a fix was released.
Or if they were created by someone else, ask the user to check that the new
version solves their problem and then close the issue if it does.
.. _`Git Flow`: http://nvie.com/posts/a-successful-git-branching-model/
.. _`Semantic Versioning`: http://www.semver.org