feat(agentic): clean up forge branches after publish

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-02 01:59:03 +00:00
parent 1f6e10fd8e
commit 3ef37ff453
4 changed files with 49 additions and 4 deletions

View file

@ -79,6 +79,8 @@ func (s *PrepSubsystem) autoCreatePR(workspaceDir string) {
return
}
s.cleanupForgeBranch(ctx, repoDir, forgeRemote, workspaceStatus.Branch)
if result := ReadStatusResult(workspaceDir); result.OK {
workspaceStatusUpdate, ok := workspaceStatusValue(result)
if !ok {
@ -106,6 +108,21 @@ func (s *PrepSubsystem) buildAutoPRBody(workspaceStatus *WorkspaceStatus, commit
return b.String()
}
// cleanupForgeBranch removes an agent branch from the Forge remote after the PR is published.
//
// s.cleanupForgeBranch(context.Background(), "/workspace/repo", "ssh://git@forge.lthn.ai:2223/core/go-io.git", "agent/fix-tests")
func (s *PrepSubsystem) cleanupForgeBranch(ctx context.Context, repoDir, remote, branch string) bool {
if repoDir == "" || remote == "" || branch == "" {
return false
}
if s == nil || s.ServiceRuntime == nil {
return false
}
result := s.Core().Process().RunIn(ctx, repoDir, "git", "push", remote, "--delete", branch)
return result.OK
}
func truncate(s string, max int) string {
if len(s) <= max {
return s

View file

@ -9,6 +9,7 @@ import (
core "dappco.re/go/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAutopr_AutoCreatePR_Good(t *testing.T) {
@ -21,8 +22,8 @@ func TestAutopr_AutoCreatePR_Bad(t *testing.T) {
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
// No status file → early return (no panic)
@ -83,8 +84,8 @@ func TestAutopr_AutoCreatePR_Ugly(t *testing.T) {
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
// git log origin/dev..HEAD will fail (no origin remote) → early return
@ -92,3 +93,27 @@ func TestAutopr_AutoCreatePR_Ugly(t *testing.T) {
s.autoCreatePR(wsDir)
})
}
func TestAutopr_CleanupForgeBranch_Good_DeletesRemoteBranch(t *testing.T) {
remoteDir := core.JoinPath(t.TempDir(), "remote.git")
require.True(t, testCore.Process().Run(context.Background(), "git", "init", "--bare", remoteDir).OK)
repoDir := core.JoinPath(t.TempDir(), "repo")
require.True(t, testCore.Process().Run(context.Background(), "git", "clone", remoteDir, repoDir).OK)
require.True(t, testCore.Process().RunIn(context.Background(), repoDir, "git", "config", "user.name", "Test").OK)
require.True(t, testCore.Process().RunIn(context.Background(), repoDir, "git", "config", "user.email", "test@example.com").OK)
branch := "agent/fix-branch"
require.True(t, testCore.Process().RunIn(context.Background(), repoDir, "git", "checkout", "-b", branch).OK)
fs.Write(core.JoinPath(repoDir, "README.md"), "# test")
require.True(t, testCore.Process().RunIn(context.Background(), repoDir, "git", "add", ".").OK)
require.True(t, testCore.Process().RunIn(context.Background(), repoDir, "git", "commit", "-m", "init").OK)
require.True(t, testCore.Process().RunIn(context.Background(), repoDir, "git", "push", "-u", "origin", branch).OK)
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{})}
assert.True(t, s.cleanupForgeBranch(context.Background(), repoDir, remoteDir, branch))
remoteHeads := testCore.Process().RunIn(context.Background(), repoDir, "git", "ls-remote", "--heads", remoteDir, branch)
require.True(t, remoteHeads.OK)
assert.NotContains(t, remoteHeads.Value.(string), branch)
}

View file

@ -147,6 +147,7 @@ func (s *PrepSubsystem) createPR(ctx context.Context, _ *mcp.CallToolRequest, in
workspaceStatus.PRURL = pullRequestURL
writeStatusResult(workspaceDir, workspaceStatus)
s.cleanupForgeBranch(ctx, repoDir, forgeRemote, workspaceStatus.Branch)
if workspaceStatus.Issue > 0 {
comment := core.Sprintf("Pull request created: %s", pullRequestURL)

View file

@ -96,6 +96,8 @@ func (s *PrepSubsystem) attemptVerifyAndMerge(repoDir, org, repo, branch string,
comment := core.Sprintf("## Auto-Verified & Merged\n\n**Tests:** `%s` — PASS\n\nAuto-merged by core-agent dispatch system.", testResult.testCmd)
s.commentOnIssue(context.Background(), org, repo, pullRequestNumber, comment)
forgeRemote := core.Sprintf("ssh://git@forge.lthn.ai:2223/%s/%s.git", org, repo)
s.cleanupForgeBranch(ctx, repoDir, forgeRemote, branch)
return mergeSuccess
}