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

feat: better CLI message when compiling a dependency produces no contracts #2130

Merged
merged 5 commits into from
Jun 12, 2024
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
29 changes: 27 additions & 2 deletions src/ape/managers/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,32 @@ def compile(
self.project.reconfigure(**override)
self._cache.cache_api(self.api)

return self.project.load_contracts(use_cache=use_cache)
result = self.project.load_contracts(use_cache=use_cache)
if not result:
contracts_folder = self.project.contracts_folder
message = "Compiling dependency produced no contract types."
if isinstance(self.project, LocalProject):
all_files = [x.name for x in get_all_files_in_directory(contracts_folder)]
has_solidity_sources = any(get_full_extension(Path(x)) == ".sol" for x in all_files)
has_vyper_sources = any(
get_full_extension(Path(x)) in (".vy", ".vyi") for x in all_files
)
compilers = self.compiler_manager.registered_compilers
warn_sol = has_solidity_sources and ".sol" not in compilers
warn_vyper = has_vyper_sources and ".vy" not in compilers
suffix = ""
if warn_sol:
suffix = "Try installing 'ape-solidity'"
if warn_vyper and warn_sol:
suffix += " or 'ape-vyper'"
elif warn_vyper:
suffix = "Try installing 'ape-vyper'"
if suffix:
message = f"{message} {suffix}."

logger.warning(message)

return result

def unpack(self, path: Path) -> Iterator["Dependency"]:
"""
Expand Down Expand Up @@ -2331,7 +2356,7 @@ def load_contracts(
starting = {
n: ContractContainer(ct)
for n, ct in (self.manifest.contract_types or {}).items()
if ct.source_id and (self.path / ct.source_id).is_file()
if use_cache and ct.source_id and (self.path / ct.source_id).is_file()
}
paths = self.sources.paths

Expand Down
28 changes: 13 additions & 15 deletions src/ape_pm/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,7 @@ def compile(cli_ctx, name, version, force, config_override):
cfg["config_override"] = config_override

dependency = pm.dependencies.install(**cfg)
try:
dependency.compile(use_cache=not force)
except Exception as err:
cli_ctx.logger.error(str(err))
continue
else:
cli_ctx.logger.success(
f"Package '{dependency.name}@{dependency.version}' compiled."
)
_compile_dependency(cli_ctx, dependency, force)

if did_error:
sys.exit(1)
Expand All @@ -321,10 +313,16 @@ def compile(cli_ctx, name, version, force, config_override):
if config_override:
dependency.api.config_override = config_override

try:
dependency.compile(use_cache=not force)
except Exception as err:
cli_ctx.logger.error(str(err))
continue
else:
_compile_dependency(cli_ctx, dependency, force)


def _compile_dependency(cli_ctx, dependency: Dependency, force: bool):
try:
result = dependency.compile(use_cache=not force)
except Exception as err:
cli_ctx.logger.error(str(err))
else:
if result:
cli_ctx.logger.success(f"Package '{dependency.name}@{dependency.version}' compiled.")
# else: user should have received warning from `dependency.compile()` if there
# was no result.
30 changes: 30 additions & 0 deletions tests/functional/test_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ape.managers.project import Dependency, LocalProject, PackagesCache, Project, ProjectManager
from ape.utils import create_tempdir
from ape_pm.dependency import GithubDependency, LocalDependency, NpmDependency
from tests.conftest import skip_if_plugin_installed


@pytest.fixture
Expand Down Expand Up @@ -543,6 +544,35 @@ def test_manifest_path(self, dependency, data_folder):
expected = data_folder / "packages" / "manifests" / name / "1_0_0.json"
assert actual == expected

def test_compile(self, project):
with create_tempdir() as path:
api = LocalDependency(local=path, name="ooga", version="1.0.0")
dependency = Dependency(api, project)
contract_path = dependency.project.contracts_folder / "CCC.json"
contract_path.write_text(
'[{"name":"foo","type":"fallback", "stateMutability":"nonpayable"}]'
)
result = dependency.compile()
assert len(result) == 1
assert result["CCC"].name == "CCC"

@skip_if_plugin_installed("vyper", "solidity")
def test_compile_missing_compilers(self, project, ape_caplog):
with create_tempdir() as path:
api = LocalDependency(local=path, name="ooga2", version="1.1.0")
dependency = Dependency(api, project)
sol_path = dependency.project.contracts_folder / "Sol.sol"
sol_path.write_text("// Sol")
vy_path = dependency.project.contracts_folder / "Vy.vy"
vy_path.write_text("# Vy")
expected = (
"Compiling dependency produced no contract types. "
"Try installing 'ape-solidity' or 'ape-vyper'."
)
result = dependency.compile()
assert len(result) == 0
assert expected in ape_caplog.head


class TestProject:
"""
Expand Down
3 changes: 3 additions & 0 deletions tests/integration/cli/projects/with-contracts/ape-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ dependencies:
config_override:
contracts_folder: .

- name: depwithunregisteredcontracts
local: ./dep_with_sol_and_vy

test:
# `false` because running pytest within pytest.
disconnect_providers_after: false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Solidity file test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Vyper file test
24 changes: 23 additions & 1 deletion tests/integration/cli/test_pm.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import pytest

from tests.conftest import ApeSubprocessRunner
from tests.conftest import ApeSubprocessRunner, skip_if_plugin_installed
from tests.integration.cli.utils import github_xfail, run_once, skip_projects_except

EXPECTED_FAIL_MESSAGE = "Unknown package '{}'."
Expand Down Expand Up @@ -157,6 +157,28 @@ def test_compile_dependency(pm_runner, integ_project):
assert result.exit_code == 0, result.output
assert f"Package '{name}@local' compiled." in result.output

# Show it can happen more than once. (no --force this time).
result = pm_runner.invoke("compile", name)
assert result.exit_code == 0, result.output
assert f"Package '{name}@local' compiled." in result.output


@skip_if_plugin_installed("vyper", "solidity")
@skip_projects_except("with-contracts")
def test_compile_missing_compiler_plugins(pm_runner, integ_project, compilers):
pm_runner.project = integ_project
name = "depwithunregisteredcontracts"
result = pm_runner.invoke("compile", name, "--force")
expected = (
"Compiling dependency produced no contract types. "
"Try installing 'ape-solidity' or 'ape-vyper'"
)
assert expected in result.output

# Also show it happens when installing _all_.
result = pm_runner.invoke("compile", ".", "--force")
assert expected in result.output


@skip_projects_except("only-dependencies")
def test_uninstall(pm_runner, integ_project):
Expand Down
Loading