mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
chore: add gitutils package to inspect local git repo
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package gitutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GitState contains raw information about the Git repository state.
|
||||
type GitState struct {
|
||||
// IsDirty indicates whether there are uncommitted changes.
|
||||
IsDirty bool
|
||||
// IsRepo indicates whether the directory is a Git repository.
|
||||
IsRepo bool
|
||||
// SHA is the full SHA-1 (40 characters) of the current commit.
|
||||
SHA string
|
||||
// Time is the current commit datetime.
|
||||
Time time.Time
|
||||
}
|
||||
|
||||
// InspectGitState inspects the Git repo state from the specified directory.
|
||||
// If the directory is not a Git repository, returns GitState with IsRepo=false.
|
||||
func InspectGitState(dir string) (GitState, error) {
|
||||
state := GitState{
|
||||
IsRepo: isGitRepo(dir),
|
||||
}
|
||||
|
||||
if !state.IsRepo {
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// Get the current commit SHA.
|
||||
sha, err := gitCommand(dir, "rev-parse", "HEAD")
|
||||
if err != nil {
|
||||
return state, fmt.Errorf("get current commit SHA: %w", err)
|
||||
}
|
||||
state.SHA = strings.TrimSpace(sha)
|
||||
|
||||
// Get the current commit timestamp.
|
||||
timestamp, err := gitCommand(dir, "log", "-1", "--format=%ct")
|
||||
if err != nil {
|
||||
return state, fmt.Errorf("get current commit timestamp: %w", err)
|
||||
}
|
||||
seconds, err := strconv.ParseInt(strings.TrimSpace(timestamp), 10, 64)
|
||||
if err != nil {
|
||||
return state, fmt.Errorf("parse current commit timestamp: %w", err)
|
||||
}
|
||||
state.Time = time.Unix(seconds, 0)
|
||||
|
||||
// Check for uncommitted changes.
|
||||
status, err := gitCommand(dir, "status", "--porcelain")
|
||||
if err != nil {
|
||||
return state, fmt.Errorf("check git status: %w", err)
|
||||
}
|
||||
state.IsDirty = strings.TrimSpace(status) != ""
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// isGitRepo checks if the directory is a Git repository.
|
||||
func isGitRepo(dir string) bool {
|
||||
_, err := gitCommand(dir, "rev-parse", "--git-dir")
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// gitCommand runs a git command in the specified directory.
|
||||
func gitCommand(dir string, args ...string) (string, error) {
|
||||
cmd := exec.Command("git", args...)
|
||||
cmd.Dir = dir
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
return "", fmt.Errorf("git command failed: %s", exitErr.Stderr)
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(output), nil
|
||||
}
|
||||
|
||||
// ShortSHA returns a truncated SHA with the specified length.
|
||||
// If length is negative, zero, or greater than the SHA length, it returns the full SHA.
|
||||
// Returns empty string if SHA is empty.
|
||||
func (s *GitState) ShortSHA(length int) string {
|
||||
if length <= 0 || length > len(s.SHA) {
|
||||
length = len(s.SHA)
|
||||
}
|
||||
return s.SHA[:length]
|
||||
}
|
||||
Reference in New Issue
Block a user