Skip to content
Snippets Groups Projects
  • Thomas Woerner's avatar
    8b8cbdd8
    utils/changelog: Fixed --tag option, new --galaxy option · 8b8cbdd8
    Thomas Woerner authored
    The --tag TAG option is now printing the changes for the given TAG and
    not since the given tag. The new option --galaxy is printing the changelog
    since the latest tag and also for the latest tag.
    
    These changes are simplifying the generation of the changelog file that
    is needed to pass the tests for galaxy and AutomationHub collections.
    8b8cbdd8
    History
    utils/changelog: Fixed --tag option, new --galaxy option
    Thomas Woerner authored
    The --tag TAG option is now printing the changes for the given TAG and
    not since the given tag. The new option --galaxy is printing the changelog
    since the latest tag and also for the latest tag.
    
    These changes are simplifying the generation of the changelog file that
    is needed to pass the tests for galaxy and AutomationHub collections.
To find the state of this project's repository at the time of any of these versions, check out the tags.
changelog 5.20 KiB
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Authors:
#   Thomas Woerner <twoerner@redhat.com>
#
# Copyright (C) 2020 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import sys
import argparse
import subprocess


class Ref:
    def __init__(self, commit):
        self.commit = commit


def store(commits, prs, authors, commit, author, merge, msg):
    if commit is not None:
        if msg[0].startswith("Merge pull request #"):
            pr_ref = int(msg[0].split()[3][1:])
            if len(msg) > 1:
                prs[pr_ref] = msg[1].strip()
            else:
                prs[pr_ref] = Ref(merge)
        else:
            commits[commit] = msg[0].strip()
            authors.setdefault(author, []).append(commit)


def get_commit(commits, commit):
    _commits = [value for key, value in commits.items()
                if key.startswith(commit)]
    if len(_commits) == 1:
        return _commits[0]
    return commit


def get_output(command):
    try:
        ret = subprocess.check_output(command, shell=True)
        ret = ret.decode("utf-8").strip()
    except subprocess.CalledProcessError:
        print("Command '%s' failed" % command)
        sys.exit(1)
    return ret


def changelog(tag):
    prev_tag = None
    if tag is not None and tag != "":
        prev_tag = get_output(
            "git describe --tag --abbrev=0 --always '%s^'" % tag)
    else:
        tag = get_output("git describe --tags --abbrev=0 "
                         "$(git rev-list --tags --max-count=1)")

    version = tag[1:]

    if prev_tag is not None:
        command = ["git", "log", "%s..%s" % (prev_tag, tag)]
    else:
        command = ["git", "log", "%s.." % tag]
    process = subprocess.run(command,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)

    if process.returncode != 0:
        print("git log failed: %s" %
              process.stderr.decode("utf8").split("\n")[0])
        sys.exit(1)

    lines = process.stdout.decode("utf-8").split("\n")

    commits = {}
    prs = {}
    authors = {}
    commit = None
    author = None
    merge = None
    msg = None
    for line in lines:
        line = line.rstrip()
        if line.startswith("commit "):
            store(commits, prs, authors, commit, author, merge, msg)
            author = None
            msg = []
            commit = line[7:]
        elif line.startswith("    "):
            msg.append(line[4:])
        else:
            try:
                key, value = line.split(":", 1)
                if key == "Author":
                    author = value.split("<")[0].strip()
                elif key == "Merge":
                    merge = value.split()[1].strip()
                # Ignore Date, ..
            except ValueError:
                pass

    # Add final commit
    if commit:
        store(commits, prs, authors, commit, author, merge, msg)

    if prev_tag is not None:
        line = "Changes for %s since %s" % (version, prev_tag[1:])
    else:
        line = "Changes since %s" % version
    print("%s" % line)
    print("-" * len(line))
    print()

    prs_sorted = sorted(prs.keys(), reverse=True)
    for pr_ref in prs_sorted:
        if isinstance(prs[pr_ref], Ref):
            msg = get_commit(commits, prs[pr_ref].commit)
        else:
            msg = prs[pr_ref]
        print("  - %s (#%d)" % (msg, pr_ref))
    print()

    if prev_tag is not None:
        line = "Detailed changelog for %s since %s by author" % (version,
                                                                 prev_tag[1:])
    else:
        line = "Detailed changelog since %s by author" % version
    print("%s" % line)
    print("-" * len(line))
    print("  %d authors, %d commits" % (len(authors), len(commits)))
    print()

    authors_sorted = sorted(authors.keys())
    for author in authors_sorted:
        print("%s (%d)\n" % (author, len(authors[author])))
        for commit in authors[author]:
            print("  - %s" % commits[commit])
        print()


parser = argparse.ArgumentParser(usage="Usage: changelog [options]")
parser.add_argument("--tag", dest="tag", help="git tag")
parser.add_argument("--galaxy", dest="galaxy", action="store_true",
                    help="Create changelog for galaxy")
options, args = parser.parse_known_args()

if len(args) != 0:
    parser.print_help()
    sys.exit(1)

if options.galaxy:
    # Get latest tag
    tag = get_output("git describe --tag --abbrev=0")
    # get number of commits since latest tag
    count = get_output("git rev-list '%s'.. --count" % tag)
    if count != "0":
        changelog(None)
    changelog(tag)
else:
    changelog(options.tag)