automatically bump pkgrel on version duplicates

The new --(no-)increment flag has been added to add, update and rebuild
subcommands. In case if it is true and package version is the same as in
repository, it will automatically bump pkgrel appending (increasing)
minor part of it (e.g. 1.0.0-1 -> 1.0.0-1.1).

Inn order to implement this, the shadow (e.g. it will not store it in
database) patch for pkgrel will be created
This commit is contained in:
2023-08-07 00:04:08 +03:00
parent 368db86dde
commit 3b3ef43863
27 changed files with 288 additions and 51 deletions

View File

@ -6,6 +6,7 @@ from unittest.mock import call as MockCall
from ahriman.application.application.application_repository import ApplicationRepository
from ahriman.core.tree import Leaf, Tree
from ahriman.models.package import Package
from ahriman.models.packagers import Packagers
from ahriman.models.result import Result
@ -170,9 +171,12 @@ def test_update(application_repository: ApplicationRepository, package_ahriman:
on_result_mock = mocker.patch(
"ahriman.application.application.application_repository.ApplicationRepository.on_result")
application_repository.update([package_ahriman], "username")
build_mock.assert_called_once_with([package_ahriman], "username")
update_mock.assert_has_calls([MockCall(paths, "username"), MockCall(paths, "username")])
application_repository.update([package_ahriman], Packagers("username"), bump_pkgrel=True)
build_mock.assert_called_once_with([package_ahriman], Packagers("username"), bump_pkgrel=True)
update_mock.assert_has_calls([
MockCall(paths, Packagers("username")),
MockCall(paths, Packagers("username")),
])
on_result_mock.assert_has_calls([MockCall(result), MockCall(result)])

View File

@ -24,6 +24,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
"""
args.package = []
args.exit_code = False
args.increment = True
args.now = False
args.refresh = 0
args.source = PackageSource.Auto
@ -70,7 +71,8 @@ def test_run_with_updates(args: argparse.Namespace, configuration: Configuration
Add.run(args, "x86_64", configuration, report=False)
updates_mock.assert_called_once_with(args.package, aur=False, local=False, manual=True, vcs=False)
application_mock.assert_called_once_with([package_ahriman],
Packagers(args.username, {package_ahriman.base: "packager"}))
Packagers(args.username, {package_ahriman.base: "packager"}),
bump_pkgrel=args.increment)
dependencies_mock.assert_called_once_with([package_ahriman], process_dependencies=args.dependencies)
check_mock.assert_called_once_with(False, False)
print_mock.assert_called_once_with([package_ahriman], log_fn=pytest.helpers.anyvar(int))

View File

@ -27,6 +27,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
args.dry_run = False
args.from_database = False
args.exit_code = False
args.increment = True
args.status = None
args.username = "username"
return args
@ -51,7 +52,7 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
Rebuild.run(args, "x86_64", configuration, report=False)
extract_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.status, from_database=args.from_database)
application_packages_mock.assert_called_once_with([package_ahriman], None)
application_mock.assert_called_once_with([package_ahriman], args.username)
application_mock.assert_called_once_with([package_ahriman], args.username, bump_pkgrel=args.increment)
check_mock.assert_has_calls([MockCall(False, False), MockCall(False, False)])
on_start_mock.assert_called_once_with()

View File

@ -27,6 +27,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
args.dependencies = True
args.dry_run = False
args.exit_code = False
args.increment = True
args.aur = True
args.local = True
args.manual = True
@ -55,7 +56,8 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
Update.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with([package_ahriman],
Packagers(args.username, {package_ahriman.base: "packager"}))
Packagers(args.username, {package_ahriman.base: "packager"}),
bump_pkgrel=args.increment)
updates_mock.assert_called_once_with(args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs)
dependencies_mock.assert_called_once_with([package_ahriman], process_dependencies=args.dependencies)
check_mock.assert_has_calls([MockCall(False, False), MockCall(False, False)])

View File

@ -18,6 +18,32 @@ def test_init(task_ahriman: Task, database: SQLite, mocker: MockerFixture) -> No
"""
must copy tree instead of fetch
"""
mocker.patch("ahriman.models.package.Package.from_build", return_value=task_ahriman.package)
load_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.load")
task_ahriman.init(Path("ahriman"), database)
task_ahriman.init(Path("ahriman"), database, None)
load_mock.assert_called_once_with(Path("ahriman"), task_ahriman.package, [], task_ahriman.paths)
def test_init_bump_pkgrel(task_ahriman: Task, database: SQLite, mocker: MockerFixture) -> None:
"""
must bump pkgrel if it is same as provided
"""
mocker.patch("ahriman.models.package.Package.from_build", return_value=task_ahriman.package)
mocker.patch("ahriman.core.build_tools.sources.Sources.load")
write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write")
local = Path("ahriman")
task_ahriman.init(local, database, task_ahriman.package.version)
write_mock.assert_called_once_with(local / "PKGBUILD")
def test_init_bump_pkgrel_skip(task_ahriman: Task, database: SQLite, mocker: MockerFixture) -> None:
"""
must keep pkgrel if version is different from provided
"""
mocker.patch("ahriman.models.package.Package.from_build", return_value=task_ahriman.package)
mocker.patch("ahriman.core.build_tools.sources.Sources.load")
write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write")
task_ahriman.init(Path("ahriman"), database, f"2:{task_ahriman.package.version}")
write_mock.assert_not_called()

View File

@ -91,4 +91,4 @@ def task_ahriman(package_ahriman: Package, configuration: Configuration, reposit
Returns:
Task: built task test instance
"""
return Task(package_ahriman, configuration, repository_paths)
return Task(package_ahriman, configuration, "x86_64", repository_paths)

View File

@ -30,22 +30,41 @@ def test_process_build(executor: Executor, package_ahriman: Package, mocker: Moc
"""
must run build process
"""
mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman])
mocker.patch("ahriman.core.build_tools.task.Task.build", return_value=[Path(package_ahriman.base)])
mocker.patch("ahriman.core.build_tools.task.Task.init")
init_mock = 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")
executor.process_build([package_ahriman], Packagers("packager"))
executor.process_build([package_ahriman], Packagers("packager"), bump_pkgrel=False)
init_mock.assert_called_once_with(pytest.helpers.anyvar(int), pytest.helpers.anyvar(int), None)
# must move files (once)
move_mock.assert_called_once_with(Path(package_ahriman.base), executor.paths.packages / package_ahriman.base)
# must update status
status_client_mock.assert_called_once_with(package_ahriman.base)
def test_process_build_bump_pkgrel(executor: Executor, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must run build process and pass current package version to build tools
"""
mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman])
mocker.patch("ahriman.core.build_tools.task.Task.build", return_value=[Path(package_ahriman.base)])
mocker.patch("shutil.move")
mocker.patch("ahriman.core.status.client.Client.set_building")
init_mock = mocker.patch("ahriman.core.build_tools.task.Task.init")
executor.process_build([package_ahriman], Packagers("packager"), bump_pkgrel=True)
init_mock.assert_called_once_with(pytest.helpers.anyvar(int),
pytest.helpers.anyvar(int),
package_ahriman.version)
def test_process_build_failure(executor: Executor, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must run correct process failed builds
"""
mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman])
mocker.patch("ahriman.core.repository.executor.Executor.packages_built")
mocker.patch("ahriman.core.build_tools.task.Task.build", return_value=[Path(package_ahriman.base)])
mocker.patch("ahriman.core.build_tools.task.Task.init")

