vaab / gitchangelog

Creates a changelog from git log history.
Other
584 stars 139 forks source link
changelog developer git packaging python

============ gitchangelog

.. image:: https://img.shields.io/pypi/v/gitchangelog.svg?style=flat :target: https://pypi.python.org/pypi/gitchangelog/ :alt: Latest PyPI version

.. image:: https://img.shields.io/pypi/dm/gitchangelog.svg?style=flat :target: https://pypi.python.org/pypi/gitchangelog/ :alt: Number of PyPI downloads

.. image:: https://img.shields.io/travis/vaab/gitchangelog/master.svg?style=flat :target: https://travis-ci.org/vaab/gitchangelog/ :alt: Travis CI build status

.. image:: https://img.shields.io/appveyor/ci/vaab/gitchangelog.svg :target: https://ci.appveyor.com/project/vaab/gitchangelog/branch/master :alt: Appveyor CI build status

.. image:: https://img.shields.io/codecov/c/github/vaab/gitchangelog.svg :target: https://codecov.io/gh/vaab/gitchangelog :alt: Test coverage

Use your commit log to make beautifull and configurable changelog file.

Feature

.. _trailers key values: https://git.wiki.kernel.org/index.php/CommitMessageConventions

Requirements

gitchangelog is compatible Python 2 and Python 3 on Linux/BSD/MacOSX and Windows.

Please submit an issue if you encounter incompatibilities.

Installation

full package

Gitchangelog is published on PyPI, thus:

pip install gitchangelog

.. is the way to go for install the full package on any platform.

If you are installing from source, please note that the development tools are not working fully yet on Windows.

The full package provides the gitchangelog.py executable as long as:

from source

If you'd rather work from the source repository, it supports the common idiom to install it on your system::

python setup.py install

Note that for linux/BSD, there's a link to the executable in the root of the source. This can be a convenient way to work on the source version.

single executable installation

The file gitchangelog.py is a full blown executable and can be used without any other files. This is easier to use naturally on Linux/BSD systems. For instance, you could type in::

curl -sSL https://raw.githubusercontent.com/vaab/gitchangelog/master/src/gitchangelog/gitchangelog.py > /usr/local/bin/gitchangelog &&
chmod +x /usr/local/bin/gitchangelog

It'll install gitchangelog to be accessible for all users and will use the default python interpreter of your running session.

Please note: if you choose to install it in this standalone mode, then you must make sure to value at least all the required configuration keys in your config file. As a good start you should probably copy the reference configuration file_ as you base configuration file.

This is due to the fact that gitchangelog can not anymore reach the reference configuration file to get default values.

Sample

The default output is ReSTructured text, so it should be readable in ASCII.

Here is a small sample of the gitchangelog changelog at work.

Current git log output so you can get an idea of the log history::

And here is the gitchangelog output::

0.1.2 (2011-05-17)

New

  - Sections in changelog are now in the order given in ``git-
    changelog.rc`` in the ``section_regexps`` option. [Valentin Lab]
  - Added ``body_split_regexp`` option to attempts to format correctly
    body of commit. [Valentin Lab]
  - Use a list of tuple instead of a dict for ``section_regexps`` to be
    able to manage order between section on find match. [Valentin Lab]
  - New ``unreleased_version_label`` option in ``gitchangelog.rc`` to
    change label of not yet released code. [Valentin Lab]
  - Use ``gitchangelog`` section in ``git config`` world appropriately.
    [Valentin Lab]

  Changes

And the rendered full result is directly used to generate the HTML webpage of the changelog of the PyPI page_.

Usage

The reference configuration file_ is delivered within gitchangelog package and is used to provides defaults to settings. If you didn't install the package and used the standalone file, then chances are that gitchangelog can't access these defaults values. This is not a problem as long as you provided all the required values in your config file.

The recommended location for gitchangelog config file is the root of the current git repository with the name .gitchangelog.rc. However you could put it elsewhere, and here are the locations checked (first match will prevail):

Then, you'll be able to call gitchangelog in a GIT repository and it'll print changelog on its standard output.

Configuration file format

The reference configuration file_ is quite heavily commented and is quite simple. You should be able to use it as required.

.. _reference configuration file: https://github.com/vaab/gitchangelog/blob/master/src/gitchangelog/gitchangelog.rc.reference

The changelog of gitchangelog is generated with himself and with the reference configuration file. You'll see the output in the changelog of the PyPI page_.

.. _changelog of the PyPI page: http://pypi.python.org/pypi/gitchangelog

Output Engines

At the end of the configuration file, you'll notice a variable called output_engine. By default, it's set to rest_py, which is the legacy python engine to produce the ReSTructured Text output format that is shown in above samples. If this engine fits your needs, you won't need to fiddle with this option.

To render the template, gitchangelog will generate a data structure that will then be rendered thanks to the output engine. This should help you get the exact output that you need.

As people might have different needs and knowledge, a templating system using mustache is available. mustache templates are provided to render both ReSTructured Text or markdown formats. If you know mustache templating, then you could easily add or modify these existing templates.

