Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
061030c
SNOW-2306184: config refactory entry point guarded by env
sfc-gh-mraba Oct 2, 2025
3e2b8f3
SNOW-2306184: config refactory entry point guarded by env - fix snapshot
sfc-gh-mraba Oct 3, 2025
bfc9b39
SNOW-2306184: config refactory - core abstraction
sfc-gh-mraba Oct 3, 2025
3a178ed
SNOW-2306184: config refactory - top tier configuration sources
sfc-gh-mraba Oct 3, 2025
ca9b7bd
SNOW-2306184: config refactory - env vars discovery
sfc-gh-mraba Oct 6, 2025
ca7c395
SNOW-2306184: config refactory - move key mappings to module level
sfc-gh-mraba Oct 6, 2025
2621490
SNOW-2306184: config refactory - SnowSQL config files behaviour
sfc-gh-mraba Oct 6, 2025
74bac2e
SNOW-2306184: config refactory - resolver history
sfc-gh-mraba Oct 6, 2025
692ce3e
SNOW-2306184: config refactory - integrate new config
sfc-gh-mraba Oct 7, 2025
2c51413
SNOW-2306184: config refactory - helpers command integration
sfc-gh-mraba Oct 7, 2025
6354a4b
SNOW-2306184: config refactory - config testing setup
sfc-gh-mraba Oct 8, 2025
e223ac9
SNOW-2306184: config refactory - fix snowsql config format parsing
sfc-gh-mraba Oct 8, 2025
add955a
SNOW-2306184: config refactory - drop tests for language functionality
sfc-gh-mraba Oct 8, 2025
7982a11
SNOW-2306184: config refactory - drop tests for language functionalit…
sfc-gh-mraba Oct 8, 2025
c9e8828
SNOW-2306184: config refactory - cleanup source config handlers naming
sfc-gh-mraba Oct 8, 2025
21e4371
SNOW-2306184: config refactory - cleanup source ConfigValue creation
sfc-gh-mraba Oct 8, 2025
c8eedcc
SNOW-2306184: config refactor - simplify abstractions
sfc-gh-mraba Oct 8, 2025
30611c5
SNOW-2306184: config refactor - simplified implementation
sfc-gh-mraba Oct 9, 2025
e4c2a8c
SNOW-2306184: config refactor - gh workflows
sfc-gh-mraba Oct 9, 2025
ee4ec0b
SNOW-2306184: config refactor - cli env update
sfc-gh-mraba Oct 9, 2025
e2cd2f8
SNOW-2306184: config refactor - snowsql env support
sfc-gh-mraba Oct 9, 2025
260435b
SNOW-2306184: config refactor - restore temp conn
sfc-gh-mraba Oct 9, 2025
09daf79
SNOW-2306184: config refactor - tests-ng fix
sfc-gh-mraba Oct 9, 2025
c0f3eb4
SNOW-2306184: config refactor - integrations ng
sfc-gh-mraba Oct 9, 2025
c18bc2b
SNOW-2306184: config refactor - old & new unit tests pass
sfc-gh-mraba Oct 9, 2025
de5689d
SNOW-2306184: config refactor - old & new unit tests
sfc-gh-mraba Oct 10, 2025
f812d28
SNOW-2306184: config refactor - plugin tests in JSON format
sfc-gh-mraba Oct 10, 2025
e32cb0e
SNOW-2306184: config refactor - e2e fix attempt
sfc-gh-mraba Oct 10, 2025
e2c837c
SNOW-2306184: config refactor - e2e fix attempt 3
sfc-gh-mraba Oct 10, 2025
f766f9d
SNOW-2306184: config refactor - e2e fix attempt 4
sfc-gh-mraba Oct 10, 2025
c969617
SNOW-2306184: config refactor - e2e fix attempt 5
sfc-gh-mraba Oct 10, 2025
3dc1043
SNOW-2306184: config refactor - e2e fix attempt 5a
sfc-gh-mraba Oct 10, 2025
d0dd951
SNOW-2306184: config refactor - e2e fix attempt 5b
sfc-gh-mraba Oct 10, 2025
dd4d403
SNOW-2306184: config refactor - config_snapshot to distingush between…
sfc-gh-mraba Oct 13, 2025
17dd32a
SNOW-2306184: config refactor - invalidate singleton between tests
sfc-gh-mraba Oct 13, 2025
bc0aceb
SNOW-2306184: config refactor - list connections --all
sfc-gh-mraba Oct 13, 2025
60664d7
SNOW-2306184: config refactor - snapshot COLUMNS=200
sfc-gh-mraba Oct 13, 2025
5499c60
SNOW-2306184: config refactor - snapshot fix 2
sfc-gh-mraba Oct 13, 2025
c841fa0
SNOW-2306184: config refactor - snapshot fix 3
sfc-gh-mraba Oct 13, 2025
9f6a524
SNOW-2306184: config refactor - show-config-sources tests
sfc-gh-mraba Oct 13, 2025
92a8f3d
SNOW-2306184: config refactor - more merging tests
sfc-gh-mraba Oct 14, 2025
25db8c5
SNOW-2306184: config refactor - connections toml merging split
sfc-gh-mraba Oct 15, 2025
a7ecfe7
SNOW-2306184: config refactor - cleanup 1
sfc-gh-mraba Oct 15, 2025
95b572e
SNOW-2306184: config refactor - cleanup 2
sfc-gh-mraba Oct 15, 2025
3178792
SNOW-2306184: config refactor - cleanup 3
sfc-gh-mraba Oct 15, 2025
4ed3df1
SNOW-2306184: config refactor - cleanup 4
sfc-gh-mraba Oct 15, 2025
defbd4f
SNOW-2306184: config refactor - cleanup 5
sfc-gh-mraba Oct 15, 2025
de18375
SNOW-2306184: config refactor - connections.toml legacy behaviour
sfc-gh-mraba Oct 15, 2025
782b677
SNOW-2306184: config refactor - improve resolution raport
sfc-gh-mraba Oct 15, 2025
71875dd
SNOW-2306184: config refactor - improve connections env parsing
sfc-gh-mraba Oct 15, 2025
8d0bc75
SNOW-2306184: config refactor - clean tmp files
sfc-gh-mraba Oct 15, 2025
d57c971
SNOW-2306184: config refactor - connection level overwrite for config…
sfc-gh-mraba Oct 16, 2025
a6e82d9
SNOW-2306184: config refactor - variables merge
sfc-gh-mraba Oct 16, 2025
4f60197
SNOW-2306184: config refactor - separate parsing from reading and mov…
sfc-gh-mraba Oct 20, 2025
bc331bc
SNOW-2306184: config refactor - Release Notes
sfc-gh-mraba Oct 21, 2025
906f0a4
SNOW-2306184: config refactor - telemetry
sfc-gh-mraba Oct 22, 2025
863a505
SNOW-2306184: config refactor - telemetry test update
sfc-gh-mraba Oct 22, 2025
f26d29e
SNOW-2306184: config refactor - allow empty connections
sfc-gh-mraba Oct 23, 2025
2efcc9e
SNOW-2306184: config refactor - allow empty connections test fix
sfc-gh-mraba Oct 23, 2025
9f628c4
SNOW-2306184: config refactor - after rebase fixes
sfc-gh-mraba Oct 23, 2025
d56c2b5
SNOW-2306184: config refactor - after rebase fixes 2
sfc-gh-mraba Oct 23, 2025
f665cb3
SNOW-2306184: config refactor - remove comments
sfc-gh-mraba Oct 24, 2025
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
28 changes: 27 additions & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
- features/*

env:
TERM: unknown # Disables colors in rich
TERM: unknown # Disables colors in rich

permissions:
contents: read
Expand Down Expand Up @@ -43,3 +43,29 @@ jobs:
- name: Test with hatch
run: hatch run test-cov
- uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24

tests-config-ng:
needs: define-matrix
strategy:
fail-fast: true
matrix:
os: ${{ fromJSON(needs.define-matrix.outputs.os) }}
python-version: ${{ fromJSON(needs.define-matrix.outputs.python) }}
runs-on: ${{ matrix.os }}
env:
SNOWFLAKE_CLI_CONFIG_V2_ENABLED: 1
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install hatch
run: |
pip install -U click==8.2.1 hatch
hatch env create default
- name: Test with hatch
run: hatch run test-cov
- uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24
28 changes: 28 additions & 0 deletions .github/workflows/test_trusted.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,31 @@ jobs:
SNOWFLAKE_CONNECTIONS_INTEGRATION_DATABASE: ${{ secrets.SNOWFLAKE_DATABASE }}
SNOWFLAKE_CONNECTIONS_INTEGRATION_PRIVATE_KEY_RAW: ${{ secrets.SNOWFLAKE_PRIVATE_KEY_RAW }}
run: python -m hatch run ${{ inputs.hatch-run }}

tests-trusted-ng:
runs-on: ${{ inputs.runs-on }}
env:
SNOWFLAKE_CLI_CONFIG_V2_ENABLED: 1
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip click==8.2.1 hatch
python -m hatch env create ${{ inputs.python-env }}
- name: Run integration tests
env:
GH_TOKEN: ${{ secrets.SNOWFLAKE_GITHUB_TOKEN }}
TERM: unknown
SNOWFLAKE_CONNECTIONS_INTEGRATION_AUTHENTICATOR: SNOWFLAKE_JWT
SNOWFLAKE_CONNECTIONS_INTEGRATION_HOST: ${{ secrets.SNOWFLAKE_HOST }}
SNOWFLAKE_CONNECTIONS_INTEGRATION_USER: ${{ secrets.SNOWFLAKE_USER }}
SNOWFLAKE_CONNECTIONS_INTEGRATION_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
SNOWFLAKE_CONNECTIONS_INTEGRATION_DATABASE: ${{ secrets.SNOWFLAKE_DATABASE }}
SNOWFLAKE_CONNECTIONS_INTEGRATION_PRIVATE_KEY_RAW: ${{ secrets.SNOWFLAKE_PRIVATE_KEY_RAW }}
run: python -m hatch run ${{ inputs.hatch-run }}
1 change: 1 addition & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
-->
# Unreleased version
## Backward incompatibility
* **Configuration System (NG)**: File-based configuration sources (`snowsql_config`, `cli_config_toml`, `connections_toml`) now use **connection-level replacement** instead of field-level merging. When a later file source defines a connection, it completely replaces the entire connection from earlier file sources - fields are NOT inherited. Environment variables and CLI arguments continue to overlay per-field on top of the file-derived connection. This provides more predictable configuration behavior where file-defined connections are atomic units.

## Deprecations

Expand Down
55 changes: 55 additions & 0 deletions src/snowflake/cli/_app/telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ class CLITelemetryField(Enum):
COMMAND_CI_ENVIRONMENT = "command_ci_environment"
# Configuration
CONFIG_FEATURE_FLAGS = "config_feature_flags"
CONFIG_PROVIDER_TYPE = "config_provider_type"
CONFIG_SOURCES_USED = "config_sources_used"
CONFIG_SOURCE_WINS = "config_source_wins"
CONFIG_TOTAL_KEYS_RESOLVED = "config_total_keys_resolved"
CONFIG_KEYS_WITH_OVERRIDES = "config_keys_with_overrides"
# Metrics
COUNTERS = "counters"
SPANS = "spans"
Expand Down Expand Up @@ -219,6 +224,55 @@ def python_version() -> str:
return f"{py_ver.major}.{py_ver.minor}.{py_ver.micro}"


def _get_config_telemetry() -> TelemetryDict:
"""Get configuration resolution telemetry data."""
try:
from snowflake.cli.api.config_ng.telemetry_integration import (
get_config_telemetry_payload,
)
from snowflake.cli.api.config_provider import (
AlternativeConfigProvider,
get_config_provider_singleton,
)

provider = get_config_provider_singleton()

# Identify which config provider is being used
provider_type = (
"ng" if isinstance(provider, AlternativeConfigProvider) else "legacy"
)

result: TelemetryDict = {CLITelemetryField.CONFIG_PROVIDER_TYPE: provider_type}

# Get detailed telemetry if using ng config
if isinstance(provider, AlternativeConfigProvider):
provider._ensure_initialized() # noqa: SLF001
payload = get_config_telemetry_payload(provider._resolver) # noqa: SLF001

# Map payload keys to telemetry fields
if payload:
if "config_sources_used" in payload:
result[CLITelemetryField.CONFIG_SOURCES_USED] = payload[
"config_sources_used"
]
if "config_source_wins" in payload:
result[CLITelemetryField.CONFIG_SOURCE_WINS] = payload[
"config_source_wins"
]
if "config_total_keys_resolved" in payload:
result[CLITelemetryField.CONFIG_TOTAL_KEYS_RESOLVED] = payload[
"config_total_keys_resolved"
]
if "config_keys_with_overrides" in payload:
result[CLITelemetryField.CONFIG_KEYS_WITH_OVERRIDES] = payload[
"config_keys_with_overrides"
]

return result
except Exception:
return {}


class CLITelemetryClient:
@property
def _ctx(self) -> _CliGlobalContextAccess:
Expand All @@ -239,6 +293,7 @@ def generate_telemetry_data_dict(
k: str(v) for k, v in get_feature_flags_section().items()
},
**_find_command_info(),
**_get_config_telemetry(),
**telemetry_payload,
}
# To map Enum to string, so we don't have to use .value every time
Expand Down
25 changes: 23 additions & 2 deletions src/snowflake/cli/_plugins/connection/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,32 @@ def _mask_sensitive_parameters(connection_params: dict):


@app.command(name="list")
def list_connections(**options) -> CommandResult:
def list_connections(
all_sources: bool = typer.Option(
False,
"--all",
"-a",
help="Include connections from all sources (environment variables, SnowSQL config). "
"By default, only shows connections from configuration files.",
),
**options,
) -> CommandResult:
"""
Lists configured connections.
"""
connections = get_all_connections()
from snowflake.cli.api.config_provider import (
get_config_provider_singleton,
is_alternative_config_enabled,
)

# Use provider directly for config_ng to pass the flag
if is_alternative_config_enabled():
provider = get_config_provider_singleton()
connections = provider.get_all_connections(include_env_connections=all_sources)
else:
# Legacy provider ignores the flag
connections = get_all_connections()

default_connection = get_default_connection_name()
result = (
{
Expand Down
10 changes: 8 additions & 2 deletions src/snowflake/cli/_plugins/dcm/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import yaml
from snowflake.cli._plugins.stage.manager import StageManager
from snowflake.cli.api.artifacts.upload import sync_artifacts_with_stage
from snowflake.cli.api.commands.utils import parse_key_value_variables
from snowflake.cli.api.console.console import cli_console
from snowflake.cli.api.constants import (
DEFAULT_SIZE_LIMIT_MB,
Expand Down Expand Up @@ -102,8 +101,15 @@ def execute(
if configuration:
query += f" CONFIGURATION {configuration}"
if variables:
from snowflake.cli.api.commands.common import Variable
from snowflake.cli.api.config_ng import get_merged_variables

# Get merged variables from SnowSQL config and CLI -D parameters
merged_vars_dict = get_merged_variables(variables)
# Convert dict to List[Variable] for compatibility with parse_execute_variables
parsed_variables = [Variable(k, v) for k, v in merged_vars_dict.items()]
query += StageManager.parse_execute_variables(
parse_key_value_variables(variables)
parsed_variables
).removeprefix(" using")
stage_path = StagePath.from_stage_str(from_stage)
query += f" FROM {stage_path.absolute_path()}"
Expand Down
87 changes: 87 additions & 0 deletions src/snowflake/cli/_plugins/helpers/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
get_all_connections,
set_config_value,
)
from snowflake.cli.api.config_provider import ALTERNATIVE_CONFIG_ENV_VAR
from snowflake.cli.api.console import cli_console
from snowflake.cli.api.output.types import (
CollectionResult,
Expand Down Expand Up @@ -317,3 +318,89 @@ def check_snowsql_env_vars(**options):

results.append(MessageResult(summary))
return MultipleResults(results)


@app.command(
name="show-config-sources",
requires_connection=False,
hidden=os.environ.get(ALTERNATIVE_CONFIG_ENV_VAR, "").lower()
not in ("1", "true", "yes", "on"),
)
def show_config_sources(
key: Optional[str] = typer.Argument(
None,
help="Specific configuration key to show resolution for (e.g., 'account', 'user'). If not provided, shows summary for all keys.",
),
show_details: bool = typer.Option(
False,
"--show-details",
"-d",
help="Show detailed resolution chains for all sources consulted.",
),
export_file: Optional[Path] = typer.Option(
None,
"--export",
"-e",
help="Export complete resolution history to JSON file for support or debugging.",
file_okay=True,
dir_okay=False,
),
**options,
) -> CommandResult:
"""
Show where configuration values come from.

This command displays the configuration resolution process, showing which
source (CLI arguments, environment variables, or config files) provided
each configuration value. Useful for debugging configuration issues.

Examples:

# Show summary of all configuration resolution
snow helpers show-config-sources

# Show detailed resolution for all keys
snow helpers show-config-sources --show-details

# Show resolution for a specific key
snow helpers show-config-sources account

# Show detailed resolution for a specific key
snow helpers show-config-sources account --show-details

# Export complete resolution history to file
snow helpers show-config-sources --export config_debug.json

Note: This command requires the enhanced configuration system to be enabled.
Set SNOWFLAKE_CLI_CONFIG_V2_ENABLED=true to enable it.
"""
from snowflake.cli.api.config_ng import (
export_resolution_history,
is_resolution_logging_available,
)
from snowflake.cli.api.config_ng.resolution_logger import (
get_configuration_explanation_results,
)

if not is_resolution_logging_available():
return MessageResult(
f"⚠️ Configuration resolution logging is not available.\n\n"
f"To enable it, set the environment variable:\n"
f" export {ALTERNATIVE_CONFIG_ENV_VAR}=true\n\n"
f"Then run this command again to see where configuration values come from."
)

# Export if requested
if export_file:
success = export_resolution_history(export_file)
if not success:
return MessageResult(
f"❌ Failed to export resolution history to {export_file}"
)
return MessageResult(
f"✅ Resolution history exported to: {export_file}\n\n"
f"This file contains complete details about configuration resolution "
f"and can be attached to support tickets."
)

return get_configuration_explanation_results(key=key, verbose=show_details)
7 changes: 3 additions & 4 deletions src/snowflake/cli/_plugins/sql/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
)
from snowflake.cli.api.commands.overrideable_parameter import OverrideableOption
from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
from snowflake.cli.api.commands.utils import parse_key_value_variables
from snowflake.cli.api.exceptions import CliArgumentError
from snowflake.cli.api.output.types import (
CommandResult,
Expand Down Expand Up @@ -136,9 +135,9 @@ def execute_sql(
The command supports variable substitution that happens on client-side.
"""

data = {}
if data_override:
data = {v.key: v.value for v in parse_key_value_variables(data_override)}
from snowflake.cli.api.config_ng import get_merged_variables

data = get_merged_variables(data_override)

template_syntax_config = _parse_template_syntax_config(enabled_templating)

Expand Down
8 changes: 6 additions & 2 deletions src/snowflake/cli/_plugins/stage/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
OnErrorType,
Variable,
)
from snowflake.cli.api.commands.utils import parse_key_value_variables
from snowflake.cli.api.console import cli_console
from snowflake.cli.api.constants import PYTHON_3_12
from snowflake.cli.api.exceptions import CliError
Expand Down Expand Up @@ -608,7 +607,12 @@ def execute(
filtered_file_list, key=lambda f: (path.dirname(f), path.basename(f))
)

parsed_variables = parse_key_value_variables(variables)
from snowflake.cli.api.config_ng import get_merged_variables

# Get merged variables from SnowSQL config and CLI -D parameters
merged_vars_dict = get_merged_variables(variables)
# Convert dict back to List[Variable] for compatibility with existing methods
parsed_variables = [Variable(k, v) for k, v in merged_vars_dict.items()]
sql_variables = self.parse_execute_variables(parsed_variables)
python_variables = self._parse_python_variables(parsed_variables)
results = []
Expand Down
Loading
Loading