mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-09-01 14:29:55 +00:00
Compare commits
2 Commits
b9900a14cd
...
6fe77eb465
Author | SHA1 | Date | |
---|---|---|---|
6fe77eb465 | |||
7c6c24a46d |
@ -4,7 +4,7 @@ set -e
|
||||
[ -n "$AHRIMAN_DEBUG" ] && set -x
|
||||
|
||||
# configuration tune
|
||||
cat <<EOF > "/etc/ahriman.ini.d/00-docker.ini"
|
||||
cat <<EOF > "/etc/ahriman.ini.d/01-docker.ini"
|
||||
[repository]
|
||||
root = $AHRIMAN_REPOSITORY_ROOT
|
||||
|
||||
|
@ -12,6 +12,14 @@ ahriman.core.configuration.configuration module
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.core.configuration.configuration\_multi\_dict module
|
||||
------------------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.configuration.configuration_multi_dict
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.core.configuration.schema module
|
||||
----------------------------------------
|
||||
|
||||
|
@ -13,7 +13,27 @@ There are two variable types which have been added to default ones, they are pat
|
||||
* By default, it splits value by spaces excluding empty elements.
|
||||
* In case if quotation mark (``"`` or ``'``) will be found, any spaces inside will be ignored.
|
||||
* In order to use quotation mark inside value it is required to put it to another quotation mark, e.g. ``wor"'"d "with quote"`` will be parsed as ``["wor'd", "with quote"]`` and vice versa.
|
||||
* Unclosed quotation mark is not allowed and will rise an exception.
|
||||
* Unclosed quotation mark is not allowed and will raise an exception.
|
||||
|
||||
It is also possible to split list option between multiple declarations. To do so, append key name with ``[]`` (like PHP, sorry!), e.g.:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[section]
|
||||
list[] = value1
|
||||
list[] = value2
|
||||
|
||||
will lead to ``${section:list}`` value to be set to ``value1 value2``. The values will be set in order of appearance, meaning that values which appear in different include files will be set in alphabetical order of file names. In order to reset list values, set option to empty string, e.g.:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[section]
|
||||
list[] = value1
|
||||
list[] =
|
||||
list[] = value2
|
||||
list[] = value3
|
||||
|
||||
will set option ``${section:list}`` to ``value2 value3``. Alternatively, setting the original option (e.g. ``list`` in the example above) will also reset value, though the subsequent options with leading ``[]`` will append the previous value.
|
||||
|
||||
Path values, except for casting to ``pathlib.Path`` type, will be also expanded to absolute paths relative to the configuration path. E.g. if path is set to ``ahriman.ini.d/logging.ini`` and root configuration path is ``/etc/ahriman.ini``, the value will be expanded to ``/etc/ahriman.ini.d/logging.ini``. In order to disable path expand, use the full path, e.g. ``/etc/ahriman.ini.d/logging.ini``.
|
||||
|
||||
@ -22,7 +42,7 @@ Configuration allows string interpolation from the same configuration file, e.g.
|
||||
.. code-block:: ini
|
||||
|
||||
[section]
|
||||
key = ${anoher_key}
|
||||
key = ${another_key}
|
||||
another_key = value
|
||||
|
||||
will read value for the ``key`` option from ``another_key`` in the same section. In case if the cross-section reference is required, the ``${section:another_key}`` notation must be used. It also allows string interpolation from environment variables, e.g.:
|
||||
|
@ -65,9 +65,19 @@ makepkg_flags = --nocolor --ignorearch
|
||||
; List of paths to be used for implicit dependency scan. Regular expressions are supported.
|
||||
scan_paths = ^usr/lib(?!/cmake).*$
|
||||
; List of enabled triggers in the order of calls.
|
||||
triggers = ahriman.core.gitremote.RemotePullTrigger ahriman.core.report.ReportTrigger ahriman.core.upload.UploadTrigger ahriman.core.gitremote.RemotePushTrigger
|
||||
triggers[] = ahriman.core.gitremote.RemotePullTrigger
|
||||
triggers[] = ahriman.core.report.ReportTrigger
|
||||
triggers[] = ahriman.core.upload.UploadTrigger
|
||||
triggers[] = ahriman.core.gitremote.RemotePushTrigger
|
||||
; List of well-known triggers. Used only for configuration purposes.
|
||||
triggers_known = ahriman.core.distributed.WorkerLoaderTrigger ahriman.core.distributed.WorkerRegisterTrigger ahriman.core.distributed.WorkerTrigger ahriman.core.distributed.WorkerUnregisterTrigger ahriman.core.gitremote.RemotePullTrigger ahriman.core.gitremote.RemotePushTrigger ahriman.core.report.ReportTrigger ahriman.core.upload.UploadTrigger ahriman.core.support.KeyringTrigger ahriman.core.support.MirrorlistTrigger
|
||||
triggers_known[] = ahriman.core.distributed.WorkerLoaderTrigger
|
||||
triggers_known[] = ahriman.core.distributed.WorkerTrigger
|
||||
triggers_known[] = ahriman.core.gitremote.RemotePullTrigger
|
||||
triggers_known[] = ahriman.core.gitremote.RemotePushTrigger
|
||||
triggers_known[] = ahriman.core.report.ReportTrigger
|
||||
triggers_known[] = ahriman.core.support.KeyringTrigger
|
||||
triggers_known[] = ahriman.core.support.MirrorlistTrigger
|
||||
triggers_known[] = ahriman.core.upload.UploadTrigger
|
||||
; Maximal age in seconds of the VCS packages before their version will be updated with its remote source.
|
||||
;vcs_allowed_age = 604800
|
||||
; List of worker nodes addresses used for build process, e.g.:
|
||||
@ -121,7 +131,7 @@ host = 127.0.0.1
|
||||
; Path to directory with static files.
|
||||
static_path = ${templates}/static
|
||||
; List of directories with templates.
|
||||
templates = ${prefix}/share/ahriman/templates
|
||||
templates[] = ${prefix}/share/ahriman/templates
|
||||
; Path to unix socket. If none set, unix socket will be disabled.
|
||||
;unix_socket =
|
||||
; Allow unix socket to be world readable.
|
||||
@ -246,7 +256,7 @@ template = email-index.jinja2
|
||||
; Template name to be used for full packages list generation (same as HTML report).
|
||||
;template_full =
|
||||
; List of directories with templates.
|
||||
templates = ${prefix}/share/ahriman/templates
|
||||
templates[] = ${prefix}/share/ahriman/templates
|
||||
; SMTP user.
|
||||
;user =
|
||||
|
||||
@ -265,7 +275,7 @@ templates = ${prefix}/share/ahriman/templates
|
||||
; Template name to be used.
|
||||
template = repo-index.jinja2
|
||||
; List of directories with templates.
|
||||
templates = ${prefix}/share/ahriman/templates
|
||||
templates[] = ${prefix}/share/ahriman/templates
|
||||
|
||||
; Remote service callback trigger configuration sample.
|
||||
[remote-call]
|
||||
@ -295,7 +305,7 @@ templates = ${prefix}/share/ahriman/templates
|
||||
; Template name to be used.
|
||||
template = rss.jinja2
|
||||
; List of directories with templates.
|
||||
templates = ${prefix}/share/ahriman/templates
|
||||
templates[] = ${prefix}/share/ahriman/templates
|
||||
|
||||
; Telegram reporting trigger configuration sample.
|
||||
[telegram]
|
||||
@ -316,7 +326,7 @@ template = telegram-index.jinja2
|
||||
; Telegram specific template mode, one of MarkdownV2, HTML or Markdown.
|
||||
;template_type = HTML
|
||||
; List of directories with templates.
|
||||
templates = ${prefix}/share/ahriman/templates
|
||||
templates[] = ${prefix}/share/ahriman/templates
|
||||
; HTTP request timeout in seconds.
|
||||
;timeout = 30
|
||||
|
||||
|
@ -161,8 +161,8 @@ class Setup(Handler):
|
||||
repository_server(str): url of the repository
|
||||
"""
|
||||
# allow_no_value=True is required because pacman uses boolean configuration in which just keys present
|
||||
# (e.g. NoProgressBar) which will lead to exception
|
||||
configuration = Configuration(allow_no_value=True)
|
||||
# (e.g. NoProgressBar) which will lead to exception. allow_multi_key=False is set just for fun
|
||||
configuration = Configuration(allow_no_value=True, allow_multi_key=False)
|
||||
# preserve case
|
||||
# stupid mypy thinks that it is impossible
|
||||
configuration.optionxform = lambda optionstr: optionstr # type: ignore[method-assign]
|
||||
|
@ -25,6 +25,7 @@ from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Any, Self
|
||||
|
||||
from ahriman.core.configuration.configuration_multi_dict import ConfigurationMultiDict
|
||||
from ahriman.core.configuration.shell_interpolator import ShellInterpolator
|
||||
from ahriman.core.exceptions import InitializeError
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
@ -69,21 +70,27 @@ class Configuration(configparser.RawConfigParser):
|
||||
SYSTEM_CONFIGURATION_PATH = Path(sys.prefix) / "share" / "ahriman" / "settings" / "ahriman.ini"
|
||||
converters: dict[str, Callable[[str], Any]] # typing guard
|
||||
|
||||
def __init__(self, allow_no_value: bool = False) -> None:
|
||||
def __init__(self, allow_no_value: bool = False, allow_multi_key: bool = True) -> None:
|
||||
"""
|
||||
Args:
|
||||
allow_no_value(bool, optional): copies :class:`configparser.RawConfigParser` behaviour. In case if it is set
|
||||
to ``True``, the keys without values will be allowed (Default value = False)
|
||||
allow_multi_key(bool, optional): if set to ``False``, then the default dictionary class will be used to
|
||||
store keys internally. Otherwise, the special implementation will be used, which supports arrays
|
||||
(Default value = True)
|
||||
"""
|
||||
configparser.RawConfigParser.__init__(
|
||||
self,
|
||||
dict_type=ConfigurationMultiDict if allow_multi_key else dict, # type: ignore[arg-type]
|
||||
allow_no_value=allow_no_value,
|
||||
strict=False,
|
||||
empty_lines_in_values=not allow_multi_key,
|
||||
interpolation=ShellInterpolator(),
|
||||
converters={
|
||||
"list": shlex.split,
|
||||
"path": self._convert_path,
|
||||
"pathlist": lambda value: [self._convert_path(element) for element in shlex.split(value)],
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
self.repository_id: RepositoryId | None = None
|
||||
|
91
src/ahriman/core/configuration/configuration_multi_dict.py
Normal file
91
src/ahriman/core/configuration/configuration_multi_dict.py
Normal file
@ -0,0 +1,91 @@
|
||||
#
|
||||
# Copyright (c) 2021-2024 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Any
|
||||
|
||||
from ahriman.core.exceptions import OptionError
|
||||
|
||||
|
||||
class ConfigurationMultiDict(dict[str, Any]):
|
||||
"""
|
||||
wrapper around :class:`dict` to handle multiple configuration keys as lists if they end with ``[]``.
|
||||
|
||||
Examples:
|
||||
This class is designed to be used only with :class:`configparser.RawConfigParser` class, but idea is that
|
||||
if the key ends with ``[]`` it will be treated as array and the result will be appended to the current value.
|
||||
In addition, if the value is empty, then it will clear previous values, e.g.:
|
||||
|
||||
>>> data = ConfigurationMultiDict()
|
||||
>>>
|
||||
>>> data["single"] = "value" # append normal key
|
||||
>>> print(data) # {"single": "value"}
|
||||
>>>
|
||||
>>> data["array[]"] = ["value1"] # append array value
|
||||
>>> data["array[]"] = ["value2"]
|
||||
>>> print(data) # {"single": "value", "array": ["value1 value2"]}
|
||||
>>>
|
||||
>>> data["array[]"] = [""] # clear previous values
|
||||
>>> data["array[]"] = ["value3"]
|
||||
>>> print(data) # {"single": "value", "array": ["value3"]}
|
||||
"""
|
||||
|
||||
def _set_array_value(self, key: str, value: Any) -> None:
|
||||
"""
|
||||
set array value. If the key already exists in the dictionary, its value will be prepended to new value
|
||||
|
||||
Args:
|
||||
key(str): key to insert
|
||||
value(Any): value of the related key
|
||||
|
||||
Raises:
|
||||
OptionError: if the key already exists in the dictionary, but not a single value list or a string
|
||||
"""
|
||||
match self.get(key):
|
||||
case [current_value] | str(current_value): # type: ignore[misc]
|
||||
value = f"{current_value} {value}"
|
||||
case None:
|
||||
pass
|
||||
case other:
|
||||
raise OptionError(other)
|
||||
super().__setitem__(key, [value])
|
||||
|
||||
def __setitem__(self, key: str, value: Any) -> None:
|
||||
"""
|
||||
set ``key`` to ``value``. If the value equals to ``[""]`` (array with empty string), then the key
|
||||
will be removed (as expected from :class:`configparser.RawConfigParser`). If the key ends with
|
||||
``[]``, the value will be treated as an array and vice versa.
|
||||
|
||||
Args:
|
||||
key(str): key to insert
|
||||
value(Any): value of the related key
|
||||
|
||||
Raises:
|
||||
OptionError: if ``key`` contains ``[]``, but not at the end of the string (e.g. ``prefix[]suffix``)
|
||||
"""
|
||||
real_key, is_key_array, remaining = key.partition("[]")
|
||||
if remaining:
|
||||
raise OptionError(key)
|
||||
|
||||
match value:
|
||||
case [""]: # empty value key
|
||||
self.pop(real_key, None)
|
||||
case [array_value] if is_key_array: # update array value
|
||||
self._set_array_value(real_key, array_value)
|
||||
case _: # normal key
|
||||
super().__setitem__(real_key, value)
|
@ -139,7 +139,7 @@ def test_add_remote(application_packages: ApplicationPackages, package_descripti
|
||||
|
||||
def test_add_remote_missing(application_packages: ApplicationPackages, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add package from remote source
|
||||
must raise UnknownPackageError if remote package wasn't found
|
||||
"""
|
||||
mocker.patch("requests.get", side_effect=Exception())
|
||||
with pytest.raises(UnknownPackageError):
|
||||
|
@ -79,7 +79,7 @@ def test_clean_packages(application_repository: ApplicationRepository, mocker: M
|
||||
|
||||
def test_clean_pacman(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must clean packages directory
|
||||
must clean pacman directory
|
||||
"""
|
||||
clear_mock = mocker.patch("ahriman.core.repository.Repository.clear_pacman")
|
||||
application_repository.clean(cache=False, chroot=False, manual=False, packages=False, pacman=True)
|
||||
|
@ -171,7 +171,7 @@ def test_repositories_extract_repository(args: argparse.Namespace, configuration
|
||||
def test_repositories_extract_repository_legacy(args: argparse.Namespace, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must generate list of available repositories based on flags and tree
|
||||
must generate list of available repositories based on flags and tree (legacy mode)
|
||||
"""
|
||||
args.architecture = "arch"
|
||||
args.configuration = configuration.path
|
||||
|
@ -190,7 +190,7 @@ def test_extract_packages_by_status(application: Application, mocker: MockerFixt
|
||||
|
||||
def test_extract_packages_from_database(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must extract packages from database
|
||||
must extract packages from database from database
|
||||
"""
|
||||
packages_mock = mocker.patch("ahriman.core.database.SQLite.packages_get")
|
||||
Rebuild.extract_packages(application, None, from_database=True)
|
||||
|
@ -40,7 +40,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
|
||||
def test_run_eval(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
must run command via eval
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.code = """print("hello world")"""
|
||||
|
@ -60,7 +60,7 @@ def test_remote_git_url(aur_package_ahriman: AURPackage) -> None:
|
||||
|
||||
def test_remote_web_url(aur_package_ahriman: AURPackage) -> None:
|
||||
"""
|
||||
must generate package git url
|
||||
must generate package web url
|
||||
"""
|
||||
web_url = AUR.remote_web_url(aur_package_ahriman.package_base)
|
||||
assert web_url.startswith(AUR.DEFAULT_AUR_URL)
|
||||
|
@ -87,7 +87,7 @@ def test_database_copy_skip(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
|
||||
def test_database_copy_no_directory(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must do not copy database if local cache already exists
|
||||
must do not copy database if directory does not exist
|
||||
"""
|
||||
database = next(db for db in pacman.handle.get_syncdbs() if db.name == "core")
|
||||
path = Path("randomname")
|
||||
|
@ -1,4 +1,6 @@
|
||||
import configparser
|
||||
from io import StringIO
|
||||
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
@ -180,6 +182,32 @@ def test_getlist_unmatched_quote(configuration: Configuration) -> None:
|
||||
configuration.getlist("build", "test_list")
|
||||
|
||||
|
||||
def test_getlist_append() -> None:
|
||||
"""
|
||||
must correctly append list values
|
||||
"""
|
||||
configuration = Configuration()
|
||||
configuration._read(
|
||||
StringIO("""
|
||||
[section]
|
||||
list1[] = value1
|
||||
list1[] = value2
|
||||
|
||||
list2[] = value3
|
||||
list2[] =
|
||||
list2[] = value4
|
||||
list2[] = value5
|
||||
|
||||
list3[] = value6
|
||||
list3 = value7
|
||||
list3[] = value8
|
||||
"""), "io")
|
||||
|
||||
assert configuration.getlist("section", "list1") == ["value1", "value2"]
|
||||
assert configuration.getlist("section", "list2") == ["value4", "value5"]
|
||||
assert configuration.getlist("section", "list3") == ["value7", "value8"]
|
||||
|
||||
|
||||
def test_getpath_absolute_to_absolute(configuration: Configuration) -> None:
|
||||
"""
|
||||
must not change path for absolute path in settings
|
||||
|
@ -0,0 +1,54 @@
|
||||
import pytest
|
||||
|
||||
from ahriman.core.configuration.configuration_multi_dict import ConfigurationMultiDict
|
||||
from ahriman.core.exceptions import OptionError
|
||||
|
||||
|
||||
def test_setitem_non_list() -> None:
|
||||
"""
|
||||
must insert not list correctly
|
||||
"""
|
||||
instance = ConfigurationMultiDict()
|
||||
instance["key"] = "value"
|
||||
assert instance["key"] == "value"
|
||||
|
||||
|
||||
def test_setitem_remove() -> None:
|
||||
"""
|
||||
must remove key
|
||||
"""
|
||||
instance = ConfigurationMultiDict()
|
||||
instance["key"] = "value"
|
||||
instance["key"] = [""]
|
||||
|
||||
assert "key" not in instance
|
||||
|
||||
|
||||
def test_setitem_array() -> None:
|
||||
"""
|
||||
must set array correctly
|
||||
"""
|
||||
instance = ConfigurationMultiDict()
|
||||
instance["key[]"] = ["value1"]
|
||||
instance["key[]"] = ["value2"]
|
||||
|
||||
assert instance["key"] == ["value1 value2"]
|
||||
|
||||
|
||||
def test_setitem_array_exception() -> None:
|
||||
"""
|
||||
must raise exception if the current value is not a single value array
|
||||
"""
|
||||
instance = ConfigurationMultiDict()
|
||||
instance["key[]"] = ["value1", "value2"]
|
||||
with pytest.raises(OptionError):
|
||||
instance["key[]"] = ["value3"]
|
||||
|
||||
|
||||
def test_setitem_exception() -> None:
|
||||
"""
|
||||
must raise exception on invalid key
|
||||
"""
|
||||
instance = ConfigurationMultiDict()
|
||||
with pytest.raises(OptionError):
|
||||
instance["prefix[]suffix"] = "value"
|
@ -44,7 +44,7 @@ def test_patches_list_filter(database: SQLite, package_ahriman: Package, package
|
||||
def test_patches_list_filter_by_variable(database: SQLite, package_ahriman: Package,
|
||||
package_python_schedule: Package) -> None:
|
||||
"""
|
||||
must list all patches filtered by package name (same as get)
|
||||
must list all patches filtered by variable (same as get)
|
||||
"""
|
||||
database.patches_insert(package_ahriman.base, [PkgbuildPatch(None, "patch1")])
|
||||
database.patches_insert(package_ahriman.base, [PkgbuildPatch("key", "patch2")])
|
||||
|
@ -63,7 +63,7 @@ def test_in_package_context(database: SQLite, package_ahriman: Package, mocker:
|
||||
|
||||
def test_in_package_context_empty_version(database: SQLite, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must set package log context
|
||||
must set package log context with empty version
|
||||
"""
|
||||
set_mock = mocker.patch("ahriman.core.log.LazyLogging._package_logger_set")
|
||||
reset_mock = mocker.patch("ahriman.core.log.LazyLogging._package_logger_reset")
|
||||
|
@ -24,7 +24,7 @@ def test_template(configuration: Configuration) -> None:
|
||||
|
||||
def test_template_full(configuration: Configuration) -> None:
|
||||
"""
|
||||
must correctly parse template name and path
|
||||
must correctly parse full template name and path
|
||||
"""
|
||||
template = "template"
|
||||
root, repository_id = configuration.check_loaded()
|
||||
|
@ -107,7 +107,7 @@ def test_generate_very_big_text(telegram: Telegram, package_ahriman: Package, re
|
||||
|
||||
def test_generate_no_empty(telegram: Telegram, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must generate report
|
||||
must skip report generation if result is empty
|
||||
"""
|
||||
send_mock = mocker.patch("ahriman.core.report.telegram.Telegram._send")
|
||||
telegram.generate([package_ahriman], Result())
|
||||
|
@ -62,7 +62,7 @@ def test_clear_packages(cleaner: Cleaner, mocker: MockerFixture) -> None:
|
||||
|
||||
def test_clear_pacman(cleaner: Cleaner, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must delete built packages
|
||||
must clear pacman root
|
||||
"""
|
||||
_mock_clear(mocker)
|
||||
cleaner.clear_pacman()
|
||||
|
@ -142,7 +142,7 @@ def test_updates_aur_load_by_package(update_handler: UpdateHandler, package_pyth
|
||||
def test_updates_aur_load_by_package_failed(update_handler: UpdateHandler, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must update status via client for failed load
|
||||
must update status via client for failed load if no remote package found
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
||||
mocker.patch("ahriman.models.package.Package.from_aur", side_effect=UnknownPackageError(package_ahriman.base))
|
||||
|
@ -9,50 +9,35 @@ from ahriman.core.sign.gpg import GPG
|
||||
from ahriman.models.sign_settings import SignSettings
|
||||
|
||||
|
||||
def test_repository_sign_args_1(gpg_with_key: GPG) -> None:
|
||||
def test_repository_sign_args(gpg_with_key: GPG) -> None:
|
||||
"""
|
||||
must generate correct sign args
|
||||
"""
|
||||
gpg_with_key.targets = {SignSettings.Repository}
|
||||
assert gpg_with_key.repository_sign_args
|
||||
|
||||
|
||||
def test_repository_sign_args_2(gpg_with_key: GPG) -> None:
|
||||
"""
|
||||
must generate correct sign args
|
||||
"""
|
||||
gpg_with_key.targets = {SignSettings.Packages, SignSettings.Repository}
|
||||
assert gpg_with_key.repository_sign_args
|
||||
|
||||
|
||||
def test_repository_sign_args_skip_1(gpg_with_key: GPG) -> None:
|
||||
def test_repository_sign_args_skip(gpg_with_key: GPG) -> None:
|
||||
"""
|
||||
must return empty args if it is not set
|
||||
"""
|
||||
gpg_with_key.targets = {}
|
||||
assert not gpg_with_key.repository_sign_args
|
||||
|
||||
|
||||
def test_repository_sign_args_skip_2(gpg_with_key: GPG) -> None:
|
||||
"""
|
||||
must return empty args if it is not set
|
||||
"""
|
||||
gpg_with_key.targets = {SignSettings.Packages}
|
||||
assert not gpg_with_key.repository_sign_args
|
||||
|
||||
|
||||
def test_repository_sign_args_skip_3(gpg: GPG) -> None:
|
||||
def test_repository_sign_args_skip_no_key(gpg: GPG) -> None:
|
||||
"""
|
||||
must return empty args if it is not set
|
||||
must return empty args if it is not set if no key set
|
||||
"""
|
||||
gpg.targets = {SignSettings.Repository}
|
||||
assert not gpg.repository_sign_args
|
||||
|
||||
|
||||
def test_repository_sign_args_skip_4(gpg: GPG) -> None:
|
||||
"""
|
||||
must return empty args if it is not set
|
||||
"""
|
||||
gpg.targets = {SignSettings.Packages, SignSettings.Repository}
|
||||
assert not gpg.repository_sign_args
|
||||
|
||||
@ -188,7 +173,7 @@ def test_process_sign_package_3(gpg_with_key: GPG, mocker: MockerFixture) -> Non
|
||||
|
||||
def test_process_sign_package_skip_1(gpg_with_key: GPG, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must not sign package if it is not set
|
||||
must not sign package on empty target list
|
||||
"""
|
||||
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
|
||||
gpg_with_key.targets = {}
|
||||
@ -198,7 +183,7 @@ def test_process_sign_package_skip_1(gpg_with_key: GPG, mocker: MockerFixture) -
|
||||
|
||||
def test_process_sign_package_skip_2(gpg_with_key: GPG, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must not sign package if it is not set
|
||||
must not sign package if repository only is enabled
|
||||
"""
|
||||
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
|
||||
gpg_with_key.targets = {SignSettings.Repository}
|
||||
@ -208,7 +193,7 @@ def test_process_sign_package_skip_2(gpg_with_key: GPG, mocker: MockerFixture) -
|
||||
|
||||
def test_process_sign_package_skip_3(gpg: GPG, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must not sign package if it is not set
|
||||
must not sign package if key is not set
|
||||
"""
|
||||
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
|
||||
gpg.targets = {SignSettings.Packages}
|
||||
@ -216,16 +201,6 @@ def test_process_sign_package_skip_3(gpg: GPG, mocker: MockerFixture) -> None:
|
||||
process_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_process_sign_package_skip_4(gpg: GPG, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must not sign package if it is not set
|
||||
"""
|
||||
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
|
||||
gpg.targets = {SignSettings.Packages, SignSettings.Repository}
|
||||
gpg.process_sign_package(Path("a"), None)
|
||||
process_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_process_sign_package_skip_already_signed(gpg_with_key: GPG, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must not sign package if it was already signed
|
||||
@ -264,7 +239,7 @@ def test_process_sign_repository_2(gpg_with_key: GPG, mocker: MockerFixture) ->
|
||||
|
||||
def test_process_sign_repository_skip_1(gpg_with_key: GPG, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must not sign repository if it is not set
|
||||
must not sign repository if no targets set
|
||||
"""
|
||||
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
|
||||
gpg_with_key.targets = {}
|
||||
@ -274,7 +249,7 @@ def test_process_sign_repository_skip_1(gpg_with_key: GPG, mocker: MockerFixture
|
||||
|
||||
def test_process_sign_repository_skip_2(gpg_with_key: GPG, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must not sign repository if it is not set
|
||||
must not sign repository if repository target is not set
|
||||
"""
|
||||
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
|
||||
gpg_with_key.targets = {SignSettings.Packages}
|
||||
@ -284,19 +259,9 @@ def test_process_sign_repository_skip_2(gpg_with_key: GPG, mocker: MockerFixture
|
||||
|
||||
def test_process_sign_repository_skip_3(gpg: GPG, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must not sign repository if it is not set
|
||||
must not sign repository if key is not set
|
||||
"""
|
||||
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
|
||||
gpg.targets = {SignSettings.Repository}
|
||||
gpg.process_sign_repository(Path("a"))
|
||||
process_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_process_sign_repository_skip_4(gpg: GPG, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must not sign repository if it is not set
|
||||
"""
|
||||
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
|
||||
gpg.targets = {SignSettings.Packages, SignSettings.Repository}
|
||||
gpg.process_sign_repository(Path("a"))
|
||||
process_mock.assert_not_called()
|
||||
|
@ -245,7 +245,7 @@ def test_set_failed(client: Client, package_ahriman: Package, mocker: MockerFixt
|
||||
|
||||
def test_set_pending(client: Client, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must set building status to the package
|
||||
must set pending status to the package
|
||||
"""
|
||||
update_mock = mocker.patch("ahriman.core.status.Client.package_status_update")
|
||||
client.set_pending(package_ahriman.base)
|
||||
|
@ -46,7 +46,7 @@ def test_changes_url(web_client: WebClient, package_ahriman: Package) -> None:
|
||||
|
||||
def test_dependencies_url(web_client: WebClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must generate changes url correctly
|
||||
must generate dependencies url correctly
|
||||
"""
|
||||
assert web_client._dependencies_url(package_ahriman.base).startswith(web_client.address)
|
||||
assert web_client._dependencies_url(package_ahriman.base).endswith(
|
||||
@ -74,7 +74,7 @@ def test_logs_url(web_client: WebClient, package_ahriman: Package) -> None:
|
||||
|
||||
def test_package_url(web_client: WebClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must generate package status url correctly
|
||||
must generate package url correctly
|
||||
"""
|
||||
assert web_client._package_url("").startswith(web_client.address)
|
||||
assert web_client._package_url("").endswith("/api/v1/packages")
|
||||
@ -86,7 +86,7 @@ def test_package_url(web_client: WebClient, package_ahriman: Package) -> None:
|
||||
|
||||
def test_patches_url(web_client: WebClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must generate changes url correctly
|
||||
must generate patches url correctly
|
||||
"""
|
||||
assert web_client._patches_url(package_ahriman.base).startswith(web_client.address)
|
||||
assert web_client._patches_url(package_ahriman.base).endswith(f"/api/v1/packages/{package_ahriman.base}/patches")
|
||||
@ -575,7 +575,7 @@ def test_package_logs_add_failed(web_client: WebClient, log_record: logging.LogR
|
||||
def test_package_logs_add_failed_http_error(web_client: WebClient, log_record: logging.LogRecord,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must pass exception during log post
|
||||
must pass HTTP exception during log post
|
||||
"""
|
||||
mocker.patch("requests.Session.request", side_effect=requests.HTTPError())
|
||||
log_record.package_base = package_ahriman.base
|
||||
@ -725,7 +725,7 @@ def test_package_patches_get_failed(web_client: WebClient, package_ahriman: Pack
|
||||
def test_package_patches_get_failed_http_error(web_client: WebClient, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must suppress HTTP exception happened during dependencies fetch
|
||||
must suppress HTTP exception happened during patches fetch
|
||||
"""
|
||||
mocker.patch("requests.Session.request", side_effect=requests.HTTPError())
|
||||
web_client.package_patches_get(package_ahriman.base, None)
|
||||
|
@ -13,7 +13,7 @@ from ahriman.models.result import Result
|
||||
|
||||
def test_known_triggers(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return used triggers
|
||||
must return known triggers
|
||||
"""
|
||||
configuration.set_option("build", "triggers_known", "a b c")
|
||||
assert TriggerLoader.known_triggers(configuration) == ["a", "b", "c"]
|
||||
|
@ -255,14 +255,14 @@ def test_from_json_view_1(package_ahriman: Package) -> None:
|
||||
|
||||
def test_from_json_view_2(package_python_schedule: Package) -> None:
|
||||
"""
|
||||
must construct same object from json
|
||||
must construct same object from json (double package)
|
||||
"""
|
||||
assert Package.from_json(package_python_schedule.view()) == package_python_schedule
|
||||
|
||||
|
||||
def test_from_json_view_3(package_tpacpi_bat_git: Package) -> None:
|
||||
"""
|
||||
must construct same object from json
|
||||
must construct same object from json (git package)
|
||||
"""
|
||||
assert Package.from_json(package_tpacpi_bat_git.view()) == package_tpacpi_bat_git
|
||||
|
||||
|
@ -86,7 +86,7 @@ def test_resolve_local(repository_paths: RepositoryPaths, mocker: MockerFixture)
|
||||
|
||||
def test_resolve_local_cache(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must resolve auto type into the local sources
|
||||
must resolve auto type into the local sources with cache
|
||||
"""
|
||||
cache_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.cache_for", return_value=Path("cache"))
|
||||
mocker.patch("pathlib.Path.is_dir", autospec=True, side_effect=lambda p: p == Path("cache"))
|
||||
|
@ -27,7 +27,7 @@ def test_is_function() -> None:
|
||||
|
||||
def test_is_plain_diff() -> None:
|
||||
"""
|
||||
must correctly define key as function
|
||||
must correctly define key as a plain diff
|
||||
"""
|
||||
assert not PkgbuildPatch("key", "value").is_plain_diff
|
||||
assert PkgbuildPatch(None, "value").is_plain_diff
|
||||
@ -112,7 +112,7 @@ def test_from_env_serialize() -> None:
|
||||
|
||||
def test_serialize_plain_diff() -> None:
|
||||
"""
|
||||
must correctly serialize function values
|
||||
must correctly serialize plain diff values
|
||||
"""
|
||||
assert PkgbuildPatch(None, "{ value }").serialize() == "{ value }"
|
||||
|
||||
|
@ -98,7 +98,7 @@ async def test_exception_handler_unauthorized(mocker: MockerFixture) -> None:
|
||||
|
||||
async def test_exception_handler_unauthorized_templated(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must handle unauthorized exception as json response
|
||||
must handle unauthorized exception as json response in html context
|
||||
"""
|
||||
request = pytest.helpers.request("", "", "")
|
||||
request_handler = AsyncMock(side_effect=HTTPUnauthorized())
|
||||
|
@ -124,7 +124,7 @@ def test_run_with_auth(application_with_auth: Application, mocker: MockerFixture
|
||||
|
||||
def test_run_with_socket(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run application
|
||||
must run application with socket
|
||||
"""
|
||||
port = 8080
|
||||
application[ConfigurationKey].set_option("web", "port", str(port))
|
||||
|
@ -158,7 +158,7 @@ async def test_post_unauthorized(client_with_auth: TestClient, user: User, mocke
|
||||
|
||||
async def test_post_invalid_json(client_with_auth: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return unauthorized on invalid auth
|
||||
must return unauthorized on invalid payload
|
||||
"""
|
||||
response_schema = pytest.helpers.schema_response(LoginView.post, code=400)
|
||||
remember_mock = mocker.patch("aiohttp_security.remember")
|
||||
|
@ -60,7 +60,7 @@ target = console
|
||||
|
||||
[email]
|
||||
host = 127.0.0.1
|
||||
link_path =
|
||||
link_path = http://example.com
|
||||
no_empty_report = no
|
||||
port = 587
|
||||
receivers = mail@example.com
|
||||
@ -72,9 +72,8 @@ templates = ../web/templates
|
||||
use_utf = yes
|
||||
|
||||
[html]
|
||||
path =
|
||||
homepage =
|
||||
link_path =
|
||||
link_path = http://example.com
|
||||
path = local/path
|
||||
template = repo-index.jinja2
|
||||
templates = ../web/templates
|
||||
|
||||
@ -82,17 +81,15 @@ templates = ../web/templates
|
||||
manual = yes
|
||||
|
||||
[rss]
|
||||
path =
|
||||
homepage =
|
||||
link_path =
|
||||
link_path = http://example.com
|
||||
path = local/path
|
||||
template = rss.jinja2
|
||||
templates = ../web/templates
|
||||
|
||||
[telegram]
|
||||
api_key = apikey
|
||||
api_key = api_key
|
||||
chat_id = @ahrimantestchat
|
||||
homepage =
|
||||
link_path =
|
||||
link_path = http://example.com
|
||||
template = telegram-index.jinja2
|
||||
templates = ../web/templates
|
||||
|
||||
@ -101,20 +98,20 @@ target =
|
||||
|
||||
[rsync]
|
||||
command = rsync --archive --verbose --compress --partial --delete
|
||||
remote =
|
||||
remote = remote@example.com
|
||||
|
||||
[disabled]
|
||||
|
||||
[customs3]
|
||||
type = s3
|
||||
access_key =
|
||||
access_key = access_key
|
||||
bucket = bucket
|
||||
region = eu-central-1
|
||||
secret_key =
|
||||
secret_key = secret_key
|
||||
|
||||
[github:x86_64]
|
||||
owner = arcan1s
|
||||
password =
|
||||
password = pa55w0rd
|
||||
repository = ahriman
|
||||
username = arcan1s
|
||||
|
||||
|
Reference in New Issue
Block a user