diff --git a/InstallerGui/MainWindow.xaml.cs b/InstallerGui/MainWindow.xaml.cs index 91a199d7..111922c0 100644 --- a/InstallerGui/MainWindow.xaml.cs +++ b/InstallerGui/MainWindow.xaml.cs @@ -416,6 +416,25 @@ await _installationService.InstallDependenciesAsync( }, cancellationToken); + /* + Log installation history to database + */ + try + { + await InstallationService.LogInstallationHistoryAsync( + _connectionString, + AppAssemblyVersion, + AppVersion, + _installationResult.StartTime, + _installationResult.FilesSucceeded, + _installationResult.FilesFailed, + _installationResult.Success); + } + catch (Exception ex) + { + LogMessage($"Warning: Could not log installation history: {ex.Message}", "Warning"); + } + /* Run validation if requested */ diff --git a/InstallerGui/Services/InstallationService.cs b/InstallerGui/Services/InstallationService.cs index 2935702e..25ccc85e 100644 --- a/InstallerGui/Services/InstallationService.cs +++ b/InstallerGui/Services/InstallationService.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; +using System.Data; using System.IO; using System.Linq; using System.Net.Http; @@ -1318,5 +1319,115 @@ public void Dispose() } GC.SuppressFinalize(this); } + + /// + /// Log installation history to config.installation_history + /// Mirrors CLI installer's LogInstallationHistory method + /// + public static async Task LogInstallationHistoryAsync( + string connectionString, + string assemblyVersion, + string infoVersion, + DateTime startTime, + int filesExecuted, + int filesFailed, + bool isSuccess) + { + try + { + using var connection = new SqlConnection(connectionString); + await connection.OpenAsync().ConfigureAwait(false); + + /*Check if this is an upgrade by checking for existing installation*/ + string? previousVersion = null; + string installationType = "INSTALL"; + + try + { + using var checkCmd = new SqlCommand(@" + SELECT TOP 1 installer_version + FROM PerformanceMonitor.config.installation_history + WHERE installation_status = 'SUCCESS' + ORDER BY installation_date DESC;", connection); + + var result = await checkCmd.ExecuteScalarAsync().ConfigureAwait(false); + if (result != null && result != DBNull.Value) + { + previousVersion = result.ToString(); + bool isSameVersion = Version.TryParse(previousVersion, out var prevVer) + && Version.TryParse(assemblyVersion, out var currVer) + && prevVer == currVer; + installationType = isSameVersion ? "REINSTALL" : "UPGRADE"; + } + } + catch (SqlException) + { + /*Table might not exist yet on first install*/ + } + + /*Get SQL Server version info*/ + string sqlVersion = ""; + string sqlEdition = ""; + + using (var versionCmd = new SqlCommand("SELECT @@VERSION, SERVERPROPERTY('Edition');", connection)) + using (var reader = await versionCmd.ExecuteReaderAsync().ConfigureAwait(false)) + { + if (await reader.ReadAsync().ConfigureAwait(false)) + { + sqlVersion = reader.GetString(0); + sqlEdition = reader.GetString(1); + } + } + + long durationMs = (long)(DateTime.Now - startTime).TotalMilliseconds; + string status = isSuccess ? "SUCCESS" : (filesFailed > 0 ? "PARTIAL" : "FAILED"); + + var insertSql = @" + INSERT INTO PerformanceMonitor.config.installation_history + ( + installer_version, + installer_info_version, + sql_server_version, + sql_server_edition, + installation_type, + previous_version, + installation_status, + files_executed, + files_failed, + installation_duration_ms + ) + VALUES + ( + @installer_version, + @installer_info_version, + @sql_server_version, + @sql_server_edition, + @installation_type, + @previous_version, + @installation_status, + @files_executed, + @files_failed, + @installation_duration_ms + );"; + + using var insertCmd = new SqlCommand(insertSql, connection); + insertCmd.Parameters.Add(new SqlParameter("@installer_version", SqlDbType.NVarChar, 50) { Value = assemblyVersion }); + insertCmd.Parameters.Add(new SqlParameter("@installer_info_version", SqlDbType.NVarChar, 100) { Value = (object?)infoVersion ?? DBNull.Value }); + insertCmd.Parameters.Add(new SqlParameter("@sql_server_version", SqlDbType.NVarChar, 500) { Value = sqlVersion }); + insertCmd.Parameters.Add(new SqlParameter("@sql_server_edition", SqlDbType.NVarChar, 128) { Value = sqlEdition }); + insertCmd.Parameters.Add(new SqlParameter("@installation_type", SqlDbType.VarChar, 20) { Value = installationType }); + insertCmd.Parameters.Add(new SqlParameter("@previous_version", SqlDbType.NVarChar, 50) { Value = (object?)previousVersion ?? DBNull.Value }); + insertCmd.Parameters.Add(new SqlParameter("@installation_status", SqlDbType.VarChar, 20) { Value = status }); + insertCmd.Parameters.Add(new SqlParameter("@files_executed", SqlDbType.Int) { Value = filesExecuted }); + insertCmd.Parameters.Add(new SqlParameter("@files_failed", SqlDbType.Int) { Value = filesFailed }); + insertCmd.Parameters.Add(new SqlParameter("@installation_duration_ms", SqlDbType.BigInt) { Value = durationMs }); + + await insertCmd.ExecuteNonQueryAsync().ConfigureAwait(false); + } + catch + { + /*Don't let history logging failure break the installation*/ + } + } } }