Skip to content

Commit

Permalink
Change: Refactor pontos-release sign and release CLI
Browse files Browse the repository at this point in the history
Use new base command classes and print errors to stderr now.
  • Loading branch information
bjoernricks committed Jul 26, 2023
1 parent c70b819 commit bb8e788
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 63 deletions.
3 changes: 2 additions & 1 deletion pontos/release/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ def main(
with term.indent():
try:
retval = parsed_args.func(
term,
parsed_args,
terminal=term,
error_terminal=error_terminal,
username=username,
token=token,
)
Expand Down
66 changes: 30 additions & 36 deletions pontos/release/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

import asyncio
from argparse import Namespace
from dataclasses import dataclass
from enum import IntEnum, auto
Expand All @@ -30,6 +29,7 @@
from pontos.git import Git
from pontos.github.actions.core import ActionIO
from pontos.github.api import GitHubAsyncRESTApi
from pontos.release.command import AsyncCommand
from pontos.terminal import Terminal
from pontos.version import Version, VersionCalculator, VersionError
from pontos.version.helper import get_last_release_version
Expand Down Expand Up @@ -72,17 +72,17 @@ class ReleaseReturnValue(IntEnum):
UPDATE_VERSION_AFTER_RELEASE_ERROR = auto()


class ReleaseCommand:
class ReleaseCommand(AsyncCommand):
"""
A CLI command for creating a release
Args:
terminal: A Terminal for output
"""

def __init__(self, terminal: Terminal) -> None:
def __init__(self, *, terminal: Terminal, error_terminal: Terminal) -> None:
super().__init__(terminal=terminal, error_terminal=error_terminal)
self.git = Git()
self.terminal = terminal

def _get_next_release_version(
self,
Expand Down Expand Up @@ -162,7 +162,7 @@ async def _create_release(
prerelease=release_version.is_pre_release,
)

async def run(
async def async_run(
self,
*,
token: str,
Expand Down Expand Up @@ -234,13 +234,11 @@ async def run(
)
except PontosError as e:
last_release_version = None
self.terminal.warning(
f"Could not determine last release version. {e}"
)
self.print_warning(f"Could not determine last release version. {e}")

if not last_release_version:
if not release_version:
self.terminal.error("Unable to determine last release version.")
self.print_error("Unable to determine last release version.")
return ReleaseReturnValue.NO_LAST_RELEASE_VERSION
else:
self.terminal.info(
Expand All @@ -260,24 +258,22 @@ async def run(
release_version=release_version,
)
except VersionError as e:
self.terminal.error(f"Unable to determine release version. {e}")
self.print_error(f"Unable to determine release version. {e}")
return ReleaseReturnValue.NO_RELEASE_VERSION

self.terminal.info(f"Preparing the release {release_version}")

git_version = f"{self.git_tag_prefix}{release_version}"

if self._has_tag(git_version):
self.terminal.error(f"Git tag {git_version} already exists.")
self.print_error(f"Git tag {git_version} already exists.")
return ReleaseReturnValue.ALREADY_TAKEN

if update_project:
try:
project = Project(versioning_scheme)
except PontosError as e:
self.terminal.error(
f"Unable to determine project settings. {e}"
)
self.print_error(f"Unable to determine project settings. {e}")
return ReleaseReturnValue.PROJECT_SETTINGS_NOT_FOUND

try:
Expand Down Expand Up @@ -335,7 +331,7 @@ async def run(

self.terminal.ok(f"Created release {release_version}")
except httpx.HTTPStatusError as e:
self.terminal.error(str(e))
self.print_error(str(e))
return ReleaseReturnValue.CREATE_RELEASE_ERROR

if not next_version:
Expand All @@ -348,7 +344,7 @@ async def run(
f"Updated version after release to {next_version}"
)
except VersionError as e:
self.terminal.error(
self.print_error(
f"Error while updating version after release. {e}"
)
return ReleaseReturnValue.UPDATE_VERSION_AFTER_RELEASE_ERROR
Expand Down Expand Up @@ -387,35 +383,33 @@ async def run(


def release(
terminal: Terminal,
args: Namespace,
*,
token: str,
terminal: Terminal,
error_terminal: Terminal,
**_kwargs,
) -> IntEnum:
if not token:
terminal.error(
error_terminal.error(
"Token is missing. The GitHub token is required to create a "
"release."
)
return ReleaseReturnValue.TOKEN_MISSING

cmd = ReleaseCommand(terminal)
return asyncio.run(
cmd.run(
token=token,
space=args.space,
project=args.project,
versioning_scheme=args.versioning_scheme,
release_type=args.release_type,
release_version=args.release_version,
next_version=args.next_version,
git_remote_name=args.git_remote_name,
git_signing_key=args.git_signing_key,
git_tag_prefix=args.git_tag_prefix,
cc_config=args.cc_config,
local=args.local,
release_series=args.release_series,
update_project=args.update_project,
)
return ReleaseCommand(terminal=terminal, error_terminal=error_terminal).run(
token=token,
space=args.space,
project=args.project,
versioning_scheme=args.versioning_scheme,
release_type=args.release_type,
release_version=args.release_version,
next_version=args.next_version,
git_remote_name=args.git_remote_name,
git_signing_key=args.git_signing_key,
git_tag_prefix=args.git_tag_prefix,
cc_config=args.cc_config,
local=args.local,
release_series=args.release_series,
update_project=args.update_project,
)
48 changes: 22 additions & 26 deletions pontos/release/sign.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
from pontos.git.git import GitError
from pontos.github.api import GitHubAsyncRESTApi
from pontos.helper import AsyncDownloadProgressIterable
from pontos.release.command import AsyncCommand
from pontos.terminal import Terminal
from pontos.terminal.rich import RichTerminal
from pontos.version import Version
from pontos.version.helper import get_last_release_version
from pontos.version.schemes import VersioningScheme
Expand Down Expand Up @@ -70,17 +70,14 @@ async def cmd_runner(*args: Iterable[str]) -> Process:
)


class SignCommand:
class SignCommand(AsyncCommand):
"""
A CLI command for signing a release
Args:
terminal: A Terminal for output
"""

def __init__(self, terminal: RichTerminal) -> None:
self.terminal = terminal

async def _async_download_progress(
self,
rich_progress: RichProgress,
Expand Down Expand Up @@ -186,7 +183,7 @@ async def sign_file(
f"{stderr.decode(errors='replace')}"
)

async def run(
async def async_run(
self,
*,
token: str,
Expand Down Expand Up @@ -224,7 +221,7 @@ async def run(
if not token and not dry_run:
# dry run doesn't upload assets. therefore a token MAY NOT be
# required # for public repositories.
self.terminal.error(
self.print_error(
"Token is missing. The GitHub token is required to upload "
"signature files."
)
Expand All @@ -237,7 +234,7 @@ async def run(
project if project is not None else get_git_repository_name()
)
except GitError as e:
self.terminal.error(f"Could not determine project. {e}")
self.print_error(f"Could not determine project. {e}")
return SignReturnValue.NO_PROJECT

try:
Expand All @@ -253,7 +250,7 @@ async def run(
)
)
except PontosError as e:
self.terminal.error(f"Could not determine release version. {e}")
self.print_error(f"Could not determine release version. {e}")
return SignReturnValue.NO_RELEASE_VERSION

if not release_version:
Expand All @@ -264,7 +261,7 @@ async def run(

async with GitHubAsyncRESTApi(token=token) as github:
if not await github.releases.exists(repo, git_version):
self.terminal.error(
self.print_error(
f"Release version {git_version} does not exist."
)
return SignReturnValue.NO_RELEASE
Expand Down Expand Up @@ -335,7 +332,7 @@ async def run(
except (asyncio.CancelledError, asyncio.InvalidStateError):
pass
except SignatureError as e:
self.terminal.error(e)
self.print_error(e)
has_error = True

for task in pending:
Expand Down Expand Up @@ -367,30 +364,29 @@ async def run(
):
self.terminal.ok(f"Uploaded: {uploaded_file}")
except httpx.HTTPStatusError as e:
self.terminal.error(f"Failed uploading asset {e}.")
self.print_error(f"Failed uploading asset {e}.")
return SignReturnValue.UPLOAD_ASSET_ERROR

return SignReturnValue.SUCCESS


def sign(
terminal: Terminal,
args: Namespace,
*,
terminal: Terminal,
error_terminal: Terminal,
token: str,
**_kwargs,
) -> IntEnum:
return asyncio.run(
SignCommand(terminal).run(
token=token,
dry_run=args.dry_run,
project=args.project,
space=args.space,
versioning_scheme=args.versioning_scheme,
git_tag_prefix=args.git_tag_prefix,
release_version=args.release_version,
signing_key=args.signing_key,
passphrase=args.passphrase,
release_series=args.release_series,
)
return SignCommand(terminal=terminal, error_terminal=error_terminal).run(
token=token,
dry_run=args.dry_run,
project=args.project,
space=args.space,
versioning_scheme=args.versioning_scheme,
git_tag_prefix=args.git_tag_prefix,
release_version=args.release_version,
signing_key=args.signing_key,
passphrase=args.passphrase,
release_series=args.release_series,
)
Loading

0 comments on commit bb8e788

Please sign in to comment.