MarketAlly.AIPlugin.Extensions/MarketAlly.AIPlugin.Refacto.../SimpleGitManager.cs

377 lines
11 KiB
C#
Executable File

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<SimpleGitRefactoringInfo> 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<bool> CommitChanges(string message, List<string> 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<SimpleGitStatus> 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<bool> 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<bool> 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<List<string>> GetBranches()
{
if (!IsGitRepository)
return new List<string>();
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<string>();
}
}
public async Task<bool> 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<string> 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<string> 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<string> OperationsPerformed { get; set; } = new List<string>();
}
// Simple Git commands generator
public static class SimpleGitCommands
{
public static List<string> GenerateAllCommands(SimpleGitRefactoringInfo gitInfo, List<string> operations)
{
var commands = new List<string>();
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;
}
}
}