Files
beads/cmd/bd/dolt_autocommit.go
Steve Yegge ab61b0956b feat(dolt): auto-commit write commands and set explicit commit authors (#1270)
Adds Dolt auto-commit functionality for write commands and sets explicit commit authors.

Includes fix for race condition in commandDidWrite (converted to atomic.Bool).

Original PR: #1267 by @coffeegoddd
Co-authored-by: Dustin Brown <dustin@dolthub.com>
2026-01-22 20:52:20 -08:00

104 lines
2.3 KiB
Go

package main
import (
"context"
"fmt"
"slices"
"strings"
"github.com/steveyegge/beads/internal/storage"
)
type doltAutoCommitParams struct {
// Command is the top-level bd command name (e.g., "create", "update").
Command string
// IssueIDs are the primary issue IDs affected by the command (optional).
IssueIDs []string
// MessageOverride, if non-empty, is used verbatim.
MessageOverride string
}
// maybeAutoCommit creates a Dolt commit after a successful write command when enabled.
//
// Semantics:
// - Only applies when dolt auto-commit is enabled (on) AND the active store is versioned (Dolt).
// - Uses Dolt's "commit all" behavior under the hood (DOLT_COMMIT -Am).
// - Treats "nothing to commit" as a no-op.
func maybeAutoCommit(ctx context.Context, p doltAutoCommitParams) error {
mode, err := getDoltAutoCommitMode()
if err != nil {
return err
}
if mode != doltAutoCommitOn {
return nil
}
st := getStore()
vs, ok := storage.AsVersioned(st)
if !ok {
return nil
}
msg := p.MessageOverride
if strings.TrimSpace(msg) == "" {
msg = formatDoltAutoCommitMessage(p.Command, getActor(), p.IssueIDs)
}
if err := vs.Commit(ctx, msg); err != nil {
if isDoltNothingToCommit(err) {
return nil
}
return err
}
return nil
}
func isDoltNothingToCommit(err error) bool {
if err == nil {
return false
}
s := strings.ToLower(err.Error())
// Dolt commonly reports "nothing to commit".
if strings.Contains(s, "nothing to commit") {
return true
}
// Some versions/paths may report "no changes".
if strings.Contains(s, "no changes") && strings.Contains(s, "commit") {
return true
}
return false
}
func formatDoltAutoCommitMessage(cmd string, actor string, issueIDs []string) string {
cmd = strings.TrimSpace(cmd)
if cmd == "" {
cmd = "write"
}
actor = strings.TrimSpace(actor)
if actor == "" {
actor = "unknown"
}
ids := make([]string, 0, len(issueIDs))
seen := make(map[string]bool, len(issueIDs))
for _, id := range issueIDs {
id = strings.TrimSpace(id)
if id == "" || seen[id] {
continue
}
seen[id] = true
ids = append(ids, id)
}
slices.Sort(ids)
const maxIDs = 5
if len(ids) > maxIDs {
ids = ids[:maxIDs]
}
if len(ids) == 0 {
return fmt.Sprintf("bd: %s (auto-commit) by %s", cmd, actor)
}
return fmt.Sprintf("bd: %s (auto-commit) by %s [%s]", cmd, actor, strings.Join(ids, ", "))
}