From 0d6f44a57099597c51a065901e6553b5efdc557c Mon Sep 17 00:00:00 2001 From: Mattia Rizzolo Date: Wed, 29 Apr 2015 20:13:04 +0200 Subject: reproducible: add a reproducible_breakages job (and relative script) to produce a page listing CI troubles (files that should not be there or package with a senseless status --- bin/reproducible_breakages.py | 245 ++++++++++++++++++++++++++++++++++++++++++ job-cfg/reproducible.yaml | 9 ++ 2 files changed, 254 insertions(+) create mode 100755 bin/reproducible_breakages.py diff --git a/bin/reproducible_breakages.py b/bin/reproducible_breakages.py new file mode 100755 index 00000000..91447321 --- /dev/null +++ b/bin/reproducible_breakages.py @@ -0,0 +1,245 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# +# Copyright © 2015 Mattia Rizzolo +# Licensed under GPL-2 +# +# Depends: python3 +# +# Build a page full of CI issues to investigate + +from reproducible_common import * + + +class bcolors: + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + WARN = '\033[93m' + UNDERLINE + FAIL = '\033[91m' + BOLD + UNDERLINE + ENDC = '\033[0m' + + +def unrep_with_dbd_issues(): + log.info('running unrep_with_dbd_issues check...') + without_dbd = [] + bad_dbd = [] + query = '''SELECT s.name, r.version, s.suite, s.architecture + FROM sources AS s JOIN results AS r ON r.package_id=s.id + WHERE r.status="unreproducible"''' + results = query_db(query) + for pkg, version, suite, arch in results: + eversion = strip_epoch(version) + dbd = DBD_PATH + '/' + suite + '/' + arch + '/' + pkg + '_' + \ + eversion + '.debbindiff.html' + if not os.access(dbd, os.R_OK): + without_dbd.append((pkg, version, suite, arch)) + log.warning(pkg + '/' + suite + ' (' + version + ') is ' + 'unreproducible without debbindiff file.') + else: + log.debug(dbd + ' found.') + data = open(dbd, 'br').read(3) + if b'<' not in data: + bad_dbd.append((pkg, version, suite, arch)) + log.warning(pkg + '/' + suite + ' (' + version + ') has a ' + 'debbindiff output, but it does not seem an ' + 'html page.') + return without_dbd, bad_dbd + + +def not_unrep_with_dbd_file(): + log.info('running not_unrep_with_dbd_file check...') + bad_pkgs = [] + query = '''SELECT s.name, r.version, s.suite, s.architecture + FROM sources AS s JOIN results AS r ON r.package_id=s.id + WHERE r.status != "unreproducible"''' + results = query_db(query) + for pkg, version, suite, arch in results: + eversion = strip_epoch(version) + dbd = DBD_PATH + '/' + suite + '/' + arch + '/' + pkg + '_' + \ + eversion + '.debbindiff.html' + if os.access(dbd, os.R_OK): + bad_pks.append((pkg, version, suite, arch)) + log.warning(pkg + '/' + suite + ' (' + version + ') has a ' + 'debbindiff file but it\'s not unreproducible.') + return bad_pkgs + + +def lack_rbuild(): + log.info('running lack_rbuild check...') + bad_pkgs = [] + query = '''SELECT s.name, r.version, s.suite, s.architecture + FROM sources AS s JOIN results AS r ON r.package_id=s.id + WHERE r.status != ""''' + results = query_db(query) + for pkg, version, suite, arch in results: + eversion = strip_epoch(version) + rbuild = RBUILD_PATH + '/' + suite + '/' + arch + '/' + pkg + '_' + \ + eversion + '.rbuild.log' + if not os.access(rbuild, os.R_OK): + bad_pkgs.append((pkg, version, suite, arch)) + log.warning(pkg + '/' + suite + ' (' + version + ') has been ' + 'built, but it\'s without a buildlog.') + return bad_pkgs + + +def pbuilder_dep_fail(): + log.info('running pbuilder_dep_fail check...') + bad_pkgs = [] + query = '''SELECT s.name, r.version, s.suite, s.architecture + FROM sources AS s JOIN results AS r ON r.package_id=s.id + WHERE r.status = "FTBFS"''' + results = query_db(query) + for pkg, version, suite, arch in results: + eversion = strip_epoch(version) + rbuild = RBUILD_PATH + '/' + suite + '/' + arch + '/' + pkg + '_' + \ + eversion + '.rbuild.log' + if os.access(rbuild, os.R_OK): + log.debug('\tlooking at ' + rbuild) + with open(rbuild, "br") as fd: + for line in fd: + if re.search(b'E: pbuilder-satisfydepends failed.', line): + bad_pkgs.append((pkg, version, suite, arch)) + log.warning(pkg + '/' + suite + ' (' + version + + ') failed to met its dependecies') + return bad_pkgs + + +def alien_rbuild(): + log.info('running alien_rbuild check...') + query = '''SELECT s.name + FROM sources AS s JOIN results AS r on r.package_id=s.id + WHERE r.status != "" AND s.name="{pkg}" AND s.suite="{suite}" + AND s.architecture="{arch}"''' + bad_files = [] + for root, dirs, files in os.walk(RBUILD_PATH): + if not files: + continue + suite, arch = root.rsplit('/', 2)[1:] + for file in files: + try: + pkg, version = file.rsplit('.', 2)[0].rsplit('_', 1) + except ValueError: + log.critical(bcolors.FAIL + '/'.join([root, file]) + + ' does not seems like a file that should be there' + + bcolors.ENDC) + if not query_db(query.format(pkg=pkg, suite=suite, arch=arch)): + bad_files.append('/'.join([root, file])) + log.warning('/'.join([root, file]) + ' should not be there') + return bad_files + + +def alien_dbd(): + log.info('running alien_dbd check...') + query = '''SELECT r.status + FROM sources AS s JOIN results AS r on r.package_id=s.id + WHERE s.name="{pkg}" AND s.suite="{suite}" + AND s.architecture="{arch}"''' + bad_files = [] + for root, dirs, files in os.walk(DBD_PATH): + if not files: + continue + suite, arch = root.rsplit('/', 2)[1:] + for file in files: + try: + pkg, version = file.rsplit('.', 2)[0].rsplit('_', 1) + except ValueError: + log.critical(bcolors.FAIL + '/'.join([root, file]) + + ' does not seems like a file that should be there' + + bcolors.ENDC) + result = query_db(query.format(pkg=pkg, suite=suite, arch=arch)) + try: + if result[0][0] != 'unreproducible': + bad_files.append('/'.join([root, file]) + '(' + + str(result[0][0]) + ' pacakge)') + log.warning('/'.join([root, file]) + ' should not be ' + 'there (' + str(result[0][0]) + ' package)') + except IndexError: + bad_files.append('/'.join([root, file]) + '(' + + 'missing pacakge)') + log.warning(bcolors.WARN + '/'.join([root, file]) + ' should ' + 'not be there (missing package)' + bcolors.ENDC) + return bad_files + + +def alien_rbpkg(): + log.info('running alien_rbpkg check...') + query = '''SELECT s.name + FROM sources AS s + WHERE s.name="{pkg}" AND s.suite="{suite}" + AND s.architecture="{arch}"''' + bad_files = [] + for root, dirs, files in os.walk(RB_PKG_PATH): + if not files: + continue + suite, arch = root.rsplit('/', 2)[1:] + for file in files: + pkg = file.rsplit('.', 1)[0] + if not query_db(query.format(pkg=pkg, suite=suite, arch=arch)): + bad_files.append('/'.join([root, file])) + log.warning('/'.join([root, file]) + ' should not be there') + return bad_files + + +def _gen_section(header, pkgs, entries=None): + if not pkgs and not entries: + return '' + if pkgs: + html = '

' + str(len(pkgs)) + ' ' + html += header + html += '

\n'
+        for pkg in pkgs:
+            html += tab + link_package(pkg[0], pkg[2], pkg[3]).strip()
+            html += ' (' + pkg[1] + ' in ' + pkg[2] + '/' + pkg[3] + ')\n'
+    elif entries:
+        html = '

' + str(len(entries)) + ' ' + html += header + html += '

\n'
+        for entry in entries:
+            html += tab + entry + '\n'
+    html += '

\n' + return html + + +def gen_html(): + html = '' + # files that should not be there (e.g. removed package without cleanup) + html += _gen_section('rbuild that should not be there', None, + entries=alien_rbuild()) + html += _gen_section('debbindiffs that should not be there', None, + entries=alien_dbd()) + html += _gen_section('rb-pkg pages that should not be there', None, + entries=alien_rbpkg()) + # debbindiff troubles + without_dbd, bad_dbd = unrep_with_dbd_issues() + html += _gen_section('are marked as unreproducible, but without ' + + 'debbindiff output:', without_dbd) + html += _gen_section('are marked as unreproducible, but their ' + + 'debbindiff output does not seem an html ' + + 'page:', bad_dbd) + # debbindiff report where it shouldn't be + html += _gen_section('are not marked as unreproducible, but they ' + + 'have a debbindiff file:', not_unrep_with_dbd_file()) + # missing buildlog + html += _gen_section('are built does not have a buildlog', lack_rbuild()) + # pbuilder-satisfydepends failed + html += _gen_section('failed to met their build-dependecies', + pbuilder_dep_fail()) + return html + + +if __name__ == '__main__': + bugs = get_bugs() + html = '

This page lists unexpected things a human should look at and ' + html += 'fix, like packages with an incoherent status or files that ' + html += 'should not be there.
Please help with empting this page!

' + breakages = gen_html() + if breakages: + html += breakages + else: + html += '

COOL!!! Everything is GOOD and not a issue was ' + html += 'detected. Enjoy!

' + title = 'CI breakages' + destfile = BASE + '/index_breakages.html' + desturl = REPRODUCIBLE_URL + '/index_breakages.html' + write_html_page(title, html, destfile, style_note=True) + log.info('CI breackages page created at ' + desturl) diff --git a/job-cfg/reproducible.yaml b/job-cfg/reproducible.yaml index 8bc2c482..fc8e0b7f 100644 --- a/job-cfg/reproducible.yaml +++ b/job-cfg/reproducible.yaml @@ -188,6 +188,10 @@ defaults: reproducible name: '{name}_json' +- job-template: + defaults: reproducible + name: '{name}_breakages' + - job-template: defaults: reproducible_builder name: '{name}_builder_alpha' @@ -310,6 +314,11 @@ my_timed: '0 6 * * H/3' my_shell: '/srv/jenkins/bin/reproducible_create_meta_pkg_sets.sh' my_recipients: 'qa-jenkins-scm@lists.alioth.debian.org' + - '{name}_breakages': + my_description: 'Generate an HTML page full with CI issues (packages with incoherent status or files that should not be there)' + my_timed: '1 0 * * *' + my_shell: '/srv/jenkins/bin/reproducible_breakages.py' + my_recipients: 'qa-jenkins-scm@lists.alioth.debian.org' - '{name}_builder_alpha': my_description: 'Try to reproducibly build a scheduled package. This is one of several builder jobs.' my_timed: 'H/2 * * * *' -- cgit v1.2.3-70-g09d2