From c35f0a93613048dc9733c028577409bf527d4a97 Mon Sep 17 00:00:00 2001 From: angus-yxz <138585512+angus-yxz@users.noreply.github.com> Date: Thu, 13 Aug 2026 05:14:11 +0800 Subject: [PATCH 1/2] added exception handling for latest release checking and tests --- app/cli.py | 28 +++++++++++++++++++++------- tests/e2e/test_version.py | 17 +++++++++++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/app/cli.py b/app/cli.py index 941e25c..e0ac230 100644 --- a/app/cli.py +++ b/app/cli.py @@ -23,6 +23,9 @@ def invoke(self, ctx: click.Context) -> None: CONTEXT_SETTINGS = {"max_content_width": 120} +# Bound the release check so the CLI cannot hang on an unresponsive network +LATEST_RELEASE_TIMEOUT_SECONDS = 5 + @click.group( cls=LoggingGroup, @@ -39,14 +42,25 @@ def cli(ctx: click.Context, verbose: bool) -> None: current_version = Version.parse_version_string(__version__) ctx.obj[CliContextKey.VERSION] = current_version - latest_version = ( - requests.get( - "https://github.com/git-mastery/app/releases/latest", allow_redirects=False + + latest_version = None + try: + response = requests.get( + "https://github.com/git-mastery/app/releases/latest", + allow_redirects=False, + timeout=LATEST_RELEASE_TIMEOUT_SECONDS, ) - .headers["Location"] - .rsplit("/", 1)[-1] - ) - if current_version.is_behind(Version.parse_version_string(latest_version)): + # GitHub redirects to the tag of the latest release; without the redirect + # there is no version to compare against + location = response.headers.get("Location") + if location is not None: + latest_version = Version.parse_version_string(location.rsplit("/", 1)[-1]) + except (requests.exceptions.RequestException, ValueError): + latest_version = None + + if latest_version is None: + warn("Unable to verify the latest version release") + elif current_version.is_behind(latest_version): warn( click.style( f"Your version of Git-Mastery app {current_version} is behind the latest version {latest_version}.", diff --git a/tests/e2e/test_version.py b/tests/e2e/test_version.py index bc9d638..11c40d4 100644 --- a/tests/e2e/test_version.py +++ b/tests/e2e/test_version.py @@ -7,3 +7,20 @@ def test_version(runner: BinaryRunner) -> None: res.assert_success() res.assert_stdout_contains("Git-Mastery app is") res.assert_stdout_matches(r"v\d+\.\d+\.\d+") + + +def test_version_unreachable_release_check(runner: BinaryRunner) -> None: + """Commands still succeed when the latest release cannot be fetched.""" + # Route the release check through a closed port so it cannot connect. + # NO_PROXY is cleared because an inherited value would bypass the proxy. + res = runner.run( + ["version"], + env={ + "HTTP_PROXY": "http://127.0.0.1:1", + "HTTPS_PROXY": "http://127.0.0.1:1", + "NO_PROXY": "", + }, + ) + res.assert_success() + res.assert_stdout_contains("Unable to verify the latest version release") + res.assert_stdout_contains("Git-Mastery app is") From 0ed625d930f2a416e6cccc162825627f792d5bab Mon Sep 17 00:00:00 2001 From: angus-yxz <138585512+angus-yxz@users.noreply.github.com> Date: Fri, 14 Aug 2026 17:56:20 +0800 Subject: [PATCH 2/2] Improved error logging, moved log into exception branch --- app/cli.py | 15 +++++++++------ tests/e2e/test_version.py | 17 ----------------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/app/cli.py b/app/cli.py index e0ac230..7eafd3f 100644 --- a/app/cli.py +++ b/app/cli.py @@ -53,14 +53,17 @@ def cli(ctx: click.Context, verbose: bool) -> None: # GitHub redirects to the tag of the latest release; without the redirect # there is no version to compare against location = response.headers.get("Location") - if location is not None: + if location is None: + warn( + "Unable to verify the latest version release: no redirect to the latest " + f"release tag (status {response.status_code})" + ) + else: latest_version = Version.parse_version_string(location.rsplit("/", 1)[-1]) - except (requests.exceptions.RequestException, ValueError): - latest_version = None + except (requests.exceptions.RequestException, ValueError) as e: + warn(f"Unable to verify the latest version release: {e}") - if latest_version is None: - warn("Unable to verify the latest version release") - elif current_version.is_behind(latest_version): + if latest_version is not None and current_version.is_behind(latest_version): warn( click.style( f"Your version of Git-Mastery app {current_version} is behind the latest version {latest_version}.", diff --git a/tests/e2e/test_version.py b/tests/e2e/test_version.py index 11c40d4..bc9d638 100644 --- a/tests/e2e/test_version.py +++ b/tests/e2e/test_version.py @@ -7,20 +7,3 @@ def test_version(runner: BinaryRunner) -> None: res.assert_success() res.assert_stdout_contains("Git-Mastery app is") res.assert_stdout_matches(r"v\d+\.\d+\.\d+") - - -def test_version_unreachable_release_check(runner: BinaryRunner) -> None: - """Commands still succeed when the latest release cannot be fetched.""" - # Route the release check through a closed port so it cannot connect. - # NO_PROXY is cleared because an inherited value would bypass the proxy. - res = runner.run( - ["version"], - env={ - "HTTP_PROXY": "http://127.0.0.1:1", - "HTTPS_PROXY": "http://127.0.0.1:1", - "NO_PROXY": "", - }, - ) - res.assert_success() - res.assert_stdout_contains("Unable to verify the latest version release") - res.assert_stdout_contains("Git-Mastery app is")