changelog-0.4.2/ 0000775 0001750 0001750 00000000000 13354475055 014545 5 ustar classic classic 0000000 0000000 changelog-0.4.2/LICENSE 0000664 0001750 0001750 00000002162 13011372263 015536 0 ustar classic classic 0000000 0000000 This is the MIT license: http://www.opensource.org/licenses/mit-license.php
Copyright (C) 2012 by Michael Bayer.
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
changelog-0.4.2/MANIFEST.in 0000664 0001750 0001750 00000000103 13011372263 016260 0 ustar classic classic 0000000 0000000 recursive-include changelog *.py *.css
include README* LICENSE
changelog-0.4.2/PKG-INFO 0000664 0001750 0001750 00000007510 13354475055 015645 0 ustar classic classic 0000000 0000000 Metadata-Version: 1.1
Name: changelog
Version: 0.4.2
Summary: Provides simple Sphinx markup to render changelog displays.
Home-page: http://bitbucket.org/zzzeek/changelog
Author: Mike Bayer
Author-email: mike@zzzcomputing.com
License: MIT
Description: ==========
Changelog
==========
A `Sphinx `_ extension to generate changelog files.
This is an experimental, possibly-not-useful extension that's used by the
`SQLAlchemy `_ project and related projects.
Configuration
=============
A sample configuration in ``conf.py`` looks like this::
extensions = [
# changelog extension
'changelog',
# your other sphinx extensions
# ...
]
# section names - optional
changelog_sections = ["general", "rendering", "tests"]
# tags to sort on inside of sections - also optional
changelog_inner_tag_sort = ["feature", "bug"]
# how to render changelog links - these are plain
# python string templates, ticket/pullreq/changeset number goes
# in "%s"
changelog_render_ticket = "http://bitbucket.org/myusername/myproject/issue/%s"
changelog_render_pullreq = "http://bitbucket.org/myusername/myproject/pullrequest/%s"
changelog_render_changeset = "http://bitbucket.org/myusername/myproject/changeset/%s"
Usage
=====
Changelog introduces the ``changelog`` and ``change`` directives::
====================
Changelog for 1.5.6
====================
.. changelog::
:version: 1.5.6
:released: Sun Oct 12 2008
.. change::
:tags: general
:tickets: 27
Improved the frobnozzle.
.. change::
:tags: rendering, tests
:pullreq: 8
:changeset: a9d7cc0b56c2
Rendering tests now correctly render.
With the above markup, the changes above will be rendered into document sections
per changelog, then each change within organized into paragraphs, including
special markup for tags, tickets mentioned, pull requests, changesets. The entries will
be grouped and sorted by tag according to the configuration of the ``changelog_sections``
and ``changelog_inner_tag_sort`` configurations.
A "compound tag" can also be used, if the configuration has a section like this::
changelog_sections = ["orm declarative", "orm"]
Then change entries which contain both the ``orm`` and ``declarative`` tags will be
grouped under a section called ``orm declarative``, followed by the ``orm`` section where
change entries that only have ``orm`` will be placed.
Other Markup
============
The ``:ticket:`` directive will make use of the ``changelog_render_ticket`` markup
to render a ticket link::
:ticket:`456`
Keywords: Sphinx
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Documentation
changelog-0.4.2/README.rst 0000664 0001750 0001750 00000004752 13011372263 016227 0 ustar classic classic 0000000 0000000 ==========
Changelog
==========
A `Sphinx `_ extension to generate changelog files.
This is an experimental, possibly-not-useful extension that's used by the
`SQLAlchemy `_ project and related projects.
Configuration
=============
A sample configuration in ``conf.py`` looks like this::
extensions = [
# changelog extension
'changelog',
# your other sphinx extensions
# ...
]
# section names - optional
changelog_sections = ["general", "rendering", "tests"]
# tags to sort on inside of sections - also optional
changelog_inner_tag_sort = ["feature", "bug"]
# how to render changelog links - these are plain
# python string templates, ticket/pullreq/changeset number goes
# in "%s"
changelog_render_ticket = "http://bitbucket.org/myusername/myproject/issue/%s"
changelog_render_pullreq = "http://bitbucket.org/myusername/myproject/pullrequest/%s"
changelog_render_changeset = "http://bitbucket.org/myusername/myproject/changeset/%s"
Usage
=====
Changelog introduces the ``changelog`` and ``change`` directives::
====================
Changelog for 1.5.6
====================
.. changelog::
:version: 1.5.6
:released: Sun Oct 12 2008
.. change::
:tags: general
:tickets: 27
Improved the frobnozzle.
.. change::
:tags: rendering, tests
:pullreq: 8
:changeset: a9d7cc0b56c2
Rendering tests now correctly render.
With the above markup, the changes above will be rendered into document sections
per changelog, then each change within organized into paragraphs, including
special markup for tags, tickets mentioned, pull requests, changesets. The entries will
be grouped and sorted by tag according to the configuration of the ``changelog_sections``
and ``changelog_inner_tag_sort`` configurations.
A "compound tag" can also be used, if the configuration has a section like this::
changelog_sections = ["orm declarative", "orm"]
Then change entries which contain both the ``orm`` and ``declarative`` tags will be
grouped under a section called ``orm declarative``, followed by the ``orm`` section where
change entries that only have ``orm`` will be placed.
Other Markup
============
The ``:ticket:`` directive will make use of the ``changelog_render_ticket`` markup
to render a ticket link::
:ticket:`456`
changelog-0.4.2/changelog/ 0000775 0001750 0001750 00000000000 13354475055 016474 5 ustar classic classic 0000000 0000000 changelog-0.4.2/changelog/__init__.py 0000664 0001750 0001750 00000000074 13354475017 020604 0 ustar classic classic 0000000 0000000 __version__ = '0.4.2'
from .sphinxext import setup # noqa
changelog-0.4.2/changelog/changelog.css 0000664 0001750 0001750 00000000141 13011372263 021114 0 ustar classic classic 0000000 0000000 a.changeset-link {
visibility: hidden;
}
li:hover a.changeset-link {
visibility: visible;
}
changelog-0.4.2/changelog/cmd.py 0000664 0001750 0001750 00000004120 13241610175 017573 0 ustar classic classic 0000000 0000000 import re
import os
import tempfile
import shutil
import argparse
import sys
def release_notes_into_changelog_file(target_filename, version, release_date):
output = tempfile.NamedTemporaryFile(mode='w', delete=False, encoding='utf-8')
with open(target_filename) as handle:
for line in handle:
m = re.match(r".*:version: %s" % version, line)
if m:
output.write(line)
output.write(" :released: %s\n" % release_date)
continue
m = re.match(r".*:include_notes_from: (.+)", line)
if m:
notes_dir = os.path.join(
os.path.dirname(target_filename),
m.group(1)
)
for fname in os.listdir(notes_dir):
if not fname.endswith(".rst"):
continue
fname_path = os.path.join(notes_dir, fname)
output.write("\n")
with open(fname_path) as inner:
for inner_line in inner:
output.write((" " + inner_line).rstrip() + "\n")
os.system("git rm %s" % fname_path)
else:
output.write(line)
output.close()
shutil.move(output.name, target_filename)
def main(argv=None):
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
subparser = subparsers.add_parser(
"release-notes",
help="Merge notes files into changelog and git rm"
)
subparser.add_argument("filename", help="target changelog filename")
subparser.add_argument("version",
help="version string as it appears in changelog")
subparser.add_argument("date", help="full text of datestamp to insert")
subparser.set_defaults(
cmd=(release_notes_into_changelog_file,
["filename", "version", "date"]))
options = parser.parse_args(argv)
fn, argnames = options.cmd
fn(*[getattr(options, name) for name in argnames])
if __name__ == '__main__':
main(sys.argv)
changelog-0.4.2/changelog/render.py 0000664 0001750 0001750 00000016007 13354475006 020325 0 ustar classic classic 0000000 0000000 #! coding: utf-8
from docutils import nodes
import itertools
import collections
def render_changelog(changelog_directive):
changes = changelog_directive.get_changes_list(
changelog_directive.env, changelog_directive.version).values()
output = []
id_prefix = "change-%s" % (changelog_directive.version, )
topsection = _run_top(changelog_directive, id_prefix)
output.append(topsection)
bysection, all_sections = _organize_by_section(
changelog_directive, changes)
counter = itertools.count()
sections_to_render = [
s for s in changelog_directive.sections if s in all_sections]
if not sections_to_render:
for cat in changelog_directive.inner_tag_sort:
append_sec = _append_node(changelog_directive)
for rec in bysection[(changelog_directive.default_section, cat)]:
rec["id"] = "%s-%s" % (id_prefix, next(counter))
_render_rec(changelog_directive, rec, None, cat, append_sec)
if append_sec.children:
topsection.append(append_sec)
else:
for section in sections_to_render + [
changelog_directive.default_section]:
sec = nodes.section(
'',
nodes.title(section, section),
ids=["%s-%s" % (id_prefix, section.replace(" ", "-"))]
)
append_sec = _append_node(changelog_directive)
sec.append(append_sec)
for cat in changelog_directive.inner_tag_sort:
for rec in bysection[(section, cat)]:
rec["id"] = "%s-%s" % (id_prefix, next(counter))
_render_rec(
changelog_directive,
rec, section, cat, append_sec)
if append_sec.children:
topsection.append(sec)
return output
def _organize_by_section(changelog_directive, changes):
compound_sections = [
(s, s.split(" ")) for s in changelog_directive.sections if " " in s]
bysection = collections.defaultdict(list)
all_sections = set()
for rec in changes:
assert changelog_directive.version == rec['render_for_version']
inner_tag = rec['tags'].intersection(
changelog_directive.inner_tag_sort)
if inner_tag:
inner_tag = inner_tag.pop()
else:
inner_tag = ""
for compound, comp_words in compound_sections:
if rec['tags'].issuperset(comp_words):
bysection[(compound, inner_tag)].append(rec)
all_sections.add(compound)
break
else:
intersect = rec['tags'].intersection(changelog_directive.sections)
if intersect:
for sec in rec['sorted_tags']:
if sec in intersect:
bysection[(sec, inner_tag)].append(rec)
all_sections.add(sec)
break
else:
bysection[
(changelog_directive.default_section, inner_tag)
].append(rec)
return bysection, all_sections
def _append_node(changelog_directive):
return nodes.bullet_list()
def _run_top(changelog_directive, id_prefix):
version = changelog_directive._parsed_content.get('version', '')
topsection = nodes.section(
'',
nodes.title(version, version),
ids=[id_prefix]
)
if changelog_directive._parsed_content.get("released"):
topsection.append(
nodes.Text("Released: %s" %
changelog_directive._parsed_content['released'])
)
else:
topsection.append(nodes.Text("no release date"))
intro_para = nodes.paragraph('', '')
len_ = -1
for len_, text in enumerate(changelog_directive._parsed_content['text']):
if ".. change::" in text:
break
# if encountered any text elements that didn't start with
# ".. change::", those become the intro
if len_ > 0:
changelog_directive.state.nested_parse(
changelog_directive._parsed_content['text'][0:len_], 0,
intro_para)
topsection.append(intro_para)
return topsection
def _render_rec(changelog_directive, rec, section, cat, append_sec):
para = rec['node'].deepcopy()
targetid = "change-%s" % (
rec['version_to_hash'][changelog_directive.version],
)
targetnode = nodes.target('', '', ids=[targetid])
para.insert(0, targetnode)
permalink = nodes.reference(
'', '',
nodes.Text(u"¶", u"¶"),
refid=targetid,
classes=['changeset-link', 'headerlink'],
)
para.append(permalink)
if len(rec['versions']) > 1:
backported_changes = rec['sorted_versions'][
rec['sorted_versions'].index(changelog_directive.version) + 1:]
if backported_changes:
backported = nodes.paragraph('')
backported.append(nodes.Text("This change is also ", ""))
backported.append(nodes.strong("", "backported"))
backported.append(
nodes.Text(" to: %s" % ", ".join(backported_changes), ""))
para.append(backported)
insert_ticket = nodes.paragraph('')
para.append(insert_ticket)
i = 0
for collection, render, prefix in (
(rec['tickets'],
changelog_directive.env.config.changelog_render_ticket, "#%s"),
(rec['pullreq'],
changelog_directive.env.config.changelog_render_pullreq,
"pull request %s"),
(rec['changeset'],
changelog_directive.env.config.changelog_render_changeset, "r%s"),
):
for refname in sorted(collection):
if i > 0:
insert_ticket.append(nodes.Text(", ", ", "))
else:
insert_ticket.append(nodes.Text("References: """))
i += 1
if render is not None:
if isinstance(render, dict):
if ":" in refname:
typ, refval = refname.split(":")
else:
typ = "default"
refval = refname
refuri = render[typ] % refval
else:
refuri = render % refname
node = nodes.reference(
'', '',
nodes.Text(prefix % refname, prefix % refname),
refuri=refuri
)
else:
node = nodes.Text(prefix % refname, prefix % refname)
insert_ticket.append(node)
if rec['tags']:
tag_node = nodes.strong(
'',
" ".join(
"[%s]" % t for t in
[t1 for t1 in [section, cat] if t1 in rec['tags']] +
list(sorted(rec['tags'].difference([section, cat])))
) + " "
)
para.children[0].insert(0, tag_node)
append_sec.append(
nodes.list_item(
'',
nodes.target('', '', ids=[rec['id']]),
para
)
)
changelog-0.4.2/changelog/sphinxext.py 0000664 0001750 0001750 00000031162 13353522554 021077 0 ustar classic classic 0000000 0000000 import collections
import copy
import hashlib as md5
import os
import re
import warnings
import sys
from docutils.parsers.rst import Directive
from docutils import nodes
from sphinx.util.console import bold
from sphinx.util.osutil import copyfile
from sphinx.util import status_iterator
from sphinx.util import logging
from . import render
py3k = sys.version_info >= (3, 0)
LOG = logging.getLogger(__name__)
def _is_html(app):
return app.builder.name in ('html', 'readthedocs')
def _comma_list(text):
return re.split(r"\s*,\s*", text.strip())
def _parse_content(content):
d = {}
d['text'] = []
idx = 0
for line in content:
idx += 1
m = re.match(r' *\:(.+?)\:(?: +(.+))?', line)
if m:
attrname, value = m.group(1, 2)
d[attrname] = value or ''
elif idx == 1 and line:
# accomodate a unique value on the edge of .. change::
continue
else:
break
d["text"] = content[idx:]
return d
class EnvDirective(object):
@property
def env(self):
return self.state.document.settings.env
@classmethod
def get_changes_list(cls, env, hash_on_version):
key = ('ChangeLogDirective_changes', hash_on_version)
if key not in env.temp_data:
env.temp_data[key] = collections.OrderedDict()
return env.temp_data[key]
class ChangeLogDirective(EnvDirective, Directive):
"""Implement the ``.. changelog::`` directive.
"""
has_content = True
default_section = 'misc'
def run(self):
self._parse()
if not ChangeLogImportDirective.in_include_directive(self.env):
return render.render_changelog(self)
else:
return []
def _parse(self):
# 1. pull in global configuration from conf.py
self.sections = self.env.config.changelog_sections
self.inner_tag_sort = self.env.config.changelog_inner_tag_sort + [""]
# 2. examine top level directives inside the .. changelog::
# directive. version, release date
self._parsed_content = parsed = _parse_content(self.content)
self.version = version = parsed.get('version', '')
self.release_date = parsed.get('released', None)
self.is_released = bool(self.release_date)
self.env.temp_data['ChangeLogDirective'] = self
content = self.content
# 3. read extra per-file included notes
if 'include_notes_from' in parsed:
if content.items and content.items[0]:
source = content.items[0][0]
# seems we are now getting strings like:
# changelog/changelog_11.rst
source = source.split(' ')[0]
path = os.path.join(
os.path.dirname(source), parsed['include_notes_from'])
else:
path = parsed['include_notes_from']
if not os.path.exists(path):
raise Exception("included nodes path %s does not exist" % path)
content = copy.deepcopy(content)
files = [
fname for fname in os.listdir(path) if fname.endswith(".rst")
]
for fname in status_iterator(
files,
"reading changelog note files (version %s)..." % version,
"purple", length=len(files), verbosity=self.env.app.verbosity
):
fpath = os.path.join(path, fname)
with open(fpath) as handle:
content.append("", path, 0)
for num, line in enumerate(handle):
if not py3k:
line = line.decode('utf-8')
if "\t" in line:
warnings.warn(
"file %s has a tab in it! please "
"convert to spaces." % fname)
line = line.replace("\t", " ")
line = line.rstrip()
content.append(
line, path, num
)
# 4. parse the content of the .. changelog:: directive. This
# is where we parse individual .. change:: directives and construct
# a list of items, stored in the env via self.get_changes_list(env)
p = nodes.paragraph('', '',)
self.state.nested_parse(content[1:], 0, p)
class ChangeLogImportDirective(EnvDirective, Directive):
"""Implement the ``.. changelog_imports::`` directive.
Here, we typically load in other changelog.rst files which may feature
elements that also apply to our current changelog.rst file, when they
specify the ``:version:`` modifier.
"""
has_content = True
@classmethod
def in_include_directive(cls, env):
return 'ChangeLogDirective_includes' in env.temp_data
def run(self):
# tell ChangeLogDirective we're here, also prevent
# nested .. include calls
if not self.in_include_directive(self.env):
self.env.temp_data['ChangeLogDirective_includes'] = True
p = nodes.paragraph('', '',)
self.state.nested_parse(self.content, 0, p)
del self.env.temp_data['ChangeLogDirective_includes']
return []
class ChangeDirective(EnvDirective, Directive):
"""Implement the ``.. change::`` directive.
"""
has_content = True
def run(self):
# don't do anything if we're not inside of a version
if 'ChangeLogDirective' not in self.env.temp_data:
return []
content = _parse_content(self.content)
body_paragraph = nodes.paragraph('', '',)
sorted_tags = _comma_list(content.get('tags', ''))
changelog_directive = self.env.temp_data['ChangeLogDirective']
declared_version = changelog_directive.version
versions = set(
_comma_list(content.get("versions", ""))).difference(['']).\
union([declared_version])
# if we don't refer to any other versions and we're in an include,
# skip
if len(versions) == 1 and \
ChangeLogImportDirective.in_include_directive(self.env):
return []
self.state.nested_parse(content['text'], 0, body_paragraph)
raw_text = _text_rawsource_from_node(body_paragraph)
tickets = set(_comma_list(content.get('tickets', ''))).difference([''])
pullreq = set(_comma_list(content.get('pullreq', ''))).difference([''])
tags = set(sorted_tags).difference([''])
for hash_on_version in versions:
issue_hash = _get_robust_version_hash(
raw_text, hash_on_version, tickets, tags)
rec = ChangeLogDirective.get_changes_list(
changelog_directive.env, hash_on_version).setdefault(
issue_hash, {})
if not rec:
rec.update({
'hash': issue_hash,
"render_for_version": hash_on_version,
'tags': tags,
'tickets': tickets,
'pullreq': pullreq,
'changeset': set(
_comma_list(content.get('changeset', ''))
).difference(['']),
'node': body_paragraph,
'raw_text': raw_text,
'type': "change",
"title": content.get("title", None),
'sorted_tags': sorted_tags,
"versions": versions,
"version_to_hash": {
version: _get_legacy_version_hash(raw_text, version)
for version in versions
},
"source_versions": [declared_version],
"sorted_versions": list(
reversed(sorted(versions, key=_str_version_as_tuple)))
})
else:
# This seems to occur repeated times for each included
# changelog, not clear if sphinx has changed the scope
# of self.env to lead to this occurring more often
LOG.debug(
"Merging changelog record '%s' from version(s) %s "
"with that of version %s",
_quick_rec_str(rec),
", ".join(rec['source_versions']),
declared_version
)
rec["source_versions"].append(declared_version)
assert rec['raw_text'] == raw_text
assert rec['tags'] == tags
assert rec["render_for_version"] == hash_on_version
rec['tickets'].update(tickets)
rec['pullreq'].update(pullreq)
rec['changeset'].update(
set(
_comma_list(content.get('changeset', ''))).
difference([''])
)
rec['versions'].update(versions)
rec['version_to_hash'].update(
{
version: _get_legacy_version_hash(raw_text, version)
for version in versions
}
)
rec["sorted_versions"] = list(
reversed(
sorted(rec['versions'], key=_str_version_as_tuple)))
return []
def _quick_rec_str(rec):
"""try to print an identifiable description of a record"""
if rec['tickets']:
return "[tickets: %s]" % ", ".join(rec["tickets"])
else:
return "%s..." % rec["raw_text"][0:25]
def _get_legacy_version_hash(raw_text, version):
# this needs to stay like this for link compatibility
# with thousands of already-published changelogs
to_hash = "%s %s" % (version, raw_text[0:100])
return md5.md5(to_hash.encode('ascii', 'ignore')).hexdigest()
def _get_robust_version_hash(raw_text, version, tickets, tags):
# this needs to stay like this for link compatibility
# with thousands of already-published changelogs
to_hash = "%s %s %s %s" % (
version, ", ".join(tickets), ", ".join(tags), raw_text)
return md5.md5(to_hash.encode('ascii', 'ignore')).hexdigest()
def _text_rawsource_from_node(node):
src = []
stack = [node]
while stack:
n = stack.pop(0)
if isinstance(n, nodes.Text):
src.append(n.rawsource)
stack.extend(n.children)
return "".join(src)
_VERSION_IDS = {}
def _str_version_as_tuple(ver):
if ver in _VERSION_IDS:
return _VERSION_IDS[ver]
out = []
for dig in ver.split("."):
try:
out.append(int(dig))
except ValueError:
out.append(dig)
_VERSION_IDS[ver] = result = tuple(out)
return result
def make_ticket_link(
name, rawtext, text, lineno, inliner,
options={}, content=[]):
env = inliner.document.settings.env
render_ticket = env.config.changelog_render_ticket or "%s"
prefix = "#%s"
if render_ticket:
ref = render_ticket % text
node = nodes.reference(rawtext, prefix % text, refuri=ref, **options)
else:
node = nodes.Text(prefix % text, prefix % text)
return [node], []
def add_stylesheet(app):
app.add_stylesheet('changelog.css')
def copy_stylesheet(app, exception):
LOG.info(
bold('The name of the builder is: %s' % app.builder.name), nonl=True)
if not _is_html(app) or exception:
return
LOG.info(bold('Copying sphinx_paramlinks stylesheet... '), nonl=True)
source = os.path.abspath(os.path.dirname(__file__))
# the '_static' directory name is hardcoded in
# sphinx.builders.html.StandaloneHTMLBuilder.copy_static_files.
# would be nice if Sphinx could improve the API here so that we just
# give it the path to a .css file and it does the right thing.
dest = os.path.join(app.builder.outdir, '_static', 'changelog.css')
copyfile(os.path.join(source, "changelog.css"), dest)
LOG.info('done')
def setup(app):
app.add_directive('changelog', ChangeLogDirective)
app.add_directive('change', ChangeDirective)
app.add_directive('changelog_imports', ChangeLogImportDirective)
app.add_config_value("changelog_sections", [], 'env')
app.add_config_value("changelog_inner_tag_sort", [], 'env')
app.add_config_value("changelog_render_ticket", None, 'env')
app.add_config_value("changelog_render_pullreq", None, 'env')
app.add_config_value("changelog_render_changeset", None, 'env')
app.connect('builder-inited', add_stylesheet)
app.connect('build-finished', copy_stylesheet)
app.add_role('ticket', make_ticket_link)
changelog-0.4.2/changelog.egg-info/ 0000775 0001750 0001750 00000000000 13354475055 020166 5 ustar classic classic 0000000 0000000 changelog-0.4.2/changelog.egg-info/PKG-INFO 0000664 0001750 0001750 00000007510 13354475054 021265 0 ustar classic classic 0000000 0000000 Metadata-Version: 1.1
Name: changelog
Version: 0.4.2
Summary: Provides simple Sphinx markup to render changelog displays.
Home-page: http://bitbucket.org/zzzeek/changelog
Author: Mike Bayer
Author-email: mike@zzzcomputing.com
License: MIT
Description: ==========
Changelog
==========
A `Sphinx `_ extension to generate changelog files.
This is an experimental, possibly-not-useful extension that's used by the
`SQLAlchemy `_ project and related projects.
Configuration
=============
A sample configuration in ``conf.py`` looks like this::
extensions = [
# changelog extension
'changelog',
# your other sphinx extensions
# ...
]
# section names - optional
changelog_sections = ["general", "rendering", "tests"]
# tags to sort on inside of sections - also optional
changelog_inner_tag_sort = ["feature", "bug"]
# how to render changelog links - these are plain
# python string templates, ticket/pullreq/changeset number goes
# in "%s"
changelog_render_ticket = "http://bitbucket.org/myusername/myproject/issue/%s"
changelog_render_pullreq = "http://bitbucket.org/myusername/myproject/pullrequest/%s"
changelog_render_changeset = "http://bitbucket.org/myusername/myproject/changeset/%s"
Usage
=====
Changelog introduces the ``changelog`` and ``change`` directives::
====================
Changelog for 1.5.6
====================
.. changelog::
:version: 1.5.6
:released: Sun Oct 12 2008
.. change::
:tags: general
:tickets: 27
Improved the frobnozzle.
.. change::
:tags: rendering, tests
:pullreq: 8
:changeset: a9d7cc0b56c2
Rendering tests now correctly render.
With the above markup, the changes above will be rendered into document sections
per changelog, then each change within organized into paragraphs, including
special markup for tags, tickets mentioned, pull requests, changesets. The entries will
be grouped and sorted by tag according to the configuration of the ``changelog_sections``
and ``changelog_inner_tag_sort`` configurations.
A "compound tag" can also be used, if the configuration has a section like this::
changelog_sections = ["orm declarative", "orm"]
Then change entries which contain both the ``orm`` and ``declarative`` tags will be
grouped under a section called ``orm declarative``, followed by the ``orm`` section where
change entries that only have ``orm`` will be placed.
Other Markup
============
The ``:ticket:`` directive will make use of the ``changelog_render_ticket`` markup
to render a ticket link::
:ticket:`456`
Keywords: Sphinx
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Documentation
changelog-0.4.2/changelog.egg-info/SOURCES.txt 0000664 0001750 0001750 00000000531 13354475055 022051 0 ustar classic classic 0000000 0000000 LICENSE
MANIFEST.in
README.rst
setup.py
changelog/__init__.py
changelog/changelog.css
changelog/cmd.py
changelog/render.py
changelog/sphinxext.py
changelog.egg-info/PKG-INFO
changelog.egg-info/SOURCES.txt
changelog.egg-info/dependency_links.txt
changelog.egg-info/entry_points.txt
changelog.egg-info/not-zip-safe
changelog.egg-info/top_level.txt changelog-0.4.2/changelog.egg-info/dependency_links.txt 0000664 0001750 0001750 00000000001 13354475054 024233 0 ustar classic classic 0000000 0000000
changelog-0.4.2/changelog.egg-info/entry_points.txt 0000664 0001750 0001750 00000000062 13354475055 023462 0 ustar classic classic 0000000 0000000 [console_scripts]
changelog = changelog.cmd:main
changelog-0.4.2/changelog.egg-info/not-zip-safe 0000664 0001750 0001750 00000000001 13011374666 022410 0 ustar classic classic 0000000 0000000
changelog-0.4.2/changelog.egg-info/top_level.txt 0000664 0001750 0001750 00000000012 13354475055 022711 0 ustar classic classic 0000000 0000000 changelog
changelog-0.4.2/setup.cfg 0000664 0001750 0001750 00000000046 13354475055 016366 0 ustar classic classic 0000000 0000000 [egg_info]
tag_build =
tag_date = 0
changelog-0.4.2/setup.py 0000664 0001750 0001750 00000002261 13134737626 016261 0 ustar classic classic 0000000 0000000 from setuptools import setup
import os
import re
v = open(os.path.join(os.path.dirname(__file__), 'changelog', '__init__.py'))
VERSION = re.compile(r".*__version__ = '(.*?)'", re.S).match(v.read()).group(1)
v.close()
readme = os.path.join(os.path.dirname(__file__), 'README.rst')
setup(name='changelog',
version=VERSION,
description="Provides simple Sphinx markup to render changelog displays.",
long_description=open(readme).read(),
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: Console',
'Intended Audience :: Developers',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Documentation',
],
keywords='Sphinx',
author='Mike Bayer',
author_email='mike@zzzcomputing.com',
url='http://bitbucket.org/zzzeek/changelog',
license='MIT',
packages=['changelog'],
include_package_data=True,
zip_safe=False,
entry_points={
'console_scripts': ['changelog = changelog.cmd:main'],
}
)