#!/usr/bin/env python
# Cheddar changelog generator
# (c) cheddar-lang 2016-
# 
# Outputs data including name, hash, email & message


from subprocess import check_output
from collections import namedtuple, defaultdict
import re
import sys
import argparse

ITEM_LENGTH = 80
INDENT = ' - '

# Handle process arguments
parser = argparse.ArgumentParser()
parser.add_argument("logfile", help="file to write to, default stdout", nargs='?', type=argparse.FileType('w+'), default=sys.stdout)
parser.add_argument("--latest", help="only shows the latest changes", action="store_true")
args = parser.parse_args()

LOGFILE = args.logfile

# These do most of the heavy lifting
Commit = namedtuple('Commit', ['author', 'email', 'hash', 'change'])

def getlog(start, end):
    rawdata = check_output(["git", "log", start + ".." + end, "--format=%cn%n%ce%n%h%n%s"]).decode("utf-8").splitlines()
    ITEMS_PER_COMMIT = 4
    return list(map(Commit, *[iter(rawdata)] * ITEMS_PER_COMMIT))

# Get all info we need
if args.latest:
    tags = ["HEAD", check_output([ "git", "describe", "--tags", "--abbrev=0" ]).decode("utf-8").strip()]
else:
    tags = check_output([ "git", "for-each-ref", "--sort=taggerdate", "--format", "%(tag)" ]).decode("utf-8").strip().splitlines()[::-1]

# parse commit format
commit_format = re.compile(r"^(.+?) \[(.+?)\]: (.+)")

# Start generating change log
# Writes to `CHANGELOG`
with LOGFILE as log:
    # Generate changes
    # This goes from old -> new
    for i in range(len(tags) - 1):
        former, latter = tags[i + 1], tags[i]
        logItems = getlog(former, latter)

        longestName = len(max(logItems, key=lambda s: len(s.author)).author)

        log.write(
            (former + " -> " + latter).center(ITEM_LENGTH, ' ') + '\n'
        )

        log.write(  "=" * ITEM_LENGTH + '\n' )

        # Now handle sorting of commits
        commits = defaultdict(list)

        for item in logItems:
            res = re.match(commit_format, item.change)
            if res == None:
                commits['other'].append(item)
            elif res.group(1) != 'version':
                commits[res.group(1).lower().strip()].append(
                    item._replace(change='{}: {}'.format(res.group(2), res.group(3)))
                )

        for category, items in sorted(commits.items()):
            log.write("{}:\n".format(category))

            lastLogAuthor = ""
            for logItem in items:
                log.write(
                    INDENT + '{1} ({0.hash}) {0.change}\n'.format(logItem, logItem.author.ljust(longestName))
                )

        log.write('\n\n')

eb3f92d67155e8d187caefabfa9996d54a97bdad
<mask token>


def getlog(start, end):
    rawdata = check_output(['git', 'log', start + '..' + end,
        '--format=%cn%n%ce%n%h%n%s']).decode('utf-8').splitlines()
    ITEMS_PER_COMMIT = 4
    return list(map(Commit, *([iter(rawdata)] * ITEMS_PER_COMMIT)))


<mask token>

<mask token>
parser.add_argument('logfile', help='file to write to, default stdout',
    nargs='?', type=argparse.FileType('w+'), default=sys.stdout)
parser.add_argument('--latest', help='only shows the latest changes',
    action='store_true')
<mask token>


def getlog(start, end):
    rawdata = check_output(['git', 'log', start + '..' + end,
        '--format=%cn%n%ce%n%h%n%s']).decode('utf-8').splitlines()
    ITEMS_PER_COMMIT = 4
    return list(map(Commit, *([iter(rawdata)] * ITEMS_PER_COMMIT)))


if args.latest:
    tags = ['HEAD', check_output(['git', 'describe', '--tags', '--abbrev=0'
        ]).decode('utf-8').strip()]
else:
    tags = check_output(['git', 'for-each-ref', '--sort=taggerdate',
        '--format', '%(tag)']).decode('utf-8').strip().splitlines()[::-1]
