Skip to main content

Continuous delivery helpers for python projects

Project description

hatchery
========

|Latest Version| |Build Status| |Coverage Status|

A helper for continuous delivery of python packages

What is the problem, exactly?
-----------------------------

Python's packaging and distribution scheme is really designed for manual
intervention, most notably as regards versions. In your typical project,
the version is hardcoded *somewhere* in the source tree, and the project
history will be littered with messages like "bumped version to x.y."
Isn't this what tagging is for? Also, why should a work in progress be
given a version number in the first place? It seems backwards. It also
is solvable.

Aside from that major issue, there are a number of minor annoyances that
arise when handling python projects in github. Chief among these is the
problem of README files. Github clearly prefers ``README.md`` files, and
the markdown syntax widely available and very natural to use. Pypi, on
the other hand, requires the use of ``README.rst`` files (or at least
that format) in order to display on the project's main site. I find this
more difficult to work with and, regardless, one should be able to use
one's preferred README syntax. Converting from one to the other is
doable, so it should also be simple.

Finally, when doing any kind of modification of source files on the fly
(a build process) it is important that the package tree be untouched.
This is largely due to the fact that an automated tagging process
(critical to CD) falls down when the working copy is dirty. As such,
automated management of a working directory which can be safely ignored
in VCS is an integrated part of ``hatchery``.

Core features
-------------

- Isolation of all source manipulations to a working directory
(``.hatchery.work``)
- On-the-fly version management using the popular ``_version.py``
specification method
- Logic to make sure that only pypi-accepted (see
`PEP-386 <https://www.python.org/dev/peps/pep-0386/>`__) versions are
used
- Optional on-the-fly readme conversion from ``md`` to ``rst``
- Notion of "tasks" which must be run in a particular order
- Dictate as little project structure as possible (see below)

Project prerequisites
---------------------

As of the time of this writing, there are a few prerequisites that a
project must meet in order to integrate with ``hatchery``:

- The project should consist of a single root package which contains
all of the python logic. That package can be as large or as small as
is needed, containing as many subpackages as you like, but there must
only be one.
- There are some code requirements in ``setup.py`` and
``<packagename>._version.py``. Run ``hatchery check`` for more
information. And don't worry, if these prereqs aren't met,
``hatchery`` will tell you about it instead of doing something wonky.
- In order to make use of some of the features (running tests,
registering and uploading releases of your project), you will have to
maintain a configuration file. More information below.

Top-level project
~~~~~~~~~~~~~~~~~

``hatchery`` automatically infers the name of top-level package during
operation based on the layout of the file system, and it expects there
to be exactly one. In order for this to work properly, your project
needs to look like this:

::

# the project directory is the path you cloned to
project_directory/

.git/

.hatchery.yml

...

# the package name can be whatever you want, so long as it's not "tests"
package_name/

__init__.py

...

# the "tests" directory is where your tests are stored, and will be ignored when determining
# the top-level package -- any other directories which contain an __init__.py and are not
# children of package_name will cause the inference to fail
tests/

__init__.py

...

So, if you want your tests in a python package, make sure it's called
``tests``. If there are two python packages which are not named
``tests``, ``hatchery`` will throw an error. This is in service of a
unified package version. In order for ``setup.py`` (and ``setuptools``)
to infer the project version from the package safely, there should only
be one package from which to infer.

Installation
------------

::

$ pip install hatchery

As always, it is strongly recommended that you use this inside of a
virtual environment.

Configuration
-------------

As previously mentioned, in order to take full advantage of what
``hatchery`` has to offer, there is a little configuration that is
required...and I do mean a little. There are a number of parameters
available, but most of them can just be left to their default values:

+------------+----------------+--------+
| Parameter | Default value | Usage |
+============+================+========+
| ``auto_pus | ``False`` | Automa |
| h_tag`` | | ticall |
| | | y |
| | | run |
| | | the |
| | | tag-an |
| | | d-push |
| | | logic |
| | | after |
| | | a |
| | | succes |
| | | sful |
| | | upload |
| | | operat |
| | | ion |
+------------+----------------+--------+
| ``create_w | ``True`` | Create |
| heel`` | | a |
| | | wheel |
| | | along |
| | | with |
| | | the |
| | | source |
| | | distri |
| | | bution |
| | | during |
| | | the |
| | | packag |
| | | ing |
| | | step |
+------------+----------------+--------+
| ``git_remo | ``'origin'`` | The |
| te_name`` | | name |
| | | of the |
| | | remote |
| | | to |
| | | push |
| | | to |
| | | when |
| | | pushin |
| | | g |
| | | a git |
| | | tag |
+------------+----------------+--------+
| ``pypi_rep | ``None`` | String |
| ository`` | | parame |
| | | ter |
| | | descri |
| | | bing |
| | | which |
| | | pypi |
| | | index |
| | | server |
| | | to |
| | | upload |
| | | packag |
| | | es |
| | | to. It |
| | | actual |
| | | ly |
| | | refers |
| | | to an |
| | | alias |
| | | which |
| | | must |
| | | be |
| | | define |
| | | d |
| | | in |
| | | your |
| | | `pypir |
| | | c |
| | | file < |
| | | https: |
| | | //docs |
| | | .pytho |
| | | n.org/ |
| | | 3.5/di |
| | | stutil |
| | | s/pack |
| | | ageind |
| | | ex.htm |
| | | l#the- |
| | | pypirc |
| | | -file> |
| | | `__ |
+------------+----------------+--------+
| ``readme_t | ``True`` | Conver |
| o_rst`` | | t |
| | | a |
| | | README |
| | | .md |
| | | file |
| | | to |
| | | README |
| | | .rst |
| | | on the |
| | | fly if |
| | | the |
| | | former |
| | | is |
| | | detect |
| | | ed |
| | | and |
| | | the |
| | | latter |
| | | is |
| | | not. |
| | | This |
| | | featur |
| | | e |
| | | requir |
| | | es |
| | | ``pand |
| | | oc`` |
| | | (OS-le |
| | | vel |
| | | depend |
| | | ency) |
| | | ... so |
| | | if you |
| | | do not |
| | | want |
| | | to |
| | | depend |
| | | on |
| | | ``pand |
| | | oc``, |
| | | set to |
| | | ``Fals |
| | | e`` |
| | | and |
| | | this |
| | | featur |
| | | e |
| | | won't |
| | | be |
| | | used. |
+------------+----------------+--------+
| ``test_com | ``None`` | A list |
| mand`` | | of |
| | | arbitr |
| | | ary |
| | | shell |
| | | comman |
| | | ds |
| | | that |
| | | should |
| | | be run |
| | | during |
| | | the |
| | | test |
| | | task. |
| | | If any |
| | | of |
| | | them |
| | | fails, |
| | | the |
| | | test |
| | | will |
| | | be |
| | | consid |
| | | ered |
| | | a |
| | | failur |
| | | e. |
+------------+----------------+--------+