A mako templating engine is also provided. You'll find also a mako template producing the same ReSTructured Text output than the legacy one. It's provided for reference and/or further tweak if you would rather use mako_ templates.

Mustache


The ``mustache``  output engine uses `mustache templates`_.

The `mustache`_ templates are powered via `pystache`_ the python
implementation of the `mustache`_ specifications. So `mustache`_ output engine
will only be available if you have `pystache`_ module available in your python
environment.

There are `mustache templates`_ bundled with the default installation
of gitchangelog. These can be called by providing a simple label to the
``mustache(..)`` output_engine, for instance (in your ``.gitchangelog.rc``)::

    output_engine = mustache("markdown")

Or you could provide your own mustache template by specifying an
absolute path (or a relative one, starting from the git toplevel of
your project by default, or if set, the
``git config gitchangelog.template-path``
location) to your template file, for instance::

    output_engine = mustache(".gitchangelog.tpl")

And feel free to copy the bundled templates to use them as bases for
your own variations. In the source code, these are located in
``src/gitchangelog/templates/mustache`` directory, once installed they
are in ``templates/mustache`` directory starting from where your
``gitchangelog.py`` was installed.

.. _mustache: http://mustache.github.io
.. _pystache: https://pypi.python.org/pypi/pystache
.. _mustache templates: http://mustache.github.io/mustache.5.html

Mako

The makotemplate output engine templates for gitchangelog are powered via mako python templating system. So mako output engine will only be available if you have mako_ module available in your python environment.

There are mako_ templates bundled with the default installation of gitchangelog. These can be called by providing a simple label to the makotemplate(..) output_engine, for instance (in your .gitchangelog.rc)::

output_engine = makotemplate("markdown")

Or you could provide your own mustache template by specifying an absolute path (or a relative one, starting from the git toplevel of your project by default, or if set, the git config gitchangelog.template-path location) to your template file, for instance::

output_engine = makotemplate(".gitchangelog.tpl")

And feel free to copy the bundled templates to use them as bases for your own variations. In the source code, these are located in src/gitchangelog/templates/mako directory, once installed they are in templates/mako directory starting from where your gitchangelog.py was installed.

.. _mako: http://www.makotemplates.org

Changelog data tree


This is a sample of the current data structure sent to output engines::

  {'title': 'Changelog',
   'versions': [{'label': '%%version%% (unreleased)',
                 'date': None,
                 'tag': None
                 'sections': [{'label': 'Changes',
                               'commits': [{'author': 'John doe',
                                            'body': '',
                                            'subject': 'Adding some extra values.'},
                                           {'author': 'John Doe',
                                            'body': '',
                                            'subject': 'Some more changes'}]},
                              {'label': 'Other',
                               'commits': [{'author': 'Jim Foo',
                                            'body': '',
                                            'subject': 'classic modification'},
                                           {'author': 'Jane Done',
                                            'body': '',
                                            'subject': 'Adding some stuff to do.'}]}]},
                {'label': 'v0.2.5 (2013-08-06)',
                 'date': '2013-08-06',
                 'tag': 'v0.2.5'
                 'sections': [{'commits': [{'author': 'John Doe',
                                            'body': '',
                                            'subject': 'Updating Changelog installation.'}],
                               'label': 'Changes'}]}]}

Merged branches history support

Commit attribution to a specific version could be tricky. Suppose you have this typical merge tree (spot the tags!)::

* new: something  (HEAD, tag: 0.2, develop)
*   Merge tag '0.1.1' into develop
|\
| * fix: out-of-band hotfix  (tag: 0.1.1)
* | chg: continued development
|/
* fix: something  (tag: 0.1)
* first commit  (tag: 0.0.1, master)

Here's a minimal draft of gitchangelog to show how commit are attributed to versions::

0.2
  * new: something.
  * Merge tag '0.1.1' into develop.
  * chg: continued development.

0.1.1
  * fix: out-of-band hotfix.

0.1
  * fix: something.

.. note:: you can remove automatically all merge commit from gitchangelog output by using include_merge = False in the .gitchangelog.rc file.

Use cases

No sectionning

If you want to remove sectionning but keep anything else, you should probably use::

section_regexps = [
    ('', None)
]

subject_process = (strip | ucfirst | final_dot)

This will disable sectionning and won't remove the prefixes used for sectionning from the commit's summary.

Incremental changelog

Also known as partial changelog generation, this feature allows to generate only a subpart of your changelog, and combined with configurable publishing actions, you can insert the result inside an existing changelog. Usually this makes sense:

Generating partial changelog is as simple as gitchangelog REVLIST. Examples follows::

## will output only tags between 0.0.2 (excluded) and 0.0.3 (included)
gitchangelog 0.0.2..0.0.3

## will output only tags since 0.0.3 (excluded)
gitchangelog ^0.0.3 HEAD

## will output all tags up to 0.0.3 (included)
gitchangelog 0.0.3

Additionally, gitchangelog can figure out automatically which revision is the last for you (with some little help). This is done by specifying the revs config option. This config file option will be used as if specified on the command line.