View File

@ -8,12 +8,12 @@ import subprocess
from pathlib import Path
from pytest_mock import MockerFixture
from typing import Any
from unittest.mock import MagicMock
from unittest.mock import MagicMock, call as MockCall
from ahriman.core.exceptions import BuildError, OptionError, UnsafeRunError
from ahriman.core.util import check_output, check_user, dataclass_view, enum_values, exception_response_text, \
extract_user, filter_json, full_version, package_like, partition, pretty_datetime, pretty_size, safe_filename, \
srcinfo_property, srcinfo_property_list, trim_package, utcnow, walk
extract_user, filter_json, full_version, package_like, parse_version, partition, pretty_datetime, pretty_size, \
safe_filename, srcinfo_property, srcinfo_property_list, trim_package, utcnow, walk
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
from ahriman.models.repository_paths import RepositoryPaths
@ -128,6 +128,15 @@ def test_check_output_failure_exception(mocker: MockerFixture) -> None:
check_output("echo", "hello", exception=exception, logger=logging.getLogger(""))
def test_check_output_empty_line(mocker: MockerFixture) -> None:
"""
must correctly process empty lines in command output
"""
logger_mock = mocker.patch("logging.Logger.debug")
assert check_output("python", "-c", """print(); print("hello")""", logger=logging.getLogger("")) == "\nhello"
logger_mock.assert_has_calls([MockCall(""), MockCall("hello")])
def test_check_user(mocker: MockerFixture) -> None:
"""
must check user correctly
@ -273,6 +282,17 @@ def test_package_like_sig(package_ahriman: Package) -> None:
assert not package_like(sig_file)
def test_parse_version() -> None:
"""
must correctly parse version into components
"""
assert parse_version("1.2.3-4") == (None, "1.2.3", "4")
assert parse_version("5:1.2.3-4") == ("5", "1.2.3", "4")
assert parse_version("1.2.3-4.2") == (None, "1.2.3", "4.2")
assert parse_version("0:1.2.3-4.2") == ("0", "1.2.3", "4.2")
assert parse_version("0:1.2.3-4") == ("0", "1.2.3", "4")
def test_partition() -> None:
"""
must partition list based on predicate

View File

@ -501,6 +501,30 @@ def test_is_outdated_fresh_package(package_ahriman: Package, repository_paths: R
actual_version_mock.assert_not_called()
def test_next_pkgrel(package_ahriman: Package) -> None:
"""
must correctly bump pkgrel
"""
assert package_ahriman.next_pkgrel(package_ahriman.version) == "1.1"
package_ahriman.version = "1.0.0-1.1"
assert package_ahriman.next_pkgrel(package_ahriman.version) == "1.2"
package_ahriman.version = "1.0.0-1.2.1"
assert package_ahriman.next_pkgrel(package_ahriman.version) == "1.2.2"
package_ahriman.version = "1:1.0.0-1"
assert package_ahriman.next_pkgrel("1:1.0.1-1") is None
assert package_ahriman.next_pkgrel("2:1.0.0-1") is None
package_ahriman.version = "1.0.0-1.1"
assert package_ahriman.next_pkgrel("1.0.1-2") is None
assert package_ahriman.next_pkgrel("1.0.0-2") == "2.1"
package_ahriman.version = "1.0.0-2"
assert package_ahriman.next_pkgrel("1.0.0-1.1") is None
def test_build_status_pretty_print(package_ahriman: Package) -> None:
"""
must return string in pretty print function