Skip to content

Commit

Permalink
Merge branch 'main' into work/CRAFT-2120-missing-library-package
Browse files Browse the repository at this point in the history
  • Loading branch information
cmatsuoka authored Nov 1, 2023
2 parents bac2a0d + fb9a01d commit 4d35250
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 50 deletions.
7 changes: 6 additions & 1 deletion snapcraft/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import snapcraft_legacy
from snapcraft import __version__, errors, store, utils
from snapcraft.parts import plugins
from snapcraft.remote import RemoteBuildError
from snapcraft_legacy.cli import legacy

from . import commands
Expand Down Expand Up @@ -243,7 +244,8 @@ def _emit_error(error, cause=None):
emit.error(error)


def run(): # noqa: C901
# pylint: disable-next=too-many-statements
def run(): # noqa: C901 (complex-structure)
"""Run the CLI."""
dispatcher = get_dispatcher()
retcode = 1
Expand Down Expand Up @@ -298,6 +300,9 @@ def run(): # noqa: C901
except errors.LinterError as err:
emit.error(craft_cli.errors.CraftError(f"linter error: {err}"))
retcode = err.exit_code
except RemoteBuildError as err:
emit.error(craft_cli.errors.CraftError(f"remote-build error: {err}"))
retcode = 1
except errors.SnapcraftError as err:
_emit_error(err)
retcode = 1
Expand Down
33 changes: 19 additions & 14 deletions snapcraft/commands/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def _run_new_or_fallback_remote_build(self, base: str) -> None:
"""
# bases newer than core22 must use the new remote-build
if base in yaml_utils.CURRENT_BASES - {"core22"}:
emit.debug("Running new remote-build because base is newer than core22.")
emit.debug("Running new remote-build because base is newer than core22")
self._run_new_remote_build()
return

Expand All @@ -180,27 +180,27 @@ def _run_new_or_fallback_remote_build(self, base: str) -> None:
if strategy == _Strategies.DISABLE_FALLBACK:
emit.debug(
"Running new remote-build because environment variable "
f"{_STRATEGY_ENVVAR!r} is {_Strategies.DISABLE_FALLBACK.value!r}."
f"{_STRATEGY_ENVVAR!r} is {_Strategies.DISABLE_FALLBACK.value!r}"
)
self._run_new_remote_build()
return

if strategy == _Strategies.FORCE_FALLBACK:
emit.debug(
"Running fallback remote-build because environment variable "
f"{_STRATEGY_ENVVAR!r} is {_Strategies.FORCE_FALLBACK.value!r}."
f"{_STRATEGY_ENVVAR!r} is {_Strategies.FORCE_FALLBACK.value!r}"
)
run_legacy()
return

if is_repo(Path().absolute()):
emit.debug(
"Running new remote-build because project is in a git repository."
"Running new remote-build because project is in a git repository"
)
self._run_new_remote_build()
return

emit.debug("Running fallback remote-build.")
emit.debug("Running fallback remote-build")
run_legacy()

def _get_project_name(self) -> str:
Expand All @@ -218,7 +218,7 @@ def _get_project_name(self) -> str:
if project_name:
emit.debug(
f"Using project name {project_name!r} from "
f"{str(self._snapcraft_yaml)!r}."
f"{str(self._snapcraft_yaml)!r}"
)
return project_name

Expand All @@ -228,7 +228,7 @@ def _get_project_name(self) -> str:

def _run_new_remote_build(self) -> None:
"""Run new remote-build code."""
emit.progress("Setting up launchpad environment.")
emit.progress("Setting up launchpad environment")
remote_builder = RemoteBuilder(
app_name="snapcraft",
build_id=self._parsed_args.build_id,
Expand All @@ -242,14 +242,14 @@ def _run_new_remote_build(self) -> None:
remote_builder.print_status()
return

emit.progress("Looking for existing builds.")
emit.progress("Looking for existing build")
has_outstanding_build = remote_builder.has_outstanding_build()
if self._parsed_args.recover and not has_outstanding_build:
emit.message("No build found.")
emit.progress("No build found", permanent=True)
return

if has_outstanding_build:
emit.message("Found previously started build.")
emit.progress("Found existing build", permanent=True)
remote_builder.print_status()

# If recovery specified, monitor build and exit.
Expand All @@ -260,22 +260,27 @@ def _run_new_remote_build(self) -> None:
remote_builder.monitor_build()
emit.progress("Cleaning")
remote_builder.clean_build()
emit.progress("Build completed", permanent=True)
return

# Otherwise clean running build before we start a new one.
emit.progress("Cleaning previously existing build.")
emit.progress("Cleaning existing build")
remote_builder.clean_build()
else:
emit.progress("No existing build found", permanent=True)

emit.message(
emit.progress(
"If interrupted, resume with: 'snapcraft remote-build --recover "
f"--build-id {remote_builder.build_id}'."
f"--build-id {remote_builder.build_id}'",
permanent=True,
)
emit.progress("Starting build")
remote_builder.start_build()
emit.progress("Building")
remote_builder.monitor_build()
emit.progress("Cleaning")
remote_builder.clean_build()
emit.progress("Build completed", permanent=True)

def _get_build_strategy(self) -> Optional[_Strategies]:
"""Get the build strategy from the envvar `SNAPCRAFT_REMOTE_BUILD_STRATEGY`.
Expand Down Expand Up @@ -316,7 +321,7 @@ def _get_effective_base(self) -> str:
f"Could not determine base from {str(self._snapcraft_yaml)!r}."
)

emit.debug(f"Got base {base!r} from {str(self._snapcraft_yaml)!r}.")
emit.debug(f"Got base {base!r} from {str(self._snapcraft_yaml)!r}")

