feat(worker): detect company repos by origin remote pattern

This commit is contained in:
mika kuns
2026-10-01 10:28:54 +02:00
parent db3c7e69e5
commit faa91e0661
4 changed files with 61 additions and 0 deletions
+7
View File
@@ -414,6 +414,13 @@ public sealed class GitService
.ToList();
}
/// <summary>URL des Remotes <paramref name="remote"/>, oder null wenn es keins gibt.</summary>
public async Task<string?> GetRemoteUrlAsync(string repoDir, string remote = "origin", CancellationToken ct = default)
{
var (exitCode, stdout, _) = await RunGitAsync(repoDir, ["remote", "get-url", remote], ct);
return exitCode == 0 && !string.IsNullOrWhiteSpace(stdout) ? stdout.Trim() : null;
}
public async Task<bool> IsMidMergeAsync(string repoDir, CancellationToken ct = default)
{
var (exitCode, stdout, _) = await RunGitAsync(repoDir, ["rev-parse", "--git-dir"], ct);
@@ -70,6 +70,10 @@ public sealed class WorkerConfig
[JsonPropertyName("ticket_api_base_url")]
public string? TicketApiBaseUrl { get; set; }
/// <summary>Teilstring der <c>origin</c>-URL, an dem ein Firmen-Repo erkannt wird. Nur per Hand editierbar.</summary>
[JsonPropertyName("company_remote_pattern")]
public string CompanyRemotePattern { get; set; } = "/_git/";
public static string DefaultConfigPath =>
Path.Combine(Paths.AppDataRoot(), "worker.config.json");
+16
View File
@@ -0,0 +1,16 @@
using ClaudeDo.Data.Git;
namespace ClaudeDo.Worker.Git;
/// <summary>Erkennt Firmen-Repos am <c>origin</c>-Remote; das Muster kommt aus <c>WorkerConfig.CompanyRemotePattern</c>.</summary>
public static class CompanyRepo
{
/// <summary>True wenn <paramref name="remoteUrl"/> das (nicht-leere) Muster enthält, ohne Groß-/Kleinschreibung.</summary>
public static bool Matches(string? remoteUrl, string? pattern) =>
!string.IsNullOrWhiteSpace(remoteUrl) && !string.IsNullOrWhiteSpace(pattern)
&& remoteUrl.Contains(pattern, StringComparison.OrdinalIgnoreCase);
/// <summary>Liest <c>origin</c> live (kein Cache — ein Remote kann sich jederzeit ändern).</summary>
public static async Task<bool> IsCompanyAsync(GitService git, string workingDir, string? pattern, CancellationToken ct) =>
Matches(await git.GetRemoteUrlAsync(workingDir, "origin", ct), pattern);
}
@@ -0,0 +1,34 @@
using ClaudeDo.Data.Git;
using ClaudeDo.Worker.Git;
using ClaudeDo.Worker.Tests.Infrastructure;
namespace ClaudeDo.Worker.Tests.Git;
public sealed class CompanyRepoTests : IDisposable
{
private readonly GitRepoFixture _repo = new();
public void Dispose() => _repo.Dispose();
[Theory]
[InlineData("https://srv.local/Coll/Proj/_git/Repo", "/_git/", true)]
[InlineData("https://mika@srv.local/tfs/Coll/Proj/_git/Mein%20Repo.git", "/_git/", true)]
[InlineData("ssh://git@git.kuns.dev:22222/kuns/ClaudeDo.git", "/_git/", false)]
[InlineData(null, "/_git/", false)]
[InlineData("https://srv.local/Coll/Proj/_git/Repo", "", false)]
[InlineData("https://GITHUB.com/acme/repo.git", "github.com/acme", true)]
public void Matches(string? url, string pattern, bool expected)
=> Assert.Equal(expected, CompanyRepo.Matches(url, pattern));
[Fact]
public async Task IsCompanyAsync_reads_origin()
{
if (!GitRepoFixture.IsGitAvailable()) return;
var git = new GitService();
Assert.False(await CompanyRepo.IsCompanyAsync(git, _repo.RepoDir, "/_git/", CancellationToken.None));
GitRepoFixture.RunGit(_repo.RepoDir, "remote", "add", "origin", "https://srv.local/Coll/Proj/_git/Repo");
Assert.True(await CompanyRepo.IsCompanyAsync(git, _repo.RepoDir, "/_git/", CancellationToken.None));
Assert.Equal("https://srv.local/Coll/Proj/_git/Repo", await git.GetRemoteUrlAsync(_repo.RepoDir));
}
}