namespace marlin.core.functional; using System.Diagnostics; public interface IGitClient { Task> GetRemoteRefs(string remote); } public class GitBinaryClient : IGitClient { public virtual async Task> GetRemoteRefs(string remote) { var psi = this.CreateProcess(remote); var proc = Process.Start(psi)!; string stdout = await proc.StandardOutput.ReadToEndAsync(); await proc.WaitForExitAsync(); return ParseOutput(stdout); } private Dictionary ParseOutput(string stdout) { return stdout .Split("\n", StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Split('\t')) .ToDictionary(k => k[1], k => k[0]); } protected virtual ProcessStartInfo CreateProcess(string remote) { var psi = new ProcessStartInfo("git", $"ls-remote --heads --tags {remote}") { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true, Environment = { ["GIT_TERMINAL_PROMPT"] = "0" } }; return psi; } /*private async Task SshAuth(string privateKeyPem) { string keyPath = Path.Combine(Path.GetTempPath(), $"key_{Guid.NewGuid():N}"); await File.WriteAllTextAsync(keyPath, privateKeyPem); File.SetUnixFileMode(keyPath, UnixFileMode.UserRead | UnixFileMode.UserWrite); try { psi.Environment["GIT_SSH_COMMAND"] = $"ssh -i {keyPath} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new"; // run ls-remote against the ssh:// or git@ URL } finally { File.Delete(keyPath); } } private async Task BasicAuth(string accessToken) { psi.Environment["GIT_CONFIG_COUNT"] = "1"; psi.Environment["GIT_CONFIG_KEY_0"] = "http.extraheader"; psi.Environment["GIT_CONFIG_VALUE_0"] = $"AUTHORIZATION: basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"x-access-token:{accessToken}"))}"; }*/ }