diff --git a/sqlmesh/integrations/github/cicd/command.py b/sqlmesh/integrations/github/cicd/command.py index cedee1fa58..bf2863145b 100644 --- a/sqlmesh/integrations/github/cicd/command.py +++ b/sqlmesh/integrations/github/cicd/command.py @@ -276,7 +276,9 @@ def _run_all(controller: GithubController) -> None: if has_required_approval and prod_plan_generated and controller.pr_targets_prod_branch: deployed_to_prod = _deploy_production(controller) elif is_auto_deploying_prod: - if not has_required_approval: + if controller.deploy_command_enabled and not has_required_approval: + skip_reason = "Skipped Deploying to Production because a `/deploy` command has not been detected yet" + elif controller.do_required_approval_check and not has_required_approval: skip_reason = ( "Skipped Deploying to Production because a required approver has not approved" ) diff --git a/sqlmesh/integrations/github/cicd/controller.py b/sqlmesh/integrations/github/cicd/controller.py index 5a0ad36d71..f179834e2b 100644 --- a/sqlmesh/integrations/github/cicd/controller.py +++ b/sqlmesh/integrations/github/cicd/controller.py @@ -1022,7 +1022,7 @@ def conclusion_handler( conclusion_to_title = { GithubCheckConclusion.SUCCESS: "Deployed to Prod", GithubCheckConclusion.CANCELLED: "Cancelled deploying to prod", - GithubCheckConclusion.SKIPPED: skip_reason, + GithubCheckConclusion.SKIPPED: "Skipped deployment", GithubCheckConclusion.FAILURE: "Failed to deploy to prod", GithubCheckConclusion.ACTION_REQUIRED: "Failed due to error applying plan", } @@ -1031,7 +1031,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_github_commands.py b/tests/integrations/github/cicd/test_github_commands.py index f5098ac525..5f1dfd0a91 100644 --- a/tests/integrations/github/cicd/test_github_commands.py +++ b/tests/integrations/github/cicd/test_github_commands.py @@ -1295,3 +1295,74 @@ def test_comment_command_deploy_prod_not_enabled( with open(github_output_file, "r", encoding="utf-8") as f: output = f.read() assert output == "" + + +def test_comment_command_deploy_prod_no_deploy_detected_yet( + github_client, + make_controller, + make_mock_check_run, + make_mock_issue_comment, + tmp_path: pathlib.Path, + mocker: MockerFixture, +): + """ + Scenario: + - PR is not merged + - No requred approvers defined + - Tests passed + - PR Merge Method defined + - Deploy command enabled but not yet triggered + + Outcome: + - "Prod Environment Synced" step should explain the reason why it was skipped is because /deploy has not yet been detected + """ + mock_repo = github_client.get_repo() + mock_repo.create_check_run = mocker.MagicMock( + side_effect=lambda **kwargs: make_mock_check_run(**kwargs) + ) + + created_comments = [] + mock_issue = mock_repo.get_issue() + mock_issue.create_comment = mocker.MagicMock( + side_effect=lambda comment: make_mock_issue_comment( + comment=comment, created_comments=created_comments + ) + ) + mock_issue.get_comments = mocker.MagicMock(side_effect=lambda: created_comments) + + mock_pull_request = mock_repo.get_pull() + mock_pull_request.get_reviews = mocker.MagicMock(lambda: []) + mock_pull_request.merged = False + mock_pull_request.merge = mocker.MagicMock() + + controller = make_controller( + "tests/fixtures/github/pull_request_synchronized.json", + github_client, + bot_config=GithubCICDBotConfig(merge_method=MergeMethod.REBASE, enable_deploy_command=True), + ) + controller._context._run_tests = mocker.MagicMock( + side_effect=lambda **kwargs: (TestResult(), "") + ) + + github_output_file = tmp_path / "github_output.txt" + + with mock.patch.dict(os.environ, {"GITHUB_OUTPUT": str(github_output_file)}): + command._run_all(controller) + + assert "SQLMesh - Prod Plan Preview" in controller._check_run_mapping + assert "SQLMesh - PR Environment Synced" in controller._check_run_mapping + assert "SQLMesh - Prod Environment Synced" in controller._check_run_mapping + assert "SQLMesh - Run Unit Tests" in controller._check_run_mapping + prod_checks_runs = controller._check_run_mapping["SQLMesh - Prod Environment Synced"].all_kwargs + assert len(prod_checks_runs) == 2 + assert GithubCheckStatus(prod_checks_runs[0]["status"]).is_queued + assert GithubCheckStatus(prod_checks_runs[1]["status"]).is_completed + assert prod_checks_runs[1]["output"]["title"] == "Skipped deployment" + assert ( + prod_checks_runs[1]["output"]["summary"] + == "Skipped Deploying to Production because a `/deploy` command has not been detected yet" + ) + assert GithubCheckConclusion(prod_checks_runs[1]["conclusion"]).is_skipped + + # required approvers are irrelevant because /deploy command is enabled + assert "SQLMesh - Has Required Approval" not in controller._check_run_mapping diff --git a/tests/integrations/github/cicd/test_integration.py b/tests/integrations/github/cicd/test_integration.py index 2d9a129a3f..ab5b9f2245 100644 --- a/tests/integrations/github/cicd/test_integration.py +++ b/tests/integrations/github/cicd/test_integration.py @@ -691,9 +691,11 @@ def test_merge_pr_has_non_breaking_change_no_categorization( assert GithubCheckStatus(prod_checks_runs[0]["status"]).is_queued assert GithubCheckStatus(prod_checks_runs[1]["status"]).is_completed assert GithubCheckConclusion(prod_checks_runs[1]["conclusion"]).is_skipped - skip_reason = "Skipped Deploying to Production because the PR environment was not updated" - assert prod_checks_runs[1]["output"]["title"] == skip_reason - assert prod_checks_runs[1]["output"]["summary"] == skip_reason + assert prod_checks_runs[1]["output"]["title"] == "Skipped deployment" + assert ( + prod_checks_runs[1]["output"]["summary"] + == "Skipped Deploying to Production because the PR environment was not updated" + ) assert "SQLMesh - Has Required Approval" in controller._check_run_mapping approval_checks_runs = controller._check_run_mapping[ @@ -1024,9 +1026,11 @@ def test_no_merge_since_no_deploy_signal( assert GithubCheckStatus(prod_checks_runs[0]["status"]).is_queued assert GithubCheckStatus(prod_checks_runs[1]["status"]).is_completed assert GithubCheckConclusion(prod_checks_runs[1]["conclusion"]).is_skipped - skip_reason = "Skipped Deploying to Production because a required approver has not approved" - assert prod_checks_runs[1]["output"]["title"] == skip_reason - assert prod_checks_runs[1]["output"]["summary"] == skip_reason + assert prod_checks_runs[1]["output"]["title"] == "Skipped deployment" + assert ( + prod_checks_runs[1]["output"]["summary"] + == "Skipped Deploying to Production because a required approver has not approved" + ) assert "SQLMesh - Has Required Approval" in controller._check_run_mapping approval_checks_runs = controller._check_run_mapping[ @@ -1528,9 +1532,11 @@ def test_error_msg_when_applying_plan_with_bug( assert GithubCheckStatus(prod_checks_runs[0]["status"]).is_queued assert GithubCheckStatus(prod_checks_runs[1]["status"]).is_completed assert GithubCheckConclusion(prod_checks_runs[1]["conclusion"]).is_skipped - skip_reason = "Skipped Deploying to Production because the PR environment was not updated" - assert prod_checks_runs[1]["output"]["title"] == skip_reason - assert prod_checks_runs[1]["output"]["summary"] == skip_reason + assert prod_checks_runs[1]["output"]["title"] == "Skipped deployment" + assert ( + prod_checks_runs[1]["output"]["summary"] + == "Skipped Deploying to Production because the PR environment was not updated" + ) assert "SQLMesh - Has Required Approval" in controller._check_run_mapping approval_checks_runs = controller._check_run_mapping[