Implementation:TobikoData Sqlmesh CICD Gen Prod Plan
| Knowledge Sources | |
|---|---|
| Domains | Data_Engineering, CICD |
| Last Updated | 2026-02-07 00:00 GMT |
Overview
Concrete implementation for generating production deployment plan previews as GitHub Check Runs provided by SQLMesh.
Description
The gen_prod_plan command and get_plan_summary controller method generate detailed previews of production deployments by comparing PR environments to production. It creates a plan with no_gaps enabled to detect missing data intervals, formats a comprehensive summary showing added/modified/removed models, displays date ranges requiring backfills, includes categorization (breaking/non-breaking/forward-only), updates a GitHub Check Run with the formatted plan, and provides warnings about deployment impacts. This implementation enables informed review of production changes before deployment execution.
Usage
Use gen_prod_plan as a GitHub Actions workflow step after PR environment creation to preview what would happen if changes are deployed to production. This typically runs before the deploy_production step to provide visibility into deployment impacts.
Code Reference
Source Location
- Repository: sqlmesh
- File: sqlmesh/integrations/github/cicd/command.py:L174-181 (CLI), sqlmesh/integrations/github/cicd/controller.py:L519-564 (get_plan_summary method)
Signature
# CLI Command
@github.command()
@click.pass_context
@cli_analytics
def gen_prod_plan(ctx: click.Context) -> None:
"""Generates the production plan"""
controller = ctx.obj["github"]
controller.update_prod_plan_preview_check(status=GithubCheckStatus.IN_PROGRESS)
if not _gen_prod_plan(controller):
raise CICDBotError(
"Failed to generate production plan. See Pull Requests Checks for more information."
)
# Controller Method
def get_plan_summary(self, plan: Plan) -> str:
# use Verbosity.VERY_VERBOSE to prevent the list of models from being truncated
orig_verbosity = self._console.verbosity
self._console.verbosity = Verbosity.VERY_VERBOSE
try:
# Clear out any output that might exist from prior steps
self._console.consume_captured_output()
if plan.restatements:
self._console._print("\n**Restating models**\n")
else:
self._console.show_environment_difference_summary(
context_diff=plan.context_diff,
no_diff=False,
)
if plan.context_diff.has_changes:
self._console.show_model_difference_summary(
context_diff=plan.context_diff,
environment_naming_info=plan.environment_naming_info,
default_catalog=self._context.default_catalog,
no_diff=False,
)
difference_summary = self._console.consume_captured_output()
self._console._show_missing_dates(plan, self._context.default_catalog)
missing_dates = self._console.consume_captured_output()
plan_flags_section = (
f"\n\n{self._generate_plan_flags_section(plan.user_provided_flags)}"
if plan.user_provided_flags
else ""
)
if not difference_summary and not missing_dates:
return f"No changes to apply.{plan_flags_section}"
warnings_block = self._console.consume_captured_warnings()
errors_block = self._console.consume_captured_errors()
return f"{warnings_block}{errors_block}{difference_summary}\n{missing_dates}{plan_flags_section}"
except PlanError as e:
logger.exception("Plan failed to generate")
return f"Plan failed to generate. Check for pending or unresolved changes. Error: {e}"
finally:
self._console.verbosity = orig_verbosity
Import
from sqlmesh.integrations.github.cicd.command import gen_prod_plan
from sqlmesh.integrations.github.cicd.controller import GithubController
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| ctx | click.Context | Yes | Click context containing initialized GithubController in ctx.obj["github"] |
| plan | Plan | Yes (for get_plan_summary) | SQLMesh Plan object to generate summary from |
Outputs
| Name | Type | Description |
|---|---|---|
| None | None | Command updates GitHub Check Run with plan summary; raises CICDBotError if generation fails |
| summary | str | (get_plan_summary) Formatted markdown summary of the plan |
Usage Examples
Basic Usage
# In GitHub Actions workflow:
# - name: Generate Production Plan
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# run: sqlmesh_cicd bot github gen-prod-plan
# Programmatic usage:
from sqlmesh.integrations.github.cicd.controller import (
GithubController,
GithubCheckStatus,
GithubCheckConclusion
)
controller = GithubController(
paths=["path/to/project"],
token="github_token"
)
# Update check to in-progress
controller.update_prod_plan_preview_check(status=GithubCheckStatus.IN_PROGRESS)
try:
# Get production plan
plan = controller.prod_plan
# Generate plan summary
summary = controller.get_plan_summary(plan)
# Update check with summary
controller.update_prod_plan_preview_check(
status=GithubCheckStatus.COMPLETED,
conclusion=GithubCheckConclusion.SUCCESS,
summary=summary
)
except Exception as e:
# Update check with failure
controller.update_prod_plan_preview_check(
status=GithubCheckStatus.COMPLETED,
conclusion=GithubCheckConclusion.FAILURE,
summary=str(e)
)
# Example plan summary in GitHub Check Run:
# Prod Plan Preview
#
# This is a preview that shows the differences between this PR environment
# `my_repo_123` and `prod`.
#
# These are the changes that would be deployed.
#
# Summary of differences against `prod`:
# └── Added Models:
# └── db.customers_v2
# └── Modified Models:
# ├── Directly Modified:
# │ └── db.orders (Breaking)
# └── Indirectly Modified:
# └── db.order_stats (Indirect Non-breaking)
#
# Models needing backfill (missing dates):
# ├── db.orders: 2024-02-01 - 2024-12-31
# └── db.order_stats: 2024-02-01 - 2024-12-31
#
# Apply this plan by merging to main or commenting `/deploy`