Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doctor command tweaks #98

Merged
merged 4 commits into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/algokit/cli/doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ def doctor_command(*, copy_to_clipboard: bool) -> None:
service_outputs["Docker Compose"] = doctor_functions.get_docker_compose_info()
service_outputs["Git"] = doctor_functions.get_git_info(os_type)
service_outputs["AlgoKit Python"] = doctor_functions.get_algokit_python_info()
service_outputs["Global Python"] = doctor_functions.get_global_python_info()
service_outputs["Global Python"] = doctor_functions.get_global_python_info("python")
service_outputs["Global Python3"] = doctor_functions.get_global_python_info("python3")
service_outputs["Pipx"] = doctor_functions.get_pipx_info()
service_outputs["Poetry"] = doctor_functions.get_poetry_info()
service_outputs["Node.js"] = doctor_functions.get_node_info()
service_outputs["Npm"] = doctor_functions.get_npm_info()
service_outputs["Npm"] = doctor_functions.get_npm_info(os_type)

critical_services = ["Docker", "Docker Compose", "Git"]
# Print the status details
Expand Down
58 changes: 36 additions & 22 deletions src/algokit/core/doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ def get_algokit_info() -> ProcessResult:
pipx_venv_location = algokit_pip_line[0].split("=")[1]
algokit_location = f"{pipx_venv_location}/algokit"
return ProcessResult(f"{algokit_version} {algokit_location}", 0)
except Exception:
except Exception as e:
logger.debug(f"Getting algokit version failed: {e}", exc_info=True)
return ProcessResult("None found", 1)


Expand All @@ -53,16 +54,18 @@ def get_choco_info() -> ProcessResult:
process_results = proc.run(["choco"]).output.splitlines()[0].split(" v")[1]
major, minor, build = get_version_from_str(process_results)
return ProcessResult(f"{major}.{minor}.{build}", 0)
except Exception:
except Exception as e:
logger.debug(f"Getting chocolatey version failed: {e}", exc_info=True)
return ProcessResult("None found", 1)


def get_brew_info() -> ProcessResult:
try:
process_results = proc.run(["brew", "-v"]).output.splitlines()[0].split(" ")[1]
process_results = proc.run(["brew", "-v"]).output.splitlines()[0].split(" ")[1].split("-")[0]
major, minor, build = get_version_from_str(process_results)
return ProcessResult(f"{major}.{minor}.{build}", 0)
except Exception:
except Exception as e:
logger.debug(f"Getting brew version failed: {e}", exc_info=True)
return ProcessResult("None found", 1)


Expand All @@ -86,7 +89,8 @@ def get_docker_info() -> ProcessResult:
process_results = proc.run(["docker", "-v"]).output.splitlines()[0].split(" ")[2].split(",")[0]
major, minor, build = get_version_from_str(process_results)
return ProcessResult(f"{major}.{minor}.{build}", 0)
except Exception:
except Exception as e:
logger.debug(f"Getting docker version failed: {e}", exc_info=True)
return ProcessResult(
(
"None found.\nDocker required to `run algokit sandbox` command;"
Expand All @@ -109,16 +113,18 @@ def get_docker_compose_info() -> ProcessResult:
),
process_results.exit_code if minimum_version_met else 1,
)
except Exception:
except Exception as e:
logger.debug(f"Getting docker compose version failed: {e}", exc_info=True)
return ProcessResult(f"None found. {DOCKER_COMPOSE_MINIMUM_VERSION_MESSAGE}", 1)


