chore(claude-do): Worktrees sollten nach dem Task benannt werden

Durch die GUID namen kann ein User die Worktrees keinem Task zuordnen, und in Rider Müllen mir die Worktrees die BRanches voll. Also sollten wir einfach den Task titel oder Nummer stattdessen nehmen

ClaudeDo-Task: 63f08d944d3341c081267158ef4bbb3e
This commit is contained in:
Mika Kuns
2026-09-30 10:49:07 +02:00
parent 0d029717f8
commit 44ec89b0e6
4 changed files with 68 additions and 18 deletions
@@ -65,7 +65,9 @@ public class WorktreeManagerTests : IDisposable
Assert.NotNull(ctx);
Assert.True(Directory.Exists(ctx.WorktreePath));
Assert.Equal($"claudedo/{task.Id.Replace("-", "")}", ctx.BranchName);
// StartsWith: a folder leaked into the shared %TEMP% root by another test forces the id suffix.
Assert.StartsWith($"claudedo/{task.Number}-test-task", ctx.BranchName);
Assert.StartsWith($"{task.Number}-test-task", Path.GetFileName(ctx.WorktreePath));
Assert.Equal(repo.BaseCommit, ctx.BaseCommit);
using var readCtx = db.CreateContext();
@@ -77,6 +79,15 @@ public class WorktreeManagerTests : IDisposable
Assert.Null(row.HeadCommit);
}
[Theory]
[InlineData("Fix: Löschen des Tasks!", "7-fix-lschen-des-tasks")]
[InlineData("äöü", "7")]
[InlineData("a very long title that goes well beyond the forty char cap", "7-a-very-long-title-that-goes-well-beyond")]
public void NameFor_NumberPlusCappedTitleSlug(string title, string expected)
{
Assert.Equal(expected, WorktreeManager.NameFor(new TaskEntity { Id = "x", ListId = "y", Title = title, Number = 7, CreatedAt = DateTime.UtcNow }));
}
[Fact]
public async Task CreateAsync_BroadcastsCreatingWorktreePhase()
{
@@ -107,6 +118,28 @@ public class WorktreeManagerTests : IDisposable
Assert.Equal(WorktreeManager.PhaseCreatingWorktree, (string?)progressCalls[0].Args[1]);
}
[Fact]
public async Task CreateAsync_NameTakenByForeignBranch_FallsBackToIdSuffixAndLeavesBranchIntact()
{
if (!GitAvailable) { Assert.True(true, "git not available -- skipping"); return; }
var repo = CreateRepo();
var (task, list) = MakeEntities(repo.RepoDir);
var (mgr, _) = await CreateManagerAsync(task, list);
// A leftover from an earlier DB whose task happened to get the same number and title.
var foreign = $"claudedo/{WorktreeManager.NameFor(task)}";
GitRepoFixture.RunGit(repo.RepoDir, "branch", foreign, repo.BaseCommit);
var ctx = await mgr.CreateAsync(task, list, CancellationToken.None);
_worktreeCleanups.Add((repo.RepoDir, ctx.WorktreePath));
var suffixed = $"{WorktreeManager.NameFor(task)}-{task.Id.Replace("-", "")[..8]}";
Assert.Equal($"claudedo/{suffixed}", ctx.BranchName);
Assert.Equal(suffixed, Path.GetFileName(ctx.WorktreePath));
Assert.False(string.IsNullOrWhiteSpace(GitRepoFixture.RunGit(repo.RepoDir, "branch", "--list", foreign)));
}
[Fact]
public async Task CreateAsync_SelfHealPath_BroadcastsCreatingWorktreePhaseForEachSection()
{
@@ -122,9 +155,11 @@ public class WorktreeManagerTests : IDisposable
await new TaskRepository(seedCtx).AddAsync(task);
}
// Pre-create the branch so `git worktree add -b` hits the "already exists" self-heal path.
var branchName = $"claudedo/{task.Id.Replace("-", "")}";
// Occupy the plain name (-> id-suffixed fallback) and the fallback too, so
// `git worktree add -b` hits the "already exists" self-heal path.
var branchName = $"claudedo/{WorktreeManager.NameFor(task)}";
GitRepoFixture.RunGit(repo.RepoDir, "branch", branchName, repo.BaseCommit);
GitRepoFixture.RunGit(repo.RepoDir, "branch", $"{branchName}-{task.Id.Replace("-", "")[..8]}", repo.BaseCommit);
var fakeHub = new CapturingHubContext();
var broadcaster = new HubBroadcaster(fakeHub);
@@ -276,13 +311,13 @@ public class WorktreeManagerTests : IDisposable
await Assert.ThrowsAnyAsync<Exception>(
() => mgr.CreateAsync(task, list, CancellationToken.None));
var branchName = $"claudedo/{task.Id.Replace("-", "")}";
var branchName = $"claudedo/{WorktreeManager.NameFor(task)}";
var branchList = GitRepoFixture.RunGit(repo.RepoDir, "branch", "--list", branchName);
Assert.True(string.IsNullOrWhiteSpace(branchList),
$"orphaned branch {branchName} should be cleaned up, got: {branchList}");
var worktreeList = GitRepoFixture.RunGit(repo.RepoDir, "worktree", "list");
Assert.DoesNotContain(task.Id, worktreeList);
Assert.DoesNotContain(WorktreeManager.NameFor(task), worktreeList);
}
[Fact]