Skip to content

Commit

Permalink
Fix: Update and fix pontos-version CLI
Browse files Browse the repository at this point in the history
`pontos-version` got broken due to refactoring in the version handling.
This changes fixes the CLI and adds tests to ensure that it works as
expected in future too.
  • Loading branch information
bjoernricks committed Mar 3, 2023
1 parent e825027 commit cb2e179
Show file tree
Hide file tree
Showing 5 changed files with 257 additions and 58 deletions.
45 changes: 2 additions & 43 deletions pontos/version/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,47 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import sys
from typing import NoReturn
from .main import main

from pontos.errors import PontosError
from pontos.version.project import Project

from .__version__ import __version__
from .errors import VersionError
from .parser import initialize_default_parser


def main() -> NoReturn:
parser = initialize_default_parser()

args = parser.parse_args()

if not getattr(args, "command"):
parser.print_usage()
sys.exit(1)

try:
project = Project.gather_project()
except PontosError:
print("No project found.", file=sys.stderr)
sys.exit(1)

try:
if args.command == "update":
updated = project.update_version(args.version, force=args.force)
if updated:
print(
f"Updated version from {updated.previous} to {updated.new}."
)
else:
print("Version is already up-to-date.")
elif args.command == "show":
print(project.get_current_version())
elif args.command == "verify":
project.verify_version(args.version)
except VersionError as e:
print(str(e), file=sys.stderr)
sys.exit(1)

sys.exit(0)
__all__ = ("main",)
4 changes: 2 additions & 2 deletions pontos/version/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

# pylint: disable=invalid-name

from pontos import version
from .main import main

if __name__ == "__main__":
version.main()
main()
74 changes: 74 additions & 0 deletions pontos/version/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Copyright (C) 2020-2022 Greenbone Networks GmbH
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# 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/>.

import sys
from enum import IntEnum, auto
from typing import List, NoReturn, Optional

from pontos.errors import PontosError

from .__version__ import __version__
from .parser import initialize_default_parser
from .project import Project


class VersionExitCode(IntEnum):
SUCCESS = 0
NO_PROJECT = auto()
UPDATE_ERROR = auto()
CURRENT_VERSION_ERROR = auto()
VERIFY_ERROR = auto()


def main(args: Optional[List[str]] = None) -> NoReturn:
parser = initialize_default_parser()

parsed_args = parser.parse_args(args)

try:
project = Project.gather_project()
except PontosError:
print("No project found.", file=sys.stderr)
sys.exit(VersionExitCode.NO_PROJECT)

if parsed_args.command == "update":
try:
update = project.update_version(
parsed_args.version, force=parsed_args.force
)
except PontosError as e:
print(str(e), file=sys.stderr)
sys.exit(VersionExitCode.UPDATE_ERROR)

if update.new == update.previous:
print("Version is already up-to-date.")
else:
print(f"Updated version from {update.previous} to {update.new}.")
elif parsed_args.command == "show":
try:
print(str(project.get_current_version()))
except PontosError as e:
print(str(e), file=sys.stderr)
sys.exit(VersionExitCode.CURRENT_VERSION_ERROR)
elif parsed_args.command == "verify":
try:
project.verify_version(parsed_args.version)
except PontosError as e:
print(str(e), file=sys.stderr)
sys.exit(VersionExitCode.VERIFY_ERROR)

sys.exit(VersionExitCode.SUCCESS)
33 changes: 20 additions & 13 deletions pontos/version/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import argparse
from typing import Literal, Union

from pontos.version.version import Version, parse_version


def verify_version_type(version: str) -> Union[Version, Literal["current"]]:
if version == "current":
return version

return parse_version(version)


def initialize_default_parser() -> argparse.ArgumentParser:
Expand All @@ -29,31 +39,28 @@ def initialize_default_parser() -> argparse.ArgumentParser:
description="Version handling utilities.",
prog="version",
)
parser.add_argument(
"--quiet", help="don't print messages", action="store_true"
)

subparsers = parser.add_subparsers(
title="subcommands",
description="valid subcommands",
help="additional help",
description="Valid subcommands",
help="Additional help",
dest="command",
required=True,
)

verify_parser = subparsers.add_parser("verify")
verify_parser.add_argument("version", help="version string to compare")
verify_parser.add_argument(
"version", help="Version string to compare", type=verify_version_type
)
subparsers.add_parser("show")

update_parser = subparsers.add_parser("update")
update_parser.add_argument("version", help="version string to use")
update_parser.add_argument(
"--force",
help="don't check if version is already set",
action="store_true",
"version", help="Version string to use", type=parse_version
)
update_parser.add_argument(
"--develop",
help="indicates if it is a develop version",
"--force",
help="Don't check if version is already set. "
"This will override existing version information!",
action="store_true",
)
return parser
159 changes: 159 additions & 0 deletions tests/version/test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# Copyright (C) 2023 Greenbone Networks GmbH
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# 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/>.

