repo_checker: provide optional parsing of install check output and mapping to package.

This commit is contained in:
Jimmy Berry 2017-08-02 21:17:28 -05:00
parent 4f64386366
commit e1bf4522af

View File

@ -3,12 +3,14 @@
from collections import namedtuple
import os
import pipes
import re
import subprocess
import sys
import tempfile
from osclib.core import binary_list
from osclib.core import depends_on
from osclib.core import package_binary_list
from osclib.core import request_staged
from osclib.core import target_archs
from osclib.cycle import CycleDetector
@ -18,6 +20,8 @@ import ReviewBot
SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__))
CheckResult = namedtuple('CheckResult', ('success', 'comment'))
INSTALL_REGEX = r"^(?:can't install (.*?)|found conflict of (.*?) with (.*?)):$"
InstallSection = namedtuple('InstallSection', ('binaries', 'text'))
class RepoChecker(ReviewBot.ReviewBot):
def __init__(self, *args, **kwargs):
@ -59,6 +63,9 @@ class RepoChecker(ReviewBot.ReviewBot):
self.group = None
self.mirrored = set()
# Stores parsed install_check() results grouped by package.
self.package_results = {}
# Look for requests of interest and group by staging.
for request in self.requests:
# Only interesting if request is staged.
@ -208,7 +215,7 @@ class RepoChecker(ReviewBot.ReviewBot):
whitelist.update(self.staging_config[project].get(key, '').split(' '))
return whitelist
def install_check(self, directory_project, directory_group, arch, ignore, whitelist):
def install_check(self, directory_project, directory_group, arch, ignore, whitelist, parse=False):
self.logger.info('install check: start')
with tempfile.NamedTemporaryFile() as ignore_file:
@ -233,6 +240,10 @@ class RepoChecker(ReviewBot.ReviewBot):
if p.returncode == 126:
self.logger.warn('mirror cache reset due to corruption')
self.mirrored = set()
elif parse:
# Parse output for later consumption for posting comments.
sections = self.install_check_parse(stdout)
self.install_check_sections_group(parse, arch, sections)
# Format output as markdown comment.
code = '```\n'
@ -251,6 +262,42 @@ class RepoChecker(ReviewBot.ReviewBot):
self.logger.info('install check: passed')
return CheckResult(True, None)
def install_check_sections_group(self, project, arch, sections):
_, binary_map = package_binary_list(self.apiurl, project, 'standard', arch)
for section in sections:
# If switch to creating bugs likely makes sense to join packages to
# form grouping key and create shared bugs for conflicts.
packages = set([binary_map[b] for b in section.binaries])
for package in packages:
self.package_results.setdefault(package, [])
self.package_results[package].append(section)
def install_check_parse(self, output):
section = None
text = None
# Loop over lines and parse into chunks assigned to binaries.
for line in output.splitlines(True):
if line.startswith(' '):
if section:
text += line
else:
if section:
yield InstallSection(section, text)
match = re.match(INSTALL_REGEX, line)
if match:
# Remove empty groups since regex matches different patterns.
binaries = [b for b in match.groups() if b is not None]
section = binaries
text = line
else:
section = None
if section:
yield InstallSection(section, text)
def cycle_check(self, project, group, arch):
if self.skip_cycle:
self.logger.info('cycle check: skip due to --skip-cycle')