more options in setup command

This commit is contained in:
Evgenii Alekseev 2021-04-04 15:42:06 +03:00
parent 56c600e5ac
commit ffe6aec190
12 changed files with 75 additions and 47 deletions

View File

@ -41,4 +41,5 @@ command = rsync --archive --verbose --compress --partial --delete
command = aws s3 sync --quiet --delete
[web]
host = 0.0.0.0
templates = /usr/share/ahriman

View File

@ -28,6 +28,8 @@ from ahriman.models.build_status import BuildStatusEnum
# pylint thinks it is bad idea, but get the fuck off
# pylint: disable=protected-access
from ahriman.models.sign_settings import SignSettings
SubParserAction = argparse._SubParsersAction
@ -181,7 +183,11 @@ def _set_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
default="/usr/share/devtools/pacman-extra.conf")
parser.add_argument("--no-multilib", help="do not add multilib repository", action="store_true")
parser.add_argument("--packager", help="packager name and email", required=True)
parser.add_argument("--repository", help="repository name", default="aur-clone")
parser.add_argument("--repository", help="repository name", required=True)
parser.add_argument("--sign-key", help="sign key id")
parser.add_argument("--sign-target", help="sign options",
choices=[sign.name.lower() for sign in SignSettings], nargs="*")
parser.add_argument("--web-port", help="port of the web service", type=int)
parser.set_defaults(handler=handlers.Setup, lock=None, no_report=True, unsafe=True)
return parser

View File

@ -56,7 +56,7 @@ class Setup(Handler):
Setup.create_executable(args.build_command, architecture)
Setup.create_devtools_configuration(args.build_command, architecture, Path(args.from_configuration),
args.no_multilib, args.repository, application.repository.paths)
Setup.create_ahriman_configuration(args.build_command, architecture, args.repository, configuration.include)
Setup.create_ahriman_configuration(args, architecture, args.repository, configuration.include)
Setup.create_sudo_configuration(args.build_command, architecture)
@staticmethod
@ -70,23 +70,36 @@ class Setup(Handler):
return Setup.BIN_DIR_PATH / f"{prefix}-{architecture}-build"
@staticmethod
def create_ahriman_configuration(prefix: str, architecture: str, repository: str, include_path: Path) -> None:
def create_ahriman_configuration(args: argparse.Namespace, architecture: str, repository: str,
include_path: Path) -> None:
"""
create service specific configuration
:param prefix: command prefix in {prefix}-{architecture}-build
:param args: command line args
:param architecture: repository architecture
:param repository: repository name
:param include_path: path to directory with configuration includes
"""
configuration = configparser.ConfigParser()
configuration.add_section("build")
configuration.set("build", "build_command", str(Setup.build_command(prefix, architecture)))
section = Configuration.section_name("build", architecture)
configuration.add_section(section)
configuration.set(section, "build_command", str(Setup.build_command(args.build_command, architecture)))
configuration.add_section("repository")
configuration.set("repository", "name", repository)
target = include_path / "build-overrides.ini"
if args.sign_key is not None:
section = Configuration.section_name("sign", architecture)
configuration.add_section(section)
configuration.set(section, "target", " ".join(args.sign_target))
configuration.set(section, "key", args.sign_key)
if args.web_port is not None:
section = Configuration.section_name("web", architecture)
configuration.add_section(section)
configuration.set(section, "port", str(args.web_port))
target = include_path / "setup-overrides.ini"
with target.open("w") as ahriman_configuration:
configuration.write(ahriman_configuration)

View File

@ -112,8 +112,8 @@ class HTML(Report):
html = template.render(
homepage=self.homepage,
link_path=self.link_path,
has_package_signed=SignSettings.SignPackages in self.sign_targets,
has_repo_signed=SignSettings.SignRepository in self.sign_targets,
has_package_signed=SignSettings.Packages in self.sign_targets,
has_repo_signed=SignSettings.Repository in self.sign_targets,
packages=sorted(content, key=comparator),
pgp_key=self.default_pgp_key,
repository=self.name)

View File

@ -56,7 +56,7 @@ class GPG:
"""
:return: command line arguments for repo-add command to sign database
"""
if SignSettings.SignRepository not in self.targets:
if SignSettings.Repository not in self.targets:
return []
if self.default_key is None:
self.logger.error("no default key set, skip repository sign")
@ -107,7 +107,7 @@ class GPG:
:param base: package base required to check for key overrides
:return: list of generated files including original file
"""
if SignSettings.SignPackages not in self.targets:
if SignSettings.Packages not in self.targets:
return [path]
key = self.configuration.get("sign", f"key_{base}", fallback=self.default_key)
if key is None:
@ -122,7 +122,7 @@ class GPG:
:param path: path to repository database
:return: list of generated files including original file
"""
if SignSettings.SignRepository not in self.targets:
if SignSettings.Repository not in self.targets:
return [path]
if self.default_key is None:
self.logger.error("no default key set, skip repository sign")

