395 lines
11 KiB
C#
Executable File
395 lines
11 KiB
C#
Executable File
using MarketAlly.AIPlugin;
|
|
using LibGit2Sharp;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.Json;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace MarketAlly.AIPlugin.Refactoring.Plugins
|
|
{
|
|
public class GitConfiguration
|
|
{
|
|
public string AuthorName { get; set; } = "MarketAlly Refactoring Tool";
|
|
public string AuthorEmail { get; set; } = "refactor@localhost";
|
|
}
|
|
|
|
// Corrected Git integration manager with proper LibGit2Sharp API usage
|
|
public class GitRefactoringManager
|
|
{
|
|
private readonly string _repositoryPath;
|
|
private readonly GitConfiguration _gitConfig;
|
|
public bool IsGitRepository { get; private set; }
|
|
|
|
public GitRefactoringManager(string repositoryPath, GitConfiguration gitConfig = null)
|
|
{
|
|
_repositoryPath = repositoryPath;
|
|
_gitConfig = gitConfig ?? new GitConfiguration();
|
|
IsGitRepository = Repository.IsValid(repositoryPath);
|
|
}
|
|
|
|
public async Task<GitRefactoringInfo> CreateRefactoringBranch(string branchName, bool applyChanges)
|
|
{
|
|
if (!IsGitRepository)
|
|
return null;
|
|
|
|
var gitInfo = new GitRefactoringInfo
|
|
{
|
|
RepositoryPath = _repositoryPath,
|
|
NewBranchName = branchName,
|
|
CreatedAt = DateTime.UtcNow
|
|
};
|
|
|
|
try
|
|
{
|
|
using (var repo = new Repository(_repositoryPath))
|
|
{
|
|
gitInfo.OriginalBranch = repo.Head.FriendlyName;
|
|
gitInfo.OriginalCommit = repo.Head.Tip.Sha;
|
|
|
|
// Check if working directory is clean
|
|
var status = repo.RetrieveStatus();
|
|
if (status.IsDirty)
|
|
{
|
|
gitInfo.Success = false;
|
|
gitInfo.Error = "Working directory has uncommitted changes. Please commit or stash changes before refactoring.";
|
|
return gitInfo;
|
|
}
|
|
|
|
if (applyChanges)
|
|
{
|
|
// Check if branch already exists
|
|
var existingBranch = repo.Branches[branchName];
|
|
if (existingBranch != null)
|
|
{
|
|
// Generate unique branch name
|
|
var timestamp = DateTime.Now.ToString("HHmmss");
|
|
branchName = $"{branchName}-{timestamp}";
|
|
gitInfo.NewBranchName = branchName;
|
|
}
|
|
|
|
// Create and checkout new branch using Commands.Checkout
|
|
var newBranch = repo.CreateBranch(branchName);
|
|
Commands.Checkout(repo, newBranch);
|
|
gitInfo.BranchCreated = true;
|
|
}
|
|
|
|
gitInfo.Success = true;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
gitInfo.Success = false;
|
|
gitInfo.Error = ex.Message;
|
|
}
|
|
|
|
return await Task.FromResult(gitInfo);
|
|
}
|
|
|
|
public async Task<bool> CommitChanges(string message, List<string> operationsPerformed)
|
|
{
|
|
if (!IsGitRepository)
|
|
return false;
|
|
|
|
try
|
|
{
|
|
using (var repo = new Repository(_repositoryPath))
|
|
{
|
|
// Get repository status
|
|
var status = repo.RetrieveStatus();
|
|
|
|
if (!status.IsDirty)
|
|
{
|
|
Console.WriteLine("No changes to commit.");
|
|
return await Task.FromResult(false);
|
|
}
|
|
|
|
// Stage all modified files
|
|
foreach (var modified in status.Modified)
|
|
{
|
|
repo.Index.Add(modified.FilePath);
|
|
}
|
|
|
|
// Stage all new files
|
|
foreach (var untracked in status.Untracked)
|
|
{
|
|
repo.Index.Add(untracked.FilePath);
|
|
}
|
|
|
|
// Stage all renamed files
|
|
foreach (var renamed in status.RenamedInIndex)
|
|
{
|
|
repo.Index.Add(renamed.FilePath);
|
|
}
|
|
|
|
// Write the index changes
|
|
repo.Index.Write();
|
|
|
|
// Create commit if there are staged changes
|
|
var indexStatus = repo.RetrieveStatus();
|
|
if (indexStatus.Added.Any() || indexStatus.Modified.Any() || indexStatus.Staged.Any())
|
|
{
|
|
var signature = new Signature(_gitConfig.AuthorName, _gitConfig.AuthorEmail, DateTimeOffset.Now);
|
|
|
|
// Enhanced commit message with operation details
|
|
var enhancedMessage = $"{message}\n\nOperations performed:\n{string.Join("\n", operationsPerformed.Select(op => $"- {op}"))}";
|
|
|
|
var commit = repo.Commit(enhancedMessage, signature, signature);
|
|
Console.WriteLine($"Created commit: {commit.Sha[..8]} - {message}");
|
|
return await Task.FromResult(true);
|
|
}
|
|
|
|
return await Task.FromResult(false);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Git commit failed: {ex.Message}");
|
|
return await Task.FromResult(false);
|
|
}
|
|
}
|
|
|
|
public async Task<GitStatusInfo> GetRepositoryStatus()
|
|
{
|
|
if (!IsGitRepository)
|
|
return null;
|
|
|
|
try
|
|
{
|
|
using (var repo = new Repository(_repositoryPath))
|
|
{
|
|
var status = repo.RetrieveStatus();
|
|
|
|
return await Task.FromResult(new GitStatusInfo
|
|
{
|
|
IsClean = !status.IsDirty,
|
|
CurrentBranch = repo.Head.FriendlyName,
|
|
LatestCommitSha = repo.Head.Tip.Sha,
|
|
LatestCommitMessage = repo.Head.Tip.MessageShort,
|
|
LatestCommitAuthor = repo.Head.Tip.Author.Name,
|
|
LatestCommitDate = repo.Head.Tip.Author.When,
|
|
ModifiedFiles = status.Modified.Select(f => f.FilePath).ToList(),
|
|
AddedFiles = status.Added.Select(f => f.FilePath).ToList(),
|
|
DeletedFiles = status.Removed.Select(f => f.FilePath).ToList(),
|
|
UntrackedFiles = status.Untracked.Select(f => f.FilePath).ToList(),
|
|
StagedFiles = status.Staged.Select(f => f.FilePath).ToList()
|
|
});
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return new GitStatusInfo
|
|
{
|
|
IsClean = false,
|
|
Error = ex.Message
|
|
};
|
|
}
|
|
}
|
|
|
|
public async Task<bool> SwitchToBranch(string branchName)
|
|
{
|
|
if (!IsGitRepository)
|
|
return false;
|
|
|
|
try
|
|
{
|
|
using (var repo = new Repository(_repositoryPath))
|
|
{
|
|
var branch = repo.Branches[branchName];
|
|
if (branch == null)
|
|
{
|
|
Console.WriteLine($"Branch '{branchName}' not found.");
|
|
return false;
|
|
}
|
|
|
|
Commands.Checkout(repo, branch);
|
|
Console.WriteLine($"Switched to branch '{branchName}'");
|
|
return await Task.FromResult(true);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Failed to switch to branch '{branchName}': {ex.Message}");
|
|
return await Task.FromResult(false);
|
|
}
|
|
}
|
|
|
|
public async Task<bool> DeleteBranch(string branchName, bool force = false)
|
|
{
|
|
if (!IsGitRepository)
|
|
return false;
|
|
|
|
try
|
|
{
|
|
using (var repo = new Repository(_repositoryPath))
|
|
{
|
|
var branch = repo.Branches[branchName];
|
|
if (branch == null)
|
|
{
|
|
Console.WriteLine($"Branch '{branchName}' not found.");
|
|
return false;
|
|
}
|
|
|
|
if (branch.IsCurrentRepositoryHead)
|
|
{
|
|
Console.WriteLine($"Cannot delete current branch '{branchName}'. Switch to another branch first.");
|
|
return false;
|
|
}
|
|
|
|
repo.Branches.Remove(branch);
|
|
Console.WriteLine($"Deleted branch '{branchName}'");
|
|
return await Task.FromResult(true);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Failed to delete branch '{branchName}': {ex.Message}");
|
|
return await Task.FromResult(false);
|
|
}
|
|
}
|
|
|
|
public async Task<List<string>> GetBranches()
|
|
{
|
|
if (!IsGitRepository)
|
|
return new List<string>();
|
|
|
|
try
|
|
{
|
|
using (var repo = new Repository(_repositoryPath))
|
|
{
|
|
return await Task.FromResult(repo.Branches.Select(b => b.FriendlyName).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
|
|
{
|
|
using (var repo = new Repository(_repositoryPath))
|
|
{
|
|
var status = repo.RetrieveStatus();
|
|
return await Task.FromResult(status.IsDirty);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Failed to check repository status: {ex.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public async Task<string> GetCurrentBranch()
|
|
{
|
|
if (!IsGitRepository)
|
|
return "Not a Git repository";
|
|
|
|
try
|
|
{
|
|
using (var repo = new Repository(_repositoryPath))
|
|
{
|
|
return await Task.FromResult(repo.Head.FriendlyName);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return $"Error: {ex.Message}";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Enhanced Git status information
|
|
public class GitStatusInfo
|
|
{
|
|
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 DateTimeOffset LatestCommitDate { get; set; }
|
|
public List<string> ModifiedFiles { get; set; } = new List<string>();
|
|
public List<string> AddedFiles { get; set; } = new List<string>();
|
|
public List<string> DeletedFiles { get; set; } = new List<string>();
|
|
public List<string> UntrackedFiles { get; set; } = new List<string>();
|
|
public List<string> StagedFiles { get; set; } = new List<string>();
|
|
public string Error { get; set; } = string.Empty;
|
|
}
|
|
|
|
// Enhanced commands for the solution plugin
|
|
public static class GitCommands
|
|
{
|
|
public static List<string> GenerateReviewCommands(GitRefactoringInfo gitInfo)
|
|
{
|
|
var commands = new List<string>();
|
|
|
|
if (gitInfo?.NewBranchName != null)
|
|
{
|
|
commands.Add("# Review the refactoring changes:");
|
|
commands.Add($"git log --oneline -5 # See recent commits");
|
|
commands.Add($"git diff {gitInfo.OriginalBranch}..{gitInfo.NewBranchName} --stat # See file changes summary");
|
|
commands.Add($"git diff {gitInfo.OriginalBranch}..{gitInfo.NewBranchName} # See detailed changes");
|
|
commands.Add("");
|
|
}
|
|
|
|
return commands;
|
|
}
|
|
|
|
public static List<string> GenerateMergeCommands(GitRefactoringInfo gitInfo)
|
|
{
|
|
var commands = new List<string>();
|
|
|
|
if (gitInfo?.NewBranchName != null && gitInfo?.OriginalBranch != null)
|
|
{
|
|
commands.Add("# To merge the refactoring back to main:");
|
|
commands.Add($"git checkout {gitInfo.OriginalBranch}");
|
|
commands.Add($"git merge {gitInfo.NewBranchName}");
|
|
commands.Add($"git branch -d {gitInfo.NewBranchName} # Delete the refactor branch");
|
|
commands.Add("");
|
|
}
|
|
|
|
return commands;
|
|
}
|
|
|
|
public static List<string> GenerateRollbackCommands(GitRefactoringInfo gitInfo)
|
|
{
|
|
var commands = new List<string>();
|
|
|
|
if (gitInfo?.NewBranchName != null && gitInfo?.OriginalBranch != null)
|
|
{
|
|
commands.Add("# To discard all refactoring changes:");
|
|
commands.Add($"git checkout {gitInfo.OriginalBranch}");
|
|
commands.Add($"git branch -D {gitInfo.NewBranchName} # Force delete the refactor branch");
|
|
commands.Add("# Your original code is completely restored!");
|
|
commands.Add("");
|
|
}
|
|
|
|
return commands;
|
|
}
|
|
|
|
public static List<string> GenerateCommitCommands(GitRefactoringInfo gitInfo, List<string> operations)
|
|
{
|
|
var commands = new List<string>();
|
|
|
|
if (gitInfo?.NewBranchName != null)
|
|
{
|
|
var operationsSummary = string.Join(", ", operations);
|
|
commands.Add("# To commit the refactoring changes:");
|
|
commands.Add("git add .");
|
|
commands.Add($"git commit -m \"Automated refactoring: {operationsSummary}\"");
|
|
commands.Add("");
|
|
}
|
|
|
|
return commands;
|
|
}
|
|
}
|
|
} |