<mask token>
with LOGFILE as log:
    for i in range(len(tags) - 1):
        former, latter = tags[i + 1], tags[i]
        logItems = getlog(former, latter)
        longestName = len(max(logItems, key=lambda s: len(s.author)).author)
        log.write((former + ' -> ' + latter).center(ITEM_LENGTH, ' ') + '\n')
        log.write('=' * ITEM_LENGTH + '\n')
        commits = defaultdict(list)
        for item in logItems:
            res = re.match(commit_format, item.change)
            if res == None:
                commits['other'].append(item)
            elif res.group(1) != 'version':
                commits[res.group(1).lower().strip()].append(item._replace(
                    change='{}: {}'.format(res.group(2), res.group(3))))
        for category, items in sorted(commits.items()):
            log.write('{}:\n'.format(category))
            lastLogAuthor = ''
            for logItem in items:
                log.write(INDENT + '{1} ({0.hash}) {0.change}\n'.format(
                    logItem, logItem.author.ljust(longestName)))
        log.write('\n\n')

<mask token>
ITEM_LENGTH = 80
INDENT = ' - '
parser = argparse.ArgumentParser()
parser.add_argument('logfile', help='file to write to, default stdout',
    nargs='?', type=argparse.FileType('w+'), default=sys.stdout)
parser.add_argument('--latest', help='only shows the latest changes',
    action='store_true')
args = parser.parse_args()
LOGFILE = args.logfile
Commit = namedtuple('Commit', ['author', 'email', 'hash', 'change'])


def getlog(start, end):
    rawdata = check_output(['git', 'log', start + '..' + end,
        '--format=%cn%n%ce%n%h%n%s']).decode('utf-8').splitlines()
    ITEMS_PER_COMMIT = 4
    return list(map(Commit, *([iter(rawdata)] * ITEMS_PER_COMMIT)))


if args.latest:
    tags = ['HEAD', check_output(['git', 'describe', '--tags', '--abbrev=0'
        ]).decode('utf-8').strip()]
else:
    tags = check_output(['git', 'for-each-ref', '--sort=taggerdate',
        '--format', '%(tag)']).decode('utf-8').strip().splitlines()[::-1]
commit_format = re.compile('^(.+?) \\[(.+?)\\]: (.+)')
with LOGFILE as log:
    for i in range(len(tags) - 1):
        former, latter = tags[i + 1], tags[i]
        logItems = getlog(former, latter)
        longestName = len(max(logItems, key=lambda s: len(s.author)).author)
        log.write((former + ' -> ' + latter).center(ITEM_LENGTH, ' ') + '\n')
        log.write('=' * ITEM_LENGTH + '\n')
        commits = defaultdict(list)
        for item in logItems:
            res = re.match(commit_format, item.change)
            if res == None:
                commits['other'].append(item)
            elif res.group(1) != 'version':
                commits[res.group(1).lower().strip()].append(item._replace(
                    change='{}: {}'.format(res.group(2), res.group(3))))
        for category, items in sorted(commits.items()):
            log.write('{}:\n'.format(category))
            lastLogAuthor = ''
            for logItem in items:
                log.write(INDENT + '{1} ({0.hash}) {0.change}\n'.format(
                    logItem, logItem.author.ljust(longestName)))
        log.write('\n\n')

from subprocess import check_output
from collections import namedtuple, defaultdict
import re
import sys
import argparse
ITEM_LENGTH = 80
INDENT = ' - '
parser = argparse.ArgumentParser()
parser.add_argument('logfile', help='file to write to, default stdout',
    nargs='?', type=argparse.FileType('w+'), default=sys.stdout)
parser.add_argument('--latest', help='only shows the latest changes',
    action='store_true')
args = parser.parse_args()
LOGFILE = args.logfile
Commit = namedtuple('Commit', ['author', 'email', 'hash', 'change'])


def getlog(start, end):
    rawdata = check_output(['git', 'log', start + '..' + end,
        '--format=%cn%n%ce%n%h%n%s']).decode('utf-8').splitlines()
    ITEMS_PER_COMMIT = 4
    return list(map(Commit, *([iter(rawdata)] * ITEMS_PER_COMMIT)))


