187 lines
7.3 KiB
C#
Executable File
187 lines
7.3 KiB
C#
Executable File
using MarketAlly.AIPlugin;
|
|
using LibGit2Sharp;
|
|
using System.Text.Json;
|
|
|
|
namespace MarketAlly.AIPlugin.Refactoring.Plugins;
|
|
|
|
[AIPlugin("git-branches", "List and analyze branches in a Git repository")]
|
|
public class GitBranchesPlugin : IAIPlugin
|
|
{
|
|
[AIParameter("Local repository path to analyze branches", required: true)]
|
|
public string RepositoryPath { get; set; } = string.Empty;
|
|
|
|
[AIParameter("Include remote branches in the listing", required: false)]
|
|
public bool IncludeRemote { get; set; } = true;
|
|
|
|
[AIParameter("Include detailed branch information (commits, dates)", required: false)]
|
|
public bool IncludeDetails { get; set; } = true;
|
|
|
|
public IReadOnlyDictionary<string, Type> SupportedParameters => new Dictionary<string, Type>
|
|
{
|
|
["repositoryPath"] = typeof(string),
|
|
["repositorypath"] = typeof(string),
|
|
["includeRemote"] = typeof(bool),
|
|
["includeremote"] = typeof(bool),
|
|
["includeDetails"] = typeof(bool),
|
|
["includedetails"] = typeof(bool)
|
|
};
|
|
|
|
public async Task<AIPluginResult> ExecuteAsync(IReadOnlyDictionary<string, object> parameters)
|
|
{
|
|
try
|
|
{
|
|
// Extract parameters
|
|
var repositoryPath = (parameters.ContainsKey("repositoryPath") ? parameters["repositoryPath"] :
|
|
parameters.ContainsKey("repositorypath") ? parameters["repositorypath"] : null)?.ToString();
|
|
var includeRemote = parameters.ContainsKey("includeRemote") ? Convert.ToBoolean(parameters["includeRemote"]) :
|
|
parameters.ContainsKey("includeremote") ? Convert.ToBoolean(parameters["includeremote"]) : true;
|
|
var includeDetails = parameters.ContainsKey("includeDetails") ? Convert.ToBoolean(parameters["includeDetails"]) :
|
|
parameters.ContainsKey("includedetails") ? Convert.ToBoolean(parameters["includedetails"]) : true;
|
|
|
|
// Validate repository path
|
|
if (string.IsNullOrEmpty(repositoryPath) || !Directory.Exists(repositoryPath))
|
|
{
|
|
return new AIPluginResult(new ArgumentException("Invalid repository path"), "Repository path does not exist");
|
|
}
|
|
|
|
// Check if it's a Git repository
|
|
if (!Directory.Exists(Path.Combine(repositoryPath, ".git")))
|
|
{
|
|
return new AIPluginResult(new ArgumentException("Not a Git repository"), "Directory is not a Git repository");
|
|
}
|
|
|
|
var result = await GetBranchesAsync(repositoryPath, includeRemote, includeDetails);
|
|
return new AIPluginResult(result, "Branches retrieved successfully");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Provide specific error messages based on exception type
|
|
if (ex.InnerException is RepositoryNotFoundException || ex is RepositoryNotFoundException)
|
|
{
|
|
return new AIPluginResult(ex, "Repository not found or corrupted. The directory exists but is not a valid Git repository.");
|
|
}
|
|
else if (ex.Message.Contains("corrupt") || ex.Message.Contains("invalid"))
|
|
{
|
|
return new AIPluginResult(ex, "Git repository is corrupted or invalid. Repository reset required.");
|
|
}
|
|
else if (ex.Message.Contains("access") || ex.Message.Contains("permission"))
|
|
{
|
|
return new AIPluginResult(ex, "Repository access denied. Check permissions.");
|
|
}
|
|
else
|
|
{
|
|
return new AIPluginResult(ex, $"Failed to retrieve branches: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task<GitBranchesResult> GetBranchesAsync(string repositoryPath, bool includeRemote, bool includeDetails)
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
using var repo = new Repository(repositoryPath);
|
|
|
|
var result = new GitBranchesResult
|
|
{
|
|
RepositoryPath = repositoryPath,
|
|
CurrentBranch = repo.Head.FriendlyName,
|
|
Branches = new List<GitBranchInfo>()
|
|
};
|
|
|
|
// Get local branches
|
|
foreach (var branch in repo.Branches.Where(b => !b.IsRemote))
|
|
{
|
|
var branchInfo = CreateBranchInfo(branch, GitBranchType.Local, includeDetails);
|
|
result.Branches.Add(branchInfo);
|
|
}
|
|
|
|
// Get remote branches if requested
|
|
if (includeRemote)
|
|
{
|
|
foreach (var branch in repo.Branches.Where(b => b.IsRemote))
|
|
{
|
|
var branchInfo = CreateBranchInfo(branch, GitBranchType.Remote, includeDetails);
|
|
result.Branches.Add(branchInfo);
|
|
}
|
|
}
|
|
|
|
// Set default branch info
|
|
var defaultBranch = result.Branches.FirstOrDefault(b => b.IsDefault);
|
|
if (defaultBranch != null)
|
|
{
|
|
result.DefaultBranch = defaultBranch.Name;
|
|
}
|
|
|
|
result.TotalBranches = result.Branches.Count;
|
|
result.LocalBranches = result.Branches.Count(b => b.Type == GitBranchType.Local);
|
|
result.RemoteBranches = result.Branches.Count(b => b.Type == GitBranchType.Remote);
|
|
|
|
return result;
|
|
});
|
|
}
|
|
|
|
private GitBranchInfo CreateBranchInfo(Branch branch, GitBranchType type, bool includeDetails)
|
|
{
|
|
var branchInfo = new GitBranchInfo
|
|
{
|
|
Name = branch.FriendlyName,
|
|
Type = type,
|
|
IsDefault = IsDefaultBranch(branch.FriendlyName),
|
|
IsCurrent = branch.IsCurrentRepositoryHead,
|
|
IsActive = !branch.IsRemote && branch.Tip != null
|
|
};
|
|
|
|
if (includeDetails && branch.Tip != null)
|
|
{
|
|
branchInfo.LastCommitHash = branch.Tip.Sha;
|
|
branchInfo.LastCommitMessage = branch.Tip.MessageShort;
|
|
branchInfo.LastCommitAuthor = branch.Tip.Author.Name;
|
|
branchInfo.LastCommitDate = branch.Tip.Author.When.DateTime;
|
|
branchInfo.CommitsAhead = 0; // Would need complex calculation
|
|
branchInfo.CommitsBehind = 0; // Would need complex calculation
|
|
}
|
|
|
|
return branchInfo;
|
|
}
|
|
|
|
private bool IsDefaultBranch(string branchName)
|
|
{
|
|
var defaultBranches = new[] { "main", "master", "develop", "development" };
|
|
return defaultBranches.Contains(branchName.ToLower());
|
|
}
|
|
}
|
|
|
|
|
|
// Data models for Git branches
|
|
public class GitBranchesResult
|
|
{
|
|
public string RepositoryPath { get; set; } = string.Empty;
|
|
public string CurrentBranch { get; set; } = string.Empty;
|
|
public string? DefaultBranch { get; set; }
|
|
public int TotalBranches { get; set; }
|
|
public int LocalBranches { get; set; }
|
|
public int RemoteBranches { get; set; }
|
|
public List<GitBranchInfo> Branches { get; set; } = new();
|
|
}
|
|
|
|
public class GitBranchInfo
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public GitBranchType Type { get; set; }
|
|
public bool IsDefault { get; set; }
|
|
public bool IsCurrent { get; set; }
|
|
public bool IsActive { get; set; }
|
|
public string? LastCommitHash { get; set; }
|
|
public string? LastCommitMessage { get; set; }
|
|
public string? LastCommitAuthor { get; set; }
|
|
public DateTime? LastCommitDate { get; set; }
|
|
public int CommitsAhead { get; set; }
|
|
public int CommitsBehind { get; set; }
|
|
}
|
|
|
|
|
|
public enum GitBranchType
|
|
{
|
|
Local,
|
|
Remote
|
|
} |