Metadata-Version: 2.1
Name: polyvers
Version: 0.1.0a0
Summary: Bump sub-project versions in Git monorepos independently.
Home-page: https://github.com/jrcstu/polyvers
Author: Kostis Anagnostopoulos
Author-email: ankostis@gmail.com
License: EUPL 1.2
Download-URL: https://pypi.org/project/polyvers/
Project-URL: Documentation, https://polyvers.readthedocs.io/
Project-URL: Source, https://github.com/jrcstu/polyvers
Project-URL: Tracker, https://github.com/jrcstu/polyvers/issues
Project-URL: Polyversion, https://pypi.org/project/polyversion/
Keywords: version-management,configuration-management,versioning,git,monorepo,tool,library
Platform: any
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: European Union Public Licence 1.1 (EUPL 1.1)
Classifier: Natural Language :: English
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Requires-Python: >=3.6
Provides-Extra: test
Requires-Dist: polyversion (>=0.1.0a4)
Requires-Dist: boltons
Requires-Dist: toolz
Requires-Dist: rainbow-logging-handler
Requires-Dist: ruamel.yaml
Requires-Dist: ipython-genutils
Requires-Dist: spectate
Requires-Dist: ruamel.yaml (>=0.15.37)
Requires-Dist: packaging (>=17.1)
Requires-Dist: contextvars; python_version < "3.7"
Provides-Extra: test
Requires-Dist: pytest (>=3.5.0); extra == 'test'
Requires-Dist: pytest-runner; extra == 'test'
Requires-Dist: pytest-cov; extra == 'test'
Requires-Dist: flake8; extra == 'test'
Requires-Dist: flake8-builtins; extra == 'test'
Requires-Dist: flake8-mutable; extra == 'test'
Provides-Extra: test
Requires-Dist: mypy; (python_version>="3") and extra == 'test'

==================================================================
Polyvers: Bump sub-project versions in Git monorepos independently
==================================================================

.. _opening-start:
..  https://img.shields.io/pypi/v/polyvers.svg
    :alt: Deployed in PyPi?
    :target: https://pypi.org/pypi/polyvers

..  https://img.shields.io/travis/JRCSTU/polyvers.svg
    :alt: TravisCI (linux) build ok?
    :target: https://travis-ci.org/JRCSTU/polyvers

..  https://ci.appveyor.com/api/projects/status/lyyjtmit5ti7tg1n?svg=true
    :alt: Apveyor (Windows) build?
    :scale: 100%
    :target: https://ci.appveyor.com/project/ankostis/polyvers

..  https://img.shields.io/coveralls/github/JRCSTU/polyvers.svg
    :alt: Test-case coverage report
    :scale: 100%
    :target: https://coveralls.io/github/JRCSTU/polyvers?branch=master&service=github

..  https://readthedocs.org/projects/polyvers/badge/?version=latest
    :target: https://polyvers.readthedocs.io/en/latest/?badge=latest
    :alt: Auto-generated documentation status

..  https://pyup.io/repos/github/JRCSTU/polyvers/shield.svg
    :target: https://pyup.io/repos/github/JRCSTU/polyvers/
    :alt: Dependencies needing updates?

..  https://api.codacy.com/project/badge/Grade/11b2545fd0264f1cab4c862998833503
    :target: https://www.codacy.com/app/ankostis/polyvers_jrc
    :alt: Code quality metric

:version:       0.1.0a0
:updated:       2018-06-05T14:47:37.754676
:Documentation: https://polyvers.readthedocs.io
:repository:    https://github.com/JRCSTU/polyvers
:pypi-repo:     https://pypi.org/project/polyvers/, https://pypi.org/project/polyversion/
:keywords:      version-management, configuration-management, versioning, git, monorepos,
                tool, library
:copyright:     2018 JRC.C4(STU), European Commission (`JRC <https://ec.europa.eu/jrc/>`_)
:license:       `EUPL 1.2 <https://joinup.ec.europa.eu/software/page/eupl>`_

A Python 3.6+ command-line tool to manage `PEP-440 version-ids
<https://www.python.org/dev/peps/pep-0440/>`_ of dependent sub-projects
hosted in a *Git* **monorepo**\s, independently.

The key features are:

- **setuptools integration**,
- x2 **repo scheme**\s (**monorepo**, **mono-project**),
- configurable **version scheme**,
- *leaf* **release scheme**,
- intuitive **version-bump algebra** (TODO),
- configurable **engravings**.

