Skip to content

Commit

Permalink
fix: localnet displays a warning when image is out of date (#308)
Browse files Browse the repository at this point in the history
* feat: add check for localnet update

---------

Co-authored-by: Daniel McGregor <daniel.mcgregor@makerx.com.au>
Co-authored-by: Altynbek Orumbayev <altynbek.orumbayev@makerx.com.au>
  • Loading branch information
3 people authored Aug 21, 2023
1 parent caca2b5 commit be5a5df
Show file tree
Hide file tree
Showing 18 changed files with 268 additions and 14 deletions.
5 changes: 5 additions & 0 deletions src/algokit/cli/localnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ def localnet_group() -> None:
def start_localnet() -> None:
sandbox = ComposeSandbox()
compose_file_status = sandbox.compose_file_status()
sandbox.check_docker_compose_for_new_image_versions()

if compose_file_status is ComposeFileStatus.MISSING:
logger.debug("Sandbox compose file does not exist yet; writing it out for the first time")
sandbox.write_compose_file()
Expand Down Expand Up @@ -101,6 +103,9 @@ def reset_localnet(*, update: bool) -> None:
sandbox.write_compose_file()
if update:
sandbox.pull()
else:
sandbox.check_docker_compose_for_new_image_versions()

sandbox.up()


Expand Down
55 changes: 53 additions & 2 deletions src/algokit/core/sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,55 @@ def ps(self, service_name: str | None = None) -> list[dict[str, Any]]:
assert isinstance(data, list)
return cast(list[dict[str, Any]], data)

def _get_local_image_version(self, image_name: str) -> str | None:
"""
Get the local version of a Docker image
"""
try:
arg = '{{index (split (index .RepoDigests 0) "@") 1}}'
local_version = run(
["docker", "image", "inspect", image_name, "--format", arg],
cwd=self.directory,
bad_return_code_error_message="Failed to get image inspect",
)

return local_version.output.strip()
except Exception:
return None

def _get_latest_image_version(self, image_name: str) -> str | None:
"""
Get the latest version of a Docker image from Docker Hub
"""
args = image_name.split(":")
name = args[0]
tag = args[1] if len(args) > 1 else "latest"
url = f"https://registry.hub.docker.com/v2/repositories/{name}/tags/{tag}"
try:
data = httpx.get(url=url)
return str(data.json()["digest"])
except Exception as err:
logger.debug(f"Error checking indexer status: {err}", exc_info=True)
return None

def is_image_up_to_date(self, image_name: str) -> bool:
local_version = self._get_local_image_version(image_name)
latest_version = self._get_latest_image_version(image_name)
return local_version is None or latest_version is None or local_version == latest_version

def check_docker_compose_for_new_image_versions(self) -> None:
is_indexer_up_to_date = self.is_image_up_to_date(INDEXER_IMAGE)
if is_indexer_up_to_date is False:
logger.warning(
"indexer has a new version available, run `algokit localnet reset --update` to get the latest version"
)

is_algorand_up_to_date = self.is_image_up_to_date(ALGORAND_IMAGE)
if is_algorand_up_to_date is False:
logger.warning(
"algod has a new version available, run `algokit localnet reset --update` to get the latest version"
)


DEFAULT_ALGOD_SERVER = "http://localhost"
DEFAULT_ALGOD_TOKEN = "a" * 64
Expand All @@ -128,6 +177,8 @@ def ps(self, service_name: str | None = None) -> list[dict[str, Any]]:
DEFAULT_WAIT_FOR_ALGOD = 60
DEFAULT_HEALTH_TIMEOUT = 1
ALGOD_HEALTH_URL = f"{DEFAULT_ALGOD_SERVER}:{DEFAULT_ALGOD_PORT}/v2/status"
INDEXER_IMAGE = "makerxau/algorand-indexer-dev:latest"
ALGORAND_IMAGE = "algorand/algod:latest"


def _wait_for_algod() -> bool:
Expand Down Expand Up @@ -171,7 +222,7 @@ def get_docker_compose_yml(
services:
algod:
container_name: {name}_algod
image: algorand/algod:latest
image: {ALGORAND_IMAGE}
ports:
- {algod_port}:8080
- {kmd_port}:7833
Expand All @@ -189,7 +240,7 @@ def get_docker_compose_yml(
indexer:
container_name: {name}_indexer
image: makerxau/algorand-indexer-dev:latest
image: {INDEXER_IMAGE}
ports:
- {indexer_port}:8980
restart: unless-stopped
Expand Down
32 changes: 31 additions & 1 deletion tests/localnet/conftest.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import pytest
from algokit.core.sandbox import ALGOD_HEALTH_URL
from algokit.core.sandbox import ALGOD_HEALTH_URL, ALGORAND_IMAGE, INDEXER_IMAGE
from pytest_httpx import HTTPXMock
from pytest_mock import MockerFixture

from tests.utils.proc_mock import ProcMock


@pytest.fixture(autouse=True)
def algod_health_fast_timings(mocker: MockerFixture) -> None: # noqa: ignore[PT004]
Expand All @@ -13,3 +15,31 @@ def algod_health_fast_timings(mocker: MockerFixture) -> None: # noqa: ignore[PT
@pytest.fixture()
def health_success(httpx_mock: HTTPXMock) -> None: # noqa: ignore[PT004]
httpx_mock.add_response(url=ALGOD_HEALTH_URL)


@pytest.fixture()
def _localnet_up_to_date(proc_mock: ProcMock, httpx_mock: HTTPXMock) -> None:
arg = '{{index (split (index .RepoDigests 0) "@") 1}}'
proc_mock.set_output(
["docker", "image", "inspect", ALGORAND_IMAGE, "--format", arg],
["sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"],
)

proc_mock.set_output(
["docker", "image", "inspect", INDEXER_IMAGE, "--format", arg],
["sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"],
)

httpx_mock.add_response(
url="https://registry.hub.docker.com/v2/repositories/makerxau/algorand-indexer-dev/tags/latest",
json={
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
},
)

httpx_mock.add_response(
url="https://registry.hub.docker.com/v2/repositories/algorand/algod/tags/latest",
json={
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
},
)
4 changes: 2 additions & 2 deletions tests/localnet/test_localnet_reset.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def test_localnet_reset_without_existing_sandbox(app_dir_mock: AppDirs) -> None:
)


@pytest.mark.usefixtures("proc_mock", "health_success")
@pytest.mark.usefixtures("proc_mock", "health_success", "_localnet_up_to_date")
def test_localnet_reset_with_existing_sandbox_with_out_of_date_config(app_dir_mock: AppDirs) -> None:
(app_dir_mock.app_config_dir / "sandbox").mkdir()
(app_dir_mock.app_config_dir / "sandbox" / "docker-compose.yml").write_text("out of date config")
Expand All @@ -44,7 +44,7 @@ def test_localnet_reset_with_existing_sandbox_with_out_of_date_config(app_dir_mo
)


@pytest.mark.usefixtures("proc_mock", "health_success")
@pytest.mark.usefixtures("proc_mock", "health_success", "_localnet_up_to_date")
def test_localnet_reset_with_existing_sandbox_with_up_to_date_config(app_dir_mock: AppDirs) -> None:
(app_dir_mock.app_config_dir / "sandbox").mkdir()
(app_dir_mock.app_config_dir / "sandbox" / "docker-compose.yml").write_text(get_docker_compose_yml())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ DEBUG: Running 'docker compose down' in '{app_config}/sandbox'
DEBUG: docker: STDOUT
DEBUG: docker: STDERR
Sandbox definition is out of date; updating it to latest
DEBUG: Running 'docker image inspect makerxau/algorand-indexer-dev:latest --format {{index (split (index .RepoDigests 0) "@") 1}}' in '{app_config}/sandbox'
DEBUG: docker: sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
DEBUG: HTTP Request: GET https://registry.hub.docker.com/v2/repositories/makerxau/algorand-indexer-dev/tags/latest "HTTP/1.1 200 OK"
DEBUG: Running 'docker image inspect algorand/algod:latest --format {{index (split (index .RepoDigests 0) "@") 1}}' in '{app_config}/sandbox'
DEBUG: docker: sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
DEBUG: HTTP Request: GET https://registry.hub.docker.com/v2/repositories/algorand/algod/tags/latest "HTTP/1.1 200 OK"
Starting AlgoKit LocalNet now...
DEBUG: Running 'docker compose up --detach --quiet-pull --wait' in '{app_config}/sandbox'
docker: STDOUT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ Deleting any existing LocalNet...
DEBUG: Running 'docker compose down' in '{app_config}/sandbox'
DEBUG: docker: STDOUT
DEBUG: docker: STDERR
DEBUG: Running 'docker image inspect makerxau/algorand-indexer-dev:latest --format {{index (split (index .RepoDigests 0) "@") 1}}' in '{app_config}/sandbox'
DEBUG: docker: sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
DEBUG: HTTP Request: GET https://registry.hub.docker.com/v2/repositories/makerxau/algorand-indexer-dev/tags/latest "HTTP/1.1 200 OK"
DEBUG: Running 'docker image inspect algorand/algod:latest --format {{index (split (index .RepoDigests 0) "@") 1}}' in '{app_config}/sandbox'
DEBUG: docker: sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
DEBUG: HTTP Request: GET https://registry.hub.docker.com/v2/repositories/algorand/algod/tags/latest "HTTP/1.1 200 OK"
Starting AlgoKit LocalNet now...
DEBUG: Running 'docker compose up --detach --quiet-pull --wait' in '{app_config}/sandbox'
docker: STDOUT
Expand Down
76 changes: 67 additions & 9 deletions tests/localnet/test_localnet_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

import httpx
import pytest
from algokit.core.sandbox import ALGOD_HEALTH_URL, get_config_json, get_docker_compose_yml
from algokit.core.sandbox import (
ALGOD_HEALTH_URL,
ALGORAND_IMAGE,
INDEXER_IMAGE,
get_config_json,
get_docker_compose_yml,
)
from pytest_httpx import HTTPXMock

from tests import get_combined_verify_output
Expand All @@ -12,7 +18,42 @@
from tests.utils.proc_mock import ProcMock


@pytest.mark.usefixtures("proc_mock", "health_success")
@pytest.fixture()
def _localnet_out_of_date(proc_mock: ProcMock, httpx_mock: HTTPXMock) -> None:
arg = '{{index (split (index .RepoDigests 0) "@") 1}}'
proc_mock.set_output(
["docker", "image", "inspect", ALGORAND_IMAGE, "--format", arg],
["sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"],
)

proc_mock.set_output(
["docker", "image", "inspect", INDEXER_IMAGE, "--format", arg],
["sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"],
)

httpx_mock.add_response(
url="https://registry.hub.docker.com/v2/repositories/makerxau/algorand-indexer-dev/tags/latest",
json={
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
},
)

httpx_mock.add_response(
url="https://registry.hub.docker.com/v2/repositories/algorand/algod/tags/latest",
json={
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
},
)


@pytest.fixture()
def _localnet_img_check_cmd_error(proc_mock: ProcMock) -> None:
arg = '{{index (split (index .RepoDigests 0) "@") 1}}'
proc_mock.should_fail_on(["docker", "image", "inspect", ALGORAND_IMAGE, "--format", arg])
proc_mock.should_fail_on(["docker", "image", "inspect", INDEXER_IMAGE, "--format", arg])


@pytest.mark.usefixtures("proc_mock", "health_success", "_localnet_up_to_date")
def test_localnet_start(app_dir_mock: AppDirs) -> None:
result = invoke("localnet start")

Expand All @@ -26,7 +67,7 @@ def test_localnet_start(app_dir_mock: AppDirs) -> None:
)


@pytest.mark.usefixtures("proc_mock")
@pytest.mark.usefixtures("proc_mock", "_localnet_up_to_date")
def test_localnet_start_health_failure(app_dir_mock: AppDirs, httpx_mock: HTTPXMock) -> None:
httpx_mock.add_exception(httpx.RemoteProtocolError("No response"), url=ALGOD_HEALTH_URL)
result = invoke("localnet start")
Expand All @@ -41,7 +82,7 @@ def test_localnet_start_health_failure(app_dir_mock: AppDirs, httpx_mock: HTTPXM
)


@pytest.mark.usefixtures("proc_mock")
@pytest.mark.usefixtures("proc_mock", "_localnet_up_to_date")
def test_localnet_start_health_bad_status(app_dir_mock: AppDirs, httpx_mock: HTTPXMock) -> None:
httpx_mock.add_response(status_code=500, url=ALGOD_HEALTH_URL)
result = invoke("localnet start")
Expand All @@ -56,6 +97,7 @@ def test_localnet_start_health_bad_status(app_dir_mock: AppDirs, httpx_mock: HTT
)


@pytest.mark.usefixtures("_localnet_up_to_date")
def test_localnet_start_failure(app_dir_mock: AppDirs, proc_mock: ProcMock) -> None:
proc_mock.should_bad_exit_on("docker compose up")

Expand All @@ -65,7 +107,7 @@ def test_localnet_start_failure(app_dir_mock: AppDirs, proc_mock: ProcMock) -> N
verify(result.output.replace(str(app_dir_mock.app_config_dir), "{app_config}").replace("\\", "/"))


@pytest.mark.usefixtures("proc_mock", "health_success")
@pytest.mark.usefixtures("proc_mock", "health_success", "_localnet_up_to_date")
def test_localnet_start_up_to_date_definition(app_dir_mock: AppDirs) -> None:
(app_dir_mock.app_config_dir / "sandbox").mkdir()
(app_dir_mock.app_config_dir / "sandbox" / "docker-compose.yml").write_text(get_docker_compose_yml())
Expand All @@ -77,7 +119,7 @@ def test_localnet_start_up_to_date_definition(app_dir_mock: AppDirs) -> None:
verify(result.output.replace(str(app_dir_mock.app_config_dir), "{app_config}").replace("\\", "/"))


@pytest.mark.usefixtures("proc_mock", "health_success")
@pytest.mark.usefixtures("proc_mock", "health_success", "_localnet_up_to_date")
def test_localnet_start_out_of_date_definition(app_dir_mock: AppDirs) -> None:
(app_dir_mock.app_config_dir / "sandbox").mkdir()
(app_dir_mock.app_config_dir / "sandbox" / "docker-compose.yml").write_text("out of date config")
Expand All @@ -99,7 +141,7 @@ def test_localnet_start_out_of_date_definition(app_dir_mock: AppDirs) -> None:
)