if args.latest:
    tags = ['HEAD', check_output(['git', 'describe', '--tags', '--abbrev=0'
        ]).decode('utf-8').strip()]
else:
    tags = check_output(['git', 'for-each-ref', '--sort=taggerdate',
        '--format', '%(tag)']).decode('utf-8').strip().splitlines()[::-1]
commit_format = re.compile('^(.+?) \\[(.+?)\\]: (.+)')
with LOGFILE as log:
    for i in range(len(tags) - 1):
        former, latter = tags[i + 1], tags[i]
        logItems = getlog(former, latter)
        longestName = len(max(logItems, key=lambda s: len(s.author)).author)
        log.write((former + ' -> ' + latter).center(ITEM_LENGTH, ' ') + '\n')
        log.write('=' * ITEM_LENGTH + '\n')
        commits = defaultdict(list)
        for item in logItems:
            res = re.match(commit_format, item.change)
            if res == None:
                commits['other'].append(item)
            elif res.group(1) != 'version':
                commits[res.group(1).lower().strip()].append(item._replace(
                    change='{}: {}'.format(res.group(2), res.group(3))))
        for category, items in sorted(commits.items()):
            log.write('{}:\n'.format(category))
            lastLogAuthor = ''
            for logItem in items:
                log.write(INDENT + '{1} ({0.hash}) {0.change}\n'.format(
                    logItem, logItem.author.ljust(longestName)))
        log.write('\n\n')

#!/usr/bin/env python
# Cheddar changelog generator
# (c) cheddar-lang 2016-
# 
# Outputs data including name, hash, email & message


from subprocess import check_output
from collections import namedtuple, defaultdict
import re
import sys
import argparse

ITEM_LENGTH = 80
INDENT = ' - '

# Handle process arguments
parser = argparse.ArgumentParser()
parser.add_argument("logfile", help="file to write to, default stdout", nargs='?', type=argparse.FileType('w+'), default=sys.stdout)
parser.add_argument("--latest", help="only shows the latest changes", action="store_true")
args = parser.parse_args()

LOGFILE = args.logfile

# These do most of the heavy lifting
Commit = namedtuple('Commit', ['author', 'email', 'hash', 'change'])

def getlog(start, end):
    rawdata = check_output(["git", "log", start + ".." + end, "--format=%cn%n%ce%n%h%n%s"]).decode("utf-8").splitlines()
    ITEMS_PER_COMMIT = 4
    return list(map(Commit, *[iter(rawdata)] * ITEMS_PER_COMMIT))

# Get all info we need
if args.latest:
    tags = ["HEAD", check_output([ "git", "describe", "--tags", "--abbrev=0" ]).decode("utf-8").strip()]
else:
    tags = check_output([ "git", "for-each-ref", "--sort=taggerdate", "--format", "%(tag)" ]).decode("utf-8").strip().splitlines()[::-1]

# parse commit format
commit_format = re.compile(r"^(.+?) \[(.+?)\]: (.+)")

# Start generating change log
# Writes to `CHANGELOG`
with LOGFILE as log:
    # Generate changes
    # This goes from old -> new
    for i in range(len(tags) - 1):
        former, latter = tags[i + 1], tags[i]
        logItems = getlog(former, latter)

        longestName = len(max(logItems, key=lambda s: len(s.author)).author)

        log.write(
            (former + " -> " + latter).center(ITEM_LENGTH, ' ') + '\n'
        )

        log.write(  "=" * ITEM_LENGTH + '\n' )

        # Now handle sorting of commits
        commits = defaultdict(list)

        for item in logItems:
            res = re.match(commit_format, item.change)
            if res == None:
                commits['other'].append(item)
            elif res.group(1) != 'version':
                commits[res.group(1).lower().strip()].append(
                    item._replace(change='{}: {}'.format(res.group(2), res.group(3)))
                )

        for category, items in sorted(commits.items()):
            log.write("{}:\n".format(category))

            lastLogAuthor = ""
            for logItem in items:
                log.write(
                    INDENT + '{1} ({0.hash}) {0.change}\n'.format(logItem, logItem.author.ljust(longestName))
                )

        log.write('\n\n')
