Skip to content

Commit

Permalink
LITE-28324 Fix --version check for updates
Browse files Browse the repository at this point in the history
  • Loading branch information
bdjilka committed Aug 7, 2023
1 parent 2528c43 commit f1464fd
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 14 deletions.
42 changes: 39 additions & 3 deletions connect/cli/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
import os
from collections import OrderedDict
from importlib.metadata import entry_points
from distutils.version import StrictVersion

import click
import requests
from packaging.version import InvalidVersion, Version

from connect.cli import get_version
from connect.cli.core.constants import PYPI_JSON_API_URL
from connect.cli.core.constants import DEFAULT_ENDPOINT, PYPI_JSON_API_URL
from connect.cli.core.terminal import console


Expand All @@ -37,6 +38,18 @@ def sort_and_filter_tags(tags, desired_major):
return sorted_tags


def get_last_version_by_major(tags, major):
major = int(major)

while major >= 0:
result = sort_and_filter_tags(tags, str(major))
if result:
return result.popitem()[0]
major -= 1

return None


def get_last_cli_version():
try:
res = requests.get(PYPI_JSON_API_URL)
Expand All @@ -47,14 +60,37 @@ def get_last_cli_version():
pass


def get_connect_version():
try:
response = requests.get(DEFAULT_ENDPOINT)
return response.headers.get('Connect-Version')
except requests.RequestException:
return


def check_for_updates(*args):
connect_version = get_connect_version()
if not connect_version:
return

current = get_version()
last_version = get_last_cli_version()
last_version = None
try:
res = requests.get(PYPI_JSON_API_URL)
if res.status_code == 200:
data = res.json()
last_version = get_last_version_by_major(
data['releases'],
connect_version.split('.', 1)[0],
)
except requests.RequestException:
return

