Skip to content

Behavior flag to handle all warnings with warn_error logic #11483

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/unreleased/Features-20250410-111023.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Features
body: Add behavior flag for handling all warnings via warn_error logic
time: 2025-04-10T11:10:23.344469-05:00
custom:
Author: QMalcolm
Issue: "11116"
4 changes: 4 additions & 0 deletions core/dbt/cli/requires.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from dbt_common.clients.system import get_env
from dbt_common.context import get_invocation_context, set_invocation_context
from dbt_common.events.base_types import EventLevel
from dbt_common.events.event_manager_client import get_event_manager
from dbt_common.events.functions import LOG_VERSION, fire_event
from dbt_common.events.helpers import get_json_string_utcnow
from dbt_common.exceptions import DbtBaseException as DbtException
Expand Down Expand Up @@ -74,6 +75,9 @@ def wrapper(*args, **kwargs):
flags = Flags(ctx)
ctx.obj["flags"] = flags
set_flags(flags)
get_event_manager().require_warn_or_error_handling = (
flags.require_all_warnings_handled_by_warn_error
)

# Reset invocation_id for each 'invocation' of a dbt command (can happen multiple times in a single process)
reset_invocation_id()
Expand Down
2 changes: 2 additions & 0 deletions core/dbt/contracts/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ class ProjectFlags(ExtensibleDbtClassMixin):
require_yaml_configuration_for_mf_time_spines: bool = False
require_nested_cumulative_type_params: bool = False
validate_macro_args: bool = False
require_all_warnings_handled_by_warn_error: bool = False

@property
def project_only_flags(self) -> Dict[str, Any]:
Expand All @@ -362,6 +363,7 @@ def project_only_flags(self) -> Dict[str, Any]:
"require_yaml_configuration_for_mf_time_spines": self.require_yaml_configuration_for_mf_time_spines,
"require_nested_cumulative_type_params": self.require_nested_cumulative_type_params,
"validate_macro_args": self.validate_macro_args,
"require_all_warnings_handled_by_warn_error": self.require_all_warnings_handled_by_warn_error,
}


Expand Down
69 changes: 68 additions & 1 deletion tests/functional/configs/test_warn_error_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import pytest

from dbt.cli.main import dbtRunner, dbtRunnerResult
from dbt.events.types import DeprecatedModel
from dbt.events.types import (
DeprecatedModel,
MainEncounteredError,
MicrobatchModelNoEventTimeInputs,
)
from dbt.flags import get_flags
from dbt.tests.util import run_dbt, update_config_file
from dbt_common.events.base_types import EventLevel
Expand Down Expand Up @@ -229,3 +233,66 @@ def test_project_flags(self, project):
# Note: WarnErrorOptions is not a dataclass, so you won't get "silence"
# from to_dict or stringifying.
assert flags.warn_error_options.silence == ["TestsConfigDeprecation"]


input_model_without_event_time_sql = """
{{ config(materialized='table') }}

select 1 as id, TIMESTAMP '2020-01-01 00:00:00-0' as event_time
union all
select 2 as id, TIMESTAMP '2020-01-02 00:00:00-0' as event_time
union all
select 3 as id, TIMESTAMP '2020-01-03 00:00:00-0' as event_time
"""

microbatch_model_sql = """
{{config(materialized='incremental', incremental_strategy='microbatch', unique_key='id', event_time='event_time', batch_size='day', begin=modules.datetime.datetime.now())}}
SELECT id, event_time FROM {{ ref('input_model') }}
"""


class TestRequireAllWarningsHandledByWarnErrorBehaviorFlag:
@pytest.fixture(scope="class")
def models(self):
return {
"input_model.sql": input_model_without_event_time_sql,
"microbatch_model.sql": microbatch_model_sql,
}

def test_require_all_warnings_handed_by_warn_error_behavior_flag(self, project):
# Setup the event catchers
microbatch_warning_catcher = EventCatcher(event_to_catch=MicrobatchModelNoEventTimeInputs)
microbatch_error_catcher = EventCatcher(event_to_catch=MainEncounteredError)
dbt_runner = dbtRunner(
callbacks=[microbatch_warning_catcher.catch, microbatch_error_catcher.catch]
)

# Run the command without the behavior flag off
project_flags = {
"flags": {
"send_anonymous_usage_stats": False,
"require_all_warnings_handled_by_warn_error": False,
}
}
update_config_file(project_flags, project.project_root, "dbt_project.yml")
dbt_runner.invoke(["run", "--warn-error"])

assert len(microbatch_warning_catcher.caught_events) == 1
assert len(microbatch_error_catcher.caught_events) == 0

# Reset the event catchers
microbatch_warning_catcher.flush()
microbatch_error_catcher.flush()

# Run the command with the behavior flag on
project_flags = {
"flags": {
"send_anonymous_usage_stats": False,
"require_all_warnings_handled_by_warn_error": True,
}
}
update_config_file(project_flags, project.project_root, "dbt_project.yml")
dbt_runner.invoke(["run", "--warn-error", "--log-format", "json"])

assert len(microbatch_warning_catcher.caught_events) == 0
assert len(microbatch_error_catcher.caught_events) == 1