Skip to content

Commit

Permalink
[TECH-272] Improve exception handling and reporting
Browse files Browse the repository at this point in the history
branch: feature/TECH-272-upgrade-monorepo
  • Loading branch information
SamTheisens committed May 15, 2023
1 parent 85e3b55 commit 274dbfd
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 12 deletions.
6 changes: 3 additions & 3 deletions src/mpyl/cli/commands/build/mpyl.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from ....stages.discovery import for_stage, find_invalidated_projects_per_stage
from ....steps.models import RunProperties
from ....steps.run import RunResult
from ....steps.steps import Steps
from ....steps.steps import Steps, ExecutionException
from ....utilities.repo import Repository, RepoConfig


Expand Down Expand Up @@ -86,10 +86,10 @@ def run_mpyl(mpyl_run_parameters: MpylRunParameters, reporter: Optional[Reporter
try:
steps = Steps(logger=logger, properties=mpyl_run_parameters.run_config.run_properties)
run_result = run_build(run_plan, steps, reporter, mpyl_run_parameters.parameters.local)
except Exception as exc: # pylint: disable=broad-except
except ExecutionException as exc: # pylint: disable=broad-except
run_result.exception = exc
console.log(f'Exception during build execution: {exc}')
console.print_exception()
run_result.exception = exc

console.print(Markdown(run_result_to_markdown(run_result)))
return run_result
Expand Down
6 changes: 4 additions & 2 deletions src/mpyl/reporting/formatting/markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ def markdown_for_stage(run_result: RunResult, stage: Stage):

def run_result_to_markdown(run_result: RunResult) -> str:
result: str = f'{run_result.status_line} \n'
if run_result.exception:
result += f"\n```\n{run_result.exception}\n```\n"
exception = run_result.exception
if exception:
result += f"For _{exception.executor}_ on _{exception.project_name}_ at _{exception.stage}_ \n"
result += f"\n```\n{exception}\n```\n"

for stage in Stage:
result += markdown_for_stage(run_result, stage)
Expand Down
8 changes: 4 additions & 4 deletions src/mpyl/steps/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@

from .models import RunProperties
from ..project import Stage, Project
from .steps import StepResult
from .steps import StepResult, ExecutionException


class RunResult:
_run_plan: dict[Stage, set[Project]]
_results: list[StepResult]
_run_properties: RunProperties
_exception: Optional[Exception]
_exception: Optional[ExecutionException]

def __init__(self, run_properties: RunProperties, run_plan=None):
if run_plan is None:
Expand Down Expand Up @@ -56,11 +56,11 @@ def progress_fraction(self) -> float:
return 1.0 - (unfinished / total)

@property
def exception(self) -> Optional[Exception]:
def exception(self) -> Optional[ExecutionException]:
return self._exception

@exception.setter
def exception(self, exception: Exception):
def exception(self, exception: ExecutionException):
self._exception = exception

@property
Expand Down
23 changes: 21 additions & 2 deletions src/mpyl/steps/steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@
yaml = YAML()


class ExecutionException(Exception):
""" Exception thrown when a step execution fails. """

def __init__(self, project_name: str, executor: str, stage: str, message: str):
self.project_name = project_name
self.executor = executor
self.stage = stage
self.message = message
super().__init__(self.message)


@dataclass(frozen=True)
class StepResult:
stage: Stage
Expand Down Expand Up @@ -143,15 +154,23 @@ def _execute_stage(self, stage: Stage, project: Project, dry_run: bool = False)

return result
except Exception as exc:
message = str(exc)
self._logger.warning(
f"Execution of '{executor.meta.name}' for project '{project.name}' in stage {stage} "
f"failed with exception: {str(exc)}", exc_info=True)
raise ValueError from exc
f"failed with exception: {message}", exc_info=True)
raise ExecutionException(project.name, executor.meta.name, stage.name, message) from exc
else:
self._logger.warning(f"No executor found for {stage_name} in stage {stage}")

return Output(success=False, message=f"Executor '{stage_name}' for '{stage.value}' not known or registered")

def execute(self, stage: Stage, project: Project, dry_run: bool = False) -> StepResult:
"""
:param stage: the stage to execute
:param project: the project metadata
:param dry_run: indicates whether artifacts should be submitted or deployed for real
:return: StepResult
:raise ExecutionException
"""
step_output = self._execute_stage(stage, project, dry_run)
return StepResult(stage=stage, project=project, output=step_output)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
❗ Failed with exception
For _Build SBT_ on _sbtProject_ at _Build_

```
Something went wrong
```
🏗️ _dockertest_, _test_
🧪 _test_
🧪 51 ❌ 1 💔 0 🙈 0 [link](http://localhost/tests)
🚀 _test_
8 changes: 7 additions & 1 deletion tests/reporting/test_markdown_reporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from src.mpyl.project import Stage
from src.mpyl.reporting.formatting.markdown import summary_to_markdown, run_result_to_markdown
from src.mpyl.steps import Output
from src.mpyl.steps.steps import StepResult
from src.mpyl.steps.steps import StepResult, ExecutionException
from src.mpyl.utilities.junit import TestRunSummary
from tests import root_test_path
from tests.reporting import create_test_result, create_test_result_with_plan, append_results
Expand All @@ -19,6 +19,12 @@ def test_should_print_results_as_string(self):
simple_report = run_result_to_markdown(run_result)
assert_roundtrip(self.test_resource_path / "markdown_run.md", simple_report)

def test_should_print_exception(self):
run_result = create_test_result()
run_result.exception = ExecutionException('sbtProject', 'Build SBT', 'Build', 'Something went wrong')
simple_report = run_result_to_markdown(run_result)
assert_roundtrip(self.test_resource_path / "markdown_run_with_exception.md", simple_report)

def test_should_print_results_with_plan_as_string(self):
run_result = create_test_result_with_plan()
append_results(run_result)
Expand Down

0 comments on commit 274dbfd

Please sign in to comment.