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 from collections import namedtuple
import os import os
import pipes import pipes
import re
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
from osclib.core import binary_list from osclib.core import binary_list
from osclib.core import depends_on from osclib.core import depends_on
from osclib.core import package_binary_list
from osclib.core import request_staged from osclib.core import request_staged
from osclib.core import target_archs from osclib.core import target_archs
from osclib.cycle import CycleDetector from osclib.cycle import CycleDetector
@ -18,6 +20,8 @@ import ReviewBot
SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__)) SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__))
CheckResult = namedtuple('CheckResult', ('success', 'comment')) CheckResult = namedtuple('CheckResult', ('success', 'comment'))
INSTALL_REGEX = r"^(?:can't install (.*?)|found conflict of (.*?) with (.*?)):$"
InstallSection = namedtuple('InstallSection', ('binaries', 'text'))
class RepoChecker(ReviewBot.ReviewBot): class RepoChecker(ReviewBot.ReviewBot):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -59,6 +63,9 @@ class RepoChecker(ReviewBot.ReviewBot):
self.group = None self.group = None
self.mirrored = set() self.mirrored = set()
# Stores parsed install_check() results grouped by package.
self.package_results = {}
# Look for requests of interest and group by staging. # Look for requests of interest and group by staging.
for request in self.requests: for request in self.requests:
# Only interesting if request is staged. # Only interesting if request is staged.
@ -208,7 +215,7 @@ class RepoChecker(ReviewBot.ReviewBot):
whitelist.update(self.staging_config[project].get(key, '').split(' ')) whitelist.update(self.staging_config[project].get(key, '').split(' '))
return whitelist 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') self.logger.info('install check: start')
with tempfile.NamedTemporaryFile() as ignore_file: with tempfile.NamedTemporaryFile() as ignore_file:
@ -233,6 +240,10 @@ class RepoChecker(ReviewBot.ReviewBot):
if p.returncode == 126: if p.returncode == 126:
self.logger.warn('mirror cache reset due to corruption') self.logger.warn('mirror cache reset due to corruption')
self.mirrored = set() 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. # Format output as markdown comment.
code = '```\n' code = '```\n'
@ -251,6 +262,42 @@ class RepoChecker(ReviewBot.ReviewBot):
self.logger.info('install check: passed') self.logger.info('install check: passed')
return CheckResult(True, None) 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): def cycle_check(self, project, group, arch):
if self.skip_cycle: if self.skip_cycle:
self.logger.info('cycle check: skip due to --skip-cycle') self.logger.info('cycle check: skip due to --skip-cycle')