Build a Release for the Project

Even though our app does very little at this stage, we wish to go ahead and “release” our first version for it.

Note

Whether or not you actually need to build releases for your project, may depend on your use case. For instance if you have reason to run the app(s) directly from source (i.e. git HEAD) then you may have no use for a built package.

Project Versioning

The project’s current version “number” is kept in only one place really, in our case ~/src/rattail-tutorial/rattail_tutorial/_version.py. Other files are configured to read the current project version from there.

The initial version for a new project will generally be ‘0.1.0’ and it’s assumed that subsequent versions will be ‘0.1.1’ then ‘0.1.2’ etc. until you’ve decided that it’s time to do a ‘0.2.0’ release, and the cycle begins again.

You can be as aggressive or conservative as you like when it comes to incrementing the more “major” parts of the version number, e.g. you can increment conservatively to where you’ve just released say, ‘0.1.427’ before you finally go to ‘0.2.0’. The only real “requirement” (assumption) here is that you will build a new version release every time you update the production environment(s). Sometimes that may mean multiple releases in a given day, e.g. if the first one ships with a bug and you have to push a release to fix.

Install Invoke

While you can most certainly go about the build/release task in various ways, the convention within Rattail-land is to use Invoke.

So next we’ll install that to your virtualenv:

pip install invoke

You may also want to declare this within your project’s dependencies (in setup.py), but that’s up to you.

Create Tasks File

The invoke command will invoke tasks which we have defined in a tasks file. (Duh!)

We will now create a file at ~/src/rattail-tutorial/tasks.py and in it place some minimal contents:

# -*- coding: utf-8; -*-
"""
Tasks for 'rattail-tutorial' project
"""

from invoke import task

# this is needed to read current `__version__` value
#import os
#here = os.path.abspath(os.path.dirname(__file__))
#exec(open(os.path.join(here, 'rattail_tutorial', '_version.py')).read())


@task
def release(c):
    """
    Release a new version of `rattail-tutorial`.
    """
    # clear out previous package info
    c.run('rm -rf rattail_tutorial.egg-info')

    # build fresh package!
    c.run('python setup.py sdist --formats=gztar')

    # enable this if you intend to publish package to PyPI
    #c.run('twine upload dist/rattail-tutorial-{}.tar.gz'.format(__version__))

If you’re creating your own project then you can use the above as a starting point for your own file. Instead of using twine to upload the package to PyPI, you may need to push to some private package repository which you control.

Run Release Task

As you can see above, release is the one and only task we have defined so far. In most cases that will be the only task you ever define for the project, but YMMV.

At any rate it’s all we need for now, so let’s run it:

cd ~/src/rattail-tutorial
invoke release

If you’re feeling lazy you can even shorten that second one to:

inv release

This will build a new “release” which may then be found within e.g. the ~/src/rattail-tutorial/dist/ folder. Depending on the specifics of your tasks file, this release may also be uploaded to some (public or private) package index.