using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; namespace MarketAlly.AIPlugin.Refactoring.Plugins { // Simple Git integration using Process calls - no external dependencies required public class SimpleGitManager { private readonly string _repositoryPath; public bool IsGitRepository { get; private set; } public SimpleGitManager(string repositoryPath) { _repositoryPath = repositoryPath; IsGitRepository = Directory.Exists(Path.Combine(repositoryPath, ".git")); } public async Task CreateRefactoringBranch(string branchName, bool applyChanges) { var gitInfo = new SimpleGitRefactoringInfo { RepositoryPath = _repositoryPath, NewBranchName = branchName, CreatedAt = DateTime.UtcNow }; if (!IsGitRepository) { gitInfo.Success = false; gitInfo.Error = "Not a Git repository"; return gitInfo; } try { // Get current branch gitInfo.OriginalBranch = await RunGitCommand("branch --show-current"); // Get current commit gitInfo.OriginalCommit = await RunGitCommand("rev-parse HEAD"); // Check if working directory is clean var status = await RunGitCommand("status --porcelain"); if (!string.IsNullOrWhiteSpace(status)) { gitInfo.Success = false; gitInfo.Error = "Working directory has uncommitted changes. Please commit or stash changes before refactoring."; return gitInfo; } if (applyChanges) { // Check if branch exists var branchExists = await RunGitCommand($"show-ref --verify --quiet refs/heads/{branchName}", ignoreErrors: true); if (string.IsNullOrEmpty(branchExists)) // Branch doesn't exist (git command failed) { // Create and checkout new branch await RunGitCommand($"checkout -b {branchName}"); gitInfo.BranchCreated = true; } else { // Branch exists, create with timestamp var timestamp = DateTime.Now.ToString("HHmmss"); branchName = $"{branchName}-{timestamp}"; gitInfo.NewBranchName = branchName; await RunGitCommand($"checkout -b {branchName}"); gitInfo.BranchCreated = true; } } gitInfo.Success = true; } catch (Exception ex) { gitInfo.Success = false; gitInfo.Error = ex.Message; } return gitInfo; } public async Task CommitChanges(string message, List operationsPerformed) { if (!IsGitRepository) return false; try { // Check if there are changes to commit var status = await RunGitCommand("status --porcelain"); if (string.IsNullOrWhiteSpace(status)) { Console.WriteLine("No changes to commit."); return false; } // Stage all changes await RunGitCommand("add ."); // Create enhanced commit message var enhancedMessage = $"{message}\n\nOperations performed:\n{string.Join("\n", operationsPerformed.Select(op => $"- {op}"))}"; // Commit changes with secure argument handling await RunGitCommandSecure(new[] { "commit", "-m", enhancedMessage }); Console.WriteLine($"Changes committed: {message}"); return true; } catch (Exception ex) { Console.WriteLine($"Git commit failed: {ex.Message}"); return false; } } public async Task GetRepositoryStatus() { if (!IsGitRepository) return new SimpleGitStatus { Error = "Not a Git repository" }; try { var currentBranch = await RunGitCommand("branch --show-current"); var latestCommit = await RunGitCommand("log -1 --format=\"%H|%s|%an|%ad\" --date=iso"); var status = await RunGitCommand("status --porcelain"); var commitParts = latestCommit.Split('|'); return new SimpleGitStatus { IsClean = string.IsNullOrWhiteSpace(status), CurrentBranch = currentBranch.Trim(), LatestCommitSha = commitParts.Length > 0 ? commitParts[0].Trim() : "", LatestCommitMessage = commitParts.Length > 1 ? commitParts[1].Trim() : "", LatestCommitAuthor = commitParts.Length > 2 ? commitParts[2].Trim() : "", LatestCommitDate = commitParts.Length > 3 ? commitParts[3].Trim() : "", StatusOutput = status }; } catch (Exception ex) { return new SimpleGitStatus { Error = ex.Message }; } } public async Task SwitchToBranch(string branchName) { if (!IsGitRepository) return false; try { await RunGitCommand($"checkout {branchName}"); Console.WriteLine($"Switched to branch '{branchName}'"); return true; } catch (Exception ex) { Console.WriteLine($"Failed to switch to branch '{branchName}': {ex.Message}"); return false; } } public async Task DeleteBranch(string branchName, bool force = false) { if (!IsGitRepository) return false; try { var flag = force ? "-D" : "-d"; await RunGitCommand($"branch {flag} {branchName}"); Console.WriteLine($"Deleted branch '{branchName}'"); return true; } catch (Exception ex) { Console.WriteLine($"Failed to delete branch '{branchName}': {ex.Message}"); return false; } } public async Task> GetBranches() { if (!IsGitRepository) return new List(); try { var output = await RunGitCommand("branch --format='%(refname:short)'"); return output.Split('\n', StringSplitOptions.RemoveEmptyEntries) .Select(b => b.Trim()) .ToList(); } catch (Exception ex) { Console.WriteLine($"Failed to get branches: {ex.Message}"); return new List(); } } public async Task HasUncommittedChanges() { if (!IsGitRepository) return false; try { var status = await RunGitCommand("status --porcelain"); return !string.IsNullOrWhiteSpace(status); } catch (Exception ex) { Console.WriteLine($"Failed to check repository status: {ex.Message}"); return false; } } private async Task RunGitCommandSecure(string[] arguments, bool ignoreErrors = false) { var processInfo = new ProcessStartInfo { FileName = "git", WorkingDirectory = _repositoryPath, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; // Use ArgumentList for secure parameter passing foreach (var arg in arguments) { processInfo.ArgumentList.Add(arg); } using var process = Process.Start(processInfo); if (process == null) throw new InvalidOperationException("Failed to start git process"); var output = await process.StandardOutput.ReadToEndAsync(); var error = await process.StandardError.ReadToEndAsync(); await process.WaitForExitAsync(); if (process.ExitCode != 0 && !ignoreErrors) { throw new InvalidOperationException($"Git command failed: {error}"); } return output.Trim(); } private async Task RunGitCommand(string arguments, bool ignoreErrors = false) { var processInfo = new ProcessStartInfo { FileName = "git", Arguments = arguments, WorkingDirectory = _repositoryPath, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; using var process = Process.Start(processInfo); if (process == null) throw new InvalidOperationException("Failed to start git process"); var output = await process.StandardOutput.ReadToEndAsync(); var error = await process.StandardError.ReadToEndAsync(); await process.WaitForExitAsync(); if (process.ExitCode != 0 && !ignoreErrors) { throw new InvalidOperationException($"Git command failed: {arguments}\nError: {error}"); } return output.Trim(); } } // Simplified Git status public class SimpleGitStatus { public bool IsClean { get; set; } public string CurrentBranch { get; set; } = string.Empty; public string LatestCommitSha { get; set; } = string.Empty; public string LatestCommitMessage { get; set; } = string.Empty; public string LatestCommitAuthor { get; set; } = string.Empty; public string LatestCommitDate { get; set; } = string.Empty; public string StatusOutput { get; set; } = string.Empty; public string Error { get; set; } = string.Empty; } // Updated SolutionRefactoringPlugin to use SimpleGitManager instead public class SimpleGitRefactoringInfo { public string RepositoryPath { get; set; } = string.Empty; public string OriginalBranch { get; set; } = string.Empty; public string OriginalCommit { get; set; } = string.Empty; public string NewBranchName { get; set; } = string.Empty; public bool BranchCreated { get; set; } public bool Success { get; set; } public string Error { get; set; } = string.Empty; public DateTime CreatedAt { get; set; } public List OperationsPerformed { get; set; } = new List(); } // Simple Git commands generator public static class SimpleGitCommands { public static List GenerateAllCommands(SimpleGitRefactoringInfo gitInfo, List operations) { var commands = new List(); if (gitInfo?.Success == true && gitInfo.BranchCreated) { commands.Add($"# Refactoring completed on branch: {gitInfo.NewBranchName}"); commands.Add($"# Original branch: {gitInfo.OriginalBranch}"); commands.Add(""); // Review commands commands.Add("# 1. REVIEW CHANGES:"); commands.Add("git status # See what files changed"); commands.Add("git diff HEAD~1 # See detailed changes"); commands.Add("git log --oneline -5 # See recent commits"); commands.Add(""); // Commit commands (if not auto-committed) commands.Add("# 2. COMMIT CHANGES (if needed):"); commands.Add("git add ."); commands.Add($"git commit -m \"Refactoring: {string.Join(", ", operations)}\""); commands.Add(""); // Merge commands commands.Add("# 3. MERGE TO MAIN (when ready):"); commands.Add($"git checkout {gitInfo.OriginalBranch}"); commands.Add($"git merge {gitInfo.NewBranchName}"); commands.Add($"git branch -d {gitInfo.NewBranchName}"); commands.Add(""); // Rollback commands commands.Add("# 4. ROLLBACK (if needed):"); commands.Add($"git checkout {gitInfo.OriginalBranch}"); commands.Add($"git branch -D {gitInfo.NewBranchName}"); commands.Add("# All changes discarded, original code restored!"); commands.Add(""); // Status commands commands.Add("# 5. USEFUL COMMANDS:"); commands.Add("git branch # List all branches"); commands.Add($"git diff {gitInfo.OriginalBranch}..{gitInfo.NewBranchName} # Compare branches"); commands.Add("git stash # Temporarily save changes"); commands.Add("git stash pop # Restore stashed changes"); } else if (gitInfo?.Success == false) { commands.Add($"# Git operation failed: {gitInfo.Error}"); commands.Add("# Suggestions:"); commands.Add("git status # Check repository status"); commands.Add("git add . # Stage changes"); commands.Add("git commit -m \"Work in progress\" # Commit current work"); commands.Add("# Then retry the refactoring operation"); } return commands; } } }