#!/usr/bin/python3
# -*- coding: utf-8 -*-
# pylint: disable=line-too-long
# kate: space-indent on; indent-width 4; replace-tabs on; indent-mode python; remove-trailing-space modified;
# pylint: enable=line-too-long
# vim: expandtab ts=4
############################################################################
# Copyright © 2017-2020 José Manuel Santamaría Lema <panfaust@gmail.com> #
# #
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or #
# (at your option) any later version. #
############################################################################
"""
This module just provides the KAGraphProposedMigrationStatus class.
"""
import re
from libka.kagraph.ka_graph import KAGraph
from libka.kagraph.ka_graph_node_status import KAGraphNodeStatus
from libka.excuses.excuses_yaml_parser import ExcusesYAMLParser
[docs]
class KAGraphProposedMigrationStatus(KAGraph): #pylint: disable=too-many-instance-attributes
"""
Class to represent a graph with our current proposed migration status, it's
meant to point out which packages are stuck in -proposed.
"""
def __init__(self, dist, title=''):
#Call the superclass constructor
super(KAGraphProposedMigrationStatus, self).__init__(title)
#Define all possible kinds of status
#pylint: disable=line-too-long
self._status_ok = KAGraphNodeStatus(
name='status_ok',
color='green3',
text="already migrated")
self._status_ftbfs = KAGraphNodeStatus(
name='status_ftbfs',
color='red',
text="FTBFS",
url="https://people.canonical.com/~ubuntu-archive/proposed-migration/update_excuses.html#\\N")
self._status_chrootproblem = KAGraphNodeStatus(
name='status_chrootproblem',
color='orangered',
text="Chroot problem",
url="https://people.canonical.com/~ubuntu-archive/proposed-migration/update_excuses.html#\\N")
self._status_depwait = KAGraphNodeStatus(
name='status_depwait',
color='lightblue',
text="dep wait",
url="https://people.canonical.com/~ubuntu-archive/proposed-migration/update_excuses.html#\\N")
self._status_stuck = KAGraphNodeStatus(
name='status_stuck',
color='orange',
text="not migrated yet",
url="https://people.canonical.com/~ubuntu-archive/proposed-migration/update_excuses.html#\\N")
self._status_notfound = KAGraphNodeStatus(
name='status_notfound',
color='grey',
text="Package not found")
self._status_new = KAGraphNodeStatus(
name='status_new',
color='chocolate',
text="Package in the NEW queue",
url="https://launchpad.net/ubuntu/%s/+queue" % dist)
self._status_wrongversion = KAGraphNodeStatus(
name='status_wrongversion',
color='firebrick',
text="Incorrect version")
self._status_autopkgtests_running = KAGraphNodeStatus(
name='status_autopkgtests_running',
color='dodgerblue',
text="Autopkgtests running",
url="https://people.canonical.com/~ubuntu-archive/proposed-migration/update_excuses.html#\\N")
self._status_autopkgtests_failed = KAGraphNodeStatus(
name='status_autopkgtest_failed',
color='salmon',
text="Autopkgtests failed",
url="https://people.canonical.com/~ubuntu-archive/proposed-migration/update_excuses.html#\\N")
self._status_valid_candidate = KAGraphNodeStatus(
name='status_valid_candidate',
color='greenyellow',
text="Valid candidate",
url="https://people.canonical.com/~ubuntu-archive/proposed-migration/update_excuses.html#\\N")
self.set_package_status_list([
self._status_ok, self._status_stuck,
self._status_depwait, self._status_ftbfs, self._status_wrongversion,
self._status_new, self._status_notfound])
#pylint: enable=line-too-long
#Wether to check the update excuses to set some nodes status or not
self._check_excuses = False
self._update_excuses_url = None
[docs]
def set_check_excuses(self, enabled):
"""
Determine if we should use the excuses output to set the package status.
"""
self._check_excuses = enabled
self.set_package_status_list([
self._status_ok, self._status_valid_candidate,
self._status_stuck,
self._status_depwait, self._status_autopkgtests_running,
self._status_autopkgtests_failed, self._status_ftbfs, self._status_chrootproblem,
self._status_wrongversion,
self._status_new, self._status_notfound])
[docs]
def set_excuses_url(self, url):
"""
Set the excuses output url.
"""
self._update_excuses_url = url
#pylint: disable=too-many-branches,too-many-statements,too-many-locals
[docs]
def set_package_status_from_lp_sources_and_builds(self, all_sources, all_builds, lpseries): #pylint: disable=invalid-name
"""
Set the package status info from Launchpad.
"""
#For each package check its state and print the proper node info line
#Parse excuses
if self._check_excuses:
excuses_parser = ExcusesYAMLParser()
excuses_parser.parse_excuses_url(self._update_excuses_url)
excuses_info_map = excuses_parser.get_package_info()
#Check all packages
for package in all_sources: #pylint: disable=too-many-nested-blocks
sources = all_sources[package]
if len(sources) == 0:
#This package is not on Proposed nor Release
package_uploads_new = lpseries.getPackageUploads(name=package,
exact_match=True,
status='New')
if len(package_uploads_new) != 0:
self.set_package_status(package, self._status_new)
else:
self.set_package_status(package, self._status_notfound)
else:
#Check if the package is at the correct version
if package not in self._different_versions:
actual_version = sources[0].source_package_version.split(':')[-1]
expected_version = self._expected_version
if not actual_version.startswith(expected_version):
#This package has a wrong version
self.set_package_status(package, self._status_wrongversion)
#Set the package node url in the graph
url = sources[0].self_link
url = re.sub(r"api\.launchpad\.net/[^/]*",
"launchpad.net", url) + "/+listing-archive-extra"
self.set_package_url(package, url)
continue
#This package is ok, set it as such and continue
if sources[0].pocket == "Release":
self.set_package_status(package, self._status_ok)
continue
#This package is still stuck @ -proposed
builds = all_builds[package]
its_ftbfs = False
its_chrootproblem = False
its_depwait = False
for build in builds:
#Ignore this build if it's not in the arch list; None means 'consider all'
if self._arch_list is not None:
if build.arch_tag not in self._arch_list:
continue
#Check build state
if build.buildstate == "Dependency wait":
its_depwait = True
elif build.buildstate == "Chroot problem":
its_chrootproblem = True
elif build.buildstate == "Failed to build":
its_ftbfs = True
if its_ftbfs:
self.set_package_status(package, self._status_ftbfs)
elif its_chrootproblem:
self.set_package_status(package, self._status_chrootproblem)
elif its_depwait:
self.set_package_status(package, self._status_depwait)
else:
#Check if the package is stuck in the new queue
package_uploads_new = lpseries.getPackageUploads(name=package,
exact_match=True,
status='New')
if len(package_uploads_new) != 0:
self.set_package_status(package, self._status_new)
else:
if not self._check_excuses:
self.set_package_status(package, self._status_stuck)
else:
#Check the excuses status
if not its_ftbfs and not its_depwait and package in excuses_info_map:
excuses_package_info = excuses_info_map[package]
if excuses_package_info.is_candidate:
self.set_package_status(package, self._status_valid_candidate)
else:
found_autopkgtest_failing = False
found_autopkgtest_running = False
for autopkgtest_package in excuses_package_info.autopkgtests:
autopkgtest_info_map = (
excuses_package_info.autopkgtests[autopkgtest_package])
for autopkgtest_arch in autopkgtest_info_map:
autopkgtest_status = (
autopkgtest_info_map[autopkgtest_arch])
if autopkgtest_status == "REGRESSION":
found_autopkgtest_failing = True
break
elif autopkgtest_status == "RUNNING":
found_autopkgtest_running = True
if autopkgtest_status == "REGRESSION":
break
if found_autopkgtest_failing:
self.set_package_status(package,
self._status_autopkgtests_failed)
elif found_autopkgtest_running:
self.set_package_status(package,
self._status_autopkgtests_running)
else:
self.set_package_status(package,
self._status_stuck)
else:
self.set_package_status(package, self._status_stuck)
#pylint: enable=too-many-branches,too-many-statements,too-many-locals