@pytest.mark.usefixtures("proc_mock", "health_success")
@pytest.mark.usefixtures("proc_mock", "health_success", "_localnet_up_to_date")
def test_localnet_start_out_of_date_definition_and_missing_config(app_dir_mock: AppDirs) -> None:
(app_dir_mock.app_config_dir / "sandbox").mkdir()
(app_dir_mock.app_config_dir / "sandbox" / "docker-compose.yml").write_text("out of date config")
Expand Down Expand Up @@ -158,7 +200,7 @@ def test_localnet_start_with_old_docker_compose_version(proc_mock: ProcMock) ->
verify(result.output)


@pytest.mark.usefixtures("health_success")
@pytest.mark.usefixtures("health_success", "_localnet_up_to_date")
def test_localnet_start_with_unparseable_docker_compose_version(app_dir_mock: AppDirs, proc_mock: ProcMock) -> None:
proc_mock.set_output("docker compose version --format json", [json.dumps({"version": "v2.5-dev123"})])

Expand All @@ -168,11 +210,27 @@ def test_localnet_start_with_unparseable_docker_compose_version(app_dir_mock: Ap
verify(result.output.replace(str(app_dir_mock.app_config_dir), "{app_config}").replace("\\", "/"))


@pytest.mark.usefixtures("health_success")
@pytest.mark.usefixtures("health_success", "_localnet_up_to_date")
def test_localnet_start_with_gitpod_docker_compose_version(app_dir_mock: AppDirs, proc_mock: ProcMock) -> None:
proc_mock.set_output("docker compose version --format json", [json.dumps({"version": "v2.10.0-gitpod.0"})])

result = invoke("localnet start")

assert result.exit_code == 0
verify(result.output.replace(str(app_dir_mock.app_config_dir), "{app_config}").replace("\\", "/"))


@pytest.mark.usefixtures("proc_mock", "health_success", "_localnet_out_of_date")
def test_localnet_start_out_date(app_dir_mock: AppDirs) -> None:
result = invoke("localnet start")

assert result.exit_code == 0
verify(result.output.replace(str(app_dir_mock.app_config_dir), "{app_config}").replace("\\", "/"))


@pytest.mark.usefixtures("proc_mock", "health_success", "_localnet_img_check_cmd_error")
def test_localnet_img_check_cmd_error(app_dir_mock: AppDirs) -> None:
result = invoke("localnet start")

assert result.exit_code == 0
verify(result.output.replace(str(app_dir_mock.app_config_dir), "{app_config}").replace("\\", "/"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
DEBUG: Running 'docker compose version --format json' in '{current_working_directory}'
DEBUG: docker: {"version": "v2.5.0"}
DEBUG: Running 'docker version' in '{current_working_directory}'
DEBUG: docker: STDOUT
DEBUG: docker: STDERR
DEBUG: Sandbox directory does not exist yet; creating it
DEBUG: Running 'docker image inspect makerxau/algorand-indexer-dev:latest --format {{index (split (index .RepoDigests 0) "@") 1}}' in '{app_config}/sandbox'
DEBUG: Error checking indexer status: No response can be found for GET request on https://registry.hub.docker.com/v2/repositories/makerxau/algorand-indexer-dev/tags/latest amongst:
Match all requests on http://localhost:4001/v2/status
DEBUG: Running 'docker image inspect algorand/algod:latest --format {{index (split (index .RepoDigests 0) "@") 1}}' in '{app_config}/sandbox'
DEBUG: Error checking indexer status: No response can be found for GET request on https://registry.hub.docker.com/v2/repositories/algorand/algod/tags/latest amongst:
Match all requests on http://localhost:4001/v2/status
DEBUG: Sandbox compose file does not exist yet; writing it out for the first time
Starting AlgoKit LocalNet now...
DEBUG: Running 'docker compose up --detach --quiet-pull --wait' in '{app_config}/sandbox'
docker: STDOUT
docker: STDERR
DEBUG: AlgoKit LocalNet started, waiting for health check
DEBUG: HTTP Request: GET http://localhost:4001/v2/status "HTTP/1.1 200 OK"
DEBUG: AlgoKit LocalNet health check successful, algod is ready
Started; execute `algokit explore` to explore LocalNet in a web user interface.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ DEBUG: Running 'docker version' in '{current_working_directory}'
DEBUG: docker: STDOUT
DEBUG: docker: STDERR
DEBUG: Sandbox directory does not exist yet; creating it
DEBUG: Running 'docker image inspect makerxau/algorand-indexer-dev:latest --format {{index (split (index .RepoDigests 0) "@") 1}}' in '{app_config}/sandbox'
DEBUG: docker: sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
DEBUG: HTTP Request: GET https://registry.hub.docker.com/v2/repositories/makerxau/algorand-indexer-dev/tags/latest "HTTP/1.1 200 OK"
DEBUG: Running 'docker image inspect algorand/algod:latest --format {{index (split (index .RepoDigests 0) "@") 1}}' in '{app_config}/sandbox'
DEBUG: docker: sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
DEBUG: HTTP Request: GET https://registry.hub.docker.com/v2/repositories/algorand/algod/tags/latest "HTTP/1.1 200 OK"
DEBUG: Sandbox compose file does not exist yet; writing it out for the first time
Starting AlgoKit LocalNet now...
DEBUG: Running 'docker compose up --detach --quiet-pull --wait' in '{app_config}/sandbox'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ DEBUG: Running 'docker version' in '{current_working_directory}'
DEBUG: docker: STDOUT
DEBUG: docker: STDERR
DEBUG: Sandbox directory does not exist yet; creating it
DEBUG: Running 'docker image inspect makerxau/algorand-indexer-dev:latest --format {{index (split (index .RepoDigests 0) "@") 1}}' in '{app_config}/sandbox'
DEBUG: docker: sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
DEBUG: HTTP Request: GET https://registry.hub.docker.com/v2/repositories/makerxau/algorand-indexer-dev/tags/latest "HTTP/1.1 200 OK"
DEBUG: Running 'docker image inspect algorand/algod:latest --format {{index (split (index .RepoDigests 0) "@") 1}}' in '{app_config}/sandbox'
DEBUG: docker: sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
DEBUG: HTTP Request: GET https://registry.hub.docker.com/v2/repositories/algorand/algod/tags/latest "HTTP/1.1 200 OK"
DEBUG: Sandbox compose file does not exist yet; writing it out for the first time
Starting AlgoKit LocalNet now...
DEBUG: Running 'docker compose up --detach --quiet-pull --wait' in '{app_config}/sandbox'
Expand Down
Loading

1 comment on commit be5a5df

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage

Coverage Report
FileStmtsMissCoverMissing
src/algokit
   __init__.py15753%6–13, 17–24, 32–34
   __main__.py220%1–3
src/algokit/cli
   completions.py105298%80, 95
   deploy.py56591%34–36, 78, 96
   doctor.py48394%142–144
   generate.py57198%116
   goal.py39197%57
   init.py1901692%268–269, 319, 322–324, 335, 379, 405, 445, 454–456, 459–464, 477
   localnet.py93397%162, 183–184
src/algokit/core
   bootstrap.py1612485%103–104, 126, 149, 214, 217, 223–237, 246–251
   conf.py54885%10, 24, 28, 36, 38, 71–73
   deploy.py691184%61–64, 73–75, 79, 84, 91–93
   doctor.py65789%67–69, 92–94, 134
   generate.py41295%68, 86
   goal.py56395%27–28, 38
   log_handlers.py68790%50–51, 63, 112–116, 125
   proc.py45198%98
   sandbox.py1811592%100–107, 118, 278, 294, 309–311, 327
   typed_client_generation.py80594%55–57, 70, 75
   version_prompt.py73889%27–28, 40, 59–62, 80, 109
TOTAL166213192% 

Tests Skipped Failures Errors Time
249 0 💤 0 ❌ 0 🔥 23.738s ⏱️

Please sign in to comment.