Repository: dbt-labs/dbt-core
Pull request: Deprecate more env vars
resolves #6903

### Description

Deprecate the rest of the environment variables outlined in the issue.

### Checklist

- [X] I have read [the contributing guide](https://github.com/dbt-labs/dbt-core/blob/main/CONTRIBUTING.md) and understand what's expected of me
- [X] I have signed the [CLA](https://docs.getdbt.com/docs/contributor-license-agreements)
- [X] I have run this code in development and it appears to resolve the stated issue
- [X] This PR includes tests, or tests are not required/relevant for this PR
- [X] I have [opened an issue to add/update docs](https://github.com/dbt-labs/docs.getdbt.com/issues/new/choose), or docs changes are not required/relevant for this PR
- [X] I have run `changie new` to [create a changelog entry](https://github.com/dbt-labs/dbt-core/blob/main/CONTRIBUTING.md#adding-a-changelog-entry)


Problem statement:
[CT-2066] Handle old param/flag names in new CLI
We're renaming some flags to match the common naming convention:
- `no_print` &rarr; `print`
- `flags.DEFER_MODE` / (env var) `DBT_DEFER_TO_STATE` &rarr; `defer`
- `flags.FAVOR_STATE_MODE` &rarr; `favor_state`
- `flags.ARTIFACT_STATE_PATH` / (env var) `DBT_ARTIFACT_STATE_PATH` &rarr; `state`
- (`--single-threaded` was renamed, but it's not something we publicly document, and it might only be relevant for `dbt-rpc`?)


**Acceptance criteria:** We continue to respect the old name:
- respect the old name in env var
- respect the old name in CLI flag
- raise a deprecation warning encouraging them to switch over to the new name
- have tests for each flag changed

I'm less concerned about the CLI flag, which raises a clear error already:
```
$ python3 -m dbt.cli.main --no-send-anonymous-usage-stats run
Usage: python -m dbt.cli.main [OPTIONS] COMMAND [ARGS]...
Try 'python -m dbt.cli.main -h' for help.

Error: No such option: --no-send-anonymous-usage-stats (Possible options: --anonymous-usage-stats, --no-anonymous-usage-stats)
```

Hints from issue discussion:
After speaking with @iknox-fa, we can keep the `send_anonymous_usage_stats` as is, as it conforms with existing naming of params. I will edit the issue description to remove this change, and any mentions of the `UserConfig`, as this was the only env var held in `UserConfig`.
@stu-k The `no_print` &rarr; `print` rename _should_ also be relevant for `UserConfig`, since this is in the same category of "global config" that's settable in three places (CLI flag, env var, user config): https://docs.getdbt.com/reference/global-configs#suppress-print-messages-in-stdout

I see it's actually missing from [the class here](https://github.com/dbt-labs/dbt-core/blob/6b5e38ee2855e8739414c7f5172b80a2090c3a0c/core/dbt/contracts/project.py#L244-L260)! That's an oversight, and speaks to the way that the definition and initialization of these configs have been poorly coordinated to date.

Not very high priority, so I'd be open to discussing kicking it out of scope — just want to make sure we're aligned on the functionality that's documented / expected.
@jtcohen6 This work is currently turning out large enough that I'd rather keep that out of scope for now.
@stu-k Opened as a new ticket: https://github.com/dbt-labs/dbt-core/issues/7036

Commit message: Deprecate more env vars

Patch to review:
diff --git a/.changes/unreleased/Under the Hood-20230315-122723.yaml b/.changes/unreleased/Under the Hood-20230315-122723.yaml
new file mode 100644
index 00000000000..d99b7133b3b
--- /dev/null
+++ b/.changes/unreleased/Under the Hood-20230315-122723.yaml	
@@ -0,0 +1,6 @@
+kind: Under the Hood
+body: Deprecate additional environment variables
+time: 2023-03-15T12:27:23.194686-05:00
+custom:
+  Author: stu-k
+  Issue: "6903"
diff --git a/core/dbt/cli/flags.py b/core/dbt/cli/flags.py
index c0cae646688..ef2f50f2032 100644
--- a/core/dbt/cli/flags.py
+++ b/core/dbt/cli/flags.py
@@ -80,7 +80,10 @@ def args_to_context(args: List[str]) -> Context:
 
 
 DEPRECATED_PARAMS = {
+    "deprecated_defer": "defer",
+    "deprecated_favor_state": "favor_state",
     "deprecated_print": "print",
+    "deprecated_state": "state",
 }
 
 
@@ -132,7 +135,8 @@ def assign_params(ctx, params_assigned_from_default, deprecated_env_vars):
                             continue
                         elif param_source != ParameterSource.ENVIRONMENT:
                             raise BadOptionUsage(
-                                "Deprecated parameters can only be set via environment variables"
+                                param_name,
+                                "Deprecated parameters can only be set via environment variables",
                             )
 
                         # rename for clarity
@@ -148,6 +152,10 @@ def assign_params(ctx, params_assigned_from_default, deprecated_env_vars):
                                 f"No deprecated param name match from {dep_name} to {new_name}"
                             )
 
+                        # remove from defaulted set
+                        if new_name in params_assigned_from_default:
+                            params_assigned_from_default.remove(new_name)
+
                         # adding the deprecation warning function to the set
                         deprecated_env_vars[new_name] = renamed_env_var(
                             old_name=dep_opt.envvar,
@@ -259,3 +267,6 @@ def _assert_mutually_exclusive(
                 )
             elif flag_set_by_user:
                 set_flag = flag
+
+    def clear_deprecations(self):
+        object.__delattr__(self, "deprecated_env_var_warnings")
diff --git a/core/dbt/cli/main.py b/core/dbt/cli/main.py
index dbe24205d4b..26ad48c613f 100644
--- a/core/dbt/cli/main.py
+++ b/core/dbt/cli/main.py
@@ -104,9 +104,11 @@ def cli(ctx, **kwargs):
 @cli.command("build")
 @click.pass_context
 @p.defer
+@p.deprecated_defer
 @p.exclude
 @p.fail_fast
 @p.favor_state
+@p.deprecated_favor_state
 @p.full_refresh
 @p.indirect_selection
 @p.profile
@@ -117,6 +119,7 @@ def cli(ctx, **kwargs):
 @p.selector
 @p.show
 @p.state
+@p.deprecated_state
 @p.store_failures
 @p.target
 @p.target_path
@@ -173,14 +176,17 @@ def docs(ctx, **kwargs):
 @click.pass_context
 @p.compile_docs
 @p.defer
+@p.deprecated_defer
 @p.exclude
 @p.favor_state
+@p.deprecated_favor_state
 @p.profile
 @p.profiles_dir
 @p.project_dir
 @p.select
 @p.selector
 @p.state
+@p.deprecated_state
 @p.target
 @p.target_path
 @p.threads
@@ -236,8 +242,10 @@ def docs_serve(ctx, **kwargs):
 @cli.command("compile")
 @click.pass_context
 @p.defer
+@p.deprecated_defer
 @p.exclude
 @p.favor_state
+@p.deprecated_favor_state
 @p.full_refresh
 @p.indirect_selection
 @p.introspect
@@ -249,6 +257,7 @@ def docs_serve(ctx, **kwargs):
 @p.selector
 @p.inline
 @p.state
+@p.deprecated_state
 @p.target
 @p.target_path
 @p.threads
@@ -351,6 +360,7 @@ def init(ctx, **kwargs):
 @p.raw_select
 @p.selector
 @p.state
+@p.deprecated_state
 @p.target
 @p.vars
 @requires.preflight
@@ -405,7 +415,9 @@ def parse(ctx, **kwargs):
 @cli.command("run")
 @click.pass_context
 @p.defer
+@p.deprecated_defer
 @p.favor_state
+@p.deprecated_favor_state
 @p.exclude
 @p.fail_fast
 @p.full_refresh
@@ -415,6 +427,7 @@ def parse(ctx, **kwargs):
 @p.select
 @p.selector
 @p.state
+@p.deprecated_state
 @p.target
 @p.target_path
 @p.threads
@@ -478,6 +491,7 @@ def run_operation(ctx, **kwargs):
 @p.selector
 @p.show
 @p.state
+@p.deprecated_state
 @p.target
 @p.target_path
 @p.threads
@@ -504,14 +518,17 @@ def seed(ctx, **kwargs):
 @cli.command("snapshot")
 @click.pass_context
 @p.defer
+@p.deprecated_defer
 @p.exclude
 @p.favor_state
+@p.deprecated_favor_state
 @p.profile
 @p.profiles_dir
 @p.project_dir
 @p.select
 @p.selector
 @p.state
+@p.deprecated_state
 @p.target
 @p.threads
 @p.vars
@@ -551,6 +568,7 @@ def source(ctx, **kwargs):
 @p.select
 @p.selector
 @p.state
+@p.deprecated_state
 @p.target
 @p.threads
 @p.vars
@@ -582,9 +600,11 @@ def freshness(ctx, **kwargs):
 @cli.command("test")
 @click.pass_context
 @p.defer
+@p.deprecated_defer
 @p.exclude
 @p.fail_fast
 @p.favor_state
+@p.deprecated_favor_state
 @p.indirect_selection
 @p.profile
 @p.profiles_dir
@@ -592,6 +612,7 @@ def freshness(ctx, **kwargs):
 @p.select
 @p.selector
 @p.state
+@p.deprecated_state
 @p.store_failures
 @p.target
 @p.target_path
diff --git a/core/dbt/cli/params.py b/core/dbt/cli/params.py
index 8c7b95293ef..2e148e4121f 100644
--- a/core/dbt/cli/params.py
+++ b/core/dbt/cli/params.py
@@ -62,16 +62,21 @@
     help="Display debug logging during dbt execution. Useful for debugging and making bug reports.",
 )
 
-# TODO:  The env var and name (reflected in flags) are corrections!
-# The original name was `DEFER_MODE` and used an env var called "DBT_DEFER_TO_STATE"
-# Both of which break existing naming conventions.
-# This will need to be fixed before use in the main codebase and communicated as a change to the community!
+# flag was previously named DEFER_MODE
 defer = click.option(
     "--defer/--no-defer",
     envvar="DBT_DEFER",
     help="If set, defer to the state variable for resolving unselected nodes.",
 )
 
+deprecated_defer = click.option(
+    "--deprecated-defer",
+    envvar="DBT_DEFER_TO_STATE",
+    help="Internal flag for deprecating old env var.",
+    default=False,
+    hidden=True,
+)
+
 enable_legacy_logger = click.option(
     "--enable-legacy-logger/--no-enable-legacy-logger",
     envvar="DBT_ENABLE_LEGACY_LOGGER",
@@ -95,6 +100,12 @@
     help="If set, defer to the argument provided to the state flag for resolving unselected nodes, even if the node(s) exist as a database object in the current environment.",
 )
 
+deprecated_favor_state = click.option(
+    "--deprecated-favor-state",
+    envvar="DBT_FAVOR_STATE_MODE",
+    help="Internal flag for deprecating old env var.",
+)
+
 full_refresh = click.option(
     "--full-refresh",
     "-f",
@@ -214,7 +225,6 @@
     type=click.INT,
 )
 
-# envvar was previously named DBT_NO_PRINT
 print = click.option(
     "--print/--no-print",
     envvar="DBT_PRINT",
@@ -359,10 +369,6 @@
     "--skip-profile-setup", "-s", envvar=None, help="Skip interactive profile setup.", is_flag=True
 )
 
-# TODO:  The env var and name (reflected in flags) are corrections!
-# The original name was `ARTIFACT_STATE_PATH` and used the env var `DBT_ARTIFACT_STATE_PATH`.
-# Both of which break existing naming conventions.
-# This will need to be fixed before use in the main codebase and communicated as a change to the community!
 state = click.option(
     "--state",
     envvar="DBT_STATE",
@@ -376,6 +382,20 @@
     ),
 )
 
+deprecated_state = click.option(
+    "--deprecated-state",
+    envvar="DBT_ARTIFACT_STATE_PATH",
+    help="Internal flag for deprecating old env var.",
+    hidden=True,
+    type=click.Path(
+        dir_okay=True,
+        file_okay=False,
+        readable=True,
+        resolve_path=True,
+        path_type=Path,
+    ),
+)
+
 static_parser = click.option(
     "--static-parser/--no-static-parser",
     envvar="DBT_STATIC_PARSER",
diff --git a/core/dbt/cli/requires.py b/core/dbt/cli/requires.py
index 57f0df82795..49f35ef7a9f 100644
--- a/core/dbt/cli/requires.py
+++ b/core/dbt/cli/requires.py
@@ -42,6 +42,7 @@ def wrapper(*args, **kwargs):
 
         # Deprecation warnings
         [dep_fn() for dep_fn in flags.deprecated_env_var_warnings]
+        flags.clear_deprecations()
 
         if active_user is not None:  # mypy appeasement, always true
             fire_event(MainTrackingUserState(user_state=active_user.state()))
diff --git a/core/dbt/events/types.py b/core/dbt/events/types.py
index 9ff34f84b52..9060807d68c 100644
--- a/core/dbt/events/types.py
+++ b/core/dbt/events/types.py
@@ -401,7 +401,7 @@ def code(self):
     def message(self):
         description = (
             f"The environment variable `{self.old_name}` has been renamed as `{self.new_name}`.\n"
-            f"If `{self.old_name}` is currently set, its value will be used instead of `{self.old_name}`.\n"
+            f"If `{self.old_name}` is currently set, its value will be used instead of `{self.new_name}`.\n"
             f"Set `{self.new_name}` and unset `{self.old_name}` to avoid this deprecation warning and "
             "ensure it works properly in a future release."
         )
diff --git a/tests/functional/cli/test_env_var_deprecations.py b/tests/functional/cli/test_env_var_deprecations.py
new file mode 100644
index 00000000000..6880cc6890d
--- /dev/null
+++ b/tests/functional/cli/test_env_var_deprecations.py
@@ -0,0 +1,60 @@
+import pytest
+import os
+
+from dbt.tests.util import read_file, run_dbt
+
+
+model_one_sql = """
+    select 1 as fun
+"""
+
+
+class TestDeprecatedEnvVars:
+    @pytest.fixture(scope="class")
+    def models(self):
+        return {"model_one.sql": model_one_sql}
+
+    def test_defer(self, project, logs_dir):
+        self.assert_deprecated(
+            logs_dir,
+            "DBT_DEFER_TO_STATE",
+            "DBT_DEFER",
+        )
+
+    def test_favor_state(self, project, logs_dir):
+        self.assert_deprecated(
+            logs_dir,
+            "DBT_FAVOR_STATE_MODE",
+            "DBT_FAVOR_STATE",
+            command="build",
+        )
+
+    def test_print(self, project, logs_dir):
+        self.assert_deprecated(
+            logs_dir,
+            "DBT_NO_PRINT",
+            "DBT_PRINT",
+        )
+
+    def test_state(self, project, logs_dir):
+        self.assert_deprecated(
+            logs_dir,
+            "DBT_ARTIFACT_STATE_PATH",
+            "DBT_STATE",
+            old_val=".",
+        )
+
+    def assert_deprecated(self, logs_dir, old_env_var, new_env_var, command="run", old_val="0"):
+        os.environ[old_env_var] = old_val
+        run_dbt([command])
+
+        # replacing new lines with spaces accounts for text wrapping
+        log_file = read_file(logs_dir, "dbt.log").replace("\n", " ").replace("\\n", " ")
+        dep_str = f"The environment variable `{old_env_var}` has been renamed as `{new_env_var}`"
+
+        try:
+            assert dep_str in log_file
+        except Exception as e:
+            del os.environ[old_env_var]
+            raise e
+        del os.environ[old_env_var]


Code review comments:
diff_hunk: @@ -42,6 +42,7 @@ def wrapper(*args, **kwargs):
 
         # Deprecation warnings
         [dep_fn() for dep_fn in flags.deprecated_env_var_warnings]
path: core/dbt/cli/requires.py
text: @user1:
Nit: should we combing this line and the next line into the a single function that's called here? I guess we can't do it in flags init because logger is not ready when we construct flags?