if last_version and last_version != current:
console.echo()
console.secho(
f'You are running CloudBlue Connect CLI version {current}. '
f'A newer version is available: {last_version}',
f'Suggested latest version for used Connect version: {last_version}',
fg='yellow',
)
console.echo()
Expand Down
3 changes: 2 additions & 1 deletion connect/cli/plugins/project/extension/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from connect.cli.plugins.project.extension.utils import (
get_event_definitions,
get_pypi_runner_version,
get_pypi_runner_version_by_connect_version,
initialize_git_repository,
)
from connect.cli.plugins.project.extension.wizard import (
Expand Down Expand Up @@ -244,7 +245,7 @@ def bump_runner_extension_project(project_dir: str): # noqa: CCR001
console.secho(f'Bumping runner version on project {project_dir}...\n', fg='blue')

updated_files = set()
latest_version = get_pypi_runner_version()
latest_version = get_pypi_runner_version_by_connect_version()
latest_runner_version = f'cloudblueconnect/connect-extension-runner:{latest_version}'
docker_compose_file = os.path.join(project_dir, 'docker-compose.yml')
if not os.path.isfile(docker_compose_file):
Expand Down
18 changes: 17 additions & 1 deletion connect/cli/plugins/project/extension/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
from connect.client import ClientError

from connect.cli import get_version
from connect.cli.core.utils import sort_and_filter_tags
from connect.cli.core.utils import (
get_connect_version,
get_last_version_by_major,
sort_and_filter_tags,
)
from connect.cli.plugins.project.extension.constants import (
PRE_COMMIT_HOOK,
PYPI_EXTENSION_RUNNER_URL,
Expand All @@ -34,6 +38,18 @@ def get_pypi_runner_version():
return content['info']['version']


def get_pypi_runner_version_by_connect_version():
connect_version = get_connect_version()
res = requests.get(PYPI_EXTENSION_RUNNER_URL)
if res.status_code != 200 or not connect_version:
raise ClickException(
f'We can not retrieve the current connect-extension-runner version from {PYPI_EXTENSION_RUNNER_URL}.',
)
content = res.json()
version = get_last_version_by_major(content['releases'], connect_version.split('.', 1)[0])
return version or content['info']['version']


def get_extension_types(config):
if config.active.is_provider():
extension_types = [('hub', 'Hub integration')]
Expand Down
128 changes: 122 additions & 6 deletions tests/core/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,142 @@
from requests import RequestException

from connect.cli.core import utils
from connect.cli.core.constants import PYPI_JSON_API_URL
from connect.cli.core.constants import DEFAULT_ENDPOINT, PYPI_JSON_API_URL
from connect.cli.core.utils import iter_entry_points, sort_and_filter_tags


def test_check_for_updates_ok(mocker, capsys, mocked_responses):
mocker.patch('connect.cli.core.utils.get_version', return_value='1.0.0')
mocked_responses.add('GET', PYPI_JSON_API_URL, json={'info': {'version': '2.0.0'}})
mocked_responses.add(
'GET',
DEFAULT_ENDPOINT,
status=401,
headers={'Connect-Version': '2.0.1-abc'},
)
mocked_responses.add(
'GET',
PYPI_JSON_API_URL,
json={
'releases': {
'1.6.0': ['release info'],
'1.7.1': ['release info'],
'2.0.0': ['release info'],
'2.1.0': ['release info'],
'2.1.1': ['release info'],
},
},
)

utils.check_for_updates()

captured = capsys.readouterr()

assert 'You are running CloudBlue Connect CLI version 1.0.0. ' in captured.out
assert 'A newer version is available: 2.0.0' in captured.out
assert 'Suggested latest version for used Connect version: 2.1.1' in captured.out


def test_check_for_updates_is_latest(mocker, capsys, mocked_responses):
mocker.patch('connect.cli.core.utils.get_version', return_value='2.0.0')
mocked_responses.add('GET', PYPI_JSON_API_URL, json={'info': {'version': '2.0.0'}})
mocked_responses.add(
'GET',
DEFAULT_ENDPOINT,
status=401,
headers={'Connect-Version': '2.0.1-abc'},
)
mocked_responses.add(
'GET',
PYPI_JSON_API_URL,
json={
'releases': {
'2.0.0': ['release info'],
},
},
)

utils.check_for_updates()

captured = capsys.readouterr()

assert 'Suggested latest version' not in captured.out


def test_check_for_updates_no_update_needed(mocker, capsys, mocked_responses):
mocker.patch('connect.cli.core.utils.get_version', return_value='2.0.0')
mocked_responses.add(
'GET',
DEFAULT_ENDPOINT,
status=401,
headers={'Connect-Version': '3.0.1-abc'},
)
mocked_responses.add(
'GET',
PYPI_JSON_API_URL,
json={
'releases': {
'2.0.0': ['release info'],
},
},
)

utils.check_for_updates()

captured = capsys.readouterr()

assert 'Suggested latest version' not in captured.out


def test_check_for_updates_need_downgrade(mocker, capsys, mocked_responses):
mocker.patch('connect.cli.core.utils.get_version', return_value='4.0.0')
mocked_responses.add(
'GET',
DEFAULT_ENDPOINT,
status=401,
headers={'Connect-Version': '2.2.1-abc'},
)
mocked_responses.add(
'GET',
PYPI_JSON_API_URL,
json={
'releases': {
'4.1.0': ['release info'],
'3.0.0': ['release info'],
'2.1.1': ['release info'],
},
},
)

utils.check_for_updates()

captured = capsys.readouterr()

assert 'You are running CloudBlue Connect CLI version 1.0.0. ' not in captured.out
assert 'A newer version is available: 2.0.0' not in captured.out
assert 'You are running CloudBlue Connect CLI version 4.0.0. ' in captured.out
assert 'Suggested latest version for used Connect version: 2.1.1' in captured.out


def test_check_for_updates_no_matching_version_downgrade(mocker, capsys, mocked_responses):
mocker.patch('connect.cli.core.utils.get_version', return_value='4.0.0')
mocked_responses.add(
'GET',
DEFAULT_ENDPOINT,
status=401,
headers={'Connect-Version': '2.2.1-abc'},
)
mocked_responses.add(
'GET',
PYPI_JSON_API_URL,
json={
'releases': {
'3.0.0': ['release info'],
'1.1.1': ['release info'],
},
},
)

utils.check_for_updates()

captured = capsys.readouterr()

assert 'Suggested latest version for used Connect version: 1.1.1' in captured.out


def test_check_for_updates_exception(mocker, capsys, mocked_responses):
Expand All @@ -46,6 +156,12 @@ def test_check_for_updates_exception(mocker, capsys, mocked_responses):

def test_check_for_updates_invalid_response(mocker, capsys, mocked_responses):
mocker.patch('connect.cli.core.utils.get_version', return_value='1.0.0')
mocked_responses.add(
'GET',
DEFAULT_ENDPOINT,
status=401,
headers={'Connect-Version': '3.0.1-abc'},
)
mocked_responses.add('GET', PYPI_JSON_API_URL, status=400)

utils.check_for_updates()
Expand Down
20 changes: 17 additions & 3 deletions tests/plugins/project/test_extension_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from click import ClickException
from flake8.api import legacy as flake8

from connect.cli.core.constants import DEFAULT_ENDPOINT
from connect.cli.plugins.project.extension.constants import PYPI_EXTENSION_RUNNER_URL
from connect.cli.plugins.project.extension.helpers import (
bootstrap_extension_project,
bump_runner_extension_project,
Expand Down Expand Up @@ -890,8 +892,20 @@ def test_bootstrap_extension_project_if_destination_exists(mocker):
assert 'Answers cannot be saved' in str(cv.value)


def test_bump_runner_version(mocker, capsys):
_mock_pypi_version(mocker)
def test_bump_runner_version(mocker, mocked_responses, capsys):
mocker.patch('connect.cli.plugins.project.extension.utils.get_version', return_value='0.5')
mocked_responses.add(
'GET',
DEFAULT_ENDPOINT,
status=401,
headers={'Connect-Version': '1.0.1-abc'},
)
mocked_responses.add(
'GET',
PYPI_EXTENSION_RUNNER_URL,
json={'releases': {'1.0': ['release info']}},
)

with tempfile.TemporaryDirectory() as tmp_data:
project_dir = f'{tmp_data}/project'
os.mkdir(project_dir)
Expand Down Expand Up @@ -1010,7 +1024,7 @@ def test_bump_runner_docker_yaml_error(mocker):

def _mock_pypi_version(mocker):
mocker.patch(
'connect.cli.plugins.project.extension.helpers.get_pypi_runner_version',
'connect.cli.plugins.project.extension.helpers.get_pypi_runner_version_by_connect_version',
return_value='1.0',
)

Expand Down

0 comments on commit f1464fd

Please sign in to comment.