mirror of
https://github.com/Theodor-Springmann-Stiftung/hamann-ausgabe-core.git
synced 2025-10-28 16:55:32 +00:00
172 lines
6.9 KiB
C#
172 lines
6.9 KiB
C#
namespace HaWeb.FileHelpers;
|
|
using LibGit2Sharp;
|
|
using HaWeb.Models;
|
|
|
|
public class GitService : IGitService {
|
|
private readonly string _repositoryPath;
|
|
private readonly string _remoteName;
|
|
private readonly string _branch;
|
|
private readonly string _url;
|
|
private readonly ILogger<GitService>? _logger;
|
|
|
|
public GitService(IConfiguration config, ILogger<GitService>? logger = null) {
|
|
_logger = logger;
|
|
_remoteName = "origin";
|
|
_branch = config.GetValue<string>("RepositoryBranch") ?? "main";
|
|
_url = config.GetValue<string>("RepositoryURL") ?? string.Empty;
|
|
|
|
var fileStoragePath = config.GetValue<string>("FileStoragePath") ?? throw new ArgumentException("FileStoragePath not configured");
|
|
_repositoryPath = Path.Combine(fileStoragePath, "GIT");
|
|
|
|
// Ensure repository exists
|
|
if (!Repository.IsValid(_repositoryPath)) {
|
|
_logger?.LogWarning("Repository not found at {Path}, attempting to initialize/clone", _repositoryPath);
|
|
InitializeRepository();
|
|
}
|
|
}
|
|
|
|
public GitState? GetGitState() {
|
|
try {
|
|
using var repo = new Repository(_repositoryPath);
|
|
var headCommit = repo.Head.Tip;
|
|
|
|
if (headCommit == null) {
|
|
_logger?.LogWarning("No commits found in repository");
|
|
return null;
|
|
}
|
|
|
|
return new GitState {
|
|
Commit = headCommit.Sha,
|
|
Branch = repo.Head.FriendlyName,
|
|
URL = _url,
|
|
PullTime = headCommit.Author.When.ToLocalTime().DateTime
|
|
};
|
|
}
|
|
catch (Exception ex) {
|
|
_logger?.LogError(ex, "Failed to get Git state");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public bool Pull() {
|
|
try {
|
|
using var repo = new Repository(_repositoryPath);
|
|
var oldCommitSha = repo.Head.Tip?.Sha;
|
|
|
|
// Configure pull options
|
|
var options = new PullOptions {
|
|
FetchOptions = new FetchOptions {
|
|
CredentialsProvider = (_url, _user, _cred) => GetCredentials()
|
|
}
|
|
};
|
|
|
|
// Create signature for merge commit (if needed)
|
|
var signature = new Signature(
|
|
new Identity("HaWeb Service", "hawebservice@localhost"),
|
|
DateTimeOffset.Now
|
|
);
|
|
|
|
// Perform pull
|
|
var result = Commands.Pull(repo, signature, options);
|
|
|
|
var newCommitSha = repo.Head.Tip?.Sha;
|
|
var hasChanges = oldCommitSha != newCommitSha;
|
|
|
|
if (hasChanges) {
|
|
_logger?.LogInformation("Pull successful: {OldCommit} -> {NewCommit}",
|
|
oldCommitSha?[..7], newCommitSha?[..7]);
|
|
} else {
|
|
_logger?.LogInformation("Pull completed but no new changes");
|
|
}
|
|
|
|
return hasChanges;
|
|
}
|
|
catch (Exception ex) {
|
|
_logger?.LogError(ex, "Failed to pull from remote repository");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public bool HasChanged(string? previousCommitSha) {
|
|
if (string.IsNullOrEmpty(previousCommitSha)) {
|
|
return true;
|
|
}
|
|
|
|
var currentState = GetGitState();
|
|
return currentState != null && currentState.Commit != previousCommitSha;
|
|
}
|
|
|
|
private void InitializeRepository() {
|
|
try {
|
|
if (!Directory.Exists(_repositoryPath)) {
|
|
Directory.CreateDirectory(_repositoryPath);
|
|
}
|
|
|
|
// If there's a .git directory but it's invalid, try to reinitialize
|
|
var gitDir = Path.Combine(_repositoryPath, ".git");
|
|
if (Directory.Exists(gitDir)) {
|
|
_logger?.LogWarning("Invalid .git directory found, attempting to use existing repository");
|
|
return;
|
|
}
|
|
|
|
// If URL is provided, clone; otherwise just initialize
|
|
if (!string.IsNullOrEmpty(_url)) {
|
|
_logger?.LogInformation("Cloning repository from {Url} to {Path}", _url, _repositoryPath);
|
|
var cloneOptions = new CloneOptions();
|
|
cloneOptions.FetchOptions.CredentialsProvider = (_url, _user, _cred) => GetCredentials();
|
|
|
|
// Clone with default branch, then checkout the specified branch if different
|
|
Repository.Clone(_url, _repositoryPath, cloneOptions);
|
|
_logger?.LogInformation("Repository cloned successfully");
|
|
|
|
// Checkout the specified branch if it's not the default
|
|
using var repo = new Repository(_repositoryPath);
|
|
|
|
// Log diagnostic information
|
|
_logger?.LogInformation("HEAD: {Head}, IsDetached: {IsDetached}, Tip: {Tip}",
|
|
repo.Head?.FriendlyName ?? "null",
|
|
repo.Head?.IsRemote.ToString() ?? "null",
|
|
repo.Head?.Tip?.Sha.Substring(0, 7) ?? "null");
|
|
|
|
_logger?.LogInformation("Available branches: {Branches}",
|
|
string.Join(", ", repo.Branches.Select(b => $"{b.FriendlyName} (Remote: {b.IsRemote})")));
|
|
|
|
var branch = repo.Branches[_branch] ?? repo.Branches[$"origin/{_branch}"];
|
|
|
|
if (branch == null) {
|
|
_logger?.LogWarning("Branch {Branch} not found. Attempting to create local tracking branch from origin/{Branch}", _branch, _branch);
|
|
var remoteBranch = repo.Branches[$"origin/{_branch}"];
|
|
if (remoteBranch != null) {
|
|
branch = repo.CreateBranch(_branch, remoteBranch.Tip);
|
|
repo.Branches.Update(branch, b => b.TrackedBranch = remoteBranch.CanonicalName);
|
|
_logger?.LogInformation("Created local tracking branch {Branch}", _branch);
|
|
}
|
|
}
|
|
|
|
if (branch != null && branch.FriendlyName != repo.Head.FriendlyName) {
|
|
Commands.Checkout(repo, branch);
|
|
_logger?.LogInformation("Checked out branch {Branch}", _branch);
|
|
} else if (branch != null) {
|
|
_logger?.LogInformation("Already on branch {Branch}", _branch);
|
|
} else {
|
|
_logger?.LogError("Could not find or create branch {Branch}", _branch);
|
|
}
|
|
}
|
|
else {
|
|
_logger?.LogInformation("Initializing empty repository at {Path}", _repositoryPath);
|
|
Repository.Init(_repositoryPath);
|
|
}
|
|
}
|
|
catch (Exception ex) {
|
|
_logger?.LogError(ex, "Failed to initialize repository");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
private Credentials? GetCredentials() {
|
|
// For now, use default credentials (SSH agent, credential manager, etc.)
|
|
// Can be extended to support username/password or personal access tokens
|
|
// from configuration if needed
|
|
return new DefaultCredentials();
|
|
}
|
|
} |