These parameters should be defined in `yaml
format <https://en.wikipedia.org/wiki/YAML>`__ in the file
``.hatchery.yml`` in the root of your project. If you want to make any
of them global across all your projects, you can also choose to define
them in ``~/.hatchery/hatchery.yml``; just remember that the
project-level file's values will always win!

A minimal ``.hatchery.yml`` might look like this:

.. code:: yaml

---

pypi_repository: pypi

test_command:
- tox

See ``.hatchery.yml`` in this repository for a contextual example.

Aside: there are lots of different opinions about how best to test one's
code. There are many frameworks, and many ways to execute them. Allowing
users to have complete control over this was a key design decision. You
want to use ``tox``? Go for it! Prefer using ``py.test`` directly? Fine
by me. Think ``pylint`` is important? Throw it on there! The point is,
choose what testing feedback is important to you, and ``hatchery`` will
faithfully execute it for you.

Private pypi repositories
~~~~~~~~~~~~~~~~~~~~~~~~~

New feature alert! If you specify a full address of a pypi server as a
value for ``pypi_repository``, ``hatchery`` will attempt to upload to
that server, bypassing the pypirc file entirely. **This will only work
for anonymous-upload servers, and cannot be used for interaction with
public servers such as pypi.python.org!** Example:

.. code:: yaml

pypi_repository: https://pypi.mydomain.com

Examples
--------

Make sure you have all of the prerequisites in place

::

$ hatchery check

Run all tests defined in configuration

::

$ hatchery clean test

Register your project with the pypi repository defined in configuration

::

$ hatchery register

Create packages (with markdown -> rst conversion)

::

$ hatchery package --release-version=1.2.3

Upload your packages to the pypi repository defined in configuration

::

$ hatchery upload

String everything together in one go!

::

$ hatchery clean register test package upload --release-version=1.2.3

Find out what other great features you're missing out on

::

$ hatchery help

Postscript
----------

I wrote this utility because it helps me to work in the way in which I
am most productive. It will not be perfect for everyone...not yet. If
you think there's something missing that would help you find your happy
path, please open up a feature request. Better yet, implement it and
throw up a pull request. Feedback is welcome!

.. |Latest Version| image:: https://img.shields.io/pypi/v/hatchery.svg
:target: https://pypi.python.org/pypi/hatchery
.. |Build Status| image:: https://travis-ci.org/ajk8/hatchery.svg?branch=master
:target: https://travis-ci.org/ajk8/hatchery
.. |Coverage Status| image:: https://coveralls.io/repos/github/ajk8/hatchery/badge.svg?branch=master
:target: https://coveralls.io/github/ajk8/hatchery?branch=master

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hatchery-0.4.2.tar.gz (16.0 kB view details)

Uploaded Source

Built Distribution

hatchery-0.4.2-py2.py3-none-any.whl (16.4 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file hatchery-0.4.2.tar.gz.

File metadata

  • Download URL: hatchery-0.4.2.tar.gz
  • Upload date:
  • Size: 16.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for hatchery-0.4.2.tar.gz
Algorithm Hash digest
SHA256 d5ba1af214282b2c27e9aac6800fcf706b156cd99e79cf3d3a5d80e3456a4a4b
MD5 ca23b273d531e2f4ac980490ea1c80a5
BLAKE2b-256 14f1d8a48fa12b8dc0eab08aada83201cf3342d3d569640412a574bf163ce198

See more details on using hashes here.

File details

Details for the file hatchery-0.4.2-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for hatchery-0.4.2-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 528ce7af96aef0d013b99cceac67814624f289d86c3265b3a88773f0c56e07c4
MD5 27a4fbf842407015389483368d129a75
BLAKE2b-256 1d73186b79f11bd6a5df6a34a2b8a301d40655068044ba58bdafff0123be1174

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page