From 9a160c7b1d64cf50e86f40f3d635ae6395e4f551 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 04:49:48 +0000 Subject: [PATCH 1/5] Initial plan From 0056297f46b434e41a2760237688747b71584fd7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 04:57:28 +0000 Subject: [PATCH 2/5] Add data-source.health.name CLI parameter support Co-authored-by: JerryNixon <1749983+JerryNixon@users.noreply.github.com> --- src/Cli/Commands/ConfigureOptions.cs | 5 +++++ src/Cli/ConfigGenerator.cs | 18 ++++++++++++++++++ .../DatasourceHealthOptionsConvertorFactory.cs | 3 ++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Cli/Commands/ConfigureOptions.cs b/src/Cli/Commands/ConfigureOptions.cs index 11dca2a4eb..299a791e2d 100644 --- a/src/Cli/Commands/ConfigureOptions.cs +++ b/src/Cli/Commands/ConfigureOptions.cs @@ -28,6 +28,7 @@ public ConfigureOptions( string? dataSourceOptionsContainer = null, string? dataSourceOptionsSchema = null, bool? dataSourceOptionsSetSessionContext = null, + string? dataSourceHealthName = null, int? depthLimit = null, bool? runtimeGraphQLEnabled = null, string? runtimeGraphQLPath = null, @@ -80,6 +81,7 @@ public ConfigureOptions( DataSourceOptionsContainer = dataSourceOptionsContainer; DataSourceOptionsSchema = dataSourceOptionsSchema; DataSourceOptionsSetSessionContext = dataSourceOptionsSetSessionContext; + DataSourceHealthName = dataSourceHealthName; // GraphQL DepthLimit = depthLimit; RuntimeGraphQLEnabled = runtimeGraphQLEnabled; @@ -150,6 +152,9 @@ public ConfigureOptions( [Option("data-source.options.set-session-context", Required = false, HelpText = "Enable session context. Allowed values: true (default), false.")] public bool? DataSourceOptionsSetSessionContext { get; } + [Option("data-source.health.name", Required = false, HelpText = "Identifier for data source in health check report.")] + public string? DataSourceHealthName { get; } + [Option("runtime.graphql.depth-limit", Required = false, HelpText = "Max allowed depth of the nested query. Allowed values: (0,2147483647] inclusive. Default is infinity. Use -1 to remove limit.")] public int? DepthLimit { get; } diff --git a/src/Cli/ConfigGenerator.cs b/src/Cli/ConfigGenerator.cs index 648edc1950..fd01827c60 100644 --- a/src/Cli/ConfigGenerator.cs +++ b/src/Cli/ConfigGenerator.cs @@ -684,6 +684,24 @@ private static bool TryUpdateConfiguredDataSourceOptions( dbOptions.Add(namingPolicy.ConvertName(nameof(MsSqlOptions.SetSessionContext)), options.DataSourceOptionsSetSessionContext.Value); } + // Handle health.name option + if (options.DataSourceHealthName is not null) + { + // If there's no existing health config, create one with the name + if (datasourceHealthCheckConfig is null) + { + datasourceHealthCheckConfig = new DatasourceHealthCheckConfig(enabled: null, name: options.DataSourceHealthName); + } + else + { + // Update the existing health config with the new name + datasourceHealthCheckConfig = new DatasourceHealthCheckConfig( + enabled: datasourceHealthCheckConfig.Enabled, + name: options.DataSourceHealthName, + thresholdMs: datasourceHealthCheckConfig.UserProvidedThresholdMs ? datasourceHealthCheckConfig.ThresholdMs : null); + } + } + dbOptions = EnumerableUtilities.IsNullOrEmpty(dbOptions) ? null : dbOptions; DataSource dataSource = new(dbType, dataSourceConnectionString, dbOptions, datasourceHealthCheckConfig); runtimeConfig = runtimeConfig with { DataSource = dataSource }; diff --git a/src/Config/Converters/DatasourceHealthOptionsConvertorFactory.cs b/src/Config/Converters/DatasourceHealthOptionsConvertorFactory.cs index d8286ff7a0..8862645f73 100644 --- a/src/Config/Converters/DatasourceHealthOptionsConvertorFactory.cs +++ b/src/Config/Converters/DatasourceHealthOptionsConvertorFactory.cs @@ -114,7 +114,8 @@ public HealthCheckOptionsConverter(DeserializationVariableReplacementSettings? r public override void Write(Utf8JsonWriter writer, DatasourceHealthCheckConfig value, JsonSerializerOptions options) { - if (value?.UserProvidedEnabled is true) + // Write the health object if enabled was explicitly provided OR if name is set OR if threshold was explicitly provided + if (value?.UserProvidedEnabled is true || value?.Name is not null || value?.UserProvidedThresholdMs is true) { writer.WriteStartObject(); writer.WritePropertyName("enabled"); From 77cdd247c67aaf324c29abb4b1383c292e011dbe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 05:06:18 +0000 Subject: [PATCH 3/5] Add tests for data-source.health.name CLI parameter Co-authored-by: JerryNixon <1749983+JerryNixon@users.noreply.github.com> --- src/Cli.Tests/ConfigureOptionsTests.cs | 97 ++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/src/Cli.Tests/ConfigureOptionsTests.cs b/src/Cli.Tests/ConfigureOptionsTests.cs index 073f349a67..27d9dec08e 100644 --- a/src/Cli.Tests/ConfigureOptionsTests.cs +++ b/src/Cli.Tests/ConfigureOptionsTests.cs @@ -926,6 +926,103 @@ public void TestFailureWhenAddingSetSessionContextToMySQLDatabase() Assert.IsFalse(isSuccess); } + /// + /// Tests adding data-source.health.name to a config that doesn't have a health section. + /// This method verifies that the health.name can be added to a data source configuration + /// that doesn't previously have a health section. + /// Command: dab configure --data-source.health.name "My Data Source" + /// + [TestMethod] + public void TestAddDataSourceHealthName() + { + // Arrange + SetupFileSystemWithInitialConfig(INITIAL_CONFIG); + + ConfigureOptions options = new( + dataSourceHealthName: "My Data Source", + config: TEST_RUNTIME_CONFIG_FILE + ); + + // Act + bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!); + + // Assert + Assert.IsTrue(isSuccess); + string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE); + Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? config)); + Assert.IsNotNull(config.DataSource); + Assert.IsNotNull(config.DataSource.Health); + Assert.AreEqual("My Data Source", config.DataSource.Health.Name); + Assert.IsTrue(config.DataSource.Health.Enabled); // Default value + } + + /// + /// Tests updating data-source.health.name on a config that already has a health section. + /// This method verifies that the health.name can be updated while preserving other health settings. + /// Command: dab configure --data-source.health.name "Updated Name" + /// + [DataTestMethod] + [DataRow("New Name", DisplayName = "Update health name with a simple string")] + [DataRow("This is the value", DisplayName = "Update health name with the example from the issue")] + public void TestUpdateDataSourceHealthName(string healthName) + { + // Arrange - Config with existing health section + string configWithHealth = @" + { + ""$schema"": ""test"", + ""data-source"": { + ""database-type"": ""mssql"", + ""connection-string"": ""testconnectionstring"", + ""health"": { + ""enabled"": false, + ""threshold-ms"": 2000 + } + }, + ""runtime"": { + ""rest"": { + ""enabled"": true, + ""path"": ""/api"" + }, + ""graphql"": { + ""enabled"": true, + ""path"": ""/graphql"", + ""allow-introspection"": true + }, + ""host"": { + ""mode"": ""development"", + ""cors"": { + ""origins"": [], + ""allow-credentials"": false + }, + ""authentication"": { + ""provider"": ""StaticWebApps"" + } + } + }, + ""entities"": {} + }"; + SetupFileSystemWithInitialConfig(configWithHealth); + + ConfigureOptions options = new( + dataSourceHealthName: healthName, + config: TEST_RUNTIME_CONFIG_FILE + ); + + // Act + bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!); + + // Assert + Assert.IsTrue(isSuccess); + string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE); + Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? config)); + Assert.IsNotNull(config.DataSource); + Assert.IsNotNull(config.DataSource.Health); + Assert.AreEqual(healthName, config.DataSource.Health.Name); + // Verify existing health settings are preserved + Assert.IsFalse(config.DataSource.Health.Enabled); + Assert.AreEqual(2000, config.DataSource.Health.ThresholdMs); + } + /// /// Sets up the mock file system with an initial configuration file. /// This method adds a config file to the mock file system and verifies its existence. From ab532b2e34c20e04df22547047feb56826e38bef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 05:13:44 +0000 Subject: [PATCH 4/5] Improve comments based on code review feedback Co-authored-by: JerryNixon <1749983+JerryNixon@users.noreply.github.com> --- src/Cli/ConfigGenerator.cs | 3 ++- .../Converters/DatasourceHealthOptionsConvertorFactory.cs | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Cli/ConfigGenerator.cs b/src/Cli/ConfigGenerator.cs index fd01827c60..9cfdb506fa 100644 --- a/src/Cli/ConfigGenerator.cs +++ b/src/Cli/ConfigGenerator.cs @@ -688,13 +688,14 @@ private static bool TryUpdateConfiguredDataSourceOptions( if (options.DataSourceHealthName is not null) { // If there's no existing health config, create one with the name + // Note: passing enabled: null uses the default value (true) from the base constructor if (datasourceHealthCheckConfig is null) { datasourceHealthCheckConfig = new DatasourceHealthCheckConfig(enabled: null, name: options.DataSourceHealthName); } else { - // Update the existing health config with the new name + // Update the existing health config with the new name while preserving other settings datasourceHealthCheckConfig = new DatasourceHealthCheckConfig( enabled: datasourceHealthCheckConfig.Enabled, name: options.DataSourceHealthName, diff --git a/src/Config/Converters/DatasourceHealthOptionsConvertorFactory.cs b/src/Config/Converters/DatasourceHealthOptionsConvertorFactory.cs index 8862645f73..9c08cf4d81 100644 --- a/src/Config/Converters/DatasourceHealthOptionsConvertorFactory.cs +++ b/src/Config/Converters/DatasourceHealthOptionsConvertorFactory.cs @@ -114,7 +114,10 @@ public HealthCheckOptionsConverter(DeserializationVariableReplacementSettings? r public override void Write(Utf8JsonWriter writer, DatasourceHealthCheckConfig value, JsonSerializerOptions options) { - // Write the health object if enabled was explicitly provided OR if name is set OR if threshold was explicitly provided + // Write the health object if any of these conditions are met: + // - enabled was explicitly provided by the user + // - name property has a value + // - threshold was explicitly provided by the user if (value?.UserProvidedEnabled is true || value?.Name is not null || value?.UserProvidedThresholdMs is true) { writer.WriteStartObject(); From 211e1d6d070b525b01a3cb2e7e4b1ca71fe95c8a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 05:20:50 +0000 Subject: [PATCH 5/5] Improve code clarity based on review feedback Co-authored-by: JerryNixon <1749983+JerryNixon@users.noreply.github.com> --- src/Cli/ConfigGenerator.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Cli/ConfigGenerator.cs b/src/Cli/ConfigGenerator.cs index 9cfdb506fa..658a871b53 100644 --- a/src/Cli/ConfigGenerator.cs +++ b/src/Cli/ConfigGenerator.cs @@ -688,7 +688,7 @@ private static bool TryUpdateConfiguredDataSourceOptions( if (options.DataSourceHealthName is not null) { // If there's no existing health config, create one with the name - // Note: passing enabled: null uses the default value (true) from the base constructor + // Note: passing enabled: null triggers the base constructor logic that sets Enabled = true if (datasourceHealthCheckConfig is null) { datasourceHealthCheckConfig = new DatasourceHealthCheckConfig(enabled: null, name: options.DataSourceHealthName); @@ -696,10 +696,12 @@ private static bool TryUpdateConfiguredDataSourceOptions( else { // Update the existing health config with the new name while preserving other settings + // Preserve threshold only if it was explicitly set by the user + int? thresholdToPreserve = datasourceHealthCheckConfig.UserProvidedThresholdMs ? datasourceHealthCheckConfig.ThresholdMs : null; datasourceHealthCheckConfig = new DatasourceHealthCheckConfig( enabled: datasourceHealthCheckConfig.Enabled, name: options.DataSourceHealthName, - thresholdMs: datasourceHealthCheckConfig.UserProvidedThresholdMs ? datasourceHealthCheckConfig.ThresholdMs : null); + thresholdMs: thresholdToPreserve); } }