if base in yaml_utils.ESM_BASES:
raise MaintenanceBase(base)
Expand Down
25 changes: 12 additions & 13 deletions snapcraft/remote/launchpad.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def _fetch_artifacts(self, snap: Optional[Entry]) -> None:
"""Fetch build arftifacts (logs and snaps)."""
builds = self._get_builds(snap)

logger.debug("Downloading artifacts...")
logger.info("Downloading artifacts...")
for build in builds:
self._download_build_artifacts(build)
self._download_log(build)
Expand Down Expand Up @@ -220,7 +220,7 @@ def _wait_for_build_request_acceptance(self, build_request: Entry) -> None:
# Check to see if we've run out of time.
self._check_timeout_deadline()

logger.debug("Waiting on Launchpad build request...")
logger.info("Waiting on Launchpad build request...")
logger.debug(
"status=%s error=%s", build_request.status, build_request.error_message
)
Expand Down Expand Up @@ -250,7 +250,7 @@ def _wait_for_build_request_acceptance(self, build_request: Entry) -> None:
)

build_number = _get_url_basename(cast(str, build_request.self_link))
logger.debug("Build request accepted: %s", build_number)
logger.info("Build request accepted: %s", build_number)

def _login(self) -> Launchpad:
"""Login to launchpad."""
Expand Down Expand Up @@ -287,7 +287,7 @@ def _create_git_repository(self, force=False) -> Entry:
if force:
self._delete_git_repository()

logger.debug(
logger.info(
"creating git repo: name=%s, owner=%s, target=%s",
self._lp_name,
self._lp_owner,
Expand All @@ -306,7 +306,7 @@ def _delete_git_repository(self) -> None:
if git_repo is None:
return

logger.debug("Deleting source repository from Launchpad...")
logger.info("Deleting source repository from Launchpad...")
git_repo.lp_delete()

def _create_snap(self, force=False) -> Entry:
Expand All @@ -320,7 +320,7 @@ def _create_snap(self, force=False) -> Entry:
if self._lp_processors:
optional_kwargs["processors"] = self._lp_processors

logger.debug("Registering snap job on Launchpad...")
logger.info("Registering snap job on Launchpad...")
logger.debug(
"url=https://launchpad.net/%s/+snap/%s", self._lp_owner, self._lp_name
)
Expand All @@ -342,7 +342,7 @@ def _delete_snap(self) -> None:
if snap is None:
return

logger.debug("Removing snap job from Launchpad...")
logger.info("Removing snap job from Launchpad...")
snap.lp_delete()

def cleanup(self) -> None:
Expand All @@ -354,7 +354,7 @@ def start_build(self) -> None:
"""Start build with specified timeout (time.time() in seconds)."""
snap = self._create_snap(force=True)

logger.debug("Issuing build request on Launchpad...")
logger.info("Issuing build request on Launchpad...")
build_request = self._issue_build_request(snap)
self._wait_for_build_request_acceptance(build_request)

Expand All @@ -368,17 +368,16 @@ def monitor_build(self, interval: int = _LP_POLL_INTERVAL) -> None:

builds = self._get_builds(snap)
pending = False
timestamp = str(datetime.now())
status = f"Build status as of {timestamp}: "
statuses = []
for build in builds:
state = build["buildstate"]
arch = build["arch_tag"]
status += f" {arch=} {state=}"
statuses.append(f"{arch}: {state}")

if _is_build_pending(build):
pending = True

logger.info(status)
logger.info(", ".join(statuses))

if pending is False:
break
Expand Down Expand Up @@ -426,7 +425,7 @@ def _download_log(self, build: Dict[str, Any]) -> None:

def _download_file(self, *, url: str, dst: str, gunzip: bool = False) -> None:
# TODO: consolidate with, and use indicators.download_requests_stream
logger.debug("Downloading: %s", url)
logger.info("Downloading: %s", url)
try:
with requests.get(url, stream=True, timeout=3600) as response:
# Wrap response with gzipfile if gunzip is requested.
Expand Down
1 change: 0 additions & 1 deletion snapcraft/remote/remote_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ def clean_build(self) -> None:
logger.info("Cleaning existing builds and artefacts.")
self._lpc.cleanup()
self._worktree.clean_cache()
logger.info("Done.")

def start_build(self) -> None:
"""Start a build in Launchpad.
Expand Down
19 changes: 19 additions & 0 deletions tests/unit/cli/test_exit.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from craft_providers import ProviderError

from snapcraft import cli
from snapcraft.remote import RemoteBuildError


def test_no_keyring_error(capsys, mocker):
Expand Down Expand Up @@ -74,6 +75,24 @@ def test_craft_providers_error(capsys, mocker):
assert stderr[2].startswith("test resolution")


def test_remote_build_error(capsys, mocker):
"""Catch remote-build errors."""
mocker.patch.object(sys, "argv", ["cmd", "pull"])
mocker.patch.object(sys.stdin, "isatty", return_value=True)
mocker.patch(
"snapcraft.commands.lifecycle.PullCommand.run",
side_effect=RemoteBuildError(brief="test brief", details="test details"),
)

cli.run()

stderr = capsys.readouterr().err.splitlines()

# Simple verification that our expected message is being printed
assert stderr[0].startswith("remote-build error: test brief")
assert stderr[1].startswith("test details")


@pytest.mark.parametrize("is_managed,report_errors", [(True, False), (False, True)])
def test_emit_error(emitter, mocker, is_managed, report_errors):
mocker.patch("snapcraft.utils.is_managed_mode", return_value=is_managed)
Expand Down
Loading

0 comments on commit 4d35250

Please sign in to comment.