Repository: zulip/zulip-terminal
Pull request #1285 (2023-01-11 00:17:27)

Show detected platform on startup and during CI
<!-- Please see https://github.com/zulip/zulip-terminal#contributor-guidelines ! -->

**What does this PR do?**  <!-- Overall description goes here -->

This outputs the platform we detect, before ZT starts. The benefit of this is that it is clear if the platform is unsupported, and also should form part of the feedback we receive from users in bug reports.

This also checks the detected platform during CI, to ensure we test code paths there, as far as we can.

<!-- Add a link to a discussion on chat.zulip.org, if relevant -->

**Tested?** <!-- Fine to leave some of these unchecked if this is a draft/work-in-progress -->
- [X] Manually **via lint-and-test adjustment, for Linux and MacOS only**
- [X] Existing tests (adapted, if necessary)
- [X] New tests added (for any new behavior) **essentially via CI, by lint-and-test**
- [X] Passed linting & tests (each commit)
<!-- Code must pass CI (GitHub Actions) before merging - look for the green tick! -->

**Notes & Questions (maybe further work)** <!-- if any; add/delete/fill-in as appropriate -->
- We could output an additional warning if it is unsupported, but this is a good first step to aid in helping users.
- We don't currently test on WSL to ensure we detect that correctly, or on some other unsupported platform to ensure it's flagged too.


Patch:
diff --git a/zulipterminal/cli/run.py b/zulipterminal/cli/run.py
index 25343dd..20d3dd3 100755
--- a/zulipterminal/cli/run.py
+++ b/zulipterminal/cli/run.py
@@ -24,6 +24,7 @@ from zulipterminal.config.themes import (
 )
 from zulipterminal.core import Controller
 from zulipterminal.model import ServerConnectionFailure
+from zulipterminal.platform_code import detected_platform
 from zulipterminal.version import ZT_VERSION
 
 
@@ -380,6 +381,8 @@ def main(options: Optional[List[str]] = None) -> None:
     else:
         zuliprc_path = "~/zuliprc"
 
+    print(f"Detected platform: {detected_platform()}")
+
     try:
         zterm = parse_zuliprc(zuliprc_path)
 
diff --git a/zulipterminal/platform_code.py b/zulipterminal/platform_code.py
index a2c0d74..856661a 100644
--- a/zulipterminal/platform_code.py
+++ b/zulipterminal/platform_code.py
@@ -28,6 +28,10 @@ else:
 MOUSE_SELECTION_KEY = "Fn + Alt" if PLATFORM == "MacOS" else "Shift"
 
 
+def detected_platform() -> str:
+    return PLATFORM
+
+
 def notify(title: str, text: str) -> str:
     command_list = None
     if PLATFORM == "MacOS":


Test patch:
diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml
index 28d5282..3f24dd5 100644
--- a/.github/workflows/lint-and-test.yml
+++ b/.github/workflows/lint-and-test.yml
@@ -123,16 +123,18 @@ jobs:
       fail-fast: false
       matrix:
         env:
-          - {PYTHON: 3.7, OS: ubuntu-latest, NAME: "CPython 3.7 (ubuntu)"}
-          - {PYTHON: 3.8, OS: ubuntu-latest, NAME: "CPython 3.8 (ubuntu)"}
-          - {PYTHON: 3.9, OS: ubuntu-latest, NAME: "CPython 3.9 (ubuntu)", CODECOV: true}
-          - {PYTHON: "3.10", OS: ubuntu-latest, NAME: "CPython 3.10 (ubuntu)"}
-          - {PYTHON: "3.11", OS: ubuntu-latest, NAME: "CPython 3.11 (ubuntu)"}
-          - {PYTHON: 'pypy-3.6', OS: ubuntu-latest, NAME: "PyPy 3.6 (ubuntu)"}
-          - {PYTHON: 'pypy-3.7', OS: ubuntu-latest, NAME: "PyPy 3.7 (ubuntu)"}
-          - {PYTHON: 'pypy-3.8', OS: ubuntu-latest, NAME: "PyPy 3.8 (ubuntu)"}
-          - {PYTHON: 'pypy-3.9', OS: ubuntu-latest, NAME: "PyPy 3.9 (ubuntu)"}
-          - {PYTHON: '3.x', OS: macos-latest, NAME: "CPython 3.x [latest] (macos)"}
+          - {PYTHON: 3.7, OS: ubuntu-latest, NAME: "CPython 3.7 (ubuntu)", EXPECT: "Linux"}
+          - {PYTHON: 3.8, OS: ubuntu-latest, NAME: "CPython 3.8 (ubuntu)", EXPECT: "Linux"}
+          - {PYTHON: 3.9, OS: ubuntu-latest, NAME: "CPython 3.9 (ubuntu)", EXPECT: "Linux", CODECOV: true}
+          - {PYTHON: "3.10", OS: ubuntu-latest, NAME: "CPython 3.10 (ubuntu)", EXPECT: "Linux"}
+          - {PYTHON: "3.11", OS: ubuntu-latest, NAME: "CPython 3.11 (ubuntu)", EXPECT: "Linux"}
+          - {PYTHON: 'pypy-3.6', OS: ubuntu-latest, NAME: "PyPy 3.6 (ubuntu)", EXPECT: "Linux"}
+          - {PYTHON: 'pypy-3.7', OS: ubuntu-latest, NAME: "PyPy 3.7 (ubuntu)", EXPECT: "Linux"}
+          - {PYTHON: 'pypy-3.8', OS: ubuntu-latest, NAME: "PyPy 3.8 (ubuntu)", EXPECT: "Linux"}
+          - {PYTHON: 'pypy-3.9', OS: ubuntu-latest, NAME: "PyPy 3.9 (ubuntu)", EXPECT: "Linux"}
+          - {PYTHON: '3.x', OS: macos-latest, NAME: "CPython 3.x [latest] (macos)", EXPECT: "MacOS"}
+    env:
+      EXPECT: ${{ matrix.env.EXPECT }}
     runs-on: ${{ matrix.env.OS }}
     name: Install & test - ${{ matrix.env.NAME}}
     steps:
