Skip to content

merging master to official 202.5 RC#4388

Merged
ravirk91 merged 170 commits into
Releases/Official-Releasefrom
master
Dec 19, 2025
Merged

merging master to official 202.5 RC#4388
ravirk91 merged 170 commits into
Releases/Official-Releasefrom
master

Conversation

@ravirk91

@ravirk91 ravirk91 commented Dec 19, 2025

Copy link
Copy Markdown
Collaborator

Description

Type of Change

  • Bug fix - [ ] New feature - [ ] Breaking change - [ ] Plugin update

Checklist

  • PR description clearly describes the changes
  • Target branch is correct (master for features, Releases/* for fixes)
  • Latest code from target branch merged
  • No commented/junk code included
  • No new build warnings or errors
  • All existing unit tests pass
  • New unit tests added for new functionality
  • Cross-platform compatibility verified (Windows/Linux/macOS)
  • CI/CD pipeline passes
  • Code follows project conventions (Act{Platform}{Type}, {Platform}Driver)
  • Repository objects use [IsSerializedForLocalRepository] where needed
  • Error handling uses Reporter.ToLog() pattern
  • Documentation updated for user-facing changes
  • Self-review completed and code review comments addressed

Summary by CodeRabbit

Release Notes

  • New Features

    • Console driver window with recording and command execution interface
    • Variables now support initial and effective value mapping with display options
    • Data mapping enhanced with new Value type and date picker controls
  • Bug Fixes

    • Improved null safety checks in element type handling
    • Enhanced database connection validation and error handling
  • UI/UX Improvements

    • Updated console interface with status indicators and output display
    • Enhanced data mapping controls with selection and date input options

✏️ Tip: You can customize this high-level summary in your review settings.

NoahNegevDegen and others added 30 commits August 6, 2025 15:51
"Value" that allows the user to change the current value of a variable, this function now works for string variables
…ficial-Releases/Official-Release-2025.4

Releases/published official releases/official release 2025.4
…ease

Handled infinte waiting issue with Log Appender
…ficial-Releases/Official-Release-2025.4

Releases/published official releases/official release 2025.4
1- fixed loading of runset config having new Ginger Play configs
2- fixing Ginger Play pop up which hide behind app
3- improving Ginger Play icon style
4- aligning Ginger play icon in diffrent pages
Mayur Rathi and others added 24 commits December 15, 2025 17:07
…controlled-command-line

Do not assign the Expression to mValueCalculated if it was failed to …
…Issue

BugFix/StoretoEnabled Issue solved
Upgraded Magick.NET-Q16-AnyCPU nugget to 14.10.0
…ilityIssueForIOS

Mobile accessibility issue for ios - fix
Comment thread Ginger/GingerCore/Actions/ActLaunchJavaWSApplication.cs Dismissed
Comment thread Ginger/GingerCoreNET/Database/DatabaseOperations.cs Dismissed
@coderabbitai

coderabbitai Bot commented Dec 19, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This PR performs a major refactoring of the Ginger automation codebase, including migration of console driver functionality from GingerCore to GingerCoreNET namespace, removal of legacy Java agent implementation files, deletion of HTML-based execution reports, enhancement of variable mapping with a new Value output type and CurrentEffectiveValue property, refactoring of database connection string handling, and various UI updates across actions and variable pages. The PR also updates project dependencies and version metadata.

Changes

Cohort / File(s) Summary
Report Templates & Assets (Deleted)
Ginger/Ginger/Reports/GingerExecutionReport/*.html, Ginger/Ginger/Reports/GingerExecutionReport/assets/css/*, Ginger/Ginger/Reports/GingerExecutionReport/assets/js/*
Removed entire HTML report template files (ActionReport.html, ActivityGroupReport.html, ActivityReport.html, BusinessFlowReport.html, GingerExecutionReport.html, GingerRunnerReport.html, RunSetReport.html), CSS stylesheets (font-awesome.css, styles.css), and JavaScript libraries (bootstrap.js, circlechart.js, donutchart.js, jquery.js) and chart rendering functions.
HTML Report Classes (Deleted)
Ginger/Ginger/Reports/GingerExecutionReport/HTMLReports/*
Removed HTMLDetailedReport.cs, HTMLSummaryReport.cs, and HTMLReportBase.cs—eliminating the entire HTML-based report generation framework.
Java Agent Implementation (Deleted)
Ginger/GingerCore/Drivers/JavaDriverLib/GingerJavaAgent/*
Removed complete Java agent codebase including agent classes (GingerAgent.java, GingerAgentFrame.java, GingerAgentStarterFrame.java), helper utilities (ASCFHelper.java, BrowserHelper.java, EditorHelper.java, FormsDumpInfo.java, SwingHelper.java, XPathHelper.java, Utils.java, WaitForIdle.java, WindowMonitor.java, IXPath.java, PayLoad.java, Recorder.java), socket server (GingerJavaSocketServer.java), and test applications (BasicSwingApp.java, BasicSwingComponents.java, GingerAgentTestApp.java, JEditorPaneExample.java); also removed Eclipse project configuration files (.classpath, .project, .settings/, .externalToolBuilders/, *.jardesc, GingerjarPreparation.bat, MANIFEST.MF).
Legacy Console Driver (Deleted)
Ginger/GingerCore/Drivers/ConsoleDriverLib/*
Removed ConsoleDriverBase.cs, ConsoleDriverWindow.xaml, ConsoleDriverWindow.xaml.cs, ConsoleNewActionPage.xaml, ConsoleNewActionPage.xaml.cs, DOSConsoleDriver.cs, and UnixShellDriver.cs (migrated to GingerCoreNET).
New Console Driver Framework
Ginger/GingerCoreNET/Drivers/CoreDrivers/Console/ConsoleDriverBase.cs
Added new headless-capable ConsoleDriverBase with DummyDispatcher, abstract command/connection methods, command buffering, recording support, and result extraction; supports recording console logs (StartRecordingConsoleLogs, StopRecordingConsoleLogs, GetRecordedConsoleLogs).
Console Driver UI (New/Relocated)
Ginger/Ginger/Drivers/DriversWindows/ConsoleDriverWindow.xaml*, Ginger/Ginger/Drivers/DriversWindows/ConsoleNewActionPage.xaml*
Added new WPF window and page under Ginger.Drivers.DriversWindows namespace with console output rendering, command execution, recording support, and action creation UI.
Console Driver Utilities (New)
Ginger/Ginger/Drivers/DriversWindows/DriverWindowHandler.cs
Updated to dynamically resolve Driver Window class names using driver type, enabling flexible window instantiation.
Action Enum & Namespace Migration
Ginger/GingerCoreNET/ActionsLib/ActConsoleCommand.cs
Migrated ActConsoleCommand from GingerCore.Actions to Amdocs.Ginger.CoreNET.ActionsLib namespace; added console logging commands (StartRecordingConsoleLogs, StopRecordingConsoleLogs, GetRecordedConsoleLogs) and other command types (FreeCommand, CopyFile, IsFileExist, Script, ParametrizedCommand) with descriptions.
Console Action UI Updates
Ginger/Ginger/Actions/ActionEditPages/ActConsoleCommandEditPage.xaml*
Added UI element names (ExpectedStringLabel, DelimiterLabel, WaitTimeStackPanel, CommandTerminatorStackPanel) and refactored code-behind logic: introduced UpdateVisibilityForCommand, SetupValueInputParam, extended action lists for Unix/DOS platforms, and added initial UI state logic.
Variable Output Mapping Enhancement
Ginger/GingerCoreCommon/VariablesLib/VariableBase.cs
Added new eOutputType.Value enum member; introduced CurrentEffectiveValue (read-only derived property) and InitialValue properties; enhanced PostDeserialization with backward-compatibility logic for Value mapping conversion; updated property setters to notify CurrentEffectiveValue changes.
Variable Subtype Implementations
Ginger/GingerCoreCommon/VariablesLib/VariablePasswordString.cs, VariableDynamic.cs
VariablePasswordString: enabled SupportSetValue (true), added SetValue/GetInitialValue implementations, replaced NotImplementedException in GetSupportedOperations. VariableDynamic: disabled SupportSetValue (false).
Data Mapping UI & Logic
Ginger/Ginger/UserControlsLib/UCDataMapping.xaml*, UCDataMapping.xaml.cs
Added Value type support with DatePicker, datetime handling, selection list UI, numeric validation, and dynamic visibility; expanded template options and validation logic for Value mappings; added lifecycle hooks (DataContextChanged, Loaded, Unloaded).
Run Configuration UI
Ginger/Ginger/Run/BusinessFlowRunConfigurationsPage.xaml.cs
Disabled double-click editing in variables grid; changed Initial Value column binding from Value to InitialValue; removed DifferentFromOrigin column and RestrictedMappingTypes logic; preserved grid setup for configuration/summary modes.
Variable Edit Page Updates
Ginger/Ginger/Variables/VariableEditPage.xaml, VariableEditPage.xaml.cs
Reorganized UI from DockPanel to WrapPanel for control layout; updated description field styling; modified constructor to accept optional expandDetails parameter; bound CurrentValue to CurrentEffectiveValue instead of Value; added user-preference tracking for details expansion.
Variable Selection Page
Ginger/Ginger/Variables/AddVariablePage.xaml.cs
Added guards to check SupportSetValue before showing/setting input-related checkboxes and properties; prevents setting values on variables that do not support assignment.
Database Operations Refactoring
Ginger/GingerCoreNET/Database/DatabaseOperations.cs
Introduced ReplacePasswordInConnectionString, GetMSSQLConnectionStringBuilder, ValidateHostPort helpers; refactored CreateConnectionString with switch-based DB-type handling; enhanced error handling across connection paths with defensive null checks and more descriptive logging.
Action Implementations
Ginger/GingerCore/Actions/ActLaunchJavaWSApplication.cs
Added GetJavaVersion, ExtractVersion, ExtractMajorVersion helpers to detect Java version; dynamically select GingerAgent.jar (≤8) or JavaAgent_V25.jar (>8); enhanced validation with jar file existence checks.
Robot Framework Action
Ginger/GingerCoreNET/ActionsLib/RobotFramework/ActRobot.cs
Removed CSV/JSON writer methods; added password variable filtering to exclude VariablePasswordString from JSON variable lists across solution, business flow, and activity scopes.
UI Component Updates
Ginger/Ginger/UserControlsLib/ImageMakerControl.xaml.cs, TwoLevelMenuPage.xaml*
ImageMakerControl: updated GingerPlayLogo to use GingerPlayWhiteGradiant.png with explicit dimensions. TwoLevelMenuPage: redesigned Ginger Play button with layered borders, gradient background, hover effects, and badge UI.
Ginger Play Feature Logic
Ginger/Ginger/UserControlsLib/TwoLevelMenuLib/TwoLevelMenuPage.xaml.cs
Added guard condition to open Ginger Play only when enabled with gateway URL configured; assigned window owner for proper modality.
Other Action Pages
Ginger/Ginger/Actions/ActionEditPages/ActDataSourcePage.xaml.cs, ActSecurityTestingEditPage.xaml, ActLaunchJavaWSApplicationEditPage.xaml.cs
ActDataSourcePage: bound grdCondition.DataSourceList to mActDSTblElem.WhereConditions. ActSecurityTestingEditPage: adjusted grid layout to fixed widths (140, 220) and control sizing. ActLaunchJavaWSApplicationEditPage: whitespace fix.
Other UI Pages
Ginger/Ginger/ApplicationModelsLib/POMModels/POMWizardLib/LearnWizard/POMLearnConfigWizardPage.xaml, Ginger/Ginger/GeneralLib/GenericWindow.xaml
POMLearnConfigWizardPage: added "AI Integration Options" label before ImageMakerControl, adjusted margins. GenericWindow: trailing space formatting.
Wizard & Framework
Ginger/Ginger/WizardLib/WizardWindow.xaml.cs, Ginger/GingerCore/GeneralLib/General.cs
WizardWindow: wrapped AIFineTuneBaseText initialization in Dispatcher.Invoke for UI-thread safety. General.cs: refactored CheckComboItemExist to use straightforward non-empty string check instead of ambiguous null/ToString() comparison.
Analyzer & Validation
Ginger/GingerCoreNET/AnalyzerLib/RunSetConfigAnalyzer.cs
Added case for eOutputType.Value to bypass validation, treating any text input as valid.
Driver Base Classes
Ginger/GingerCore/Drivers/DriverWindowDispatcher.cs, Ginger/GingerCore/Drivers/MainFrame/MainFrameDriver.cs, Ginger/GingerCore/Drivers/MainFrame/Terminal.cs, Ginger/GingerCore/Drivers/JavaDriverLib/JavaDriver.cs
DriverWindowDispatcher: parameter rename (dispatherPriority → dispatcherPriority). MainFrameDriver: added null checks, window-load orchestration, server availability check, Dispatcher assignment. Terminal: removed explicit RowsCount/ColumnsCount config, use CurrentScreenXML instead of GetScreenAsXML. JavaDriver: added null-safety checks for ElementType before containment tests.
Interface & Common Updates
Ginger/GingerCoreCommon/InterfacesLib/IDispatcher.cs, Ginger/GingerCoreCommon/Actions/ActReturnValue.cs, Ginger/Ginger/Actions/ActionEditPage.xaml.cs
IDispatcher: parameter rename (dispatherPriority → dispatcherPriority). ActReturnValue: added null check in StoreToValue setter. ActionEditPage: added using directive for Amdocs.Ginger.CoreNET.ActionsLib.
Import/Data Operations
Ginger/Ginger/DataSource/ImportExcelWizardLib/ImportDataSourceFromExcelWizard.cs, Ginger/Ginger/DotNetFrameworkHelper.cs
ImportDataSourceFromExcelWizard: added RemoveEmptyRows to prune completely empty rows when IsImportEmptyColumns is false. DotNetFrameworkHelper: added using directive for Console driver namespace.
Project Files & Dependencies
Ginger/Ginger/Ginger.csproj, Ginger/GingerCore/GingerCore.csproj, Ginger/GingerCoreCommon/GingerCoreCommon.csproj, Ginger/Ginger.sln
Updated NuGet package Magick.NET-Q16-AnyCPU to 14.10.0; added jar files (GingerAgentStarter.jar, JavaAgent_V25.jar) to project output; removed console driver UI designer entries and Java agent build resources; updated Visual Studio solution version to 18.0.11205.157; bumped GingerCoreCommon version to 25.5.1.0.
Copilot Instructions
.github/copilot-instructions.md
Added comprehensive AI Coding Agent project guide with execution hierarchy, project structure, driver architecture, CLI commands, conventions, and testing strategies.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • ConsoleDriverBase migration: New headless driver framework with DummyDispatcher, abstract methods, command buffering, and recording support—verify interface compatibility and event handling.
  • Variable mapping enhancements: CurrentEffectiveValue derived property, backward-compatibility logic in PostDeserialization, and Value type handling—ensure correct property notification chains and serialization behavior.
  • Database operations refactoring: New connection string builders, password replacement logic, and DB-type handling across multiple providers—validate connection string construction and error handling paths.
  • Java agent removal & namespace migration: Large deletion of Java code and relocation of ActConsoleCommand to new namespace—confirm all references updated and no breaking dependencies remain.
  • UI layout and binding changes: Multiple XAML/code-behind updates (VariableEditPage, UCDataMapping, ActConsoleCommandEditPage)—verify bindings, visibility logic, and event handler wiring.
  • Ginger Play UI redesign: New button styling and gateway checks—ensure UI renders correctly and Ginger Play feature gates work as intended.

Possibly related PRs

  • PR #4362: Modifies Java agent codebase and ActLaunchJavaWSApplication logic (Java version detection, jar selection)—overlaps with console driver and Java agent changes in this PR.
  • PR #4330: Makes identical changes to BusinessFlowRunConfigurationsPage (disable double-click editing, bind InitialValue, remove RestrictedMappingTypes column)—directly related.
  • PR #4369: Makes overlapping changes to ActConsoleCommand enum, ConsoleDriverBase additions, and project version/dependency updates—code-level overlap with this PR.

Suggested reviewers

  • Maheshkale447
  • prashelke

🐰 Hoppy migrations, deletions so grand,
Variables now map to values so planned,
Console drivers dance in their new CoreNET home,
Java ghosts fade as new reports roam,
This refactor's a feast for the Ginger feast! 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description consists only of the template checklist with no actual content filled in; it lacks a meaningful description of what changes are being merged or why they are important. Complete the description section with details about the changes being merged, justification for the merge, and any known issues or breaking changes. Fill out the Type of Change section to indicate the nature of the merge.
Docstring Coverage ⚠️ Warning Docstring coverage is 5.81% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'merging master to official 202.5 RC' clearly and specifically describes the main purpose of the PR—merging code from master into the release branch for version 202.5 RC.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch master

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 33

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (14)
Ginger/Ginger/ApplicationModelsLib/POMModels/POMWizardLib/LearnWizard/POMLearnConfigWizardPage.xaml (1)

74-88: UI improvement enhances clarity.

The addition of an explicit "AI Integration Options" label improves the discoverability and understanding of the AI features section. The horizontal layout with the icon is clean and consistent with modern UI patterns.

Optional: Consider localization for the label text

While the hard-coded "AI Integration Options" text is consistent with other labels in this file (e.g., "Page Elements Setup Method:", "Elements Learning Settings:"), consider using a localized resource for better internationalization support:

-<TextBlock 
-    Text="AI Integration Options"
+<TextBlock 
+    Text="{Binding Source={StaticResource AIIntegrationOptionsLabel}, Path=Content}"

This is a minor suggestion since the file currently uses mixed approaches for label text.

Ginger/Ginger/UserControlsLib/TwoLevelMenuLib/TwoLevelMenuPage.xaml.cs (1)

248-268: Avoid duplicate method call to improve performance.

The method GingerPlayUtils.GetGingerPlayGatewayURLIfConfigured() is called twice: once in the guard condition (Line 248) and again when constructing the URL (Line 254). Store the result in a local variable to avoid redundant calls.

🔎 Proposed refactor to cache the gateway URL
-            if (GingerPlayUtils.IsGingerPlayEnabled() && !string.IsNullOrEmpty(GingerPlayUtils.GetGingerPlayGatewayURLIfConfigured()))
+            string gatewayUrl = GingerPlayUtils.GetGingerPlayGatewayURLIfConfigured();
+            if (GingerPlayUtils.IsGingerPlayEnabled() && !string.IsNullOrEmpty(gatewayUrl))
             {
                 try
                 {
                     Process.Start(new ProcessStartInfo
                     {
-                        FileName = GingerPlayUtils.GetGingerPlayGatewayURLIfConfigured() + "gingerplay/#/playHome",
+                        FileName = gatewayUrl + "gingerplay/#/playHome",
                         UseShellExecute = true
                     });
                 }
                 catch (Exception ex)
                 {
                     MessageBox.Show("Unable to open the link: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                 }
             }
Ginger/Ginger/WizardLib/WizardWindow.xaml.cs (1)

491-491: Use ERROR log level for exception logging.

Per coding guidelines, exceptions should be logged using eLogLevel.ERROR rather than eLogLevel.DEBUG.

As per coding guidelines, use Reporter.ToLog(eLogLevel.ERROR, message) for logging errors.

🔎 Proposed fixes
             catch (Exception ex)
             {
-                Reporter.ToLog(eLogLevel.DEBUG, "Error while starting the timer", ex);
+                Reporter.ToLog(eLogLevel.ERROR, "Error while starting the timer", ex);
             }
                 catch (Exception ex)
                 {
-                    Reporter.ToLog(eLogLevel.DEBUG, "Error while stopping the timer", ex);
+                    Reporter.ToLog(eLogLevel.ERROR, "Error while stopping the timer", ex);
                 }

Also applies to: 520-520

Ginger/GingerCore/GeneralLib/General.cs (1)

397-403: Consider adding defensive null check for consistency.

The else branch could benefit from similar defensive coding. On line 399, propertyInfo.GetValue(comboBox.Items[i]) could return null, and calling .ToString() on a null value would throw a NullReferenceException.

🔎 Proposed fix for defensive null handling
 else
 {
     PropertyInfo propertyInfo = (comboBox.Items[i]).GetType().GetProperty(specificValueField);
-    if (propertyInfo != null && propertyInfo.GetValue((comboBox.Items[i])).ToString() == value)
+    if (propertyInfo != null)
     {
-        return true;
+        var propertyValue = propertyInfo.GetValue(comboBox.Items[i]);
+        if (propertyValue != null && propertyValue.ToString() == value)
+        {
+            return true;
+        }
     }
 }
Ginger/GingerCoreCommon/VariablesLib/VariableDynamic.cs (1)

117-132: Inconsistency between SupportSetValue and SetValue implementation.

Setting SupportSetValue to false (line 117) while keeping a SetValue method that returns true (lines 128-132) creates an inconsistency:

  1. The base class SetValue will return false without calling this override when SupportSetValue is false
  2. GetSupportedOperations() throws NotImplementedException (lines 123-126) instead of returning an empty list or appropriate operations

If SetValue is truly not supported, consider:

  • Returning an empty list from GetSupportedOperations() instead of throwing
  • Or removing/adjusting the SetValue override to align with the flag
🔎 Suggested fix for GetSupportedOperations
 public override List<VariableBase.eSetValueOptions> GetSupportedOperations()
 {
-    throw new NotImplementedException();
+    // SetValue is not supported for dynamic variables, only ResetValue
+    return [VariableBase.eSetValueOptions.ResetValue];
 }
Ginger/GingerCore/Drivers/MainFrame/Terminal.cs (1)

41-50: Remove unused constructor parameters.

The RowsCount and ColumnsCount parameters are accepted in the constructor but never used in the body. Removing them will improve code clarity. Update the constructor signature and the call site in MainFrameDriver.cs line 174.

Ginger/Ginger/Drivers/DriversWindows/DriverWindowHandler.cs (1)

51-60: Consider adding null checks for defensive coding.

The dynamic type resolution logic relies on several chained property accesses that could result in NullReferenceException:

  1. agentOperations.Agent may be null if the cast on line 52 succeeds but the object's Agent property is null
  2. GetDriverWindowName() could return null or empty, resulting in an invalid type name "Ginger.Drivers.DriversWindows."

While the outer try-catch handles exceptions, adding explicit null checks would provide clearer error messages.

🔎 Proposed defensive checks
 DriverBase driver = args.Driver;
 AgentOperations agentOperations = (AgentOperations)args.DataObject;
+if (agentOperations?.Agent == null)
+{
+    throw new InvalidOperationException("AgentOperations or Agent is null");
+}

-string classname = "Ginger.Drivers.DriversWindows." + ((IDriverWindow)driver).GetDriverWindowName(agentOperations.Agent.DriverType);
+string windowName = ((IDriverWindow)driver).GetDriverWindowName(agentOperations.Agent.DriverType);
+if (string.IsNullOrEmpty(windowName))
+{
+    throw new InvalidOperationException($"Driver window name not found for DriverType: {agentOperations.Agent.DriverType}");
+}
+string classname = "Ginger.Drivers.DriversWindows." + windowName;
Ginger/GingerCoreCommon/GingerCoreCommon.csproj (1)

38-38: Remove duplicate LiteDB reference with conflicting version.

The project declares LiteDB 5.0.21 via PackageReference (line 38) but also includes an explicit assembly Reference pointing to LiteDB 4.1.4 (lines 62–64). The assembly reference takes precedence at runtime, causing a mismatch between the declared and actual dependency. Mixing LiteDB 4.1.4 with 5.0.x causes breaking changes. Remove the assembly reference at lines 62–64.

Ginger/GingerCore/Drivers/JavaDriverLib/JavaDriver.cs (1)

2741-2757: Still a potential NRE on ElementInfo.ElementType.Contains("JEditor")

You’ve added null checks for ElementInfo.ElementType in several JEditor branches, but the guard at Line 2743 still calls .Contains("JEditor") without a null-check:

if (ElementInfo.XPath != "/" && !ElementInfo.ElementType.Contains("JEditor")) //?????????

If ElementType is ever null (which the other new guards suggest is possible), this path will throw. Consider tightening this condition:

Proposed fix
- if (ElementInfo.XPath != "/" && !ElementInfo.ElementType.Contains("JEditor"))//?????????
+ if (ElementInfo.XPath != "/" &&
+     !string.IsNullOrEmpty(ElementInfo.ElementType) &&
+     !ElementInfo.ElementType.Contains("JEditor"))

Or equivalently using the null-propagation operator:

if (ElementInfo.XPath != "/" &&
    !(ElementInfo.ElementType?.Contains("JEditor") ?? false))
{
    ...
}
Ginger/GingerCoreNET/ActionsLib/RobotFramework/ActRobot.cs (1)

92-121: Password variables are correctly excluded, but JSON is still built unsafely by hand

The new Where(vrb => vrb is not VariablePasswordString) filters for solution, business-flow, and activity scopes do the right thing in terms of not leaking password variables into the Robot JSON parameter file. The duplicate-key check also ensures BF/activity vars don’t override each other silently.

However, WriteVariablesToJSONFile_V2 still concatenates JSON manually:

sbr.Append("\"");
sbr.Append(paramLine.key);
sbr.Append("\"");
...
sbr.Append(paramLine.value);

If any key or value contains ", \, newlines, etc., the generated JSON can become invalid or misinterpreted. Since you’re already assembling a List<GingerParam>, it would be safer and simpler to serialize that list with a JSON serializer and write the resulting string, instead of manual concatenation.

Consider refactoring WriteVariablesToJSONFile_V2 to serialize gingerParamsLst via a JSON library (or at least centralize proper escaping) so special characters are handled correctly.

Also applies to: 123-166

Ginger/GingerCore/Actions/ActLaunchJavaWSApplication.cs (1)

552-627: Jar selection by Java version is good; re-check instrumentation detection with JavaAgent_V25.jar

The new logic in ValidateArguments that:

  • Gets java.exe’s version,
  • Maps majorVersion <= 8GingerAgent.jar and majorVersion > 8JavaAgent_V25.jar, and
  • Verifies the chosen jar exists,

is a solid way to split old vs. new JVM behavior and fail fast when the agent jar is missing.

In PerformAttachGingerAgent, for Java 8 and below you still pass AgentJarPath=<...>\GingerAgent.jar while actually running -jar "<...>\GingerAgentStarter.jar", which matches the historical pattern. For newer JVMs, both AgentJarPath and -jar use JavaAgent_V25.jar.

One thing to double-check: IsInstrumentationModuleLoaded still looks only for "GingerAgent.jar" via handle.exe:

var processHandle = Process.Start(new ProcessStartInfo() {
    FileName = handleExePath,
    Arguments = String.Format(" -accepteula -p {0} GingerAgent.jar", id),
    ...
});
...
if (cliOut.Contains("GingerAgent.jar"))
{
    return true;
}

If, in the Java > 8 path, only JavaAgent_V25.jar ends up loaded into the target process and GingerAgent.jar is never present, this check will always return false. That will:

  • Make the 30s wait loop after mAttachAgentTask.Wait() always run to timeout, and
  • Prevent you from skipping already-instrumented processes during WaitForAppWindowTitle.

Consider either:

  • Ensuring JavaAgent_V25.jar still loads GingerAgent.jar into the target process, or
  • Updating IsInstrumentationModuleLoaded to look for both jar names (or a more generic token) so detection works for the new agent as well.

Functionally attach still proceeds, but this may degrade UX and the reliability of “already attached” detection.

Also applies to: 835-842, 1225-1233

Ginger/GingerCore/GingerCore.csproj (1)

3-4: Project settings and Open3270 reference look consistent; consider future framework alignment

  • Turning off EnableDefaultCompileItems and enableDefaultPageItems matches the explicit <Compile> and <Page> includes defined later in the file; just keep in mind that any new source/XAML files must be added to the project file explicitly.
  • The simplified Open3270 reference with HintPath="..\Ginger\DLLs\Open3270.dll" is reasonable as long as that DLL location is kept in sync with your packaging/runtime layout.

Separately, this project still targets net8.0-windows7.0 while the current guideline is to align on .NET 8 with Windows 10.0.17763.0 compatibility. If Windows 7 support is no longer required, consider moving to net8.0-windows10.0.17763.0 in a dedicated compatibility/infra PR.

Also applies to: 30-31, 92-94

Ginger/Ginger/Actions/ActionEditPage.xaml.cs (1)

1041-1101: Guard against null ActionOutputValueUserPreferences to avoid NRE

columnPreferences is nullable but used without a null‑check:

  • Inside the loop you’re protected by try/catch, but at Line 1095 (descriptionCheckBox.IsChecked = columnPreferences.Contains("Description", StringComparison.OrdinalIgnoreCase)) a null ActionOutputValueUserPreferences will throw a NullReferenceException and can break the Action Edit page for users with no saved preferences.

Consider normalizing columnPreferences once when you read it, e.g.:

Proposed fix
-        private string? columnPreferences;
+        private string? columnPreferences;
...
-                columnPreferences = WorkSpace.Instance.UserProfile.ActionOutputValueUserPreferences;
+                columnPreferences = WorkSpace.Instance.UserProfile.ActionOutputValueUserPreferences ?? string.Empty;
...
-                CheckBox descriptionCheckBox = new CheckBox
-                {
-                    Content = "Description",
-                    IsChecked = columnPreferences.Contains("Description", StringComparison.OrdinalIgnoreCase)
-                };
+                CheckBox descriptionCheckBox = new CheckBox
+                {
+                    Content = "Description",
+                    IsChecked = columnPreferences.Contains("Description", StringComparison.OrdinalIgnoreCase)
+                };

(Or add a local var prefs = columnPreferences ?? string.Empty; and use prefs for all .Contains(...) calls.)

Also applies to: 1163-1221

Ginger/GingerCore/Drivers/MainFrame/MainFrameDriver.cs (1)

123-138: Consider consistent Dispatcher/status behavior on connection failures

The new flow improves robustness (isConnected null‑checks MFE, and failures are logged), but there are two edge cases worth verifying:

  • If IsServerListening is false, Launchdriver logs a status and returns without ever setting Dispatcher or raising DriverStatusChanged.
  • If ConnectToMainframe() returns false, mDriverWindow is nulled but again no dispatcher is assigned and no status/event is raised.

If any caller assumes Dispatcher is always non‑null after StartDriver() (even when startup fails), or relies on a DriverStatusChanged event to detect failure, these paths could cause subtle issues.

You may want to:

  • Assign Dispatcher = new DummyDispatcher() before early returns, and/or
  • Invoke OnDriverMessage(eDriverMessageType.DriverStatusChanged) on failure as well, to keep behavior consistent with the success and exception paths.

Also applies to: 163-208

♻️ Duplicate comments (1)
Ginger/GingerCoreNET/Database/DatabaseOperations.cs (1)

372-372: Pre-existing security scan finding - not introduced by current changes.

The resource injection finding at line 372 relates to connection string construction from database configuration values. This is inherent to database connection operations and not introduced by the current refactoring.

Comment on lines +1 to +122
# Ginger Automation AI Coding Agent Guide

## Project Overview
Ginger is a comprehensive automation IDE supporting multiple platforms (Web, Mobile, APIs, Java, Windows, PowerBuilder, Linux/Unix, Mainframe). It uses a drag-and-drop approach enabling users with or without coding skills to create automation flows.

## Core Architecture Concepts

### 1. Execution Hierarchy
The fundamental execution structure follows this hierarchy:
```
Solution → RunSet → Runner → BusinessFlow → Activity → Action (Act)
```

- **BusinessFlow**: Top-level test scenario container (`GingerCoreCommon/Repository/BusinessFlowLib/BusinessFlow.cs`)
- **Activity**: Group of related actions within a BusinessFlow (`GingerCoreCommon/Repository/BusinessFlowLib/Activity.cs`)
- **Act/Action**: Individual executable step (`GingerCoreCommon/Actions/Act.cs`)
- **Agent**: Driver wrapper that connects to target applications (`GingerCoreCommon/RunLib/Agent.cs`)

### 2. Key Project Structure
- **Ginger/**: Main WPF application (UI)
- **GingerCoreCommon/**: Shared models and base classes
- **GingerCoreNET/**: .NET execution engine and CLI components
- **GingerRuntime/**: Console application entry point
- **GingerCore/**: Legacy core components (being migrated to GingerCoreNET)

### 3. Driver Architecture
Each platform has dedicated drivers under `GingerCore/Drivers/`:
- `SeleniumDriver` for web automation
- `JavaDriver` for Java applications
- `ConsoleDriverLib` for command-line interfaces
- `WindowsAutomation` for Windows applications
- Agents (`Agent.cs`) act as wrappers providing unified interface

## Development Workflows

### Building & Testing
```powershell
# Main build (Windows)
dotnet build Ginger/Ginger.sln

# Run tests
./TestDotNetFramework.ps1 # Framework tests
./CLITests.ps1 # CLI functionality tests

# Console execution
cd Ginger/GingerRuntime/bin/Release/net8.0/publish/
dotnet GingerConsole.dll run -s "path/to/solution" -e "Environment" -r "RunSet"
```

### CLI Commands
**Windows:**
- `ginger.exe help` or `dotnet ginger.dll help` - Show CLI help
- `ginger.exe run -s <solution> -e <env> -r <runset>` - Execute automation
- `ginger.exe analyze -s <solution>` - Analyze solution
- `ginger.exe grid --port <port>` - Start grid mode

**Linux:**
- `dotnet gingerruntime.dll help` - Show CLI help
- `dotnet gingerruntime.dll run -s <solution> -e <env> -r <runset>` - Execute automation
- `dotnet gingerruntime.dll analyze -s <solution>` - Analyze solution
- `dotnet gingerruntime.dll grid --port <port>` - Start grid mode

## Project Conventions

### 1. File Organization
- Actions inherit from `Act` class and implement platform-specific logic
- Repository objects use `[IsSerializedForLocalRepository]` attribute for persistence
- Test files end with `Test.cs` and use MSTest framework with `[TestClass]` and `[TestMethod]`

### 2. Naming Patterns
- Actions: `Act{PlatformType}{ActionType}` (e.g., `ActBrowserElement`, `ActConsoleCommand`)
- Drivers: `{Platform}Driver` (e.g., `SeleniumDriver`, `JavaDriver`)
- Pages/Windows: `{Feature}Page` or `{Feature}Window`

### 3. Error Handling
- Use `Reporter.ToLog(eLogLevel.ERROR, message)` for logging
- Actions set `act.Error` and `act.Status = eRunStatus.Failed` on failure
- Execution continues based on `Activity.ActionRunOption` setting

## Integration Points

### 1. Solution Structure
Solutions are XML-based with this folder structure:
```
Solution/
├── BusinessFlows/ # Test scenarios
├── Activities/ # Reusable activity groups
├── Actions/ # Shared actions
├── Agents/ # Driver configurations
├── Environments/ # Environment settings
├── DataSources/ # Test data
└── Applications/ # Target application definitions
```

### 2. Execution Engine
- `RunsetExecutor` orchestrates execution (`GingerCoreNET/Run/RunsetExecutor.cs`)
- `GingerExecutionEngine` handles individual runner execution
- Execution logging via `ExecutionLogger` implementations
- Supports parallel execution across multiple agents

### 3. Plugin Architecture
- Legacy drivers implement `DriverBase`
- New plugins use `Agent.eAgentType.Service` with `PluginId`/`ServiceId`
- External integrations via `ALM` (Application Lifecycle Management) connectors
- Plugin packages defined by `Ginger.PluginPackage.json` manifest
- Managed through `PluginsManager` (`GingerCoreNET/PlugInsLib/PluginsManager.cs`)

## Critical Development Notes

- **Target Framework**: .NET 8.0 with Windows 10.0.17763.0 compatibility
- **WPF Dependencies**: Main UI uses WPF; console components are cross-platform
- **XML Serialization**: Repository objects serialize to XML using custom attributes
- **Multi-Threading**: Execution engine supports parallel runners; use thread-safe patterns
- **Memory Management**: Dispose drivers properly; avoid memory leaks in long-running executions

## Testing Strategy
- Unit tests in `*Test.cs` files use dependency injection patterns
- Integration tests use `TestResources/Solutions/` for test data
- CLI tests verify command-line interface functionality
- Use `mConsoleMessages` pattern for testing CLI output capture

When working with this codebase, focus on the execution hierarchy and understand how Actions flow through Activities within BusinessFlows, executed by Agents that wrap platform-specific drivers. No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix Markdown formatting to comply with style guide.

The file has systematic formatting violations that should be corrected before merge:

  1. Blank lines around headings (MD022): All heading levels lack blank lines above their introductory text or preceding sections
  2. Blank lines around code blocks (MD031): Multiple fenced code blocks lack surrounding blank lines
  3. Language identifiers in code blocks (MD040): Both Solution → RunSet... blocks (lines 10, 84) are missing language identifiers
  4. Trailing newline (MD047): File should end with a single newline
🔎 Proposed fixes for Markdown formatting

Add blank lines before all headings and major sections, specify language identifiers, and add trailing newline. Example pattern:

-## Project Overview
-Ginger is a comprehensive automation IDE...
+
+## Project Overview
+
+Ginger is a comprehensive automation IDE...

For code blocks without a language:

-```
-Solution → RunSet → Runner → BusinessFlow → Activity → Action (Act)
-```
+
+```
+Solution → RunSet → Runner → BusinessFlow → Activity → Action (Act)
+```

Apply these patterns consistently throughout lines 1–122 and ensure the file ends with a newline.

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

3-3: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


8-8: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


10-10: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


19-19: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


26-26: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


36-36: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


37-37: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


50-50: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


65-65: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


70-70: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


75-75: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


82-82: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


84-84: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


84-84: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


95-95: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


101-101: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


116-116: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


122-122: Files should end with a single newline character

(MD047, single-trailing-newline)

🤖 Prompt for AI Agents
.github/copilot-instructions.md lines 1-122: the Markdown violates
MD022/MD031/MD040/MD047; fix by adding a blank line before each heading and
before/after every fenced code block, add explicit language identifiers (e.g.,
"text" or "bash") to the two code blocks at the Solution → RunSet... occurrences
(around lines ~10 and ~84), ensure all fenced blocks have surrounding blank
lines, and terminate the file with a single trailing newline.

Comment on lines +27 to +32
Each platform has dedicated drivers under `GingerCore/Drivers/`:
- `SeleniumDriver` for web automation
- `JavaDriver` for Java applications
- `ConsoleDriverLib` for command-line interfaces
- `WindowsAutomation` for Windows applications
- Agents (`Agent.cs`) act as wrappers providing unified interface

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for JavaDriver, SeleniumDriver, ConsoleDriver classes
echo "=== Searching for class definitions ==="
find . -name "*.cs" -type f | head -100 | xargs grep -l "class JavaDriver\|class SeleniumDriver\|class.*ConsoleDriver\|class WindowsAutomation" 2>/dev/null | head -20

echo ""
echo "=== Checking for ConsoleDriverLib directory ==="
find . -type d -name "*Console*" 2>/dev/null | head -20

echo ""
echo "=== Checking directory structure under Drivers ==="
find . -type d -path "*/Drivers/*" 2>/dev/null | head -30

Repository: Ginger-Automation/Ginger

Length of output: 2062


🏁 Script executed:

#!/bin/bash
# Search for specific class definitions in discovered directories
echo "=== JavaDriver in GingerCore/Drivers/JavaDriverLib ==="
find ./Ginger/GingerCore/Drivers/JavaDriverLib -name "*.cs" -type f -exec grep -l "class.*JavaDriver" {} \; 2>/dev/null

echo ""
echo "=== ConsoleDriver in GingerCore/Drivers/ConsoleDriverLib ==="
find ./Ginger/GingerCore/Drivers/ConsoleDriverLib -name "*.cs" -type f -exec grep -l "class.*ConsoleDriver" {} \; 2>/dev/null

echo ""
echo "=== ConsoleDriver in GingerCoreNET/Drivers/CoreDrivers/Console ==="
find ./Ginger/GingerCoreNET/Drivers/CoreDrivers/Console -name "*.cs" -type f -exec grep -l "class.*ConsoleDriver\|class.*Console" {} \; 2>/dev/null

echo ""
echo "=== SeleniumDriver location ==="
find ./Ginger -name "*SeleniumDriver*.cs" -type f 2>/dev/null | head -5

echo ""
echo "=== WindowsAutomation ==="
find ./Ginger -name "*WindowsAutomation*.cs" -type f 2>/dev/null | head -5
find ./Ginger -type d -name "*Windows*" 2>/dev/null | grep -i driver | head -10

Repository: Ginger-Automation/Ginger

Length of output: 733


🏁 Script executed:

#!/bin/bash
# Check contents of legacy ConsoleDriverLib
echo "=== Files in GingerCore/Drivers/ConsoleDriverLib ==="
find ./Ginger/GingerCore/Drivers/ConsoleDriverLib -type f -name "*.cs" 2>/dev/null | head -20

echo ""
echo "=== Check if ConsoleDriverLib directory is empty or deprecated ==="
ls -la ./Ginger/GingerCore/Drivers/ConsoleDriverLib 2>/dev/null

echo ""
echo "=== Verify copilot-instructions.md current content ==="
cat ./Ginger/.github/copilot-instructions.md 2>/dev/null | head -50

Repository: Ginger-Automation/Ginger

Length of output: 498


🏁 Script executed:

#!/bin/bash
echo "=== Full copilot-instructions.md content ==="
cat ./Ginger/.github/copilot-instructions.md

echo ""
echo "=== Check for WindowsDriver or Windows-related driver classes ==="
find ./Ginger/GingerCore/Drivers/WindowsLib -name "*.cs" -type f -exec grep -l "class.*Windows" {} \; 2>/dev/null | head -5

Repository: Ginger-Automation/Ginger

Length of output: 325


🏁 Script executed:

#!/bin/bash
echo "=== Find copilot-instructions.md in the repo ==="
find ./Ginger -name "copilot-instructions.md" -type f 2>/dev/null

echo ""
echo "=== Search all .github directories ==="
find ./Ginger -type d -name ".github" 2>/dev/null

Repository: Ginger-Automation/Ginger

Length of output: 156


🏁 Script executed:

#!/bin/bash
echo "=== Check if .github directory exists anywhere ==="
find . -type d -name ".github" 2>/dev/null

echo ""
echo "=== Search for any copilot or instructions files ==="
find ./Ginger -iname "*copilot*" -o -iname "*instruction*" 2>/dev/null | grep -v node_modules

echo ""
echo "=== Check git status and recent files ==="
cd ./Ginger && git ls-files | grep -i copilot | head -10

Repository: Ginger-Automation/Ginger

Length of output: 225


🏁 Script executed:

#!/bin/bash
echo "=== Contents of .github directory ==="
ls -la ./.github/

echo ""
echo "=== Check if copilot-instructions.md file exists ==="
test -f ./.github/copilot-instructions.md && echo "File exists" || echo "File does not exist"

echo ""
echo "=== Try different paths ==="
find . -name "*.md" -path "*/.github/*" 2>/dev/null

Repository: Ginger-Automation/Ginger

Length of output: 611


🏁 Script executed:

#!/bin/bash
echo "=== Full copilot-instructions.md content ==="
cat ./.github/copilot-instructions.md

echo ""
echo "=== Check specific line range (27-32) ==="
sed -n '27,32p' ./.github/copilot-instructions.md

Repository: Ginger-Automation/Ginger

Length of output: 5791


Update driver paths to reflect actual post-refactoring locations.

Lines 27–32 reference driver locations that are now outdated. SeleniumDriver and ConsoleDriver implementations have been migrated to GingerCoreNET:

  • SeleniumDriver is located in GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/, not GingerCore/Drivers/
  • Console driver implementations (DOSConsoleDriver, UnixShellDriver) are located in GingerCoreNET/Drivers/CoreDrivers/Console/, not under GingerCore/Drivers/ConsoleDriverLib
  • JavaDriver remains in GingerCore/Drivers/JavaDriverLib/ (accurate)
  • Update WindowsAutomation to WindowsDriver for consistency with actual class names and the {Platform}Driver naming pattern
🤖 Prompt for AI Agents
.github/copilot-instructions.md around lines 27 to 32: update the outdated
driver path references to the post-refactor locations and naming: change the
SeleniumDriver path to GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/, move
Console drivers to GingerCoreNET/Drivers/CoreDrivers/Console/ (include
DOSConsoleDriver and UnixShellDriver), keep JavaDriver at
GingerCore/Drivers/JavaDriverLib/, and rename WindowsAutomation to WindowsDriver
to follow the {Platform}Driver naming pattern.

Comment thread Ginger/Ginger.sln
Comment on lines +3 to +4
# Visual Studio Version 18
VisualStudioVersion = 18.0.11205.157

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Verify Visual Studio 2026 (Version 18) requirement is intentional.

The solution file has been updated to target Visual Studio 2026 (Version 18), which began rolling out on November 11, 2025. Ensure this is intentional for the 2025 RC release, as it may impact developers who haven't upgraded to Visual Studio 2026 yet. While the MinimumVisualStudioVersion remains at 10.0.40219.1 allowing older VS versions to open the solution, some features may require the newer version.

🤖 Prompt for AI Agents
In Ginger/Ginger.sln around lines 3 to 4, the solution file now lists
VisualStudioVersion = 18.0.11205.157 (Visual Studio 2026); verify this is
intentional for the 2025 RC release and either confirm and document the
requirement or revert to the previous supported IDE version to avoid forcing
upgrades. If intentional: keep the version but add a note to the repo
README/CONTRIBUTING that VS 2026 is required for certain features and update
CI/docs; if not intentional: change VisualStudioVersion to the prior supported
value (e.g., 17.x) and ensure MinimumVisualStudioVersion remains unchanged, then
run a quick solution open/test on VS 17 to validate compatibility.

Comment on lines +67 to +71
// Apply initial visibility according to current selected command
if (ConsoleActionComboBox.SelectedItem != null)
{
UpdateVisibilityForCommand((ActConsoleCommand.eConsoleCommand)Enum.Parse(typeof(ActConsoleCommand.eConsoleCommand), ConsoleActionComboBox.SelectedValue?.ToString()));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add error handling for enum parsing.

The code directly parses ConsoleActionComboBox.SelectedValue?.ToString() to an enum without validation, which could throw ArgumentException if the value is unexpected.

🔎 Proposed fix with safer enum parsing
 // Apply initial visibility according to current selected command
 if (ConsoleActionComboBox.SelectedItem != null)
 {
-    UpdateVisibilityForCommand((ActConsoleCommand.eConsoleCommand)Enum.Parse(typeof(ActConsoleCommand.eConsoleCommand), ConsoleActionComboBox.SelectedValue?.ToString()));
+    if (Enum.TryParse<ActConsoleCommand.eConsoleCommand>(ConsoleActionComboBox.SelectedValue?.ToString(), out var command))
+    {
+        UpdateVisibilityForCommand(command);
+    }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Apply initial visibility according to current selected command
if (ConsoleActionComboBox.SelectedItem != null)
{
UpdateVisibilityForCommand((ActConsoleCommand.eConsoleCommand)Enum.Parse(typeof(ActConsoleCommand.eConsoleCommand), ConsoleActionComboBox.SelectedValue?.ToString()));
}
// Apply initial visibility according to current selected command
if (ConsoleActionComboBox.SelectedItem != null)
{
if (Enum.TryParse<ActConsoleCommand.eConsoleCommand>(ConsoleActionComboBox.SelectedValue?.ToString(), out var command))
{
UpdateVisibilityForCommand(command);
}
}
🤖 Prompt for AI Agents
In Ginger/Ginger/Actions/ActionEditPages/ActConsoleCommandEditPage.xaml.cs
around lines 67 to 71, the code parses ConsoleActionComboBox.SelectedValue
directly to ActConsoleCommand.eConsoleCommand which can throw if the value is
invalid; change this to safely attempt parsing (use Enum.TryParse with
ignoreCase true) after confirming SelectedValue is not null, and if TryParse
fails handle it by using a sensible default or returning early and
logging/alerting the issue so UpdateVisibilityForCommand is only called with a
valid enum value.

Comment on lines +121 to +124
if (driver is not ConsoleDriverBase)
{
Reporter.ToLog(eLogLevel.ERROR, "ConsoleDriverWindow: driver is null");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix misleading error message.

The error message says "driver is null" but the check is actually validating that the driver is of type ConsoleDriverBase. This makes debugging confusing.

🔎 Proposed fix for accurate error message
 if (driver is not ConsoleDriverBase)
 {
-    Reporter.ToLog(eLogLevel.ERROR, "ConsoleDriverWindow: driver is null");
+    Reporter.ToLog(eLogLevel.ERROR, "ConsoleDriverWindow: driver is not ConsoleDriverBase");
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (driver is not ConsoleDriverBase)
{
Reporter.ToLog(eLogLevel.ERROR, "ConsoleDriverWindow: driver is null");
}
if (driver is not ConsoleDriverBase)
{
Reporter.ToLog(eLogLevel.ERROR, "ConsoleDriverWindow: driver is not ConsoleDriverBase");
}
🤖 Prompt for AI Agents
In Ginger/Ginger/Drivers/DriversWindows/ConsoleDriverWindow.xaml.cs around lines
121-124, the logged message "ConsoleDriverWindow: driver is null" is misleading
because the condition checks that driver is not a ConsoleDriverBase; update the
error log to accurately state that the driver is not a ConsoleDriverBase (e.g.,
"ConsoleDriverWindow: driver is not a ConsoleDriverBase") and include the actual
driver type or "null" in the message to aid debugging.

Comment on lines +274 to +285
case eDBTypes.MSSQL:
var builder = new SqlConnectionStringBuilder
{
DataSource = TNSCalculated
};

if (!string.IsNullOrEmpty(Database.Name)) builder.InitialCatalog = Database.Name;
builder.IntegratedSecurity = false;
builder.UserID = UserCalculated;
builder.Password = EncryptionHandler.DecryptwithKey(PassCalculated);
Database.ConnectionString = builder.ConnectionString;
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Inconsistent password handling in MSSQL connection string.

Line 283 decrypts the password directly and assigns it to the builder, which differs from the placeholder-based approach ({PASS}) used for other database types and in the GetConnectionString method. This inconsistency makes the code harder to maintain and may bypass the centralized ReplacePasswordInConnectionString logic.

🔎 Proposed fix to use placeholder approach
                     case eDBTypes.MSSQL:
                         var builder = new SqlConnectionStringBuilder
                         {
                             DataSource = TNSCalculated
                         };
 
                         if (!string.IsNullOrEmpty(Database.Name)) builder.InitialCatalog = Database.Name;
                         builder.IntegratedSecurity = false;
-                        builder.UserID = UserCalculated;
-                        builder.Password = EncryptionHandler.DecryptwithKey(PassCalculated);
+                        builder.UserID = "{USER}";
+                        builder.Password = "{PASS}";
                         Database.ConnectionString = builder.ConnectionString;
                         break;
🤖 Prompt for AI Agents
In Ginger/GingerCoreNET/Database/DatabaseOperations.cs around lines 274 to 285
the MSSQL branch directly decrypts and assigns the password to the
SqlConnectionStringBuilder (line ~283), which is inconsistent with the
placeholder-based pattern used elsewhere; change this to set the connection
string with a {PASS} placeholder (do not assign the decrypted password to
builder.Password), assign builder.ConnectionString to Database.ConnectionString,
and then call the existing ReplacePasswordInConnectionString (or equivalent
centralized method) to inject the decrypted password so MSSQL follows the same
placeholder-based flow as other DB types.

Comment on lines 419 to 442
case eDBTypes.PostgreSQL:
oConn = new NpgsqlConnection(connectConnectionString);
string postgreSQLHost = TNSCalculated;
int? port = null;
if (TNSCalculated.Contains(':', StringComparison.Ordinal))
{
var parts = TNSCalculated.Split(':', 2);
postgreSQLHost = parts[0];
if (int.TryParse(parts[1], out int p)) port = p;
}
ValidateHostPort(postgreSQLHost, port);

var pg = new NpgsqlConnectionStringBuilder
{
Host = postgreSQLHost,
Database = Database.Name ?? string.Empty,
Username = UserCalculated,
Password = EncryptionHandler.DecryptwithKey(PassCalculated)
};
if (port.HasValue) pg.Port = port.Value;
Database.ConnectionString = pg.ConnectionString;

oConn = new NpgsqlConnection(pg.ConnectionString);
oConn.Open();
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Significant code duplication between CreateConnectionString and Connect.

The PostgreSQL (lines 419-442) and MySQL (lines 472-499) connection string construction logic is duplicated from the CreateConnectionString method. This violates the DRY principle and creates a maintenance burden when connection string logic needs to be updated.

Consider calling GetConnectionString() or CreateConnectionString() instead of rebuilding the connection strings inline.

🔎 Example refactor for PostgreSQL
                     case eDBTypes.PostgreSQL:
-                        string postgreSQLHost = TNSCalculated;
-                        int? port = null;
-                        if (TNSCalculated.Contains(':', StringComparison.Ordinal))
-                        {
-                            var parts = TNSCalculated.Split(':', 2);
-                            postgreSQLHost = parts[0];
-                            if (int.TryParse(parts[1], out int p)) port = p;
-                        }
-                        ValidateHostPort(postgreSQLHost, port);
-
-                        var pg = new NpgsqlConnectionStringBuilder
-                        {
-                            Host = postgreSQLHost,
-                            Database = Database.Name ?? string.Empty,
-                            Username = UserCalculated,
-                            Password = EncryptionHandler.DecryptwithKey(PassCalculated)
-                        };
-                        if (port.HasValue) pg.Port = port.Value;
-                        Database.ConnectionString = pg.ConnectionString;
-
-                        oConn = new NpgsqlConnection(pg.ConnectionString);
+                        oConn = new NpgsqlConnection(GetConnectionString());
                         oConn.Open();
                         break;

Apply similar changes for MySQL.

Also applies to: 472-499

Comment on lines +572 to +595
private SqlConnectionStringBuilder GetMSSQLConnectionStringBuilder()
{
//if (string.IsNullOrEmpty(Database.ConnectionString))
{
var builder = new SqlConnectionStringBuilder();
builder.DataSource = TNSCalculated;
if (!string.IsNullOrEmpty(Database.Name)) builder.InitialCatalog = Database.Name;
builder.IntegratedSecurity = false;
builder.UserID = UserCalculated;
builder.Password = EncryptionHandler.DecryptwithKey(PassCalculated);
return builder;
}
//else
//{
// // GetConnectionString will replace {USER} and {PASS} placeholders and decrypt the password
// string connStr = ConnectionStringCalculated;
// connStr = connStr.Replace("{USER}", UserCalculated);
// connStr = ReplacePasswordInConnectionString(connStr);

// // Parse and normalise the connection string using SqlConnectionStringBuilder
// var parsedBuilder = new SqlConnectionStringBuilder(connStr);
// return parsedBuilder;
//}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove commented code.

Lines 574-594 contain extensive commented-out code that appears to be an abandoned alternative implementation. This should be removed to improve code readability.

🔎 Proposed cleanup
         private SqlConnectionStringBuilder GetMSSQLConnectionStringBuilder()
         {
-            //if (string.IsNullOrEmpty(Database.ConnectionString))
-            {
-                var builder = new SqlConnectionStringBuilder();
-                builder.DataSource = TNSCalculated;
-                if (!string.IsNullOrEmpty(Database.Name)) builder.InitialCatalog = Database.Name;
-                builder.IntegratedSecurity = false;
-                builder.UserID = UserCalculated;
-                builder.Password = EncryptionHandler.DecryptwithKey(PassCalculated);
-                return builder;
-            }
-            //else
-            //{
-            //    // GetConnectionString will replace {USER} and {PASS} placeholders and decrypt the password
-            //    string connStr = ConnectionStringCalculated;
-            //    connStr = connStr.Replace("{USER}", UserCalculated);
-            //    connStr = ReplacePasswordInConnectionString(connStr);
-
-            //    // Parse and normalise the connection string using SqlConnectionStringBuilder
-            //    var parsedBuilder = new SqlConnectionStringBuilder(connStr);
-            //    return parsedBuilder;
-            //}
+            var builder = new SqlConnectionStringBuilder();
+            builder.DataSource = TNSCalculated;
+            if (!string.IsNullOrEmpty(Database.Name)) builder.InitialCatalog = Database.Name;
+            builder.IntegratedSecurity = false;
+            builder.UserID = UserCalculated;
+            builder.Password = EncryptionHandler.DecryptwithKey(PassCalculated);
+            return builder;
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private SqlConnectionStringBuilder GetMSSQLConnectionStringBuilder()
{
//if (string.IsNullOrEmpty(Database.ConnectionString))
{
var builder = new SqlConnectionStringBuilder();
builder.DataSource = TNSCalculated;
if (!string.IsNullOrEmpty(Database.Name)) builder.InitialCatalog = Database.Name;
builder.IntegratedSecurity = false;
builder.UserID = UserCalculated;
builder.Password = EncryptionHandler.DecryptwithKey(PassCalculated);
return builder;
}
//else
//{
// // GetConnectionString will replace {USER} and {PASS} placeholders and decrypt the password
// string connStr = ConnectionStringCalculated;
// connStr = connStr.Replace("{USER}", UserCalculated);
// connStr = ReplacePasswordInConnectionString(connStr);
// // Parse and normalise the connection string using SqlConnectionStringBuilder
// var parsedBuilder = new SqlConnectionStringBuilder(connStr);
// return parsedBuilder;
//}
}
private SqlConnectionStringBuilder GetMSSQLConnectionStringBuilder()
{
var builder = new SqlConnectionStringBuilder();
builder.DataSource = TNSCalculated;
if (!string.IsNullOrEmpty(Database.Name)) builder.InitialCatalog = Database.Name;
builder.IntegratedSecurity = false;
builder.UserID = UserCalculated;
builder.Password = EncryptionHandler.DecryptwithKey(PassCalculated);
return builder;
}
🤖 Prompt for AI Agents
In Ginger/GingerCoreNET/Database/DatabaseOperations.cs around lines 572-595,
remove the commented-out alternative implementation block (lines ~574-594) so
only the active GetMSSQLConnectionStringBuilder implementation remains; ensure
no orphaned comment markers remain and keep the existing return path intact
(SqlConnectionStringBuilder with DataSource, InitialCatalog, IntegratedSecurity,
UserID, and decrypted Password).

Comment on lines 900 to 903
catch (Exception e)
{
throw e;
throw;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing error logging before rethrow.

Line 902 rethrows an exception without logging it first, which is inconsistent with other catch blocks in this file that use Reporter.ToLog before rethrowing (e.g., lines 561, 650, 727, 815, 868, 1005).

As per coding guidelines: Use Reporter.ToLog(eLogLevel.ERROR, message) for logging errors.

🔎 Proposed fix
                     catch (Exception e)
                     {
+                        Reporter.ToLog(eLogLevel.ERROR, $"Failed to query table {Table} column {Column} with where clause: {Where}", e);
                         throw;
                     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
catch (Exception e)
{
throw e;
throw;
}
catch (Exception e)
{
Reporter.ToLog(eLogLevel.ERROR, $"Failed to query table {Table} column {Column} with where clause: {Where}", e);
throw;
}
🤖 Prompt for AI Agents
In Ginger/GingerCoreNET/Database/DatabaseOperations.cs around lines 900 to 903,
the catch block rethrows the exception without logging it; update the catch to
call Reporter.ToLog(eLogLevel.ERROR, ...) before throwing so errors are
consistent with other blocks (lines 561, 650, etc.). Log a clear message
including the context (e.g., which database operation failed) and include the
exception details (message/stack) via the exception object, then rethrow the
exception as currently done.

Comment on lines +154 to +161
Dispatcher.Invoke(() =>
{
OnDriverMessage(eDriverMessageType.CloseDriverWindow);
});

// Give window time to close gracefully
Thread.Sleep(500);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Replace blocking Thread.Sleep with async synchronization.

The code uses Thread.Sleep(500) to wait for window closure, which blocks the thread unnecessarily. Consider using an event-based or async pattern for cleaner shutdown coordination.

Alternative approach using TaskCompletionSource
// In ConsoleDriverBase, add a field:
private TaskCompletionSource<bool> _windowClosedTcs;

// In CloseDriver:
if (ShowWindow && Dispatcher != null)
{
    try
    {
        _windowClosedTcs = new TaskCompletionSource<bool>();
        Dispatcher.Invoke(() =>
        {
            OnDriverMessage(eDriverMessageType.CloseDriverWindow);
        });
        
        // Wait up to 1 second for window to close
        _windowClosedTcs.Task.Wait(TimeSpan.FromSeconds(1));
    }
    catch (Exception ex)
    {
        Reporter.ToLog(eLogLevel.DEBUG, "Error closing driver window from driver", ex);
    }
}

// In ConsoleDriverWindow.xaml.cs Closing handler, signal completion:
// mConsoleDriver?.SignalWindowClosed();

@ravirk91
ravirk91 merged commit 86263a4 into Releases/Official-Release Dec 19, 2025
6 of 11 checks passed
This was referenced Dec 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.