The last feature departs from the logic of ref: *similar-tools*.
Specifically, when bumping the version of sub-project(s), this tool
adds **+2 tags and +1 commits**:

  - one **Version tag** in-trunk like ``foo-proj-v0.1.0``,
  - and another **Release tag** on a new **out-of-trunk commit** (leaf)
    like ``foo-proj-r0.1.0`` (the new version-ids are **engrave**\d only
    in this release-commit):

    ..  _static/leaf_commits.png
        :align: center
        :alt: Leaf-commits & version/release tags for the two repo's sub-projects

        Leaf-commits & version/release-tags for the two sub-project's,
        as shown in this repo's git history.

.. Note::
  The reason for this feature is to allow exchange code across branches (for the
  different sub-projects) without **engravings** getting in your way as
  merge-conflicts.

Additional capabilities and utilities:

- It is still possible to use plain **version tags (vtags)** like ``v0.1.0``,
  assuming you have a single project (called hereinafter a **mono-project**)

- A separate Python 2.7+ **polyversion** project, which contains API to extract
  sub-project's version from past tags (provided as a separate subproject
  so client programs do not get ``polyvers`` commands transitive dependencies).
  The library functions as a **setuptools  plugin**.

.. _opening-end:

.. contents:: Table of Contents
   :backlinks: top
   :depth: 4


.. _usage:

Tutorial
========
1. Install the tool
-------------------
And you get the ``polyvers`` command:

.. code-block:: console

    $ pip install polyvers
    ...
    $ polyvers --version
    0.0.0
    $ polyvers --help
    ...

    $ polyvers status
    polyvers: Neither `setup.py` nor `.polyvers(.json|.py|.salt)` config-files found!

.. Note::
    Actually two projects are installed:

    - **polyvers** cmd-line tool, for developing python **monorepo**\s,
    - **polyversion**: the base python library used by projects developed
      with *polyvers* tool, so that their sources can discover their subproject-version
      on runtime from Git.


2. Prepare project
------------------
Assuming our **monorepo** project ``/monorepo.git/`` contains two sub-projects,
then you need enter the following configurations into your build files::

    /monorepo.git/
        +--setup.py               # see below for contents
        +--mainprog/__init__.py
        |                         from polyversion import polyversion, polytime
        |                         __version__ = polyversion()
        |                         __updated__ = polytime()
        |                         ...
        |
        +--core-lib/
            +--setup.py:          # like above
            +--core/__init__.py   # like above
            +--...

.. Tip::
    You may see different sample approaches for your setup-files by looking
    into both `polyvers` & `polyversion` subprojects of this repo (because
    they eat their own dog food).

The `polyversion` library function as a *setuptools* "plugin", and
adds a new ``setup()`` keyword ``polyversion = (bool | dict)``
(see func(`polyversion.init_plugin_kw`) for its content), which you can use it
like this:

.. code-block:: python

    from setuptools import setup

    setup(
        project='myname',
        version=''              # omit (or None) to abort if cannot auto-version
        polyversion={           # dict or bool
            'version_scheme: 'mono-project',
            ...  # See `polyversion.init_plugin_kw()` for more keys.
        },
        setup_requires=[..., 'polyversion'],
        ...
    )

.. Hint::
    The ``setup_requires=['polyvers']`` keyword  (only available with *setuptools*,
    and not *distutils*), enables the new ``polyversion=`` setup-keyword.

Alternatively, a subproject may use pep(`0518`) to pre-install `polyversion`
library *before* pip-installing or launching ``setup.py`` script.
To do that, add the ``pyproject.toml`` file below next to your `setup` script::

    [build-system]
    requires = ["setuptools", "wheel", "polyversion"]

and then you can simply import ``polyversion`` from your ``setup.py``:

