2017-12-19 17:03:51 +01:00
|
|
|
import json
|
|
|
|
import requests
|
2018-03-10 22:46:33 +01:00
|
|
|
import datetime
|
2017-12-19 17:03:51 +01:00
|
|
|
|
2018-01-29 03:39:04 +01:00
|
|
|
from .. import db
|
2020-11-12 15:35:02 +01:00
|
|
|
from app.models.appcatalog import App
|
2017-12-19 17:03:51 +01:00
|
|
|
|
|
|
|
class AppCIBranch(db.Model):
|
|
|
|
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
name = db.Column(db.String(64), unique=True, nullable=False)
|
2018-11-02 01:30:50 +01:00
|
|
|
arch = db.Column(db.String(64), nullable=False)
|
|
|
|
branch = db.Column(db.String(64), nullable=False)
|
2017-12-19 17:03:51 +01:00
|
|
|
display_name = db.Column(db.String(64), unique=True, nullable=False)
|
|
|
|
url = db.Column(db.String(128), nullable=False)
|
2018-12-12 17:33:24 +01:00
|
|
|
url_per_app = db.Column(db.String(128), nullable=False)
|
2017-12-19 17:03:51 +01:00
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return '<AppCIBranch %r>' % self.name
|
|
|
|
|
|
|
|
def init():
|
|
|
|
yield AppCIBranch(name='stable',
|
2021-03-21 22:07:10 +01:00
|
|
|
arch="amd64",
|
2018-11-02 01:30:50 +01:00
|
|
|
branch="stable",
|
2017-12-19 17:03:51 +01:00
|
|
|
display_name='Stable (x86)',
|
2021-03-17 20:32:22 +01:00
|
|
|
url='https://ci-apps.yunohost.org/ci/logs/list_level_stable_amd64.json',
|
2018-12-12 17:33:24 +01:00
|
|
|
url_per_app='https://ci-apps.yunohost.org/ci/apps/{}/')
|
2017-12-19 17:03:51 +01:00
|
|
|
|
2019-01-25 16:44:55 +01:00
|
|
|
yield AppCIBranch(name='unstable',
|
2021-03-21 22:07:10 +01:00
|
|
|
arch="amd64",
|
2019-01-25 16:44:55 +01:00
|
|
|
branch="unstable",
|
|
|
|
display_name='Unstable (x86)',
|
2021-03-17 20:32:22 +01:00
|
|
|
url='https://ci-apps-unstable.yunohost.org/ci/logs/list_level_unstable_amd64.json',
|
2019-01-25 16:44:55 +01:00
|
|
|
url_per_app='https://ci-apps-unstable.yunohost.org/ci/apps/{}/')
|
|
|
|
|
2017-12-19 17:03:51 +01:00
|
|
|
def last_build_url(self, app):
|
2018-12-12 17:33:24 +01:00
|
|
|
return self.url_per_app.format(app.name)
|
2017-12-19 17:03:51 +01:00
|
|
|
|
|
|
|
def most_recent_tests_per_app(self):
|
|
|
|
|
2020-11-12 15:35:02 +01:00
|
|
|
apps = App.query.filter_by(state="working").all()
|
2019-01-22 17:07:00 +01:00
|
|
|
most_recent_tests = AppCIResult.query \
|
|
|
|
.filter_by(branch = self) \
|
2019-04-29 22:29:56 +02:00
|
|
|
.order_by(AppCIResult.date.desc()) \
|
2019-01-22 17:07:00 +01:00
|
|
|
.all()
|
|
|
|
|
2017-12-19 17:03:51 +01:00
|
|
|
for app in apps:
|
2019-01-22 17:07:00 +01:00
|
|
|
most_recent_test = [ t for t in most_recent_tests if t.app == app ]
|
2017-12-19 17:03:51 +01:00
|
|
|
if most_recent_test:
|
2019-01-22 17:07:00 +01:00
|
|
|
yield most_recent_test[0]
|
2018-11-02 02:07:16 +01:00
|
|
|
else:
|
2021-03-21 22:58:04 +01:00
|
|
|
yield AppCIResult({"app": app.name,
|
|
|
|
"architecture": self.arch,
|
|
|
|
"yunohost_branch": self.branch,
|
|
|
|
"commit": "",
|
|
|
|
"level": None,
|
|
|
|
"timestamp": 0,
|
|
|
|
"tests": {}})
|
2017-12-19 17:03:51 +01:00
|
|
|
|
|
|
|
|
2021-03-21 22:07:10 +01:00
|
|
|
test_categories = []
|
|
|
|
def test_category(category_name):
|
|
|
|
def decorator(func):
|
|
|
|
test_categories.append((func.__name__, category_name, func))
|
|
|
|
return func
|
|
|
|
return decorator
|
|
|
|
|
2017-12-19 17:03:51 +01:00
|
|
|
class AppCIResult(db.Model):
|
|
|
|
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
|
|
|
|
app = db.relationship(App, backref='tests', lazy=True, uselist=False)
|
|
|
|
branch = db.relationship(AppCIBranch, backref='tests', lazy=True, uselist=False)
|
|
|
|
|
|
|
|
app_id = db.Column(db.ForeignKey(App.id))
|
|
|
|
branch_id = db.Column(db.ForeignKey(AppCIBranch.id))
|
|
|
|
|
|
|
|
results = db.Column(db.PickleType)
|
|
|
|
|
2018-02-26 14:46:51 +01:00
|
|
|
date = db.Column(db.DateTime, nullable=True)
|
|
|
|
level = db.Column(db.Integer, nullable=True)
|
2018-11-02 01:30:50 +01:00
|
|
|
url = db.Column(db.String(128), nullable=True)
|
2018-02-26 14:46:51 +01:00
|
|
|
commit = db.Column(db.String(64), nullable=True)
|
2017-12-19 17:03:51 +01:00
|
|
|
|
|
|
|
def __repr__(self):
|
2019-05-14 19:00:37 +02:00
|
|
|
return '<AppCIResult %s>' % self.date
|
2017-12-19 17:03:51 +01:00
|
|
|
|
2021-03-21 22:07:10 +01:00
|
|
|
def __init__(self, infos):
|
|
|
|
|
|
|
|
self.app = App.query.filter_by(name=infos["app"]).first()
|
|
|
|
self.branch = AppCIBranch.query.filter_by(arch=infos["architecture"], branch=infos["yunohost_branch"]).first()
|
|
|
|
self.level = infos["level"]
|
|
|
|
self.commit = infos["commit"]
|
|
|
|
self.date = datetime.datetime.fromtimestamp(infos["timestamp"])
|
|
|
|
self.results = { category: result for category, result in list(self.analyze_test_categories(infos["tests"])) }
|
|
|
|
|
|
|
|
def analyze_test_categories(self, raw_results):
|
|
|
|
|
|
|
|
for category_id, category_display, is_in_category in test_categories:
|
|
|
|
|
|
|
|
relevant_tests = [test for test in raw_results if is_in_category(test)]
|
|
|
|
|
|
|
|
if not relevant_tests:
|
|
|
|
yield (category_id, None)
|
|
|
|
else:
|
|
|
|
yield (category_id, all(test["main_result"] == "success" for test in relevant_tests))
|
|
|
|
|
|
|
|
@test_category("Linter")
|
|
|
|
def package_linter(test):
|
|
|
|
return test["test_type"] == "PACKAGE_LINTER"
|
|
|
|
|
|
|
|
@test_category("Install on domain's root")
|
|
|
|
def install_root(test):
|
|
|
|
return test["test_type"] == "TEST_INSTALL" and test["test_arg"] == "root"
|
|
|
|
|
|
|
|
@test_category("Install on domain subpath")
|
|
|
|
def install_subpath(test):
|
|
|
|
return test["test_type"] == "TEST_INSTALL" and test["test_arg"] == "subdir"
|
|
|
|
|
|
|
|
@test_category("Install with no url")
|
|
|
|
def install_nourl(test):
|
|
|
|
return test["test_type"] == "TEST_INSTALL" and test["test_arg"] == "nourl"
|
|
|
|
|
|
|
|
@test_category("Install in private mode")
|
|
|
|
def install_private(test):
|
|
|
|
return test["test_type"] == "TEST_INSTALL" and test["test_arg"] == "private"
|
|
|
|
|
|
|
|
@test_category("Install multi-instance")
|
|
|
|
def install_multi(test):
|
|
|
|
return test["test_type"] == "TEST_INSTALL" and test["test_arg"] == "multi"
|
|
|
|
|
|
|
|
@test_category("Upgrade (same version)")
|
|
|
|
def upgrade_same_version(test):
|
|
|
|
return test["test_type"] == "TEST_UPGRADE" and test["test_arg"] == ""
|
|
|
|
|
|
|
|
@test_category("Upgrade (older versions)")
|
|
|
|
def upgrade_older_versions(test):
|
|
|
|
return test["test_type"] == "TEST_UPGRADE" and test["test_arg"] != ""
|
|
|
|
|
|
|
|
@test_category("Backup / restore")
|
|
|
|
def backup_restore(test):
|
|
|
|
return test["test_type"] == "TEST_BACKUP_RESTORE"
|
|
|
|
|
|
|
|
@test_category("Change url")
|
|
|
|
def change_url(test):
|
|
|
|
return test["test_type"] == "TEST_CHANGE_URL"
|
|
|
|
|
2017-12-19 17:03:51 +01:00
|
|
|
def init():
|
|
|
|
pass
|
|
|
|
|
|
|
|
def score(self):
|
|
|
|
s_dict = { True: +1, False: -1, None: 0 }
|
2018-11-08 14:48:35 +01:00
|
|
|
return sum([ s_dict[result] for result in self.results.values() ])
|
2017-12-19 17:03:51 +01:00
|
|
|
|
2020-09-03 19:33:59 +02:00
|
|
|
@property
|
|
|
|
def outdated(self):
|
2020-11-07 18:55:59 +01:00
|
|
|
return (datetime.datetime.now() - self.date).days > 30
|
2020-09-03 19:33:59 +02:00
|
|
|
|
2020-11-13 01:46:54 +01:00
|
|
|
@property
|
|
|
|
def needs_attention(self):
|
2021-03-21 19:32:07 +01:00
|
|
|
return self.outdated or self.level is None or self.app.public_level == "?" or (int(self.app.public_level) > self.level)
|
2020-11-13 01:46:54 +01:00
|
|
|
|
2017-12-19 17:03:51 +01:00
|
|
|
|
|
|
|
class AppCI():
|
|
|
|
|
|
|
|
def update():
|
|
|
|
|
|
|
|
cibranches = AppCIBranch.query.all()
|
|
|
|
|
|
|
|
# Scrap jenkins
|
2018-11-02 01:30:50 +01:00
|
|
|
for cibranch in cibranches:
|
|
|
|
print("> Fetching current CI results for C.I. branch {}".format(cibranch.name))
|
2020-04-15 03:55:50 +02:00
|
|
|
try:
|
2021-03-21 22:07:10 +01:00
|
|
|
results = requests.get(cibranch.url).json()
|
2020-04-15 03:55:50 +02:00
|
|
|
except:
|
|
|
|
print("Failed to fetch %s" % cibranch.url)
|
|
|
|
continue
|
2018-11-02 01:30:50 +01:00
|
|
|
|
2021-03-21 22:07:10 +01:00
|
|
|
for app, test_summary in results.items():
|
|
|
|
|
|
|
|
if (test_summary["architecture"], test_summary["yunohost_branch"]) != (cibranch.arch, cibranch.branch):
|
|
|
|
continue
|
2018-11-08 14:48:35 +01:00
|
|
|
|
2019-01-22 17:07:00 +01:00
|
|
|
app = App.query.filter_by(name=test_summary["app"]).first()
|
2019-05-14 19:00:37 +02:00
|
|
|
if app is None:
|
|
|
|
print("Couldnt found corresponding app object for %s, skipping" % test_summary["app"])
|
|
|
|
continue
|
2019-01-22 17:07:00 +01:00
|
|
|
date = datetime.datetime.fromtimestamp(test_summary["timestamp"])
|
|
|
|
|
|
|
|
existing_test = AppCIResult.query \
|
|
|
|
.filter_by(branch = cibranch) \
|
|
|
|
.filter_by(date = date) \
|
|
|
|
.first()
|
|
|
|
|
2019-05-14 19:00:37 +02:00
|
|
|
if existing_test and existing_test.app is None:
|
|
|
|
print("Uh erasing old weird buggy record")
|
|
|
|
db.session.delete(existing_test)
|
|
|
|
existing_test = None
|
|
|
|
|
2019-01-22 17:07:00 +01:00
|
|
|
if not existing_test:
|
2021-03-21 22:07:10 +01:00
|
|
|
print("New record for app %s" % str(app))
|
|
|
|
results = AppCIResult(test_summary)
|
|
|
|
db.session.add(results)
|
2017-12-19 17:03:51 +01:00
|
|
|
|
|
|
|
db.session.commit()
|