Here is an example that fits the current changelog format::

revs = [
    Caret(
        FileFirstRegexMatch(
            "CHANGELOG.rst",
            r"(?P<rev>[0-9]+\.[0-9]+(\.[0-9]+))\s+\([0-9]+-[0-9]{2}-[0-9]{2}\)\n--+\n")),
]

This will look into the file CHANGELOG.rst for the first match of the given regex and return the match of the rev regex sub-pattern it as a string. The Caret function will simply prefix the given string with a ^. As a consequence, this code will prevent recreating any previously generated changelog section (more information about the REVLIST syntax_ from git rev-list arguments.)

.. _REVLIST syntax: https://git-scm.com/docs/git-rev-list#_description

Note that the data structure provided to the template will set the title to None if you provided no REVLIST through command-line or the config file (or if the revlist was equivalently set to ["HEAD", ]). This a good way to make your template detect it is in "incremental mode".

By default, this will only output to standard output the new sections of your changelog, you might want to insert it directly in your existing changelog. This is where publish parameters will help you. By default it is set to stdout, and you might want to set it to::

publish = FileInsertIntoFirstRegexMatch(
    "CHANGELOG.rst",
    r'/(?P<rev>[0-9]+\.[0-9]+(\.[0-9]+)?)\s+\([0-9]+-[0-9]{2}-[0-9]{2}\)\n--+\n/',
    idx=lambda m: m.start(1)
)

The full recipe could be::

OUTPUT_FILE = "CHANGELOG.rst"
INSERT_POINT = r"\b(?P<rev>[0-9]+\.[0-9]+)\s+\([0-9]+-[0-9]{2}-[0-9]{2}\)\n--+\n"
revs = [
        Caret(FileFirstRegexMatch(OUTPUT_FILE, INSERT_POINT)),
        "HEAD"
]

action = FileInsertAtFirstRegexMatch(
    OUTPUT_FILE, INSERT_POINT,
    idx=lambda m: m.start(1)
)

Alternatively, you can use this other recipe, using FileRegexSubst, that has the added advantage of being able to update the unreleased part if you had it already generated and need a re-fresh because you added new commits or amended some commits::

OUTPUT_FILE = "CHANGELOG.rst"
INSERT_POINT_REGEX = r'''(?isxu)
^
(
  \s*Changelog\s*(\n|\r\n|\r)        ## ``Changelog`` line
  ==+\s*(\n|\r\n|\r){2}              ## ``=========`` rest underline
)

(                     ## Match all between changelog and release rev
    (
      (?!
         (?<=(\n|\r))                ## look back for newline
         %(rev)s                     ## revision
         \s+
         \([0-9]+-[0-9]{2}-[0-9]{2}\)(\n|\r\n|\r)   ## date
           --+(\n|\r\n|\r)                          ## ``---`` underline
      )
      .
    )*
)

(?P<rev>%(rev)s)
''' % {'rev': r"[0-9]+\.[0-9]+(\.[0-9]+)?"}

revs = [
    Caret(FileFirstRegexMatch(OUTPUT_FILE, INSERT_POINT_REGEX)),
    "HEAD"
]

publish = FileRegexSubst(OUTPUT_FILE, INSERT_POINT_REGEX, r"\1\o\g<rev>")

As a second example, here is the same recipe for mustache markdown format::

OUTPUT_FILE = "CHANGELOG.rst"
INSERT_POINT_REGEX = r'''(?isxu)
^
(
  \s*\#\s+Changelog\s*(\n|\r\n|\r)        ## ``Changelog`` line
)

(                     ## Match all between changelog and release rev
    (
      (?!
         (?<=(\n|\r))                ## look back for newline
         \#\#\s+%(rev)s                     ## revision
         \s+
         \([0-9]+-[0-9]{2}-[0-9]{2}\)(\n|\r\n|\r)   ## date
      )
      .
    )*
)

(?P<tail>\#\#\s+(?P<rev>%(rev)s))
''' % {'rev': r"[0-9]+\.[0-9]+(\.[0-9]+)?"}

revs = [
    Caret(FileFirstRegexMatch(OUTPUT_FILE, INSERT_POINT_REGEX)),
    "HEAD"
]

publish = FileRegexSubst(OUTPUT_FILE, INSERT_POINT_REGEX, r"\1\o\n\g<tail>")

Contributing

Any suggestion or issue is welcome. Push request are very welcome, please check out the guidelines.

Push Request Guidelines

You can send any code. I'll look at it and will integrate it myself in the code base while leaving you as the commit(s) author. This process can take time and it'll take less time if you follow the following guidelines:

If you have some questions about guidelines which is not answered here, please check the current git log, you might find previous commit that would show you how to deal with your issue. Otherwise, just send your PR and ask your question. I won't bite. Promise.

License

Copyright (c) 2012-2018 Valentin Lab.

Licensed under the BSD License_.

.. _BSD License: http://raw.github.com/vaab/gitchangelog/master/LICENSE