import unittest
from contextlib import redirect_stderr, redirect_stdout
from io import StringIO

from pontos.testing import temp_directory
from pontos.version.main import VersionExitCode, main


class MainTestCase(unittest.TestCase):
def test_no_command(self):
with self.assertRaises(SystemExit), redirect_stderr(StringIO()):
main([])

def test_no_project(self):
with temp_directory(change_into=True), self.assertRaises(
SystemExit
) as cm, redirect_stderr(StringIO()):
main(["show"])

self.assertEqual(cm.exception.code, VersionExitCode.NO_PROJECT)

def test_update_success(self):
with temp_directory(change_into=True) as temp_dir, redirect_stdout(
StringIO()
) as out, self.assertRaises(SystemExit) as cm:
version_file = temp_dir / "package.json"
version_file.write_text(
'{"name": "foo", "version": "1.2.3"}',
encoding="utf8",
)
main(["update", "2.0.0"])

self.assertEqual(
out.getvalue(), "Updated version from 1.2.3 to 2.0.0.\n"
)

self.assertEqual(cm.exception.code, VersionExitCode.SUCCESS)

def test_update_failure(self):
with temp_directory(change_into=True) as temp_dir, redirect_stderr(
StringIO()
), self.assertRaises(SystemExit) as cm:
version_file = temp_dir / "package.json"
version_file.write_text(
"{}",
encoding="utf8",
)
main(["update", "2.0.0"])

self.assertEqual(cm.exception.code, VersionExitCode.UPDATE_ERROR)

def test_update_already_up_to_date(self):
with temp_directory(change_into=True) as temp_dir, redirect_stdout(
StringIO()
) as out, self.assertRaises(SystemExit) as cm:
version_file = temp_dir / "package.json"
version_file.write_text(
'{"name": "foo", "version": "1.2.3"}',
encoding="utf8",
)
main(["update", "1.2.3"])

self.assertEqual(out.getvalue(), "Version is already up-to-date.\n")

self.assertEqual(cm.exception.code, VersionExitCode.SUCCESS)

def test_show(self):
with temp_directory(change_into=True) as temp_dir, redirect_stdout(
StringIO()
) as out, self.assertRaises(SystemExit) as cm:
version_file = temp_dir / "package.json"
version_file.write_text(
'{"name": "foo", "version": "1.2.3"}',
encoding="utf8",
)
main(["show"])

self.assertEqual(out.getvalue(), "1.2.3\n")

self.assertEqual(cm.exception.code, VersionExitCode.SUCCESS)

def test_show_error(self):
with temp_directory(change_into=True) as temp_dir, redirect_stderr(
StringIO()
) as out, self.assertRaises(SystemExit) as cm:
version_file = temp_dir / "package.json"
version_file.write_text(
'{"name": "foo", "version": "abc"}',
encoding="utf8",
)
main(["show"])

self.assertEqual(out.getvalue(), "Invalid version: 'abc'\n")

self.assertEqual(
cm.exception.code, VersionExitCode.CURRENT_VERSION_ERROR
)

def test_verify_failure(self):
with temp_directory(change_into=True) as temp_dir, redirect_stderr(
StringIO()
) as out, self.assertRaises(SystemExit) as cm:
version_file = temp_dir / "package.json"
version_file.write_text(
'{"name": "foo", "version": "1.2.3"}',
encoding="utf8",
)
main(["verify", "1.2.4"])

self.assertEqual(
out.getvalue(),
"Provided version 1.2.4 does not match the current version "
f"1.2.3 in {version_file}.\n",
)

self.assertEqual(cm.exception.code, VersionExitCode.VERIFY_ERROR)

def test_verify_success(self):
with temp_directory(change_into=True) as temp_dir, self.assertRaises(
SystemExit
) as cm:
version_file = temp_dir / "package.json"
version_file.write_text(
'{"name": "foo", "version": "1.2.3"}',
encoding="utf8",
)
main(["verify", "1.2.3"])

self.assertEqual(cm.exception.code, VersionExitCode.SUCCESS)

def test_verify_current(self):
with temp_directory(change_into=True) as temp_dir, self.assertRaises(
SystemExit
) as cm:
version_file = temp_dir / "package.json"
version_file.write_text(
'{"name": "foo", "version": "1.2.3"}',
encoding="utf8",
)
main(["verify", "current"])

self.assertEqual(cm.exception.code, VersionExitCode.SUCCESS)

0 comments on commit cb2e179

Please sign in to comment.