def get_git_info(system: str) -> ProcessResult:
try:
process_results = proc.run(["git", "--version"]).output.splitlines()[0].split(" ")[2]
major, minor, build = map(int, process_results.split("."))
major, minor, build = get_version_from_str(process_results)
return ProcessResult(f"{major}.{minor}.{build}", 0)
except Exception:
except Exception as e:
logger.debug(f"Getting git version failed: {e}", exc_info=True)
if system == "windows":
return ProcessResult(
(
Expand All @@ -138,28 +144,32 @@ def get_git_info(system: str) -> ProcessResult:
def get_algokit_python_info() -> ProcessResult:
try:
return ProcessResult(
f"{sys_version_info.major}.{sys_version_info.minor}.{sys_version_info.micro} {sys_executable}", 0
f"{sys_version_info.major}.{sys_version_info.minor}.{sys_version_info.micro} (location: {sys_executable})",
0,
)
except Exception:
except Exception as e:
logger.debug(f"Getting AlgoKit python version failed: {e}", exc_info=True)
return ProcessResult("None found.", 1)


def get_global_python_info() -> ProcessResult:
def get_global_python_info(python_command_name: str) -> ProcessResult:
try:
major, minor, build = get_version_from_str(
proc.run(["python3", "--version"]).output.splitlines()[0].split(" ")[1]
proc.run([python_command_name, "--version"]).output.splitlines()[0].split(" ")[1]
)
global_python3_location = shutil.which("python3")
return ProcessResult(f"{major}.{minor}.{build} {global_python3_location}", 0)
except Exception:
global_python3_location = shutil.which(python_command_name)
return ProcessResult(f"{major}.{minor}.{build} (location: {global_python3_location})", 0)
except Exception as e:
logger.debug(f"Getting python version failed: {e}", exc_info=True)
return ProcessResult("None found.", 1)


def get_pipx_info() -> ProcessResult:
try:
major, minor, build = get_version_from_str(proc.run(["pipx", "--version"]).output.splitlines()[0])
return ProcessResult(f"{major}.{minor}.{build}", 0)
except Exception:
except Exception as e:
logger.debug(f"Getting pipx version failed: {e}", exc_info=True)
return ProcessResult(
"None found.\nPipx is required to install Poetry; install via https://pypa.github.io/pipx/", 1
)
Expand All @@ -170,7 +180,8 @@ def get_poetry_info() -> ProcessResult:
process_results = proc.run(["poetry", "--version"]).output.splitlines()[-1].split("version ")[1].split(")")[0]
major, minor, build = get_version_from_str(process_results)
return ProcessResult(f"{major}.{minor}.{build}", 0)
except Exception:
except Exception as e:
logger.debug(f"Getting poetry version failed: {e}", exc_info=True)
return ProcessResult(
(
"None found.\nPoetry is required for some Python-based templates; install via `algokit bootstrap` "
Expand All @@ -185,7 +196,8 @@ def get_node_info() -> ProcessResult:
process_results = proc.run(["node", "-v"]).output.splitlines()[0].split("v")[1]
major, minor, build = get_version_from_str(process_results)
return ProcessResult(f"{major}.{minor}.{build}", 0)
except Exception:
except Exception as e:
logger.debug(f"Getting node version failed: {e}", exc_info=True)
return ProcessResult(
(
"None found.\nNode.js is required for some Node.js-based templates; install via `algokit bootstrap` "
Expand All @@ -195,12 +207,13 @@ def get_node_info() -> ProcessResult:
)


def get_npm_info() -> ProcessResult:
def get_npm_info(system: str) -> ProcessResult:
try:
process_results = proc.run(["npm", "-v"]).output.splitlines()[0]
process_results = proc.run(["npm" if system != "windows" else "npm.cmd", "-v"]).output.splitlines()[0]
major, minor, build = get_version_from_str(process_results)
return ProcessResult(f"{major}.{minor}.{build}", 0)
except Exception:
except Exception as e:
logger.debug(f"Getting npm version failed: {e}", exc_info=True)
return ProcessResult("None found.", 1)


Expand All @@ -211,5 +224,6 @@ def is_minimum_version(system_version: str, minimum_version: str) -> bool:


def get_version_from_str(version: str) -> tuple[int, int, int]:
major, minor, build = map(int, version.split("."))
# take only the first three parts x.y.z of the version to ignore weird version
major, minor, build = map(int, version.split(".")[:3])
return major, minor, build
96 changes: 95 additions & 1 deletion tests/doctor/test_doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def mock_dependencies(mocker: MockerFixture) -> None:
mocked_date.now.return_value = datetime(1990, 12, 31, 10, 9, 8)
# Mock shutil
mocked_shutil = mocker.patch("algokit.core.doctor.shutil")
mocked_shutil.which.return_value = "/Library/Frameworks/Python.framework/Versions/3.11/bin/python3"
mocked_shutil.which.side_effect = mock_shutil_which
# Mock sys - Tuple[int, int, int, str, int]
mocker.patch("algokit.core.doctor.sys_version_info", VersionInfoType(3, 6, 2, "blah", 0))
mocker.patch("algokit.core.doctor.sys_executable", "{current_working_directory}/.venv/bin/python")
Expand All @@ -54,11 +54,21 @@ def mock_happy_values(proc_mock: ProcMock) -> None:
proc_mock.set_output(["docker", "-v"], ["Docker version 20.10.21, build baeda1f"])
proc_mock.set_output(["docker-compose", "-v"], ["Docker Compose version v2.12.2"])
proc_mock.set_output(["git", "--version"], ["git version 2.37.1 (Apple Git-137.1)"])
proc_mock.set_output(["python", "--version"], ["Python 3.10.0"])
proc_mock.set_output(["python3", "--version"], ["Python 3.11.0"])
proc_mock.set_output(["pipx", "--version"], ["1.1.0"])
proc_mock.set_output(["poetry", "--version"], ["blah blah", "", "Poetry (version 1.2.2)"])
proc_mock.set_output(["node", "-v"], ["v18.12.1"])
proc_mock.set_output(["npm", "-v"], ["8.19.2"])
proc_mock.set_output(["npm.cmd", "-v"], ["8.19.2"])


def mock_shutil_which(python_command_name: str) -> str:
if python_command_name == "python":
return "/Library/Frameworks/Python.framework/Versions/3.10/bin/python"
if python_command_name == "python3":
return "/Library/Frameworks/Python.framework/Versions/3.11/bin/python3"
return ""


def make_output_scrubber(**extra_tokens: str) -> Scrubber:
Expand Down Expand Up @@ -145,13 +155,72 @@ def test_doctor_with_git_warning_on_windows(mocker: MockerFixture, proc_mock: Pr


def test_doctor_all_failed_on_mac(mocker: MockerFixture, proc_mock: ProcMock):

mocker.patch("algokit.core.doctor.sys_version_info", "")
mocker.patch("algokit.core.doctor.sys_executable", "")

proc_mock.set_output(["pipx", "list", "--short"], [])
proc_mock.set_output(["pipx", "environment"], [])
proc_mock.set_output(["choco"], [])
proc_mock.set_output(["brew", "-v"], [])
proc_mock.set_output(["docker", "-v"], [])
proc_mock.set_output(["docker-compose", "-v"], [])
proc_mock.set_output(["git", "--version"], [])
proc_mock.set_output(["python", "--version"], [])
proc_mock.set_output(["python3", "--version"], [])
proc_mock.set_output(["pipx", "--version"], [])
proc_mock.set_output(["poetry", "--version"], [])
proc_mock.set_output(["node", "-v"], [])
proc_mock.set_output(["npm", "-v"], [])

result = invoke("doctor")

assert result.exit_code == 1
verify(result.output, scrubber=make_output_scrubber())


def test_doctor_all_failed_on_windows(mocker: MockerFixture, proc_mock: ProcMock):
mocked_os = mocker.patch("algokit.cli.doctor.platform")
mocked_os.system.return_value = "windows"

mocker.patch("algokit.core.doctor.sys_version_info", "")
mocker.patch("algokit.core.doctor.sys_executable", "")

proc_mock.set_output(["pipx", "list", "--short"], [])
proc_mock.set_output(["pipx", "environment"], [])
proc_mock.set_output(["choco"], [])
proc_mock.set_output(["brew", "-v"], [])
proc_mock.set_output(["docker", "-v"], [])
proc_mock.set_output(["docker-compose", "-v"], [])
proc_mock.set_output(["git", "--version"], [])
proc_mock.set_output(["python", "--version"], [])
proc_mock.set_output(["python3", "--version"], [])
proc_mock.set_output(["pipx", "--version"], [])
proc_mock.set_output(["poetry", "--version"], [])
proc_mock.set_output(["node", "-v"], [])
proc_mock.set_output(["npm.cmd", "-v"], [])

result = invoke("doctor")

assert result.exit_code == 1
verify(result.output, scrubber=make_output_scrubber())


def test_doctor_all_failed_on_linux(mocker: MockerFixture, proc_mock: ProcMock):
mocked_os = mocker.patch("algokit.cli.doctor.platform")
mocked_os.system.return_value = "linux"

mocker.patch("algokit.core.doctor.sys_version_info", "")
mocker.patch("algokit.core.doctor.sys_executable", "")

proc_mock.set_output(["pipx", "list", "--short"], [])
proc_mock.set_output(["pipx", "environment"], [])
proc_mock.set_output(["choco"], [])
proc_mock.set_output(["brew", "-v"], [])
proc_mock.set_output(["docker", "-v"], [])
proc_mock.set_output(["docker-compose", "-v"], [])
proc_mock.set_output(["git", "--version"], [])
proc_mock.set_output(["python", "--version"], [])
proc_mock.set_output(["python3", "--version"], [])
proc_mock.set_output(["pipx", "--version"], [])
proc_mock.set_output(["poetry", "--version"], [])
Expand All @@ -162,3 +231,28 @@ def test_doctor_all_failed_on_mac(mocker: MockerFixture, proc_mock: ProcMock):

assert result.exit_code == 1
verify(result.output, scrubber=make_output_scrubber())


def test_doctor_with_weird_values_on_mac(mocker: MockerFixture, proc_mock: ProcMock):
proc_mock.set_output(["brew", "-v"], ["Homebrew 3.6.15-31-g82d89bb"])

result = invoke("doctor")

assert result.exit_code == 0
verify(result.output, scrubber=make_output_scrubber())


def test_doctor_with_weird_values_on_windows(mocker: MockerFixture, proc_mock: ProcMock):
mocked_os = mocker.patch("algokit.cli.doctor.platform")
mocked_os.system.return_value = "windows"

proc_mock.set_output(["git", "--version"], ["git version 2.31.0.windows.1"])
proc_mock.set_output(
["choco"], ["Chocolatey v0.10.15", "choco: Please run 'choco -?' or 'choco <command> -?' for help menu."]
)
proc_mock.set_output(["npm.cmd", "-v"], [" 16.17.0 "])

result = invoke("doctor")

assert result.exit_code == 0
verify(result.output, scrubber=make_output_scrubber())
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
DEBUG: Running 'pipx list --short' in '{current_working_directory}'
DEBUG: Getting algokit version failed: list index out of range
DEBUG: Running 'docker -v' in '{current_working_directory}'
DEBUG: Getting docker version failed: list index out of range
DEBUG: Running 'docker-compose -v' in '{current_working_directory}'
DEBUG: Getting docker compose version failed: list index out of range
DEBUG: Running 'git --version' in '{current_working_directory}'
DEBUG: Getting git version failed: list index out of range
DEBUG: Getting AlgoKit python version failed: 'str' object has no attribute 'major'
DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: Getting python version failed: list index out of range
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: Getting python version failed: list index out of range
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: Getting pipx version failed: list index out of range
DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Getting poetry version failed: list index out of range
DEBUG: Running 'node -v' in '{current_working_directory}'
DEBUG: Getting node version failed: list index out of range
DEBUG: Running 'npm -v' in '{current_working_directory}'
DEBUG: Getting npm version failed: list index out of range
Time: 1990-12-31T10:09:08
AlgoKit: None found
OS: Unix/Linux linux_version
Docker: None found.
Docker required to `run algokit sandbox` command; install via https://docs.docker.com/get-docker/
Docker Compose: None found.
Docker Compose 2.5 required to `run algokit sandbox command`; install via https://docs.docker.com/compose/install/
Git: None found.
Git required to run `algokit init`; install via https://github.com/git-guides/install-git
AlgoKit Python: None found.
Global Python: None found.
Global Python3: None found.
Pipx: None found.
Pipx is required to install Poetry; install via https://pypa.github.io/pipx/
Poetry: None found.
Poetry is required for some Python-based templates; install via `algokit bootstrap` within project directory, or via https://python-poetry.org/docs/#installation
Node.js: None found.
Node.js is required for some Node.js-based templates; install via `algokit bootstrap` within project directory, or via https://nodejs.dev/en/learn/how-to-install-nodejs/
Npm: None found.
If you are experiencing a problem with algokit, feel free to submit an issue via https://github.com/algorandfoundation/algokit-cli/issues/new; please include this output, if you want to populate this message in your clipboard, run `algokit doctor -c`
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
DEBUG: Running 'pipx list --short' in '{current_working_directory}'
DEBUG: Getting algokit version failed: list index out of range
DEBUG: Running 'brew -v' in '{current_working_directory}'
DEBUG: Getting brew version failed: list index out of range
DEBUG: Running 'docker -v' in '{current_working_directory}'
DEBUG: Getting docker version failed: list index out of range
DEBUG: Running 'docker-compose -v' in '{current_working_directory}'
DEBUG: Getting docker compose version failed: list index out of range
DEBUG: Running 'git --version' in '{current_working_directory}'
DEBUG: Getting git version failed: list index out of range
DEBUG: Getting AlgoKit python version failed: 'str' object has no attribute 'major'
DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: Getting python version failed: list index out of range
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: Getting python version failed: list index out of range
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: Getting pipx version failed: list index out of range
DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Getting poetry version failed: list index out of range
DEBUG: Running 'node -v' in '{current_working_directory}'
DEBUG: Getting node version failed: list index out of range
DEBUG: Running 'npm -v' in '{current_working_directory}'
DEBUG: Getting npm version failed: list index out of range
Time: 1990-12-31T10:09:08
AlgoKit: None found
Brew: None found
Expand All @@ -18,8 +31,9 @@ Docker Compose: None found.
Docker Compose 2.5 required to `run algokit sandbox command`; install via https://docs.docker.com/compose/install/
Git: None found.
Git required to run `algokit init`; install via https://github.com/git-guides/install-git
AlgoKit Python: 3.6.2 {current_working_directory}/.venv/bin/python
AlgoKit Python: None found.
Global Python: None found.
Global Python3: None found.
Pipx: None found.
Pipx is required to install Poetry; install via https://pypa.github.io/pipx/
Poetry: None found.
Expand Down
Loading