Source code for cfme.utils.release

#!/usr/bin/env python3
import datetime
import re
import sys
import textwrap
from collections import defaultdict

import click
import git
import github
import tabulate

from cfme.utils.conf import docker

LINE_FMT = "{pr:<{pr_len}} | {label:<{label_len}} | "


[docs]def clean_commit(commit_msg): replacements = ["1LP", "RFR", "WIP", "WIPTEST", "NOTEST"] for replacement in replacements: commit_msg = commit_msg.replace("[{}]".format(replacement), "") return commit_msg.strip(" ")
VALID_LABELS = [ "LegacyBranch", "blackify", "blockers-only", "collections-conversion", "doc", "enhancement", "fix-framework", "fix-locator-or-text", "fix-test", "implement-ssui", "infra-related", "issue-bug", "issue-rfe", "manual", "new-test-or-feature", "Nuage", "other", "py3-compat", "rc-regression-fix", "Redfish", "RHV", "sprout", "tech-debt", "widgetastic-conversion", ]
[docs]def pr_numbers_in_commit_order(commits, prs): for commit in commits: pr = re.match(r".*[#](\d+).*", commit.summary) if pr: pr_number = int(pr.groups()[0].replace("#", "")) if pr_number in prs: yield pr_number
[docs]def clean_body(string): if string is None: string = "" pytest_match = re.findall(r"({{.*}}\s*)", string, flags=re.S | re.M) if pytest_match: string = string.replace(pytest_match[0], "") return string
[docs]def get_prs(): now = datetime.date.today() start_of_week = now - datetime.timedelta(days=30) string_start = start_of_week.strftime("%Y-%m-%d") # todo get date from last tag commit gh = github.Github(docker.gh_token) pulls = gh.search_issues( "", type="pr", repo="{d.gh_owner}/{d.gh_repo}".format(d=docker), merged=">" + string_start, ) prs = {} pr_nums_without_label = [] for pr in pulls: prs[pr.number] = pr for label in pr.labels: if label.name in VALID_LABELS: pr.label = label.name break else: pr_nums_without_label.append(str(pr.number)) if pr_nums_without_label: print( "ERROR: The following PRs don't have any of recognized labels:", ", ".join(pr_nums_without_label), ) print("Recognized labels:", ", ".join(VALID_LABELS)) sys.exit(1) return prs
@click.command(help="Assist in generating release changelog") @click.argument("tag") @click.option( "--old-tag", default=None, help="Build the changelog from an older tag, instead of git describe", ) @click.option( "--full", "report_type", flag_value="full", default=True, help="Generates a full report with all PR description", ) @click.option( "--brief", "report_type", flag_value="brief", help="Generates brief report" ) @click.option( "--stats", "report_type", flag_value="stats", help="Generates stats only report" ) @click.option("--line-limit", default="80", help="Line length limit", type=int) def main(tag, old_tag, report_type, line_limit): """Script to assist in generating the release changelog This script will generate a simple or full diff of PRs that are merged and present the data in a way that is easy to copy/paste into an email or git tag. """ repo = git.Repo(".") if old_tag is None: old_tag = repo.git.describe(tags=True, abbrev=0) commits = list(repo.iter_commits("{}..master".format(old_tag))) print("integration_tests {} Released".format(tag)) print("") print("Includes: {} -> {}".format(old_tag, tag)) max_len_labels = max(list(map(len, VALID_LABELS))) prs = get_prs() if report_type in ("full", "brief"): max_len_pr = len(str(max(prs))) followup_line = first_line = LINE_FMT.format( pr="", pr_len=max_len_pr, label="", label_len=max_len_labels ) for pr_number in pr_numbers_in_commit_order(commits, prs): label = prs[pr_number].label title = clean_commit(prs[pr_number].title) first_line = LINE_FMT.format( pr=pr_number, pr_len=max_len_pr, label=label, label_len=max_len_labels ) if report_type == "full": print("=" * line_limit) title = textwrap.wrap(title, line_limit - len(followup_line)) print(first_line + title[0]) for line in title[1:]: print(followup_line + line) if report_type == "full": print("-" * line_limit) string = clean_body(prs[pr_number].body) print( "\n".join( textwrap.wrap(string, line_limit, replace_whitespace=False) ) ) print("=" * line_limit) print("") elif report_type == "stats": labels = defaultdict(int) for pr_number in pr_numbers_in_commit_order(commits, prs): labels[prs[pr_number].label] += 1 print(tabulate.tabulate(sorted(labels.items()), headers=["Label", "Number"])) if __name__ == "__main__": main()