blob: 8afc83ac8dfaa26c525dbe9076c740b00f07b9d0 [file] [log] [blame]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-"
#
# Copyright 2020 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Parse ChangeLog from CPCon and generate commit message.
Usage:
1. Copy ChangeLog from CPCon (everything except the MENU bar)
2. xsel -b | ./gen_uprev_msg.py [-b BOARD] [--extra-repo-file FILE]
3. Commit message will be printed to stdout
4. Be aware of the warning messages in stderr
"""
from __future__ import print_function
import argparse
import collections
import logging
import re
import sys
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger()
MAX_LENGTH = 72
CHANGES_PATTERN = r"Changes between ([0-9\.]+) and ([0-9\.]+)"
IGNORED_PATTERNS = (
"Marking set of ebuilds as stable",
r"Incremented to version: \d+\.\d+\.\d+",
r"Increment to version R\d+-\d+\.\d+\.\d+.*",
)
DEFAULT_REPOS = (
"src/platform/bmpblk",
"src/platform/depthcharge",
"src/platform/ec",
"src/platform/firmware",
"src/platform/vboot_reference",
"src/third_party/arm-trusted-firmware",
"src/third_party/coreboot",
"src/third_party/coreboot/3rdparty/blobs",
)
CL = collections.namedtuple("CL", ["commit", "cl", "bug", "title"])
def read_extra_repos(filename):
"""Read extra repos from |filename|."""
repos = set()
with open(filename) as f:
for line in f:
repo = line.strip()
if repo:
repos.add(repo)
return repos
def parse_cl(line):
"""Parse CL."""
tokens = line.split("\t")
if len(tokens) != 6:
return None
commit, cl, bug, _date, _author, title = tokens
return CL(commit, int(cl) if cl else None, int(bug) if bug else None, title)
def wrap_line(s, max_length):
"""Wrap a line."""
# Assume words are separated by one space
words = s.split()
lines = [[]]
length = 0
for word in words:
if length + 1 + len(word) > max_length:
lines.append([])
length = 0
lines[-1].append(word)
length += 1 + len(word)
return [" ".join(line) for line in lines]
def main(args):
"""Parse ChangeLog and print commit message."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("-b", "--board", required=True)
parser.add_argument(
"--extra-repo-file", help="File containing extra repo names"
)
args = parser.parse_args(args)
board = args.board
included_repos = set(DEFAULT_REPOS)
if args.extra_repo_file:
included_repos |= read_extra_repos(args.extra_repo_file)
changes = False
repos = []
repo = None
ignored_repos = []
ignored_commits = []
skipped_lines = []
for line in sys.stdin:
line = line.strip()
# Parse "Changes between 12573.80.0 and 12573.88.0"
if not changes:
m = re.match(CHANGES_PATTERN, line)
if m:
groups = m.groups()
if len(groups) == 2:
changes = groups
continue
# Parse repo
tokens = line.split()
if len(tokens) == 1 and "/" in tokens[0]:
repo = tokens[0]
if repo in included_repos:
cl_list = []
repos.append((repo, cl_list))
else:
ignored_repos.append(repo)
repo = None
continue
# Parse CL
if not repo:
continue
cl = parse_cl(line)
if not cl:
skipped_lines.append(line)
continue
ignored = False
for pattern in IGNORED_PATTERNS:
if re.fullmatch(pattern, cl.title):
ignored = True
continue
if ignored:
ignored_commits.append((cl.commit, repo))
else:
cl_list.append(cl)
if not repos:
logger.error("No repo found from ChangeLog")
return 1
# Output
if changes:
title = (
f"chromeos-firmware-{board}: "
f"Uprev firmware to {changes[1]} for {board}"
)
print(title)
print()
print(f"Changes between {changes[0]} and {changes[1]}:")
for repo, cl_list in repos:
if not cl_list:
continue
print()
print(repo)
private = "private" in repo
for cl in cl_list:
if cl.cl:
cl_str = f"CL:*{cl.cl}" if private else f"CL:{cl.cl}"
else:
ignored = False
for pattern in IGNORED_PATTERNS:
if re.fullmatch(pattern, cl.title):
ignored = True
continue
if ignored:
continue
cl_str = "CL:" + "?" * 7
print(">>>>>>> PLEASE FILL THE CL NUMBER MANUALLY")
title = cl.title
indentation = 1 + len(cl_str) + 4
for i, title_line in enumerate(
wrap_line(cl.title, MAX_LENGTH - indentation)
):
if i == 0:
line = f" {cl_str} {title_line}"
else:
line = " " * indentation + f"{title_line}"
print(line)
print()
print("BUG=<INSERT BUGS HERE>")
print(f"TEST=emerge-{board} chromeos-firmware-{board}")
# Warnings
for repo in ignored_repos:
logger.warning("Ignore repo %s", repo)
for commit, repo in ignored_commits:
logger.warning("Ignore commit %s in %s", commit, repo)
for line in skipped_lines:
logger.warning("Skipping line: %s", line)
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))