View File

@ -28,12 +28,12 @@ from ahriman.core.exceptions import InvalidOption
class SignSettings(Enum):
"""
sign targets enumeration
:cvar SignPackages: sign each package
:cvar SignRepository: sign repository database file
:cvar Packages: sign each package
:cvar Repository: sign repository database file
"""
SignPackages = auto()
SignRepository = auto()
Packages = auto()
Repository = auto()
@classmethod
def from_option(cls: Type[SignSettings], value: str) -> SignSettings:
@ -43,7 +43,7 @@ class SignSettings(Enum):
:return: parsed value
"""
if value.lower() in ("package", "packages", "sign-package"):
return cls.SignPackages
return cls.Packages
if value.lower() in ("repository", "sign-repository"):
return cls.SignRepository
return cls.Repository
raise InvalidOption(value)

View File

@ -15,6 +15,9 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
args.no_multilib = False
args.packager = "John Doe <john@doe.com>"
args.repository = "aur-clone"
args.sign_key = "key"
args.sign_target = ["packages"]
args.web_port = 8080
return args
@ -58,14 +61,19 @@ def test_create_ahriman_configuration(args: argparse.Namespace, configuration: C
write_mock = mocker.patch("configparser.RawConfigParser.write")
command = Setup.build_command(args.build_command, "x86_64")
Setup.create_ahriman_configuration(args.build_command, "x86_64", args.repository, configuration.include)
Setup.create_ahriman_configuration(args, "x86_64", args.repository, configuration.include)
add_section_mock.assert_has_calls([
mock.call("build"),
mock.call(Configuration.section_name("build", "x86_64")),
mock.call("repository"),
mock.call(Configuration.section_name("sign", "x86_64")),
mock.call(Configuration.section_name("web", "x86_64")),
])
set_mock.assert_has_calls([
mock.call("build", "build_command", str(command)),
mock.call(Configuration.section_name("build", "x86_64"), "build_command", str(command)),
mock.call("repository", "name", args.repository),
mock.call(Configuration.section_name("sign", "x86_64"), "target", " ".join(args.sign_target)),
mock.call(Configuration.section_name("sign", "x86_64"), "key", args.sign_key),
mock.call(Configuration.section_name("web", "x86_64"), "port", str(args.web_port)),
])
write_mock.assert_called_once()

View File

@ -52,7 +52,8 @@ def test_subparsers_setup(parser: argparse.ArgumentParser) -> None:
"""
setup command must imply lock, no_report and unsafe
"""
args = parser.parse_args(["-a", "x86_64", "setup", "--packager", "John Doe <john@doe.com>"])
args = parser.parse_args(["-a", "x86_64", "setup", "--packager", "John Doe <john@doe.com>",
"--repository", "aur-clone"])
assert args.lock is None
assert args.no_report
assert args.unsafe

View File

@ -9,7 +9,7 @@ def test_repository_sign_args_1(gpg_with_key: GPG) -> None:
"""
must generate correct sign args
"""
gpg_with_key.targets = {SignSettings.SignRepository}
gpg_with_key.targets = {SignSettings.Repository}
assert gpg_with_key.repository_sign_args
@ -17,7 +17,7 @@ def test_repository_sign_args_2(gpg_with_key: GPG) -> None:
"""
must generate correct sign args
"""
gpg_with_key.targets = {SignSettings.SignPackages, SignSettings.SignRepository}
gpg_with_key.targets = {SignSettings.Packages, SignSettings.Repository}
assert gpg_with_key.repository_sign_args
@ -33,7 +33,7 @@ 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.SignPackages}
gpg_with_key.targets = {SignSettings.Packages}
assert not gpg_with_key.repository_sign_args
@ -41,7 +41,7 @@ def test_repository_sign_args_skip_3(gpg: GPG) -> None:
"""
must return empty args if it is not set
"""
gpg.targets = {SignSettings.SignRepository}
gpg.targets = {SignSettings.Repository}
assert not gpg.repository_sign_args
@ -49,7 +49,7 @@ def test_repository_sign_args_skip_4(gpg: GPG) -> None:
"""
must return empty args if it is not set
"""
gpg.targets = {SignSettings.SignPackages, SignSettings.SignRepository}
gpg.targets = {SignSettings.Packages, SignSettings.Repository}
assert not gpg.repository_sign_args
@ -78,7 +78,7 @@ def test_sign_package_1(gpg_with_key: GPG, mocker: MockerFixture) -> None:
result = [Path("a"), Path("a.sig")]
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process", return_value=result)
gpg_with_key.targets = {SignSettings.SignPackages}
gpg_with_key.targets = {SignSettings.Packages}
assert gpg_with_key.sign_package(Path("a"), "a") == result
process_mock.assert_called_once()
@ -90,7 +90,7 @@ def test_sign_package_2(gpg_with_key: GPG, mocker: MockerFixture) -> None:
result = [Path("a"), Path("a.sig")]
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process", return_value=result)
gpg_with_key.targets = {SignSettings.SignPackages, SignSettings.SignRepository}
gpg_with_key.targets = {SignSettings.Packages, SignSettings.Repository}
assert gpg_with_key.sign_package(Path("a"), "a") == result
process_mock.assert_called_once()
@ -110,7 +110,7 @@ def test_sign_package_skip_2(gpg_with_key: GPG, mocker: MockerFixture) -> None:
must not sign package if it is not set
"""
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
gpg_with_key.targets = {SignSettings.SignRepository}
gpg_with_key.targets = {SignSettings.Repository}
gpg_with_key.sign_package(Path("a"), "a")
process_mock.assert_not_called()
@ -120,7 +120,7 @@ def test_sign_package_skip_3(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.SignPackages}
gpg.targets = {SignSettings.Packages}
gpg.sign_package(Path("a"), "a")
process_mock.assert_not_called()
@ -130,7 +130,7 @@ def test_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.SignPackages, SignSettings.SignRepository}
gpg.targets = {SignSettings.Packages, SignSettings.Repository}
gpg.sign_package(Path("a"), "a")
process_mock.assert_not_called()
@ -142,7 +142,7 @@ def test_sign_repository_1(gpg_with_key: GPG, mocker: MockerFixture) -> None:
result = [Path("a"), Path("a.sig")]
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process", return_value=result)
gpg_with_key.targets = {SignSettings.SignRepository}
gpg_with_key.targets = {SignSettings.Repository}
assert gpg_with_key.sign_repository(Path("a")) == result
process_mock.assert_called_once()
@ -154,7 +154,7 @@ def test_sign_repository_2(gpg_with_key: GPG, mocker: MockerFixture) -> None:
result = [Path("a"), Path("a.sig")]
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process", return_value=result)
gpg_with_key.targets = {SignSettings.SignPackages, SignSettings.SignRepository}
gpg_with_key.targets = {SignSettings.Packages, SignSettings.Repository}
assert gpg_with_key.sign_repository(Path("a")) == result
process_mock.assert_called_once()
@ -174,7 +174,7 @@ def test_sign_repository_skip_2(gpg_with_key: GPG, mocker: MockerFixture) -> Non
must not sign repository if it is not set
"""
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
gpg_with_key.targets = {SignSettings.SignPackages}
gpg_with_key.targets = {SignSettings.Packages}
gpg_with_key.sign_repository(Path("a"))
process_mock.assert_not_called()
@ -184,7 +184,7 @@ def test_sign_repository_skip_3(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.SignRepository}
gpg.targets = {SignSettings.Repository}
gpg.sign_repository(Path("a"))
process_mock.assert_not_called()
@ -194,6 +194,6 @@ def test_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.SignPackages, SignSettings.SignRepository}
gpg.targets = {SignSettings.Packages, SignSettings.Repository}
gpg.sign_repository(Path("a"))
process_mock.assert_not_called()

View File

@ -16,11 +16,11 @@ def test_from_option_valid() -> None:
"""
must return value from valid options
"""
assert SignSettings.from_option("package") == SignSettings.SignPackages
assert SignSettings.from_option("PACKAGE") == SignSettings.SignPackages
assert SignSettings.from_option("packages") == SignSettings.SignPackages
assert SignSettings.from_option("sign-package") == SignSettings.SignPackages
assert SignSettings.from_option("package") == SignSettings.Packages
assert SignSettings.from_option("PACKAGE") == SignSettings.Packages
assert SignSettings.from_option("packages") == SignSettings.Packages
assert SignSettings.from_option("sign-package") == SignSettings.Packages
assert SignSettings.from_option("repository") == SignSettings.SignRepository
assert SignSettings.from_option("REPOSITORY") == SignSettings.SignRepository
assert SignSettings.from_option("sign-repository") == SignSettings.SignRepository
assert SignSettings.from_option("repository") == SignSettings.Repository
assert SignSettings.from_option("REPOSITORY") == SignSettings.Repository
assert SignSettings.from_option("sign-repository") == SignSettings.Repository

View File

@ -34,12 +34,10 @@ def test_run(application: web.Application, mocker: MockerFixture) -> None:
"""
must run application
"""
host = "localhost"
port = 8080
application["configuration"].set("web", "host", host)
application["configuration"].set("web", "port", str(port))
run_application_mock = mocker.patch("aiohttp.web.run_app")
run_server(application)
run_application_mock.assert_called_with(application, host=host, port=port,
run_application_mock.assert_called_with(application, host="0.0.0.0", port=port,
handle_signals=False, access_log=pytest.helpers.anyvar(int))

View File

@ -43,4 +43,5 @@ bucket =
command = aws s3 sync --quiet --delete
[web]
host = 0.0.0.0
templates = ../web/templates