Verified Commit d9fd8b36 authored by David Runge's avatar David Runge
Browse files

Merge remote-tracking branch 'origin/issues/5'

* origin/issues/5:
  cli: Change default program behavior to iterate over all projects
  argparse: Extend to show version and making project optional
  gitlab: Be explicit during release selection
  Remove hardcoded version string
  config: Raise when there are no project configurations
parents 69a13bcc c6ae77ef
Pipeline #10260 passed with stages
in 52 seconds
import argparse
from importlib import metadata
from sys import exit
class ArgParseFactory:
......@@ -11,14 +13,20 @@ class ArgParseFactory:
"""
def __init__(self, description: str = "default") -> None:
self.parser = argparse.ArgumentParser(description=description)
def __init__(self, prog: str = "program", description: str = "default") -> None:
self.parser = argparse.ArgumentParser(prog=prog, description=description)
self.parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="verbose output",
)
self.parser.add_argument(
"-V",
"--version",
action="store_true",
help="version information",
)
@classmethod
def promote(self) -> argparse.ArgumentParser:
......@@ -30,12 +38,32 @@ class ArgParseFactory:
An ArgumentParser instance specific for promotion
"""
instance = self(description="Download release artifacts from a project and promote them")
instance = self(
prog="arch-release-promotion",
description="Download release artifacts from a project and promote them",
)
instance.parser.add_argument(
"-p",
"--project",
type=self.non_zero_string,
help=(
"the project on a remote to sign (e.g. 'group/project'). "
f"By default {instance.parser.prog} attempts to promote releases for "
"all projects specified in its config"
),
)
instance.parser.add_argument(
"name",
"-r",
"--release",
type=self.non_zero_string,
help="the project on a remote to sign (e.g. 'group/project')",
help=(
"the release of a project to sign (e.g. '0.1.0'). "
f"By default {instance.parser.prog} requires user input to select a release."
),
)
if instance.parser.parse_args().version:
print(f"{instance.parser.prog} {metadata.version('arch_release_promotion')}")
exit(0)
return instance.parser
......@@ -60,5 +88,5 @@ class ArgParseFactory:
"""
if len(input_) < 1:
raise argparse.ArgumentTypeError("the provided project name can not be zero")
raise argparse.ArgumentTypeError("the provided string can not be empty")
return input_
from pathlib import Path
from sys import exit
from typing import Optional
from arch_release_promotion import (
argparse,
......@@ -12,21 +13,30 @@ from arch_release_promotion import (
)
def main() -> None:
args = argparse.ArgParseFactory.promote().parse_args()
project = config.Projects().get_project(name=args.name)
def promote_project_release(project: config.ProjectConfig, release_version: Optional[str] = None) -> None:
"""Promote a project's release
Parameters
----------
project: config.ProjectConfig
The ProjectConfig object that describes the project's configuration
release_version: Optional[str]
The optional release version to promote. If None is provided, interactive user input is required (defaults to
None)
"""
settings = config.Settings()
upstream = gitlab.Upstream(
url=settings.GITLAB_URL,
private_token=settings.PRIVATE_TOKEN,
name=project.name,
)
if settings.PRIVATE_TOKEN:
upstream.auth()
upstream.auth()
release_version = upstream.select_release()
if not release_version:
exit(1)
release_version = upstream.select_release()
if not release_version:
exit(1)
artifact_temp_dir = files.create_temp_dir()
promotion_temp_dir = files.create_temp_dir()
......@@ -97,3 +107,13 @@ def main() -> None:
files.remove_temp_dir(path=artifact_temp_dir)
files.remove_temp_dir(path=promotion_temp_dir)
def main() -> None:
args = argparse.ArgParseFactory.promote().parse_args()
if args.project:
project = config.Projects().get_project(name=args.project)
promote_project_release(project=project, release_version=args.release if args.release else None)
else:
for project in config.Projects().projects:
promote_project_release(project=project)
......@@ -135,6 +135,8 @@ def read_projects_conf(settings: BaseSettings) -> Dict[str, Any]:
if config_files:
config.update(toml.load(config_files))
else:
raise RuntimeError("There are no project configuration files!")
return config
......
......@@ -57,7 +57,7 @@ class Upstream(gitlab.Gitlab):
if release_tags:
selection_string = "".join([f"{index}) {value}\n" for index, value in enumerate(release_tags)])
selection = input(f"Select a release:\n{selection_string}")
selection = input(f"Select a release for {self.name}:\n{selection_string}")
return release_tags[int(selection)]
else:
print("There are no releases to promote!")
......
from argparse import ArgumentParser, ArgumentTypeError
from contextlib import nullcontext as does_not_raise
from typing import ContextManager
from unittest.mock import Mock, call, patch
from pytest import mark, raises
......@@ -11,8 +12,16 @@ def test_argparse_argparsefactory() -> None:
assert isinstance(argparse.ArgParseFactory(), argparse.ArgParseFactory)
def test_argparse_promote() -> None:
assert isinstance(argparse.ArgParseFactory().promote(), ArgumentParser)
@patch("argparse.ArgumentParser.parse_args")
@patch("arch_release_promotion.argparse.exit")
@patch("arch_release_promotion.argparse.metadata")
def test_argparse_promote(metadata_mock: Mock, exit_mock: Mock, parse_args_mock: Mock) -> None:
assert isinstance(argparse.ArgParseFactory.promote(), ArgumentParser)
assert call.version("arch_release_promotion") in metadata_mock.mock_calls
exit_mock.assert_called_once()
parse_args_mock.return_value = Mock(version=False)
assert isinstance(argparse.ArgParseFactory.promote(), ArgumentParser)
@mark.parametrize(
......
......@@ -110,6 +110,12 @@ def test_settings(
False,
[],
"",
raises(RuntimeError),
),
(
True,
[],
"",
raises(ValidationError),
),
],
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment