diff --git a/sqlmesh/integrations/github/cicd/command.py b/sqlmesh/integrations/github/cicd/command.py index cedee1fa58..e14f1c042f 100644 --- a/sqlmesh/integrations/github/cicd/command.py +++ b/sqlmesh/integrations/github/cicd/command.py @@ -116,7 +116,7 @@ def _update_pr_environment(controller: GithubController) -> bool: return conclusion is not None and conclusion.is_success except Exception as e: conclusion = controller.update_pr_environment_check( - status=GithubCheckStatus.COMPLETED, exception=e + status=GithubCheckStatus.COMPLETED, exception=e, plan=controller.pr_plan_or_none ) return ( conclusion is not None diff --git a/sqlmesh/integrations/github/cicd/controller.py b/sqlmesh/integrations/github/cicd/controller.py index 5a0ad36d71..efe99f9ed1 100644 --- a/sqlmesh/integrations/github/cicd/controller.py +++ b/sqlmesh/integrations/github/cicd/controller.py @@ -408,6 +408,13 @@ def pr_plan(self) -> Plan: assert self._pr_plan_builder return self._pr_plan_builder.build() + @property + def pr_plan_or_none(self) -> t.Optional[Plan]: + try: + return self.pr_plan + except: + return None + @property def prod_plan(self) -> Plan: if not self._prod_plan_builder: @@ -823,6 +830,7 @@ def update_pr_environment_check( self, status: GithubCheckStatus, exception: t.Optional[Exception] = None, + plan: t.Optional[Plan] = None, ) -> t.Optional[GithubCheckConclusion]: """ Updates the status of the merge commit for the PR environment. @@ -926,6 +934,14 @@ def conclusion_handler( if captured_errors: logger.debug(f"Captured errors: {captured_errors}") failure_msg = f"**Errors:**\n{captured_errors}\n" + elif isinstance(exception, UncategorizedPlanError) and plan: + failure_msg = f"The following models could not be categorized automatically:\n" + for snapshot in plan.uncategorized: + failure_msg += f"- {snapshot.name}\n" + failure_msg += ( + f"\nRun `sqlmesh plan {self.pr_environment_name}` locally to apply these changes.\n\n" + "If you would like the bot to automatically categorize changes, check the [documentation](https://sqlmesh.readthedocs.io/en/stable/integrations/github/) for more information." + ) elif isinstance(exception, PlanError): failure_msg = f"Plan application failed.\n\n{self._console.captured_output}" elif isinstance(exception, (SQLMeshError, SqlglotError, ValueError)): @@ -940,11 +956,12 @@ def conclusion_handler( + traceback.format_exc() ) failure_msg = f"This is an unexpected error.\n\n**Exception:**\n```\n{traceback.format_exc()}\n```" + conclusion_to_summary = { GithubCheckConclusion.SKIPPED: f":next_track_button: Skipped creating or updating PR Environment `{self.pr_environment_name}`. {skip_reason}", GithubCheckConclusion.FAILURE: f":x: Failed to create or update PR Environment `{self.pr_environment_name}`.\n\n{failure_msg}", GithubCheckConclusion.CANCELLED: f":stop_sign: Cancelled creating or updating PR Environment `{self.pr_environment_name}`", - GithubCheckConclusion.ACTION_REQUIRED: f":warning: Action Required to create or update PR Environment `{self.pr_environment_name}`. There are likely uncateogrized changes. Run `plan` locally to apply these changes. If you want the bot to automatically categorize changes, then check documentation (https://sqlmesh.readthedocs.io/en/stable/integrations/github/) for more information.", + GithubCheckConclusion.ACTION_REQUIRED: f":warning: Action Required to create or update PR Environment `{self.pr_environment_name}` :warning:\n\n{failure_msg}", } summary = conclusion_to_summary.get( conclusion, f":interrobang: Got an unexpected conclusion: {conclusion.value}" @@ -1031,7 +1048,7 @@ def conclusion_handler( or f"Got an unexpected conclusion: {conclusion.value}" ) if conclusion.is_skipped: - summary = title + summary = skip_reason elif conclusion.is_failure: captured_errors = self._console.consume_captured_errors() summary = ( diff --git a/tests/integrations/github/cicd/test_integration.py b/tests/integrations/github/cicd/test_integration.py index 2d9a129a3f..6737dd1356 100644 --- a/tests/integrations/github/cicd/test_integration.py +++ b/tests/integrations/github/cicd/test_integration.py @@ -665,7 +665,7 @@ def test_merge_pr_has_non_breaking_change_no_categorization( assert pr_checks_runs[2]["output"]["title"] == "PR Virtual Data Environment: hello_world_2" assert ( pr_checks_runs[2]["output"]["summary"] - == ":warning: Action Required to create or update PR Environment `hello_world_2`. There are likely uncateogrized changes. Run `plan` locally to apply these changes. If you want the bot to automatically categorize changes, then check documentation (https://sqlmesh.readthedocs.io/en/stable/integrations/github/) for more information." + == """:warning: Action Required to create or update PR Environment `hello_world_2` :warning:\n\nThe following models could not be categorized automatically:\n- "memory"."sushi"."waiter_revenue_by_day"\n\nRun `sqlmesh plan hello_world_2` locally to apply these changes.\n\nIf you would like the bot to automatically categorize changes, check the [documentation](https://sqlmesh.readthedocs.io/en/stable/integrations/github/) for more information.""" ) assert "SQLMesh - Prod Plan Preview" in controller._check_run_mapping