@@ -154,6 +156,8 @@ jobs:
         run: sudo apt install libxml2-dev libxslt1-dev
       - name: Ensure regular package installs from checkout
         run: pip install .
+      - name: Check we detect the platform correctly
+        run: python -c "from zulipterminal.platform_code import detected_platform; import os; e, d = os.environ['EXPECT'], detected_platform(); assert d == e, f'{d} != {e}'"
       - name: Install test dependencies
         run: pip install .[testing]
       - name: Run tests with pytest
diff --git a/tests/cli/test_run.py b/tests/cli/test_run.py
index 0cece4c..b97e1c9 100644
--- a/tests/cli/test_run.py
+++ b/tests/cli/test_run.py
@@ -117,11 +117,13 @@ def test_valid_zuliprc_but_no_connection(
     mocker: MockerFixture,
     minimal_zuliprc: str,
     server_connection_error: str = "some_error",
+    platform: str = "some_platform",
 ) -> None:
     mocker.patch(
         CONTROLLER + ".__init__",
         side_effect=ServerConnectionFailure(server_connection_error),
     )
+    mocker.patch(MODULE + ".detected_platform", return_value=platform)
 
     with pytest.raises(SystemExit) as e:
         main(["-c", minimal_zuliprc])
@@ -132,6 +134,7 @@ def test_valid_zuliprc_but_no_connection(
 
     lines = captured.out.strip().split("\n")
     expected_lines = [
+        f"Detected platform: {platform}",
         "Loading with:",
         "   theme 'zt_dark' specified with no config.",
         "   autohide setting 'no_autohide' specified with no config.",
@@ -161,11 +164,13 @@ def test_warning_regarding_incomplete_theme(
     expected_complete_incomplete_themes: Tuple[List[str], List[str]],
     expected_warning: str,
     server_connection_error: str = "sce",
+    platform: str = "some_platform",
 ) -> None:
     mocker.patch(
         CONTROLLER + ".__init__",
         side_effect=ServerConnectionFailure(server_connection_error),
     )
+    mocker.patch(MODULE + ".detected_platform", return_value=platform)
     mocker.patch(MODULE + ".all_themes", return_value=("a", "b", "c", "d"))
     mocker.patch(
         MODULE + ".complete_and_incomplete_themes",
@@ -182,6 +187,7 @@ def test_warning_regarding_incomplete_theme(
 
     lines = captured.out.strip().split("\n")
     expected_lines = [
+        f"Detected platform: {platform}",
         "Loading with:",
         f"   theme '{bad_theme}' specified on command line.",
         "\x1b[93m   WARNING: Incomplete theme; results may vary!",
@@ -377,7 +383,10 @@ def test_successful_main_function_with_config(
     config_key: str,
     config_value: str,
     footlinks_output: str,
+    platform: str = "some_platform",
 ) -> None:
+    mocker.patch(MODULE + ".detected_platform", return_value=platform)
+
     config = {
         "theme": "default",
         "autohide": "autohide",
@@ -395,6 +404,7 @@ def test_successful_main_function_with_config(
     captured = capsys.readouterr()
     lines = captured.out.strip().split("\n")
     expected_lines = [
+        f"Detected platform: {platform}",
         "Loading with:",
         "   theme 'zt_dark' specified in zuliprc file (by alias 'default').",
         "   autohide setting 'autohide' specified in zuliprc file.",
@@ -424,9 +434,11 @@ def test_main_error_with_invalid_zuliprc_options(
     parameterized_zuliprc: Callable[[Dict[str, str]], str],
     zulip_config: Dict[str, str],
     error_message: str,
+    platform: str = "some_platform",
 ) -> None:
     zuliprc = parameterized_zuliprc(zulip_config)
     mocker.patch(CONTROLLER + ".__init__", return_value=None)
+    mocker.patch(MODULE + ".detected_platform", return_value=platform)
     mocker.patch(CONTROLLER + ".main", return_value=None)
 
     with pytest.raises(SystemExit) as e:
@@ -436,7 +448,9 @@ def test_main_error_with_invalid_zuliprc_options(
 
     captured = capsys.readouterr()
     lines = captured.out.strip()
-    expected_lines = f"\033[91m{error_message}\033[0m"
+    expected_lines = "\n".join(
+        [f"Detected platform: {platform}", f"\033[91m{error_message}\033[0m"]
+    )
     assert lines == expected_lines