grokkit/internal/git/git.go
Greg Gauthier ce5367c3a7
Some checks failed
CI / Test (push) Failing after 27s
CI / Lint (push) Has been skipped
CI / Build (push) Has been skipped
feat(cmd): add changelog command for AI-generated release notes
- Implement `grokkit changelog` command with flags for version, since, stdout, and commit reminder
- Add git helpers for latest/previous tags and formatted log since ref
- Include tests for message building and full changelog construction
2026-03-03 21:59:09 +00:00

61 lines
1.5 KiB
Go

package git
import (
"fmt"
"os/exec"
"strings"
"gmgauthier.com/grokkit/internal/logger"
)
func Run(args []string) (string, error) {
cmdStr := "git " + strings.Join(args, " ")
logger.Debug("executing git command", "command", cmdStr, "args", args)
out, err := exec.Command("git", args...).Output()
if err != nil {
logger.Error("git command failed",
"command", cmdStr,
"error", err)
return "", fmt.Errorf("git command failed: %w", err)
}
outputLen := len(out)
logger.Debug("git command completed",
"command", cmdStr,
"output_length", outputLen)
return string(out), nil
}
func IsRepo() bool {
logger.Debug("checking if directory is a git repository")
_, err := exec.Command("git", "rev-parse", "--is-inside-work-tree").Output()
isRepo := err == nil
logger.Debug("git repository check completed", "is_repo", isRepo)
return isRepo
}
func LatestTag() (string, error) {
out, err := Run([]string{"describe", "--tags", "--abbrev=0"})
if err != nil {
return "", err
}
return strings.TrimSpace(out), nil
}
// PreviousTag returns the tag immediately before the given one.
func PreviousTag(current string) (string, error) {
out, err := Run([]string{"describe", "--tags", "--abbrev=0", current + "^"})
if err != nil {
return "", err
}
return strings.TrimSpace(out), nil
}
// LogSince returns formatted commit log since the given ref (exactly matches the todo spec).
func LogSince(since string) (string, error) {
args := []string{"log", "--pretty=format:%s%n%b%n---", since + "..HEAD"}
return Run(args)
}