diff --git a/Dockerfile b/Dockerfile
index 50d5d5c9..7bf68346 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -24,7 +24,7 @@ RUN YAY_DIR="$(runuser -u build -- mktemp -d)" && \
runuser -u build -- makepkg --noconfirm --install && \
cd - && rm -r "$YAY_DIR"
## install package dependencies
-RUN runuser -u build -- yay --noconfirm -Sy devtools git pyalpm python-inflection python-passlib python-srcinfo && \
+RUN runuser -u build -- yay --noconfirm -Sy devtools git pyalpm python-inflection python-passlib python-requests python-srcinfo && \
runuser -u build -- yay --noconfirm -Sy python-pip && \
runuser -u build -- yay --noconfirm -Sy breezy darcs mercurial python-aioauth-client python-aiohttp \
python-aiohttp-debugtoolbar python-aiohttp-jinja2 python-aiohttp-security \
diff --git a/package/archlinux/PKGBUILD b/package/archlinux/PKGBUILD
index e8a7d8b3..64aa8934 100644
--- a/package/archlinux/PKGBUILD
+++ b/package/archlinux/PKGBUILD
@@ -7,7 +7,7 @@ pkgdesc="ArcH Linux ReposItory MANager"
arch=('any')
url="https://github.com/arcan1s/ahriman"
license=('GPL3')
-depends=('devtools' 'git' 'pyalpm' 'python-inflection' 'python-passlib' 'python-srcinfo')
+depends=('devtools' 'git' 'pyalpm' 'python-inflection' 'python-passlib' 'python-requests' 'python-srcinfo')
makedepends=('python-pip')
optdepends=('breezy: -bzr packages support'
'darcs: -darcs packages support'
diff --git a/package/etc/ahriman.ini b/package/etc/ahriman.ini
index cb143ba6..0c1caa34 100644
--- a/package/etc/ahriman.ini
+++ b/package/etc/ahriman.ini
@@ -30,7 +30,10 @@ root = /var/lib/ahriman
target =
[report]
-target =
+target = console
+
+[console]
+use_utf = yes
[email]
full_template_path = /usr/share/ahriman/repo-index.jinja2
diff --git a/package/share/ahriman/build-status.jinja2 b/package/share/ahriman/build-status.jinja2
index 8df0a598..6aa15815 100644
--- a/package/share/ahriman/build-status.jinja2
+++ b/package/share/ahriman/build-status.jinja2
@@ -16,7 +16,7 @@
ahriman
{% if auth.authenticated %}
-
+
{% endif %}
diff --git a/src/ahriman/application/application/application.py b/src/ahriman/application/application/application.py
index 9680c9a2..72286b92 100644
--- a/src/ahriman/application/application/application.py
+++ b/src/ahriman/application/application/application.py
@@ -17,11 +17,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Iterable, Set
+from typing import Set
from ahriman.application.application.packages import Packages
from ahriman.application.application.repository import Repository
-from ahriman.models.package import Package
+from ahriman.models.result import Result
class Application(Packages, Repository):
@@ -29,12 +29,13 @@ class Application(Packages, Repository):
base application class
"""
- def _finalize(self, built_packages: Iterable[Package]) -> None:
+ def _finalize(self, result: Result) -> None:
"""
generate report and sync to remote server
+ :param result: build result
"""
- self.report([], built_packages)
- self.sync([], built_packages)
+ self.report([], result)
+ self.sync([], result.success)
def _known_packages(self) -> Set[str]:
"""
diff --git a/src/ahriman/application/application/packages.py b/src/ahriman/application/application/packages.py
index 66eb4070..852b4fbe 100644
--- a/src/ahriman/application/application/packages.py
+++ b/src/ahriman/application/application/packages.py
@@ -28,6 +28,7 @@ from ahriman.core.build_tools.sources import Sources
from ahriman.core.util import package_like
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
+from ahriman.models.result import Result
class Packages(Properties):
@@ -35,9 +36,10 @@ class Packages(Properties):
package control class
"""
- def _finalize(self, built_packages: Iterable[Package]) -> None:
+ def _finalize(self, result: Result) -> None:
"""
generate report and sync to remote server
+ :param result: build result
"""
raise NotImplementedError
@@ -141,4 +143,4 @@ class Packages(Properties):
:param names: list of packages (either base or name) to remove
"""
self.repository.process_remove(names)
- self._finalize([])
+ self._finalize(Result())
diff --git a/src/ahriman/application/application/repository.py b/src/ahriman/application/application/repository.py
index 7607ce51..bfa2b291 100644
--- a/src/ahriman/application/application/repository.py
+++ b/src/ahriman/application/application/repository.py
@@ -23,11 +23,11 @@ from pathlib import Path
from typing import Callable, Iterable, List
from ahriman.application.application.properties import Properties
-from ahriman.application.formatters.update_printer import UpdatePrinter
from ahriman.core.build_tools.sources import Sources
+from ahriman.core.formatters.update_printer import UpdatePrinter
from ahriman.core.tree import Tree
from ahriman.models.package import Package
-from ahriman.models.package_source import PackageSource
+from ahriman.models.result import Result
class Repository(Properties):
@@ -35,9 +35,10 @@ class Repository(Properties):
repository control class
"""
- def _finalize(self, built_packages: Iterable[Package]) -> None:
+ def _finalize(self, result: Result) -> None:
"""
generate report and sync to remote server
+ :param result: build result
"""
raise NotImplementedError
@@ -64,14 +65,14 @@ class Repository(Properties):
if patches:
self.repository.clear_patches()
- def report(self, target: Iterable[str], built_packages: Iterable[Package]) -> None:
+ def report(self, target: Iterable[str], result: Result) -> None:
"""
generate report
:param target: list of targets to run (e.g. html)
- :param built_packages: list of packages which has just been built
+ :param result: build result
"""
targets = target or None
- self.repository.process_report(targets, built_packages)
+ self.repository.process_report(targets, result)
def sign(self, packages: Iterable[str]) -> None:
"""
@@ -94,7 +95,7 @@ class Repository(Properties):
self.update([])
# sign repository database if set
self.repository.sign.process_sign_repository(self.repository.repo.repo_path)
- self._finalize([])
+ self._finalize(Result())
def sync(self, target: Iterable[str], built_packages: Iterable[Package]) -> None:
"""
@@ -142,26 +143,23 @@ class Repository(Properties):
run package updates
:param updates: list of packages to update
"""
- def process_update(paths: Iterable[Path]) -> None:
+ def process_update(paths: Iterable[Path], result: Result) -> None:
if not paths:
return # don't need to process if no update supplied
- updated = [
- Package.load(str(path), PackageSource.Archive, self.repository.pacman, self.repository.aur_url)
- for path in paths
- ]
- self.repository.process_update(paths)
- self._finalize(updated)
+ update_result = self.repository.process_update(paths)
+ self._finalize(result.merge(update_result))
# process built packages
packages = self.repository.packages_built()
- process_update(packages)
+ process_update(packages, Result())
# process manual packages
tree = Tree.load(updates, self.repository.paths)
for num, level in enumerate(tree.levels()):
self.logger.info("processing level #%i %s", num, [package.base for package in level])
- packages = self.repository.process_build(level)
- process_update(packages)
+ build_result = self.repository.process_build(level)
+ packages = self.repository.packages_built()
+ process_update(packages, build_result)
def updates(self, filter_packages: Iterable[str], no_aur: bool, no_local: bool, no_manual: bool, no_vcs: bool,
log_fn: Callable[[str], None]) -> List[Package]:
diff --git a/src/ahriman/application/handlers/dump.py b/src/ahriman/application/handlers/dump.py
index fd4f4b91..db7f6702 100644
--- a/src/ahriman/application/handlers/dump.py
+++ b/src/ahriman/application/handlers/dump.py
@@ -21,9 +21,9 @@ import argparse
from typing import Type
-from ahriman.application.formatters.configuration_printer import ConfigurationPrinter
from ahriman.application.handlers.handler import Handler
from ahriman.core.configuration import Configuration
+from ahriman.core.formatters.configuration_printer import ConfigurationPrinter
class Dump(Handler):
diff --git a/src/ahriman/application/handlers/rebuild.py b/src/ahriman/application/handlers/rebuild.py
index 09f9e9ac..1b28dfa8 100644
--- a/src/ahriman/application/handlers/rebuild.py
+++ b/src/ahriman/application/handlers/rebuild.py
@@ -22,9 +22,9 @@ import argparse
from typing import Type
from ahriman.application.application import Application
-from ahriman.application.formatters.update_printer import UpdatePrinter
from ahriman.application.handlers.handler import Handler
from ahriman.core.configuration import Configuration
+from ahriman.core.formatters.update_printer import UpdatePrinter
class Rebuild(Handler):
diff --git a/src/ahriman/application/handlers/remove_unknown.py b/src/ahriman/application/handlers/remove_unknown.py
index 4912e17e..07ae70ad 100644
--- a/src/ahriman/application/handlers/remove_unknown.py
+++ b/src/ahriman/application/handlers/remove_unknown.py
@@ -22,9 +22,9 @@ import argparse
from typing import Type
from ahriman.application.application import Application
-from ahriman.application.formatters.string_printer import StringPrinter
from ahriman.application.handlers.handler import Handler
from ahriman.core.configuration import Configuration
+from ahriman.core.formatters.string_printer import StringPrinter
class RemoveUnknown(Handler):
diff --git a/src/ahriman/application/handlers/report.py b/src/ahriman/application/handlers/report.py
index 9c10c3b8..46b6b4ab 100644
--- a/src/ahriman/application/handlers/report.py
+++ b/src/ahriman/application/handlers/report.py
@@ -24,6 +24,7 @@ from typing import Type
from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler
from ahriman.core.configuration import Configuration
+from ahriman.models.result import Result
class Report(Handler):
@@ -42,4 +43,4 @@ class Report(Handler):
:param no_report: force disable reporting
:param unsafe: if set no user check will be performed before path creation
"""
- Application(architecture, configuration, no_report, unsafe).report(args.target, [])
+ Application(architecture, configuration, no_report, unsafe).report(args.target, Result())
diff --git a/src/ahriman/application/handlers/search.py b/src/ahriman/application/handlers/search.py
index 0bd22c94..5f13c6df 100644
--- a/src/ahriman/application/handlers/search.py
+++ b/src/ahriman/application/handlers/search.py
@@ -22,11 +22,11 @@ import argparse
from dataclasses import fields
from typing import Callable, Iterable, List, Tuple, Type
-from ahriman.application.formatters.aur_printer import AurPrinter
from ahriman.application.handlers.handler import Handler
from ahriman.core.alpm.aur import AUR
from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import InvalidOption
+from ahriman.core.formatters.aur_printer import AurPrinter
from ahriman.models.aur_package import AURPackage
diff --git a/src/ahriman/application/handlers/status.py b/src/ahriman/application/handlers/status.py
index 60a29643..f220f9c7 100644
--- a/src/ahriman/application/handlers/status.py
+++ b/src/ahriman/application/handlers/status.py
@@ -22,10 +22,10 @@ import argparse
from typing import Callable, Iterable, Tuple, Type
from ahriman.application.application import Application
-from ahriman.application.formatters.package_printer import PackagePrinter
-from ahriman.application.formatters.status_printer import StatusPrinter
from ahriman.application.handlers.handler import Handler
from ahriman.core.configuration import Configuration
+from ahriman.core.formatters.package_printer import PackagePrinter
+from ahriman.core.formatters.status_printer import StatusPrinter
from ahriman.models.build_status import BuildStatus
from ahriman.models.package import Package
diff --git a/src/ahriman/application/handlers/unsafe_commands.py b/src/ahriman/application/handlers/unsafe_commands.py
index 8be04341..3f874cb1 100644
--- a/src/ahriman/application/handlers/unsafe_commands.py
+++ b/src/ahriman/application/handlers/unsafe_commands.py
@@ -21,9 +21,9 @@ import argparse
from typing import List, Type
-from ahriman.application.formatters.string_printer import StringPrinter
from ahriman.application.handlers.handler import Handler
from ahriman.core.configuration import Configuration
+from ahriman.core.formatters.string_printer import StringPrinter
class UnsafeCommands(Handler):
diff --git a/src/ahriman/core/exceptions.py b/src/ahriman/core/exceptions.py
index ba41574f..cd207627 100644
--- a/src/ahriman/core/exceptions.py
+++ b/src/ahriman/core/exceptions.py
@@ -136,6 +136,19 @@ class ReportFailed(RuntimeError):
RuntimeError.__init__(self, "Report failed")
+class SuccessFailed(ValueError):
+ """
+ exception for merging invalid statues
+ """
+
+ def __init__(self, package_base: str) -> None:
+ """
+ default constructor
+ :param package_base: package base name
+ """
+ ValueError.__init__(self, f"Package base {package_base} had status failed, but new status is success")
+
+
class SyncFailed(RuntimeError):
"""
remote synchronization exception
diff --git a/src/ahriman/application/formatters/__init__.py b/src/ahriman/core/formatters/__init__.py
similarity index 100%
rename from src/ahriman/application/formatters/__init__.py
rename to src/ahriman/core/formatters/__init__.py
diff --git a/src/ahriman/application/formatters/aur_printer.py b/src/ahriman/core/formatters/aur_printer.py
similarity index 57%
rename from src/ahriman/application/formatters/aur_printer.py
rename to src/ahriman/core/formatters/aur_printer.py
index 0ec2ddc6..31382cd1 100644
--- a/src/ahriman/application/formatters/aur_printer.py
+++ b/src/ahriman/core/formatters/aur_printer.py
@@ -17,17 +17,18 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import List, Optional
+from typing import List
-from ahriman.application.formatters.printer import Printer
+from ahriman.core.formatters.string_printer import StringPrinter
from ahriman.core.util import pretty_datetime
from ahriman.models.aur_package import AURPackage
from ahriman.models.property import Property
-class AurPrinter(Printer):
+class AurPrinter(StringPrinter):
"""
print content of the AUR package
+ :ivar package: AUR package description
"""
def __init__(self, package: AURPackage) -> None:
@@ -35,7 +36,8 @@ class AurPrinter(Printer):
default constructor
:param package: AUR package description
"""
- self.content = package
+ StringPrinter.__init__(self, f"{package.name} {package.version} ({package.num_votes})")
+ self.package = package
def properties(self) -> List[Property]:
"""
@@ -43,19 +45,12 @@ class AurPrinter(Printer):
:return: list of content properties
"""
return [
- Property("Package base", self.content.package_base),
- Property("Description", self.content.description, is_required=True),
- Property("Upstream URL", self.content.url or ""),
- Property("Licenses", ",".join(self.content.license)),
- Property("Maintainer", self.content.maintainer or ""),
- Property("First submitted", pretty_datetime(self.content.first_submitted)),
- Property("Last updated", pretty_datetime(self.content.last_modified)),
- Property("Keywords", ",".join(self.content.keywords)),
+ Property("Package base", self.package.package_base),
+ Property("Description", self.package.description, is_required=True),
+ Property("Upstream URL", self.package.url or ""),
+ Property("Licenses", ",".join(self.package.license)),
+ Property("Maintainer", self.package.maintainer or ""),
+ Property("First submitted", pretty_datetime(self.package.first_submitted)),
+ Property("Last updated", pretty_datetime(self.package.last_modified)),
+ Property("Keywords", ",".join(self.package.keywords)),
]
-
- def title(self) -> Optional[str]:
- """
- generate entry title from content
- :return: content title if it can be generated and None otherwise
- """
- return f"{self.content.name} {self.content.version} ({self.content.num_votes})"
diff --git a/src/ahriman/core/formatters/build_printer.py b/src/ahriman/core/formatters/build_printer.py
new file mode 100644
index 00000000..1df31112
--- /dev/null
+++ b/src/ahriman/core/formatters/build_printer.py
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2021 ahriman team.
+#
+# This file is part of ahriman
+# (see https://github.com/arcan1s/ahriman).
+#
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+from ahriman.core.formatters.string_printer import StringPrinter
+from ahriman.models.package import Package
+
+
+class BuildPrinter(StringPrinter):
+ """
+ print content of the build result
+ """
+
+ def __init__(self, package: Package, is_success: bool, use_utf: bool) -> None:
+ """
+ default constructor
+ :param package: built package
+ :param is_success: True in case if build has success status and False otherwise
+ :param use_utf: use utf instead of normal symbols
+ """
+ StringPrinter.__init__(self, f"{self.sign(is_success, use_utf)} {package.base}")
+
+ @staticmethod
+ def sign(is_success: bool, use_utf: bool) -> str:
+ """
+ generate sign according to settings
+ :param use_utf: use utf instead of normal symbols
+ :param is_success: True in case if build has success status and False otherwise
+ :return: sign symbol according to current settings
+ """
+ if is_success:
+ return "[✔]" if use_utf else "[x]"
+ return "[❌]" if use_utf else "[ ]"
diff --git a/src/ahriman/application/formatters/configuration_printer.py b/src/ahriman/core/formatters/configuration_printer.py
similarity index 73%
rename from src/ahriman/application/formatters/configuration_printer.py
rename to src/ahriman/core/formatters/configuration_printer.py
index 6a725747..aa035be0 100644
--- a/src/ahriman/application/formatters/configuration_printer.py
+++ b/src/ahriman/core/formatters/configuration_printer.py
@@ -17,15 +17,16 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Dict, List, Optional
+from typing import Dict, List
-from ahriman.application.formatters.printer import Printer
+from ahriman.core.formatters.string_printer import StringPrinter
from ahriman.models.property import Property
-class ConfigurationPrinter(Printer):
+class ConfigurationPrinter(StringPrinter):
"""
print content of the configuration section
+ :ivar values: configuration values dictionary
"""
def __init__(self, section: str, values: Dict[str, str]) -> None:
@@ -34,8 +35,8 @@ class ConfigurationPrinter(Printer):
:param section: section name
:param values: configuration values dictionary
"""
- self.section = section
- self.content = values
+ StringPrinter.__init__(self, f"[{section}]")
+ self.values = values
def properties(self) -> List[Property]:
"""
@@ -44,12 +45,5 @@ class ConfigurationPrinter(Printer):
"""
return [
Property(key, value, is_required=True)
- for key, value in sorted(self.content.items())
+ for key, value in sorted(self.values.items())
]
-
- def title(self) -> Optional[str]:
- """
- generate entry title from content
- :return: content title if it can be generated and None otherwise
- """
- return f"[{self.section}]"
diff --git a/src/ahriman/application/formatters/package_printer.py b/src/ahriman/core/formatters/package_printer.py
similarity index 69%
rename from src/ahriman/application/formatters/package_printer.py
rename to src/ahriman/core/formatters/package_printer.py
index d5fe80a0..019a4387 100644
--- a/src/ahriman/application/formatters/package_printer.py
+++ b/src/ahriman/core/formatters/package_printer.py
@@ -17,17 +17,19 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import List, Optional
+from typing import List
-from ahriman.application.formatters.printer import Printer
+from ahriman.core.formatters.string_printer import StringPrinter
from ahriman.models.build_status import BuildStatus
from ahriman.models.package import Package
from ahriman.models.property import Property
-class PackagePrinter(Printer):
+class PackagePrinter(StringPrinter):
"""
print content of the internal package object
+ :ivar package: package description
+ :ivar status: build status
"""
def __init__(self, package: Package, status: BuildStatus) -> None:
@@ -36,7 +38,8 @@ class PackagePrinter(Printer):
:param package: package description
:param status: build status
"""
- self.content = package
+ StringPrinter.__init__(self, package.pretty_print())
+ self.package = package
self.status = status
def properties(self) -> List[Property]:
@@ -45,16 +48,9 @@ class PackagePrinter(Printer):
:return: list of content properties
"""
return [
- Property("Version", self.content.version, is_required=True),
- Property("Groups", " ".join(self.content.groups)),
- Property("Licenses", " ".join(self.content.licenses)),
- Property("Depends", " ".join(self.content.depends)),
+ Property("Version", self.package.version, is_required=True),
+ Property("Groups", " ".join(self.package.groups)),
+ Property("Licenses", " ".join(self.package.licenses)),
+ Property("Depends", " ".join(self.package.depends)),
Property("Status", self.status.pretty_print(), is_required=True),
]
-
- def title(self) -> Optional[str]:
- """
- generate entry title from content
- :return: content title if it can be generated and None otherwise
- """
- return self.content.pretty_print()
diff --git a/src/ahriman/application/formatters/printer.py b/src/ahriman/core/formatters/printer.py
similarity index 100%
rename from src/ahriman/application/formatters/printer.py
rename to src/ahriman/core/formatters/printer.py
diff --git a/src/ahriman/application/formatters/status_printer.py b/src/ahriman/core/formatters/status_printer.py
similarity index 73%
rename from src/ahriman/application/formatters/status_printer.py
rename to src/ahriman/core/formatters/status_printer.py
index c3b6e6cb..76256939 100644
--- a/src/ahriman/application/formatters/status_printer.py
+++ b/src/ahriman/core/formatters/status_printer.py
@@ -17,13 +17,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Optional
-
-from ahriman.application.formatters.printer import Printer
+from ahriman.core.formatters.string_printer import StringPrinter
from ahriman.models.build_status import BuildStatus
-class StatusPrinter(Printer):
+class StatusPrinter(StringPrinter):
"""
print content of the status object
"""
@@ -33,11 +31,4 @@ class StatusPrinter(Printer):
default constructor
:param status: build status
"""
- self.content = status
-
- def title(self) -> Optional[str]:
- """
- generate entry title from content
- :return: content title if it can be generated and None otherwise
- """
- return self.content.pretty_print()
+ StringPrinter.__init__(self, status.pretty_print())
diff --git a/src/ahriman/application/formatters/string_printer.py b/src/ahriman/core/formatters/string_printer.py
similarity index 95%
rename from src/ahriman/application/formatters/string_printer.py
rename to src/ahriman/core/formatters/string_printer.py
index 3d9e2706..52d8a8af 100644
--- a/src/ahriman/application/formatters/string_printer.py
+++ b/src/ahriman/core/formatters/string_printer.py
@@ -19,7 +19,7 @@
#
from typing import Optional
-from ahriman.application.formatters.printer import Printer
+from ahriman.core.formatters.printer import Printer
class StringPrinter(Printer):
diff --git a/src/ahriman/application/formatters/update_printer.py b/src/ahriman/core/formatters/update_printer.py
similarity index 78%
rename from src/ahriman/application/formatters/update_printer.py
rename to src/ahriman/core/formatters/update_printer.py
index 6659bceb..e0b4ca63 100644
--- a/src/ahriman/application/formatters/update_printer.py
+++ b/src/ahriman/core/formatters/update_printer.py
@@ -19,14 +19,16 @@
#
from typing import List, Optional
-from ahriman.application.formatters.printer import Printer
+from ahriman.core.formatters.string_printer import StringPrinter
from ahriman.models.package import Package
from ahriman.models.property import Property
-class UpdatePrinter(Printer):
+class UpdatePrinter(StringPrinter):
"""
print content of the package update
+ :ivar package: remote (new) package object
+ :ivar local_version: local version of the package if any
"""
def __init__(self, remote: Package, local_version: Optional[str]) -> None:
@@ -35,7 +37,8 @@ class UpdatePrinter(Printer):
:param remote: remote (new) package object
:param local_version: local version of the package if any
"""
- self.content = remote
+ StringPrinter.__init__(self, remote.base)
+ self.package = remote
self.local_version = local_version or "N/A"
def properties(self) -> List[Property]:
@@ -43,11 +46,4 @@ class UpdatePrinter(Printer):
convert content into printable data
:return: list of content properties
"""
- return [Property(self.local_version, self.content.version, is_required=True)]
-
- def title(self) -> Optional[str]:
- """
- generate entry title from content
- :return: content title if it can be generated and None otherwise
- """
- return self.content.base
+ return [Property(self.local_version, self.package.version, is_required=True)]
diff --git a/src/ahriman/core/report/console.py b/src/ahriman/core/report/console.py
new file mode 100644
index 00000000..759e84b3
--- /dev/null
+++ b/src/ahriman/core/report/console.py
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2021 ahriman team.
+#
+# This file is part of ahriman
+# (see https://github.com/arcan1s/ahriman).
+#
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+from typing import Iterable
+
+from ahriman.core.configuration import Configuration
+from ahriman.core.formatters.build_printer import BuildPrinter
+from ahriman.core.report.report import Report
+from ahriman.models.package import Package
+from ahriman.models.result import Result
+
+
+class Console(Report):
+ """
+ html report generator
+ :ivar use_utf: print utf8 symbols instead of ASCII
+ """
+
+ def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
+ """
+ default constructor
+ :param architecture: repository architecture
+ :param configuration: configuration instance
+ :param section: settings section name
+ """
+ Report.__init__(self, architecture, configuration)
+ self.use_utf = configuration.getboolean(section, "use_utf")
+
+ def generate(self, packages: Iterable[Package], result: Result) -> None:
+ """
+ generate report for the specified packages
+ :param packages: list of packages to generate report
+ :param result: build result
+ """
+ for package in result.success:
+ BuildPrinter(package, is_success=True, use_utf=self.use_utf).print(verbose=True)
+ for package in result.failed:
+ BuildPrinter(package, is_success=True, use_utf=self.use_utf).print(verbose=True)
diff --git a/src/ahriman/core/report/email.py b/src/ahriman/core/report/email.py
index 64f784ea..123084fe 100644
--- a/src/ahriman/core/report/email.py
+++ b/src/ahriman/core/report/email.py
@@ -29,12 +29,14 @@ from ahriman.core.report.jinja_template import JinjaTemplate
from ahriman.core.report.report import Report
from ahriman.core.util import pretty_datetime
from ahriman.models.package import Package
+from ahriman.models.result import Result
from ahriman.models.smtp_ssl_settings import SmtpSSLSettings
class Email(Report, JinjaTemplate):
"""
email report generator
+ :ivar full_template_path: path to template for full package list
:ivar host: SMTP host to connect
:ivar no_empty_report: skip empty report generation
:ivar password: password to authenticate via SMTP
@@ -42,6 +44,7 @@ class Email(Report, JinjaTemplate):
:ivar receivers: list of receivers emails
:ivar sender: sender email address
:ivar ssl: SSL mode for SMTP connection
+ :ivar template_path: path to template for built packages
:ivar user: username to authenticate via SMTP
"""
@@ -96,17 +99,17 @@ class Email(Report, JinjaTemplate):
session.sendmail(self.sender, self.receivers, message.as_string())
session.quit()
- def generate(self, packages: Iterable[Package], built_packages: Iterable[Package]) -> None:
+ def generate(self, packages: Iterable[Package], result: Result) -> None:
"""
generate report for the specified packages
:param packages: list of packages to generate report
- :param built_packages: list of packages which has just been built
+ :param result: build result
"""
- if self.no_empty_report and not built_packages:
+ if self.no_empty_report and not result.success:
return
- text = self.make_html(built_packages, self.template_path)
+ text = self.make_html(result, self.template_path)
if self.full_template_path is not None:
- attachments = {"index.html": self.make_html(packages, self.full_template_path)}
+ attachments = {"index.html": self.make_html(Result(success=packages), self.full_template_path)}
else:
attachments = {}
self._send(text, attachments)
diff --git a/src/ahriman/core/report/html.py b/src/ahriman/core/report/html.py
index e38084fd..dd0e99a1 100644
--- a/src/ahriman/core/report/html.py
+++ b/src/ahriman/core/report/html.py
@@ -23,12 +23,14 @@ from ahriman.core.configuration import Configuration
from ahriman.core.report.jinja_template import JinjaTemplate
from ahriman.core.report.report import Report
from ahriman.models.package import Package
+from ahriman.models.result import Result
class HTML(Report, JinjaTemplate):
"""
html report generator
:ivar report_path: output path to html report
+ :ivar template_path: path to template for full package list
"""
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
@@ -44,11 +46,11 @@ class HTML(Report, JinjaTemplate):
self.report_path = configuration.getpath(section, "path")
self.template_path = configuration.getpath(section, "template_path")
- def generate(self, packages: Iterable[Package], built_packages: Iterable[Package]) -> None:
+ def generate(self, packages: Iterable[Package], result: Result) -> None:
"""
generate report for the specified packages
:param packages: list of packages to generate report
- :param built_packages: list of packages which has just been built
+ :param result: build result
"""
- html = self.make_html(packages, self.template_path)
+ html = self.make_html(Result(success=packages), self.template_path)
self.report_path.write_text(html)
diff --git a/src/ahriman/core/report/jinja_template.py b/src/ahriman/core/report/jinja_template.py
index 983790b5..e2155898 100644
--- a/src/ahriman/core/report/jinja_template.py
+++ b/src/ahriman/core/report/jinja_template.py
@@ -20,12 +20,12 @@
import jinja2
from pathlib import Path
-from typing import Callable, Dict, Iterable
+from typing import Callable, Dict
from ahriman.core.configuration import Configuration
from ahriman.core.sign.gpg import GPG
from ahriman.core.util import pretty_datetime, pretty_size
-from ahriman.models.package import Package
+from ahriman.models.result import Result
from ahriman.models.sign_settings import SignSettings
@@ -76,10 +76,10 @@ class JinjaTemplate:
self.sign_targets, self.default_pgp_key = GPG.sign_options(configuration)
- def make_html(self, packages: Iterable[Package], template_path: Path) -> str:
+ def make_html(self, result: Result, template_path: Path) -> str:
"""
generate report for the specified packages
- :param packages: list of packages to generate report
+ :param result: build result
:param template_path: path to jinja template
"""
# idea comes from https://stackoverflow.com/a/38642558
@@ -101,7 +101,7 @@ class JinjaTemplate:
"name": package,
"url": properties.url or "",
"version": base.version
- } for base in packages for package, properties in base.packages.items()
+ } for base in result.updated for package, properties in base.packages.items()
]
comparator: Callable[[Dict[str, str]], str] = lambda item: item["filename"]
diff --git a/src/ahriman/core/report/report.py b/src/ahriman/core/report/report.py
index 173ee431..91a335c9 100644
--- a/src/ahriman/core/report/report.py
+++ b/src/ahriman/core/report/report.py
@@ -27,6 +27,7 @@ from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import ReportFailed
from ahriman.models.package import Package
from ahriman.models.report_settings import ReportSettings
+from ahriman.models.result import Result
class Report:
@@ -64,23 +65,26 @@ class Report:
if provider == ReportSettings.Email:
from ahriman.core.report.email import Email
return Email(architecture, configuration, section)
+ if provider == ReportSettings.Console:
+ from ahriman.core.report.console import Console
+ return Console(architecture, configuration, section)
return cls(architecture, configuration) # should never happen
- def generate(self, packages: Iterable[Package], built_packages: Iterable[Package]) -> None:
+ def generate(self, packages: Iterable[Package], result: Result) -> None:
"""
generate report for the specified packages
:param packages: list of packages to generate report
- :param built_packages: list of packages which has just been built
+ :param result: build result
"""
- def run(self, packages: Iterable[Package], built_packages: Iterable[Package]) -> None:
+ def run(self, packages: Iterable[Package], result: Result) -> None:
"""
run report generation
:param packages: list of packages to generate report
- :param built_packages: list of packages which has just been built
+ :param result: build result
"""
try:
- self.generate(packages, built_packages)
+ self.generate(packages, result)
except Exception:
self.logger.exception("report generation failed")
raise ReportFailed()
diff --git a/src/ahriman/core/repository/executor.py b/src/ahriman/core/repository/executor.py
index c5a74f8f..1403d9ce 100644
--- a/src/ahriman/core/repository/executor.py
+++ b/src/ahriman/core/repository/executor.py
@@ -27,6 +27,7 @@ from ahriman.core.report.report import Report
from ahriman.core.repository.cleaner import Cleaner
from ahriman.core.upload.upload import Upload
from ahriman.models.package import Package
+from ahriman.models.result import Result
class Executor(Cleaner):
@@ -49,7 +50,7 @@ class Executor(Cleaner):
"""
raise NotImplementedError
- def process_build(self, updates: Iterable[Package]) -> List[Path]:
+ def process_build(self, updates: Iterable[Package]) -> Result:
"""
build packages
:param updates: list of packages properties to build
@@ -64,15 +65,18 @@ class Executor(Cleaner):
dst = self.paths.packages / src.name
shutil.move(src, dst)
+ result = Result()
for single in updates:
try:
build_single(single)
+ result.add_success(single)
except Exception:
self.reporter.set_failed(single.base)
+ result.add_failed(single)
self.logger.exception("%s (%s) build exception", single.base, self.architecture)
self.clear_build()
- return self.packages_built()
+ return result
def process_remove(self, packages: Iterable[str]) -> Path:
"""
@@ -116,17 +120,17 @@ class Executor(Cleaner):
return self.repo.repo_path
- def process_report(self, targets: Optional[Iterable[str]], built_packages: Iterable[Package]) -> None:
+ def process_report(self, targets: Optional[Iterable[str]], result: Result) -> None:
"""
generate reports
:param targets: list of targets to generate reports. Configuration option will be used if it is not set
- :param built_packages: list of packages which has just been built
+ :param result: build result
"""
if targets is None:
targets = self.configuration.getlist("report", "target")
for target in targets:
runner = Report.load(self.architecture, self.configuration, target)
- runner.run(self.packages(), built_packages)
+ runner.run(self.packages(), result)
def process_sync(self, targets: Optional[Iterable[str]], built_packages: Iterable[Package]) -> None:
"""
@@ -140,7 +144,7 @@ class Executor(Cleaner):
runner = Upload.load(self.architecture, self.configuration, target)
runner.run(self.paths.repository, built_packages)
- def process_update(self, packages: Iterable[Path]) -> Path:
+ def process_update(self, packages: Iterable[Path]) -> Result:
"""
sign packages, add them to repository and update repository database
:param packages: list of filenames to run
@@ -163,20 +167,23 @@ class Executor(Cleaner):
removed_packages: List[str] = [] # list of packages which have been removed from the base
updates = self.load_archives(packages)
+ result = Result()
for local in updates:
try:
for description in local.packages.values():
update_single(description.filename, local.base)
self.reporter.set_success(local)
+ result.add_success(local)
current_package_archives: Set[str] = next(
(set(current.packages) for current in current_packages if current.base == local.base), set())
removed_packages.extend(current_package_archives.difference(local.packages))
except Exception:
self.reporter.set_failed(local.base)
+ result.add_failed(local)
self.logger.exception("could not process %s", local.base)
self.clear_packages()
self.process_remove(removed_packages)
- return self.repo.repo_path
+ return result
diff --git a/src/ahriman/models/report_settings.py b/src/ahriman/models/report_settings.py
index c9217876..703fc58c 100644
--- a/src/ahriman/models/report_settings.py
+++ b/src/ahriman/models/report_settings.py
@@ -31,11 +31,13 @@ class ReportSettings(Enum):
:cvar Disabled: option which generates no report for testing purpose
:cvar HTML: html report generation
:cvar Email: email report generation
+ :cvar Console: print result to console
"""
Disabled = "disabled" # for testing purpose
HTML = "html"
Email = "email"
+ Console = "console"
@classmethod
def from_option(cls: Type[ReportSettings], value: str) -> ReportSettings:
@@ -48,4 +50,6 @@ class ReportSettings(Enum):
return cls.HTML
if value.lower() in ("email",):
return cls.Email
+ if value.lower() in ("console",):
+ return cls.Console
raise InvalidOption(value)
diff --git a/src/ahriman/models/result.py b/src/ahriman/models/result.py
new file mode 100644
index 00000000..7498c81f
--- /dev/null
+++ b/src/ahriman/models/result.py
@@ -0,0 +1,105 @@
+#
+# Copyright (c) 2021 ahriman team.
+#
+# This file is part of ahriman
+# (see https://github.com/arcan1s/ahriman).
+#
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+from __future__ import annotations
+
+from typing import Any, List, Optional, Iterable
+
+from ahriman.core.exceptions import SuccessFailed
+from ahriman.models.package import Package
+
+
+class Result:
+ """
+ build result class holder
+ """
+
+ def __init__(self, success: Optional[Iterable[Package]] = None, failed: Optional[Iterable[Package]] = None) -> None:
+ """
+ default constructor
+ :param success: initial list of successes packages
+ :param failed: initial list of failed packages
+ """
+ success = success or []
+ self._success = {package.base: package for package in success}
+ failed = failed or []
+ self._failed = {package.base: package for package in failed}
+
+ @property
+ def failed(self) -> List[Package]:
+ """
+ :return: list of packages which were failed
+ """
+ return list(self._failed.values())
+
+ @property
+ def success(self) -> List[Package]:
+ """
+ :return: list of packages with success result
+ """
+ return list(self._success.values())
+
+ @property
+ def updated(self) -> List[Package]:
+ """
+ :return: list of updated packages inclding both success and failed
+ """
+ return self.success + self.failed
+
+ def add_failed(self, package: Package) -> None:
+ """
+ add new package to failed built
+ :param package: package with errors during build
+ """
+ self._failed[package.base] = package
+
+ def add_success(self, package: Package) -> None:
+ """
+ add new package to success built
+ :param package: package built
+ """
+ self._success[package.base] = package
+
+ # pylint: disable=protected-access
+ def merge(self, other: Result) -> Result:
+ """
+ merge other result into this one. This method assumes that other has fresh info about status and override it
+ :param other: instance of the newest result
+ :return: updated instance
+ """
+ for base, package in other._failed.items():
+ if base in self._success:
+ del self._success[base]
+ self.add_failed(package)
+ for base, package in other._success.items():
+ if base in self._failed:
+ raise SuccessFailed(base)
+ self.add_success(package)
+ return self
+
+ # required for tests at least
+ def __eq__(self, other: Any) -> bool:
+ """
+ check if other is the same object
+ :param other: other object instance
+ :return: True if the other object is the same and False otherwise
+ """
+ if not isinstance(other, Result):
+ return False
+ return self.success == other.success and self.failed == other.failed
diff --git a/tests/ahriman/application/application/test_application.py b/tests/ahriman/application/application/test_application.py
index 8437156f..79e0aac6 100644
--- a/tests/ahriman/application/application/test_application.py
+++ b/tests/ahriman/application/application/test_application.py
@@ -2,6 +2,7 @@ from pytest_mock import MockerFixture
from ahriman.application.application import Application
from ahriman.models.package import Package
+from ahriman.models.result import Result
def test_finalize(application: Application, mocker: MockerFixture) -> None:
@@ -11,8 +12,8 @@ def test_finalize(application: Application, mocker: MockerFixture) -> None:
report_mock = mocker.patch("ahriman.application.application.Application.report")
sync_mock = mocker.patch("ahriman.application.application.Application.sync")
- application._finalize([])
- report_mock.assert_called_once_with([], [])
+ application._finalize(Result())
+ report_mock.assert_called_once_with([], Result())
sync_mock.assert_called_once_with([], [])
diff --git a/tests/ahriman/application/application/test_application_packages.py b/tests/ahriman/application/application/test_application_packages.py
index b3b531d5..7ba56b34 100644
--- a/tests/ahriman/application/application/test_application_packages.py
+++ b/tests/ahriman/application/application/test_application_packages.py
@@ -9,6 +9,7 @@ from ahriman.application.application.packages import Packages
from ahriman.models.package import Package
from ahriman.models.package_description import PackageDescription
from ahriman.models.package_source import PackageSource
+from ahriman.models.result import Result
def test_finalize(application_packages: Packages) -> None:
@@ -211,4 +212,4 @@ def test_remove(application_packages: Packages, mocker: MockerFixture) -> None:
application_packages.remove([])
executor_mock.assert_called_once_with([])
- finalize_mock.assert_called_once_with([])
+ finalize_mock.assert_called_once_with(Result())
diff --git a/tests/ahriman/application/application/test_application_repository.py b/tests/ahriman/application/application/test_application_repository.py
index 62e08397..3c3d9e98 100644
--- a/tests/ahriman/application/application/test_application_repository.py
+++ b/tests/ahriman/application/application/test_application_repository.py
@@ -6,6 +6,7 @@ from unittest import mock
from ahriman.application.application.repository import Repository
from ahriman.core.tree import Leaf, Tree
from ahriman.models.package import Package
+from ahriman.models.result import Result
def test_finalize(application_repository: Repository) -> None:
@@ -98,7 +99,7 @@ def test_sign(application_repository: Repository, package_ahriman: Package, pack
])
update_mock.assert_called_once_with([])
sign_repository_mock.assert_called_once_with(application_repository.repository.repo.repo_path)
- finalize_mock.assert_called_once_with([])
+ finalize_mock.assert_called_once_with(Result())
def test_sign_skip(application_repository: Repository, package_ahriman: Package, mocker: MockerFixture) -> None:
@@ -132,7 +133,7 @@ def test_sign_specific(application_repository: Repository, package_ahriman: Pack
application_repository.repository.paths.packages / filename.name)
update_mock.assert_called_once_with([])
sign_repository_mock.assert_called_once_with(application_repository.repository.repo.repo_path)
- finalize_mock.assert_called_once_with([])
+ finalize_mock.assert_called_once_with(Result())
def test_sync(application_repository: Repository, mocker: MockerFixture) -> None:
@@ -181,7 +182,8 @@ def test_unknown_no_local(application_repository: Repository, package_ahriman: P
assert not application_repository.unknown()
-def test_update(application_repository: Repository, package_ahriman: Package, mocker: MockerFixture) -> None:
+def test_update(application_repository: Repository, package_ahriman: Package, result: Result,
+ mocker: MockerFixture) -> None:
"""
must process package updates
"""
@@ -189,16 +191,33 @@ def test_update(application_repository: Repository, package_ahriman: Package, mo
tree = Tree([Leaf(package_ahriman, set())])
mocker.patch("ahriman.core.tree.Tree.load", return_value=tree)
- mocker.patch("ahriman.core.repository.repository.Repository.packages_built", return_value=[])
+ mocker.patch("ahriman.core.repository.repository.Repository.packages_built", return_value=paths)
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
- build_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_build", return_value=paths)
- update_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_update")
+ build_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_build", return_value=result)
+ update_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_update", return_value=result)
finalize_mock = mocker.patch("ahriman.application.application.repository.Repository._finalize")
application_repository.update([package_ahriman])
build_mock.assert_called_once_with([package_ahriman])
- update_mock.assert_called_once_with(paths)
- finalize_mock.assert_called_once_with([package_ahriman])
+ update_mock.assert_has_calls([mock.call(paths), mock.call(paths)])
+ finalize_mock.assert_has_calls([mock.call(result), mock.call(result)])
+
+
+def test_update_empty(application_repository: Repository, package_ahriman: Package, mocker: MockerFixture) -> None:
+ """
+ must skip updating repository if no packages supplied
+ """
+ paths = [package.filepath for package in package_ahriman.packages.values()]
+ tree = Tree([Leaf(package_ahriman, set())])
+
+ mocker.patch("ahriman.core.tree.Tree.load", return_value=tree)
+ mocker.patch("ahriman.core.repository.repository.Repository.packages_built", return_value=[])
+ mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
+ mocker.patch("ahriman.core.repository.executor.Executor.process_build")
+ update_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_update")
+
+ application_repository.update([package_ahriman])
+ update_mock.assert_not_called()
def test_updates_all(application_repository: Repository, package_ahriman: Package, mocker: MockerFixture) -> None:
diff --git a/tests/ahriman/application/handlers/test_handler_dump.py b/tests/ahriman/application/handlers/test_handler_dump.py
index f04bbf2a..a8ea9de5 100644
--- a/tests/ahriman/application/handlers/test_handler_dump.py
+++ b/tests/ahriman/application/handlers/test_handler_dump.py
@@ -11,7 +11,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
must run command
"""
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
- print_mock = mocker.patch("ahriman.application.formatters.printer.Printer.print")
+ print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
application_mock = mocker.patch("ahriman.core.configuration.Configuration.dump",
return_value=configuration.dump())
diff --git a/tests/ahriman/application/handlers/test_handler_remove_unknown.py b/tests/ahriman/application/handlers/test_handler_remove_unknown.py
index e3271b44..25057731 100644
--- a/tests/ahriman/application/handlers/test_handler_remove_unknown.py
+++ b/tests/ahriman/application/handlers/test_handler_remove_unknown.py
@@ -45,7 +45,7 @@ def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, pac
application_mock = mocker.patch("ahriman.application.application.Application.unknown",
return_value=[package_ahriman])
remove_mock = mocker.patch("ahriman.application.application.Application.remove")
- print_mock = mocker.patch("ahriman.application.formatters.printer.Printer.print")
+ print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
RemoveUnknown.run(args, "x86_64", configuration, True, False)
application_mock.assert_called_once_with()
@@ -65,7 +65,7 @@ def test_run_dry_run_verbose(args: argparse.Namespace, configuration: Configurat
application_mock = mocker.patch("ahriman.application.application.Application.unknown",
return_value=[package_ahriman])
remove_mock = mocker.patch("ahriman.application.application.Application.remove")
- print_mock = mocker.patch("ahriman.application.formatters.printer.Printer.print")
+ print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
RemoveUnknown.run(args, "x86_64", configuration, True, False)
application_mock.assert_called_once_with()
diff --git a/tests/ahriman/application/handlers/test_handler_report.py b/tests/ahriman/application/handlers/test_handler_report.py
index e44fd7cd..5c2ee75c 100644
--- a/tests/ahriman/application/handlers/test_handler_report.py
+++ b/tests/ahriman/application/handlers/test_handler_report.py
@@ -4,6 +4,7 @@ from pytest_mock import MockerFixture
from ahriman.application.handlers import Report
from ahriman.core.configuration import Configuration
+from ahriman.models.result import Result
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
@@ -25,4 +26,4 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
application_mock = mocker.patch("ahriman.application.application.Application.report")
Report.run(args, "x86_64", configuration, True, False)
- application_mock.assert_called_once_with(args.target, [])
+ application_mock.assert_called_once_with(args.target, Result())
diff --git a/tests/ahriman/application/handlers/test_handler_search.py b/tests/ahriman/application/handlers/test_handler_search.py
index 1d04cc7b..b3f33dd0 100644
--- a/tests/ahriman/application/handlers/test_handler_search.py
+++ b/tests/ahriman/application/handlers/test_handler_search.py
@@ -29,7 +29,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, aur_package
"""
args = _default_args(args)
search_mock = mocker.patch("ahriman.core.alpm.aur.AUR.multisearch", return_value=[aur_package_ahriman])
- print_mock = mocker.patch("ahriman.application.formatters.printer.Printer.print")
+ print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
Search.run(args, "x86_64", configuration, True, False)
search_mock.assert_called_once_with("ahriman")
diff --git a/tests/ahriman/application/handlers/test_handler_status.py b/tests/ahriman/application/handlers/test_handler_status.py
index 1d13cadd..1f635396 100644
--- a/tests/ahriman/application/handlers/test_handler_status.py
+++ b/tests/ahriman/application/handlers/test_handler_status.py
@@ -33,7 +33,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, package_ahr
packages_mock = mocker.patch("ahriman.core.status.client.Client.get",
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success)),
(package_python_schedule, BuildStatus(BuildStatusEnum.Failed))])
- print_mock = mocker.patch("ahriman.application.formatters.printer.Printer.print")
+ print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
Status.run(args, "x86_64", configuration, True, False)
application_mock.assert_called_once_with()
@@ -51,7 +51,7 @@ def test_run_verbose(args: argparse.Namespace, configuration: Configuration, pac
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
mocker.patch("ahriman.core.status.client.Client.get",
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))])
- print_mock = mocker.patch("ahriman.application.formatters.printer.Printer.print")
+ print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
Status.run(args, "x86_64", configuration, True, False)
print_mock.assert_has_calls([mock.call(True) for _ in range(2)])
@@ -83,7 +83,7 @@ def test_run_by_status(args: argparse.Namespace, configuration: Configuration, p
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success)),
(package_python_schedule, BuildStatus(BuildStatusEnum.Failed))])
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
- print_mock = mocker.patch("ahriman.application.formatters.printer.Printer.print")
+ print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
Status.run(args, "x86_64", configuration, True, False)
print_mock.assert_has_calls([mock.call(False) for _ in range(2)])
diff --git a/tests/ahriman/application/handlers/test_handler_unsafe_commands.py b/tests/ahriman/application/handlers/test_handler_unsafe_commands.py
index 80621aac..2da5145c 100644
--- a/tests/ahriman/application/handlers/test_handler_unsafe_commands.py
+++ b/tests/ahriman/application/handlers/test_handler_unsafe_commands.py
@@ -15,7 +15,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
args.parser = _parser
commands_mock = mocker.patch("ahriman.application.handlers.UnsafeCommands.get_unsafe_commands",
return_value=["command"])
- print_mock = mocker.patch("ahriman.application.formatters.printer.Printer.print")
+ print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
UnsafeCommands.run(args, "x86_64", configuration, True, False)
commands_mock.assert_called_once_with(pytest.helpers.anyvar(int))
diff --git a/tests/ahriman/conftest.py b/tests/ahriman/conftest.py
index 96afe586..1208e278 100644
--- a/tests/ahriman/conftest.py
+++ b/tests/ahriman/conftest.py
@@ -14,6 +14,7 @@ from ahriman.models.aur_package import AURPackage
from ahriman.models.package import Package
from ahriman.models.package_description import PackageDescription
from ahriman.models.repository_paths import RepositoryPaths
+from ahriman.models.result import Result
from ahriman.models.user import User
from ahriman.models.user_access import UserAccess
@@ -234,6 +235,18 @@ def repository_paths(configuration: Configuration) -> RepositoryPaths:
root=configuration.getpath("repository", "root"))
+@pytest.fixture
+def result(package_ahriman: Package) -> Result:
+ """
+ result fixture
+ :param package_ahriman: package fixture
+ :return: result test instance
+ """
+ result = Result()
+ result.add_success(package_ahriman)
+ return result
+
+
@pytest.fixture
def spawner(configuration: Configuration) -> Spawn:
"""
diff --git a/tests/ahriman/application/formatters/conftest.py b/tests/ahriman/core/formatters/conftest.py
similarity index 78%
rename from tests/ahriman/application/formatters/conftest.py
rename to tests/ahriman/core/formatters/conftest.py
index 6a38c710..d193a759 100644
--- a/tests/ahriman/application/formatters/conftest.py
+++ b/tests/ahriman/core/formatters/conftest.py
@@ -1,11 +1,11 @@
import pytest
-from ahriman.application.formatters.aur_printer import AurPrinter
-from ahriman.application.formatters.configuration_printer import ConfigurationPrinter
-from ahriman.application.formatters.package_printer import PackagePrinter
-from ahriman.application.formatters.status_printer import StatusPrinter
-from ahriman.application.formatters.string_printer import StringPrinter
-from ahriman.application.formatters.update_printer import UpdatePrinter
+from ahriman.core.formatters.aur_printer import AurPrinter
+from ahriman.core.formatters.configuration_printer import ConfigurationPrinter
+from ahriman.core.formatters.package_printer import PackagePrinter
+from ahriman.core.formatters.status_printer import StatusPrinter
+from ahriman.core.formatters.string_printer import StringPrinter
+from ahriman.core.formatters.update_printer import UpdatePrinter
from ahriman.models.aur_package import AURPackage
from ahriman.models.build_status import BuildStatus
from ahriman.models.package import Package
diff --git a/tests/ahriman/application/formatters/test_aur_printer.py b/tests/ahriman/core/formatters/test_aur_printer.py
similarity index 84%
rename from tests/ahriman/application/formatters/test_aur_printer.py
rename to tests/ahriman/core/formatters/test_aur_printer.py
index 8725dff6..1678fcd9 100644
--- a/tests/ahriman/application/formatters/test_aur_printer.py
+++ b/tests/ahriman/core/formatters/test_aur_printer.py
@@ -1,4 +1,4 @@
-from ahriman.application.formatters.aur_printer import AurPrinter
+from ahriman.core.formatters.aur_printer import AurPrinter
def test_properties(aur_package_ahriman_printer: AurPrinter) -> None:
diff --git a/tests/ahriman/core/formatters/test_build_printer.py b/tests/ahriman/core/formatters/test_build_printer.py
new file mode 100644
index 00000000..285f6a46
--- /dev/null
+++ b/tests/ahriman/core/formatters/test_build_printer.py
@@ -0,0 +1,36 @@
+import pytest
+
+from ahriman.core.formatters.build_printer import BuildPrinter
+from ahriman.models.package import Package
+
+
+def test_properties(package_ahriman: Package) -> None:
+ """
+ must return empty properties list
+ """
+ assert not BuildPrinter(package_ahriman, is_success=True, use_utf=False).properties()
+
+
+def test_sign_ascii(package_ahriman: Package) -> None:
+ """
+ must correctly generate sign in ascii
+ """
+ BuildPrinter(package_ahriman, is_success=True, use_utf=False).title().encode("ascii")
+ BuildPrinter(package_ahriman, is_success=False, use_utf=False).title().encode("ascii")
+
+
+def test_sign_utf8(package_ahriman: Package) -> None:
+ """
+ must correctly generate sign in ascii
+ """
+ with pytest.raises(UnicodeEncodeError):
+ BuildPrinter(package_ahriman, is_success=True, use_utf=True).title().encode("ascii")
+ with pytest.raises(UnicodeEncodeError):
+ BuildPrinter(package_ahriman, is_success=False, use_utf=True).title().encode("ascii")
+
+
+def test_title(package_ahriman: Package) -> None:
+ """
+ must return non empty title
+ """
+ assert BuildPrinter(package_ahriman, is_success=True, use_utf=False).title() is not None
diff --git a/tests/ahriman/application/formatters/test_configuration_printer.py b/tests/ahriman/core/formatters/test_configuration_printer.py
similarity index 87%
rename from tests/ahriman/application/formatters/test_configuration_printer.py
rename to tests/ahriman/core/formatters/test_configuration_printer.py
index b7117d4a..c82dcbf7 100644
--- a/tests/ahriman/application/formatters/test_configuration_printer.py
+++ b/tests/ahriman/core/formatters/test_configuration_printer.py
@@ -1,4 +1,4 @@
-from ahriman.application.formatters.configuration_printer import ConfigurationPrinter
+from ahriman.core.formatters.configuration_printer import ConfigurationPrinter
def test_properties(configuration_printer: ConfigurationPrinter) -> None:
diff --git a/tests/ahriman/application/formatters/test_package_printer.py b/tests/ahriman/core/formatters/test_package_printer.py
similarity index 82%
rename from tests/ahriman/application/formatters/test_package_printer.py
rename to tests/ahriman/core/formatters/test_package_printer.py
index 06525a6b..fa6f77df 100644
--- a/tests/ahriman/application/formatters/test_package_printer.py
+++ b/tests/ahriman/core/formatters/test_package_printer.py
@@ -1,4 +1,4 @@
-from ahriman.application.formatters.package_printer import PackagePrinter
+from ahriman.core.formatters.package_printer import PackagePrinter
def test_properties(package_ahriman_printer: PackagePrinter) -> None:
diff --git a/tests/ahriman/application/formatters/test_printer.py b/tests/ahriman/core/formatters/test_printer.py
similarity index 87%
rename from tests/ahriman/application/formatters/test_printer.py
rename to tests/ahriman/core/formatters/test_printer.py
index 92b3d31f..6532d646 100644
--- a/tests/ahriman/application/formatters/test_printer.py
+++ b/tests/ahriman/core/formatters/test_printer.py
@@ -1,7 +1,7 @@
from unittest.mock import MagicMock
-from ahriman.application.formatters.package_printer import PackagePrinter
-from ahriman.application.formatters.printer import Printer
+from ahriman.core.formatters.package_printer import PackagePrinter
+from ahriman.core.formatters.printer import Printer
def test_print(package_ahriman_printer: PackagePrinter) -> None:
diff --git a/tests/ahriman/application/formatters/test_status_printer.py b/tests/ahriman/core/formatters/test_status_printer.py
similarity index 81%
rename from tests/ahriman/application/formatters/test_status_printer.py
rename to tests/ahriman/core/formatters/test_status_printer.py
index b3026b9b..66849c93 100644
--- a/tests/ahriman/application/formatters/test_status_printer.py
+++ b/tests/ahriman/core/formatters/test_status_printer.py
@@ -1,4 +1,4 @@
-from ahriman.application.formatters.status_printer import StatusPrinter
+from ahriman.core.formatters.status_printer import StatusPrinter
def test_properties(status_printer: StatusPrinter) -> None:
diff --git a/tests/ahriman/application/formatters/test_string_printer.py b/tests/ahriman/core/formatters/test_string_printer.py
similarity index 81%
rename from tests/ahriman/application/formatters/test_string_printer.py
rename to tests/ahriman/core/formatters/test_string_printer.py
index c4e81906..b2e4ddc2 100644
--- a/tests/ahriman/application/formatters/test_string_printer.py
+++ b/tests/ahriman/core/formatters/test_string_printer.py
@@ -1,4 +1,4 @@
-from ahriman.application.formatters.string_printer import StringPrinter
+from ahriman.core.formatters.string_printer import StringPrinter
def test_properties(string_printer: StringPrinter) -> None:
diff --git a/tests/ahriman/application/formatters/test_update_printer.py b/tests/ahriman/core/formatters/test_update_printer.py
similarity index 80%
rename from tests/ahriman/application/formatters/test_update_printer.py
rename to tests/ahriman/core/formatters/test_update_printer.py
index 37f8b199..ad37c9fc 100644
--- a/tests/ahriman/application/formatters/test_update_printer.py
+++ b/tests/ahriman/core/formatters/test_update_printer.py
@@ -1,4 +1,4 @@
-from ahriman.application.formatters.update_printer import UpdatePrinter
+from ahriman.core.formatters.update_printer import UpdatePrinter
def test_properties(update_printer: UpdatePrinter) -> None:
diff --git a/tests/ahriman/core/report/test_console.py b/tests/ahriman/core/report/test_console.py
new file mode 100644
index 00000000..ade89c3f
--- /dev/null
+++ b/tests/ahriman/core/report/test_console.py
@@ -0,0 +1,20 @@
+from pytest_mock import MockerFixture
+from unittest import mock
+
+from ahriman.core.configuration import Configuration
+from ahriman.core.report.console import Console
+from ahriman.models.package import Package
+from ahriman.models.result import Result
+
+
+def test_generate(configuration: Configuration, result: Result, package_python_schedule: Package,
+ mocker: MockerFixture) -> None:
+ """
+ must print result to stdout
+ """
+ print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
+ result.add_failed(package_python_schedule)
+ report = Console("x86_64", configuration, "console")
+
+ report.generate([], result)
+ print_mock.assert_has_calls([mock.call(verbose=True), mock.call(verbose=True)])
diff --git a/tests/ahriman/core/report/test_email.py b/tests/ahriman/core/report/test_email.py
index 8a212073..343e4ee0 100644
--- a/tests/ahriman/core/report/test_email.py
+++ b/tests/ahriman/core/report/test_email.py
@@ -5,6 +5,7 @@ from pytest_mock import MockerFixture
from ahriman.core.configuration import Configuration
from ahriman.core.report.email import Email
from ahriman.models.package import Package
+from ahriman.models.result import Result
def test_send(configuration: Configuration, mocker: MockerFixture) -> None:
@@ -92,24 +93,26 @@ def test_generate(configuration: Configuration, package_ahriman: Package, mocker
send_mock = mocker.patch("ahriman.core.report.email.Email._send")
report = Email("x86_64", configuration, "email")
- report.generate([package_ahriman], [])
+ report.generate([package_ahriman], Result())
send_mock.assert_called_once_with(pytest.helpers.anyvar(int), {})
-def test_generate_with_built(configuration: Configuration, package_ahriman: Package, mocker: MockerFixture) -> None:
+def test_generate_with_built(configuration: Configuration, package_ahriman: Package, result: Result,
+ mocker: MockerFixture) -> None:
"""
must generate report with built packages
"""
send_mock = mocker.patch("ahriman.core.report.email.Email._send")
report = Email("x86_64", configuration, "email")
- report.generate([package_ahriman], [package_ahriman])
+ report.generate([package_ahriman], result)
send_mock.assert_called_once_with(pytest.helpers.anyvar(int), {})
def test_generate_with_built_and_full_path(
configuration: Configuration,
package_ahriman: Package,
+ result: Result,
mocker: MockerFixture) -> None:
"""
must generate report with built packages
@@ -118,7 +121,7 @@ def test_generate_with_built_and_full_path(
report = Email("x86_64", configuration, "email")
report.full_template_path = report.template_path
- report.generate([package_ahriman], [package_ahriman])
+ report.generate([package_ahriman], result)
send_mock.assert_called_once_with(pytest.helpers.anyvar(int), pytest.helpers.anyvar(int))
@@ -130,11 +133,11 @@ def test_generate_no_empty(configuration: Configuration, package_ahriman: Packag
send_mock = mocker.patch("ahriman.core.report.email.Email._send")
report = Email("x86_64", configuration, "email")
- report.generate([package_ahriman], [])
+ report.generate([package_ahriman], Result())
send_mock.assert_not_called()
-def test_generate_no_empty_with_built(configuration: Configuration, package_ahriman: Package,
+def test_generate_no_empty_with_built(configuration: Configuration, package_ahriman: Package, result: Result,
mocker: MockerFixture) -> None:
"""
must generate report with built packages if no_empty_report is set
@@ -143,5 +146,5 @@ def test_generate_no_empty_with_built(configuration: Configuration, package_ahri
send_mock = mocker.patch("ahriman.core.report.email.Email._send")
report = Email("x86_64", configuration, "email")
- report.generate([package_ahriman], [package_ahriman])
+ report.generate([package_ahriman], result)
send_mock.assert_called_once_with(pytest.helpers.anyvar(int), {})
diff --git a/tests/ahriman/core/report/test_jinja_template.py b/tests/ahriman/core/report/test_jinja_template.py
index 18d8f9ec..93deccbf 100644
--- a/tests/ahriman/core/report/test_jinja_template.py
+++ b/tests/ahriman/core/report/test_jinja_template.py
@@ -1,6 +1,7 @@
from ahriman.core.configuration import Configuration
from ahriman.core.report.jinja_template import JinjaTemplate
from ahriman.models.package import Package
+from ahriman.models.result import Result
def test_generate(configuration: Configuration, package_ahriman: Package) -> None:
@@ -9,4 +10,4 @@ def test_generate(configuration: Configuration, package_ahriman: Package) -> Non
"""
path = configuration.getpath("html", "template_path")
report = JinjaTemplate("html", configuration)
- assert report.make_html([package_ahriman], path)
+ assert report.make_html(Result(success=[package_ahriman]), path)
diff --git a/tests/ahriman/core/report/test_report.py b/tests/ahriman/core/report/test_report.py
index 883ed45d..623dd0cd 100644
--- a/tests/ahriman/core/report/test_report.py
+++ b/tests/ahriman/core/report/test_report.py
@@ -6,6 +6,7 @@ from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import ReportFailed
from ahriman.core.report.report import Report
from ahriman.models.report_settings import ReportSettings
+from ahriman.models.result import Result
def test_report_failure(configuration: Configuration, mocker: MockerFixture) -> None:
@@ -14,32 +15,41 @@ def test_report_failure(configuration: Configuration, mocker: MockerFixture) ->
"""
mocker.patch("ahriman.core.report.html.HTML.generate", side_effect=Exception())
with pytest.raises(ReportFailed):
- Report.load("x86_64", configuration, "html").run([], [])
+ Report.load("x86_64", configuration, "html").run([], Result())
-def test_report_dummy(configuration: Configuration, mocker: MockerFixture) -> None:
+def test_report_dummy(configuration: Configuration, result: Result, mocker: MockerFixture) -> None:
"""
must construct dummy report class
"""
mocker.patch("ahriman.models.report_settings.ReportSettings.from_option", return_value=ReportSettings.Disabled)
report_mock = mocker.patch("ahriman.core.report.report.Report.generate")
- Report.load("x86_64", configuration, "disabled").run([], [])
- report_mock.assert_called_once_with([], [])
+ Report.load("x86_64", configuration, "disabled").run([], result)
+ report_mock.assert_called_once_with([], result)
-def test_report_email(configuration: Configuration, mocker: MockerFixture) -> None:
+def test_report_console(configuration: Configuration, result: Result, mocker: MockerFixture) -> None:
+ """
+ must generate console report
+ """
+ report_mock = mocker.patch("ahriman.core.report.console.Console.generate")
+ Report.load("x86_64", configuration, "console").run([], result)
+ report_mock.assert_called_once_with([], result)
+
+
+def test_report_email(configuration: Configuration, result: Result, mocker: MockerFixture) -> None:
"""
must generate email report
"""
report_mock = mocker.patch("ahriman.core.report.email.Email.generate")
- Report.load("x86_64", configuration, "email").run([], [])
- report_mock.assert_called_once_with([], [])
+ Report.load("x86_64", configuration, "email").run([], result)
+ report_mock.assert_called_once_with([], result)
-def test_report_html(configuration: Configuration, mocker: MockerFixture) -> None:
+def test_report_html(configuration: Configuration, result: Result, mocker: MockerFixture) -> None:
"""
must generate html report
"""
report_mock = mocker.patch("ahriman.core.report.html.HTML.generate")
- Report.load("x86_64", configuration, "html").run([], [])
- report_mock.assert_called_once_with([], [])
+ Report.load("x86_64", configuration, "html").run([], result)
+ report_mock.assert_called_once_with([], result)
diff --git a/tests/ahriman/core/repository/test_executor.py b/tests/ahriman/core/repository/test_executor.py
index 9a8b15e0..579b766f 100644
--- a/tests/ahriman/core/repository/test_executor.py
+++ b/tests/ahriman/core/repository/test_executor.py
@@ -35,7 +35,6 @@ def test_process_build(executor: Executor, package_ahriman: Package, mocker: Moc
mocker.patch("ahriman.core.build_tools.task.Task.init")
move_mock = mocker.patch("shutil.move")
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_building")
- built_packages_mock = mocker.patch("ahriman.core.repository.executor.Executor.packages_built")
executor.process_build([package_ahriman])
# must move files (once)
@@ -45,8 +44,6 @@ def test_process_build(executor: Executor, package_ahriman: Package, mocker: Moc
# must clear directory
from ahriman.core.repository.cleaner import Cleaner
Cleaner.clear_build.assert_called_once_with()
- # must return build packages after all
- built_packages_mock.assert_called_once_with()
def test_process_build_failure(executor: Executor, package_ahriman: Package, mocker: MockerFixture) -> None:
diff --git a/tests/ahriman/models/test_report_settings.py b/tests/ahriman/models/test_report_settings.py
index effb67c9..86f489d4 100644
--- a/tests/ahriman/models/test_report_settings.py
+++ b/tests/ahriman/models/test_report_settings.py
@@ -21,3 +21,6 @@ def test_from_option_valid() -> None:
assert ReportSettings.from_option("email") == ReportSettings.Email
assert ReportSettings.from_option("EmAil") == ReportSettings.Email
+
+ assert ReportSettings.from_option("console") == ReportSettings.Console
+ assert ReportSettings.from_option("conSOle") == ReportSettings.Console
diff --git a/tests/ahriman/models/test_result.py b/tests/ahriman/models/test_result.py
new file mode 100644
index 00000000..14461bb7
--- /dev/null
+++ b/tests/ahriman/models/test_result.py
@@ -0,0 +1,119 @@
+import pytest
+
+from ahriman.core.exceptions import SuccessFailed
+from ahriman.models.package import Package
+from ahriman.models.result import Result
+
+
+def test_add_failed(package_ahriman: Package) -> None:
+ """
+ must add package to failed list
+ """
+ result = Result()
+ result.add_failed(package_ahriman)
+ assert result.failed == [package_ahriman]
+ assert not result.success
+
+
+def test_add_success(package_ahriman: Package) -> None:
+ """
+ must add package to success list
+ """
+ result = Result()
+ result.add_success(package_ahriman)
+ assert result.success == [package_ahriman]
+ assert not result.failed
+
+
+def test_merge(package_ahriman: Package, package_python_schedule: Package) -> None:
+ """
+ must merge success packages
+ """
+ left = Result()
+ left.add_success(package_ahriman)
+ right = Result()
+ right.add_success(package_python_schedule)
+
+ result = left.merge(right)
+ assert result.success == [package_ahriman, package_python_schedule]
+ assert not left.failed
+
+
+def test_merge_failed(package_ahriman: Package) -> None:
+ """
+ must merge and remove failed packages from success list
+ """
+ left = Result()
+ left.add_success(package_ahriman)
+ right = Result()
+ right.add_failed(package_ahriman)
+
+ result = left.merge(right)
+ assert result.failed == [package_ahriman]
+ assert not left.success
+
+
+def test_merge_exception(package_ahriman: Package) -> None:
+ """
+ must raise exception in case if package was failed
+ """
+ left = Result()
+ left.add_failed(package_ahriman)
+ right = Result()
+ right.add_success(package_ahriman)
+
+ with pytest.raises(SuccessFailed):
+ left.merge(right)
+
+
+def test_eq(package_ahriman: Package, package_python_schedule: Package) -> None:
+ """
+ must return True for same objects
+ """
+ left = Result()
+ left.add_success(package_ahriman)
+ left.add_failed(package_python_schedule)
+ right = Result()
+ right.add_success(package_ahriman)
+ right.add_failed(package_python_schedule)
+
+ assert left == right
+
+
+def test_eq_false(package_ahriman: Package) -> None:
+ """
+ must return False in case if lists do not match
+ """
+ left = Result()
+ left.add_success(package_ahriman)
+ right = Result()
+ right.add_failed(package_ahriman)
+
+ assert left != right
+
+
+def test_eq_false_failed(package_ahriman: Package) -> None:
+ """
+ must return False in case if failed does not match
+ """
+ left = Result()
+ left.add_failed(package_ahriman)
+
+ assert left != Result()
+
+
+def test_eq_false_success(package_ahriman: Package) -> None:
+ """
+ must return False in case if success does not match
+ """
+ left = Result()
+ left.add_success(package_ahriman)
+
+ assert left != Result()
+
+
+def test_eq_other() -> None:
+ """
+ must return False in case if object is not an instance of result
+ """
+ assert Result() != 42
diff --git a/tests/testresources/core/ahriman.ini b/tests/testresources/core/ahriman.ini
index 93e81e11..0397c762 100644
--- a/tests/testresources/core/ahriman.ini
+++ b/tests/testresources/core/ahriman.ini
@@ -42,6 +42,9 @@ receivers = mail@example.com
sender = mail@example.com
template_path = ../web/templates/repo-index.jinja2
+[console]
+use_utf = yes
+
[html]
path =
homepage =