.. code-block:: python

    from setuptools import setup
    from polyversion import polyversion

    setup(
        project='myname',
        version=polyversion(mono_project=True)  # version implied empty string.

.. Attention::
    To properly install a pep(`0518`) project you need ``pip-v10+`` version.


3. Initialize `polyvers`
------------------------
...we let the tool auto-discover the mapping of *project folders â†” project-names*
and create a `traitlets configuration YAML-file <https://traitlets.readthedocs.io>`_
named as  ``/monorepo.git/.polyvers.py``:

.. code-block:: console

    $ cd monorepo.git

    $ polyvers init --monorepo
    Created new config-file '.polyvers.yaml'.

    $ cat .polyvers.yaml
    ...
    PolyversCmd:
      projects:
      - pname: mainprog     # name extracted from `setup.py`.
        basepath: .         # path discovered by the location of `setup.py`
      - pname: core
        basepath: core-lib
    ...

    $ git add .polyvers.yaml
    $ git commit -m 'add polyvers config-gile'

And now we can use the ``polyvers`` command to inspect the versions of all
sub-projects:

.. code-block:: console

    $ polyvers status
    - mainprog
    - core

Indeed there are no tags in in git-history for the tool to derive and display
project-versions, so only project-names are shown.  With ``--all`` option
more gets displayed:

.. code-block:: console

    $ polyvers status -a
    - pname: mainprog
      basepath: .
      gitver:
      history: []
    - pname: core
      basepath: core-lib
      gitver:
      history: []

..where ``gitver`` would be the result of ``git-describe``.


4. Bump versions
----------------
We can now use tool to set the same version to all sub-projects:

.. code-block:: console

    $ polyvers bump 0.0.0 -f noengraves   # all projects implied, if no project-name given
    00:52:06       |WARNI|polyvers.bumpcmd.BumpCmd|Ignored 1 errors while checking if at least one version-engraving happened:
      ignored (--force=noengraves): CmdException: No version-engravings happened, bump aborted.
    00:52:07       |NOTIC|polyvers.bumpcmd.BumpCmd|Bumped projects: mainprog-0.0.0 --> 0.0.0, core-0.0.0 --> 0.0.0

The ``--force=noengraves`` disables a safety check that requires at least one
file modification for **engrave**\ing the current version in the leaf "Release" commit
(see next step).

.. code-block:: console

    $ polyvers status
    - mainprog-v0.0.0
    - core-v0.0.0

    $ git lg    # Ok, augmented `lg` output a bit here...HEAD --> UPPER branch.
    COMMITS BRANCH TAGS                 REMARKS
    ======= ====== ==================== ========================================
         O  latest mainprog-r0.0.0      - x2 tags on "Release" leaf-commit
        /          core-r0.0.0            outside-of-trunk (not in HEAD).
       O    MASTER mainprog-v0.0.0      - x2 tags on "Version" commit
       |           core-v0.0.0            for bumping both projects to v0.0.0
       O                                - Previous commit, before version bump.

   .. Hint::
      Note the difference between ``ABC-v0.0.0`` vs ``ABC-r0.0.0`` tags.

   In the source code, it's only the "release" commit that has **engrave**\d* version-ids:

   .. code-block:: console

    $ cat mainprog/mainprog/__init__.py    # Untouched!
    import polyvers

    __title__     = "mainprog"
    __version__ = polyvers.version('mainprog')
    ...

    $ git checkout  latest
    $ cat mainprog/mainprog/__init__.py
    import polyvers

    __title__     = "mainprog"
    __version__ = '0.0.0'
    ...

    $ git checkout  -  # to return to master.


5. Engrave version in the sources
---------------------------------
Usually programs report their version somehow when run, e.g. with ```cmd --version``.
With *polyvers* we can derive the latest from the tags created in the previous step,
using a code like this, usually in the file ``/mainprog/mainprog/__init__.py:``:

.. code-block:: python

    import polyvers

    __title__ = "mainprog"
    __version__ = polyvers.version('mainprog')
    ...

...and respectively ``/core-lib/core/__init__.py:``:

.. code-block:: python

    __version__ = polyvers.version('core')



6. Bump sub-projects selectively
--------------------------------
Now let's add another dummy commit and then bump ONLY ONE sub-project:

.. code-block:: console

    $ git commit  --allow-empty  -m "some head work"
    $ polyvers bump ^1 mainprog
    00:53:07       |NOTIC|polyvers.bumpcmd.BumpCmd|Bumped projects: mainprog-0.0.0 --> 0.0.1

    $ git lg
    COMMITS BRANCH TAGS                 REMARKS
    ======= ====== ==================== ========================================
         O  latest mainprog-r0.0.1.dev0 - The latest "Release" leaf-commit.
        /                                 branch `latest` was reset non-ff.
       O    MASTER mainprog-v0.0.1.dev0 - The latest "Version" commit.
       O                                - some head work
       | O         mainprog-r0.0.0      - Now it's obvious why "Release" commits
       |/          core-r0.0.0            are called "leafs".
       O           mainprog-v0.0.0
       |           core-v0.0.0
       O

    $ git checkout latest
    $ cat mainprog/mainprog/__init__.py
    import polyvers

    __title__     = "mainprog"
    __version__ = '0.0.1.dev0'
    ...

    $ cat core/core/__init__.py
    import polyvers

    __title__ = "core"
    __version__ = '0.0.0+mainprog.0.0.1.dev0'
    ...
    $ git checkout -

Notice how the the `"local" part of PEP-440
<https://www.python.org/dev/peps/pep-0440/#local-version-identifiers>`_ (statring with ``+...``)
is used by the engraved version of the **un-bumped** ``core`` project to signify
the correlated version of the **bumped** ``mainprog``.  This trick is not necessary
for tags because they apply repo-wide, to all sub-projects.


.. _features:

Features
========
.. include:: <xhtml1-lat1.txt>
rubric::

    PEP 440 version ids
        While most versioning tools use `Semantic versioning
        <http://semver.org/>`_, python's ``distutils`` native library
        supports the quasi-superset, but more versatile, `PEP-440 version ids
        <https://www.python.org/dev/peps/pep-0440/>`_, like that:

        - Pre-releases: when working on new features::

            X.YbN               # Beta release
            X.YrcN  or  X.YcN   # Release Candidate
            X.Y                 # Final release

        - Post-release::

            X.YaN.postM         # Post-release of an alpha release
            X.YrcN.postM        # Post-release of a release candidate

        - Dev-release::

            X.YaN.devM          # Developmental release of an alpha release
            X.Y.postN.devM      # Developmental release of a post-release

    version-bump algebra
        When bumping, the increment over the base-version can be specified with a
        "relative version", which is a combination of pep(`0440`) segments and
        one of these modifiers: ``+^~=``
        See mod(`polyvers.vermath`) for more.

    repo scheme
    monorepo
    mono-project
        whether a git repo hosts a single or multiple subprojects

        **Rational:**

        When your single project succeeds, problems like these are known only too well:

          Changes in **web-server** part depend on **core** features that cannot
          go public because the "official" **wire-protocol** is freezed.

          While downstream projects using **core** as a library complain about
          its bloated transitive dependencies (asking why *flask* library is needed??).

        So the time to "split the project" has come.  But from **Lerna**:

          |laquo|\ Splitting up large codebases into separate independently versioned packages
          is extremely useful for code sharing. However, making changes across
          many repositories is messy and difficult to track, and testing across repositories
          gets complicated really fast.\ |Raquo|

        So a *monorepo* [#]_ [#]_ is the solution.
        But as `Yarn <https://yarnpkg.com/blog/2017/08/02/introducing-workspaces/>`_ put it:

          |laquo|\ OTOH, splitting projects into their own folders is sometimes not enough.
          Testing, managing dependencies, and publishing multiple packages quickly
          gets complicated and many such projects adopt tools such as ...\ |Raquo|

        *Polyvers* is such a tool.

        .. [#] <https://medium.com/@maoberlehner/monorepos-in-the-wild-33c6eb246cb9
        .. [#] http://www.drmaciver.com/2016/10/why-you-should-use-a-single-repository-for-all-your-companys-projects/

    version scheme
        the pattern for version-tags.
        2x2 *versioning schemes* are pre-configured, for **mono-project** and
        **monorepo** repositories, respectively:

        - `v1.2.3` (and `r1.2.3` applied on **leaf commit**\s)
        - `project-v1.2.3` (and `project-r1.2.3` for **leaf commit**\s)

    release scheme
    out-of-trunk commit
    leaf commit
    release tag
    r-tag
    version tag
    v-tag
        Even in single-project repos, sharing code across branches may cause
        merge-conflicts due to the version-ids **engrave**\d" in the sources.
        In **monorepo**\s, the versions proliferate, and so does the conflicts.

        Contrary to ref: *similar-tools*, static version-ids are engraved only in out-of-trunk
        (leaf) commits, and only when the sub-projects are released.
        In-trunk code is never touched, and version-ids are reported, on runtime, based
        on Git tags (like ``git-describe``), so they are always up-to-date.

    engrave
    engravings
        the search-n-replace in files, to substitute the new version.
        Default grep-like substitutions are included, which can be re-configured
        in the ``.polyvers.yaml`` config file.

    setuptools
    setuptools plugin
    setuptools integration
        The `polyversion` library function as a *setuptools* "plugin", and
        adds a new ``setup()`` keyword ``polyversion = (bool | dict)``
        (see func(`polyversion.init_plugin_kw`) for its content).

    bdist-check
        The **setuptools plugin** aborts any `bdist...` commands if they
        are not run from an **r-tag** (unless ``skip_polyversion_check = true``
        option exists in your project's ``setup.cfg:[global]`` section.

    Marking dependent versions across sub-projects
        [TODO] When bumping the version of a sub-project the `"local" part of PEP-440
        <https://www.python.org/dev/peps/pep-0440/#local-version-identifiers>`_
        on all other the *dependent* sub-projects in the monorepo  signify their relationship
        at the time of the bump.

    Lock release trains as "developmental"
        [TODO] Specific branches can be selected always to be published into *PyPi* only as
        `PEP-440's "Developmental" releases
        <https://www.python.org/dev/peps/pep-0440/#developmental-releases>`_, meanining that
        users need ``pip install --pre`` to install from such release-trains.
        This is a safeguard to avoid accidentally landing half-baked code to users.

    Other Features
        - Highly configurable using `traitlets <https://traitlets.readthedocs.io>`_,
          with sensible defaults; it should be possible to start using the tool
          without any config file (see `init` cmd), or by adding one of the flags
          ``--monorepo``/``--mono-project`` in all commands, in the face of
          conflicting tags.
        - Always accurate version reported on runtime when run from git repos
          (never again wonder with which version your experimental-data were produced).


Known Limitations, Drawbacks & Workarounds
------------------------------------------
.. TODO: epoch vermath, and update README

- PEP440 `Epoch` handling is not yet working.
- Version-bump's grammar is not yet as described in "GRAMMAR" section
  of command's doc::

    $ polyvers config desc --class BumpCmd
    BumpCmd(_SubCmd)
    ----------------
    Increase or set the version of project(s) to the (relative/absolute) version.
    SYNTAX:
        polyvers config desc [OPTIONS] <version> [<project>]...
    - If no project(s) specified, increase the versions on all projects.
    - Denied if version for some projects is backward-in-time (or has jumped parts?);
      use --force if you might.
    VERSION: - A version specifier, either ABSOLUTE, or RELATIVE to the current
    version og each project:
      - *ABSOLUTE* PEP-440 version samples:
        - Pre-releases: when working on new features:
            X.YbN               # Beta release
            X.YrcN  or  X.YcN   # Release Candidate
            X.Y                 # Final release
    ...

- WARNING: when you build your package for distribution (*wheel*, correct?)
  remember to switch to the **out-of-trunk commit**.
  This is particularly important if your ``setup.py`` file  use ``polyversion()``
  to derive its version.. Because if it fails for whatever reason
  (``git`` command is missing, project not located in a git-repo, miss-configuration,
  etc).

  Check also that if you provide a ``default`` argument to facilitate development,
  then you may actually build a package(*wheel*, ok?) with that "default" version.
  So, always check you package's version before uploading it to *pypi*.

- (not related to this tool) In ``setup.py`` script, the kw-argument
  ``package_dir={'': <sub-dir>}`` arg is needed for `py_modules` to work
  when packaging sub-projects (also useful with ``find_packages()``,
  check this project's sources).
  But ``<sub-dir>`` must be relative to launch cwd, or else,
  ``pip install -e <subdir>`` and/or ``python setup.py develop``
  break.

- (not related to this tool) When building projects with ``python setup.py bdist_XXX``,
  you have to clean up your build directory, or else, the distribution package
  will contain the sources from all previous subprojects.  That applies also
  when rebuilding a project between versions.

- (not related to this tool) If you don't place a ``setup.py`` file at the root
  of your git-repo, then it becomes more cumbersome to ``pip`` `install directly
  from remote URLs <https://pip.pypa.io/en/stable/reference/pip_install/#vcs-support>`_,
  like this:
  ::

      pip install -e git+https://repo_url/#egg=pkg&subdirectory=pkg_dir

  You may use ``package_dir`` argument to ``setup()`` function
  (see `setuptools-docs <http://setuptools.readthedocs.io/en/latest/setuptools.html#id10>`_).

- Set branch ``latest`` as default in GitHub to show **engrave**\d sub-project version-ids.

- See ref: *to-dos*.

.. _contribute-section:
.. _similar-tools:

Similar Tools
=============
Bumped across these projects while building it...

rubric::

    bumpversion
        The original **bumpversion** project; development stopped after 2015:
        (recomended also by **python guide**)
        https://github.com/peritus/bumpversion

    bump2version
        active clone of the original:
        https://github.com/c4urself/bump2version

    releash
        another **monorepo**\s managing tool, that publishes also to PyPi:
        https://github.com/maartenbreddels/releash

    Git Bump
        bump version using git-hooks:
        https://github.com/arrdem/git-bump

    Lerna
        A tool for managing JavaScript projects
        with multiple packages.
        https://lernajs.io/

    Pants
        a build system designed for codebases that:
        - Are large and/or growing rapidly.
        - Consist of many subprojects that share a significant amount of code.
        - Have complex dependencies on third-party libraries.
        - Use a variety of languages, code generators and frameworks.
        - https://www.pantsbuild.org/

    pbr
        a ``setup_requires`` library that
        injects sensible default and behaviors into your *setuptools*.
        Crafted for *Semantic Versioning*, maintained for OpenStack projects.
        https://docs.openstack.org/pbr/

    Zest.releaser
        easy releasing and tagging for Python packages; make easy, quick and
        neat releases of your Python packages.  You need to change the version number,
        add a new heading in your changelog, record the release date, svn/git/bzr/hg tag
        your project, perhaps upload it to pypi... *zest.releaser* takes care
        of the boring bits for you.
        (recomended also by **python guide**)
        http://zestreleaser.readthedocs.io/

    incremental
        a small *setuptools* plugin library that versions Python projects.
        https://github.com/twisted/incremental

    changes
        Manages the release of a Python Library (intuitive logo,
        recomended also by **python guide**):

        - Auto generates changelog entries from commit messages
        - CLI that follows Semantic Versioning principles to auto-increment the library version
        - Runs the library tests
        - Checks the package installation from a tarball and PyPi
        - Uploads the distribution to PyPi
        - Tags the GitHub repository

        https://github.com/michaeljoseph/changes

    setuptools_scm
        managing versions in scm metadata instead of declaring them as
        the version argument or in a scm managed file, apart from  handling
        file finders for the supported scmâ€™s.
        (recomended also by **python guide**)
        https://pypi.org/project/setuptools_scm/

        .. Note:
            Interesting how this project parses ``git describe`` tags:
            https://pypi.org/project/setuptools_scm/#default-versioning-scheme

    python guide
        There is a dedicated guide for this problem in pythons docs:
        https://packaging.python.org/guides/single-sourcing-package-version/

Find more than `34 similar projects in GitHub:
<https://github.com/search?l=Python&o=desc&q=bump+version&s=updated&type=Repositories>`_
and in awesome: https://github.com/korfuri/awesome-monorepo.




Credits
=======
- Contains a function from the BSD-tool :term`pbr` to fetch version from *pkg-metadata*
  when invoked as a **setuptools plugin** from inside an egg.

- This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template.

- Using `towncrier <https://pypi.org/project/towncrier/>`_ for generating CHANGES.

.. _Cookiecutter: https://github.com/audreyr/cookiecutter
.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage


Changes
=======

.. _to-dos:

TODOs
=====
- Parse ``git describe`` like `setuptools_scm plugin
  <https://pypi.org/project/setuptools_scm/#default-versioning-scheme>`_ does.

- Drop `pvcmd/pvtags.py`, and replace it with `polyversion`?

- Configurable hooks - refactor **engravings** as one of them.
  to run, for example, housekeeping commands on all subprojects like
  ``pip install -e <project>`` and immediately start working in "develop mode".

  This would allow housekeeping commands and *validate tests*
  before/after every bump::

      ## Pre-release hook
      #
      pytest tests


      ## Post-release hook
      #
      rm -r dist/* build/*;
      python setup.py sdist bdist_wheel
      twine upload dist/*whl -s

- Add top-level engrave glob-excludes.

- Refactor **version-bump algebra** to support a single modifier per segment
  (see ``multivermath`` branch).

- Lock release-trains as "alpha/beta".., specific branches can be selected
  Based on **version-bump algebra**), this will force users to always
  use ``pip install --pre`` to fetch such release-trains.
  This is a safeguard to avoid accidentally landing half-baked code to users.

- Retrofit `polyversion` library as a plugin of `polyvers` command.

- Function as plugin for other 3rd-party projects, bake a cookiecutter


.. towncrier release notes start

2018-06-06: polyvers-v0.1.0a0, polyversion-v0.1.0a6
====================================================
+ FEAT: reinstated **engravings** on ``setup.py`` (dropped only for a while
  in `2018-06-03: polyversion-v0.1.0a3`_ ), since, assuming clients have adopted
  the new **setuptools plugin** keyword, it is the `default_version` that
  will be engraved, which is fine.

+ fix: report any version matched both from **v-tag**\s and **r-tag**'s.

+ fix: ``bump`` command does not engrave *egg*-related files.

+ ``polyversion`` command got a bit more civilized (with logging to explain
  problems with related stacktraces.

+ dev: don't test building wheel on travis...too much fuzzz.


2018-06-06: polyversion-v0.1.0a5
================================
- Disable standalone-wheel hack from ``pvlib/setup.py`` and rely on
  *setuptools* plugin even for *polyversion* ONCE MORE.
  (but no need to update standalone, which is a wheel, unaffected by that)


2018-06-06: polyversion-v0.1.0a4
================================
Bugfixing `polyversion` (and generate a non-buggy standalone wheel):

- FIX `polyversion` where it ignored ``setup(default_version`` keyword.
  (git(`6519a1ba`))
- fix: `polyversion` stop eating half of its own dog food: cannot relibly use
  **setuptools plugin** for its installation. (git(`56a894cde`))
- Monkeypatching *distutils* for **bdist-check** was failing in *PY2*
  due to being an "old class". (git(`1f72baec`))

- doc: fixed recommendation about how to bypass **bdist-check** to this:

    ...
    You may bypass this check and create a package with non-engraved sources
    (although it might not work correctly) by adding `skip_polyversion_check` option
    in your ``setup.cfg`` file, like this::

        [global]
        skip_polyversion_check = true
        ...


2018-06-03: polyversion-v0.1.0a3
================================
- `v0.1.0a2`Canceled (like the previous 2), cannot release from r-tags because ``setup()``
  reports version from v-tag.
  Q: Is a new setup-keyword needed ``--is-polyversion-release``?
  (A: no, just fetch both)
- `v0.1.0a0` had been canceled for the same reason, but somewhere down the road,
  the fix was reverted (**bdist-check** works for r-tag only).
- `v0.1.0a1` just marked that our ``setup.py`` files ate our dog food.

Breaking changes
-----------------
- Dropped all positional-arguments from func(`polyversion.polyversion()`);
  was error-prone.  They have all been converted to keyword-arguments.

- Renamed data in mod(`polyversion`)
  (also applied for class(`polyvers.pvproject.Project()`))::

        pvtag_frmt  --> pvtag_format
        vtag_frmt   --> vtag_format

- Changed arguments in func(`polyversion.polyversion()`)
  (affect also class(`polyvers.pvproject.Project()`))::

      default     --> default_version
      tag_frmt    --> tag_format
                  --> vprefixes   (new)
                  --> is_release  (new)

- REVERTED again the `0.0.2a9` default logic to raise when it version/time
  cannot be derived.  Now by default it raises, unless default-version or
  ``no_raise`` for func(`polyversion.polytime()`).

- Stopped engraving ``setup.py`` files ; clients should use *setuptools* plugin
  to derive version for those files (see new features, below)).
  For reference, this is the removed element from default class(`~Project`)'s
  configuration (in YAML)::

        globs: [setup.py]
        grafts:
            - regex: -|
                (?xm)
                    \bversion
                    (\ *=\ *)
                    .+?(,
                    \ *[\n\r])+

- *polyversion* library searches both *v-tags* and *r-tags* (unless limited).
  Previously, even checked-out on an *r-tag*, both ``polyversion`` command
  and ``polyvers bump`` would ignore it, and report +1 from the *v-tag*!

Features
--------
- The `polyversion` library function as a *setuptools* "plugin", and
  adds two new ``setup()`` keywords for deriving subproject versions
  from PKG-INFO or git tags  (see func(`polyversion.init_plugin_kw`)):

  1. keyword: ``polyversion --> (bool | dict)``
      When a dict, its keys roughly mimic those in func(`polyversion()`),
      and can be used like this:

      .. code-block:: python

          from setuptools import setup

          setup(
              project='myname',
              version=''              # omit (or None) to abort if cannot auto-version
              polyversion={           # dict or bool
                  'mono_project': True, # false by default
                  ...  # See `polyversion.init_plugin_kw()` for more keys.
              },
              setup_requires=[..., 'polyversion'],
              ...
          )

  2. keyword: ``skip_polyversion_check --> bool``
     When true, disable **bdist-check**, when false (default),
     any `bdist_*` (e.g. ``bdist_wheel``), commands will abort if not run
     from a **release tag**.
     You may bypass this check and create a package with non-engraved sources
     (although it might not work correctly) by invoking the setup-script
     from command-line like this::

         $ python setup.py bdist_wheel --skip-polyversion-check

- `bump` cmd: engrave also non-bumped projects with their ``git describe``-derived
   version (controlled by ``--BumpCmd.engrave_bumped_only`` flag).

- Assign names to engraves & grafts for readable printouts, and for refering to
  them from the new `Project.enabled_engarves` list. (namengraves)

- ``polyversion -t`` command-line tool prints the full tag (not the version)
  to make it easy to know if it is a v-tag or r-tag.

Documentation changes
---------------------

- Adopt `towncrier` for compiling CHANGES. So now each code change can describe
  its change in the same commit, without conflicts. (towncrier)
- usage: explain how to set your projects pep(`0518`) ``pyproject.toml``
  file & ``setup_requires`` keyword in ``setup.py`` in your script.
- add `pbr`, `incremental` and `Zest.release` in ref: *similar-tools* section
  as  *setuptools* plugins.
- re-wrote and shrinked opening section using glossary terms.

- Chore development:
    - deps: don't pin `packaging==17.1`, any bigger +17 is fine for parsing
      version correctly.


0.0.2a10 (2018-05-24): polyvers
-------------------------------
- fix: slight change of default engraving for ``setup.py:version=...``.
- Remove default versions from the sources of our-own-dog-food
  (affects installations for developing this tool).
- refact: merged ```pvlib.whl`` and ``pvlib.run`` into a single executable and
  importable standalone wheel in ``bin/pvlib.run``, generated from
  ``polyversion-0.0.2a9``, release below.
- doc: expand section for installing and contributing into this project.
- chore: tighten various test harnesses.

0.0.2a9 (2018-05-24): polyversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2nd interim release to embed new ``bin/pvlib.run``.

- INVERT by default ``polyversion()/polytime()`` functions not to raise
  if vtags missing.
- fix: `pvlib.run` shebang to use ``#!/usr/bin/env python`` to work on linux.

0.0.2a8 (2018-05-23): polyversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Interim release to embed new ``bin/pvlib.run``.

- FIX ``polyversion`` barebone command (a utility for when not installing
  the full `polyvers` tool).
- feat: make project-name optional in func(`polyversion.polyversion()`);
  if not given,  defaults to caller's last segment of the  module.
- doc: rudimentary explanation of how to use the lib on its own README.


0.0.2a9.post0 (2018-05-23): polyvers
------------------------------------
- feat: add ``-C`` option to change project dir before running command.
- ``init`` command:
    - fix: were creating invalid ``.polyvers.yaml`` configuration-file
      unless ``--monorepo/--mono-project`` flags were given.
    - feat: include config-help in generated file only if
      the new ``--doc`` flag given.
    - feat: inform user of the projects auto-discovered and what type of config-file
      was generated.
- various fixes.


0.0.2a8 (2018-05-19): polyvers
------------------------------
- FIX(bump): was engraving all projects and not limiting to those
  specified in the command-line - command's syntax slightly changed.
- chore: Stop increasing `polyversion` version from now on.
- doc: fix all sphinx errors and API reference.

0.0.2a7 (2018-05-18)
^^^^^^^^^^^^^^^^^^^^
Interim release to embed re-LICENSED ``pvlib/bin/pvlib.whl``,
from EUPLv1.2-->MIT


0.0.2a6 (2018-05-18)
--------------------
- ``bump`` command:
    - feat: ``--amend`` now works
    - feat: ``--engrave-only``.
    - feat: log ``PRETEND`` while doing actions.
    - feat: Log which files where engraved in the final message.
- fix(engrave): don't waste cycles/log-messages on empty-matches (minor).


0.0.2a5 (2018-05-18)
--------------------
Actually most changes happened in "interim" release `v0.0.2a2`, below.

- feat: make a standalone polyversion-lib wheel to facilitate bootstrap
  when installing & building from sources (and the lib is not yet installed).
- Add ``bin/package.sh`` that create the `pvlib` wheel as executable ``dist/pvlib.run``.
- doc: fix rtd & pypi sites.

0.0.2a4 (2018-05-18)
^^^^^^^^^^^^^^^^^^^^
doc: bad PyPi landing page.

0.0.2a3 (2018-05-17)
^^^^^^^^^^^^^^^^^^^^
The `pvcmd` was actually broken so far; was missing `polyversion` lib
dependency!

0.0.2a2 (2018-05-17)
^^^^^^^^^^^^^^^^^^^^
Interim release to produce executable wheel needed by next release.


0.0.2a1 (2018-05-17)
--------------------
- 2nd release, own "mono-project" splitted into 2-project "monorepo":
  - **polyvers:** cmdline tool
  - **polyversion:** library code for program-sources to derive version from git-tags
- `init`, `status`, `bump` and `config` commands work.
- Read/write YAML config file ``.polyvers.yaml`` at the git-root,
  and can automatically discover used configuration (from existing git *tags*
  or projects files).
- Support both ``--monorepo`` and ``--mono-project`` configurations.
- By default ``__init__.py``, ``setup.py`` and ``README.rst`` files are engraved
  with bumped version.

0.0.2a0 (2018-05-16)
^^^^^^^^^^^^^^^^^^^^
broken


0.0.1a0 (2018-01-29)
--------------------
- First release on PyPI as *mono-project*


