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>
This commit is contained in:
103
cmd/bd/dolt_autocommit.go
Normal file
103
cmd/bd/dolt_autocommit.go
Normal file
@@ -0,0 +1,103 @@
|
||||
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, ", "))
|
||||
}
|
||||
Reference in New Issue
Block a user