git

package
v0.23.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 21, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package git discovers local repositories and aggregates git-derived metrics for session analytics.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AuthorEmail

func AuthorEmail(repo string) string

AuthorEmail returns `git config user.email` run from inside the repo, falling back to the global config. Returns "" if neither is set or git is not available.

func CacheKey

func CacheKey(kind, repo, author, since, until string) string

CacheKey returns a hex-encoded sha256 digest of the (kind, repo, author, since, until) tuple. Fields are encoded as JSON before hashing so any field can contain arbitrary bytes (including '|', tabs, or newlines) without colliding with another tuple. Any change to any field produces a different key.

func DiscoverRepos

func DiscoverRepos(cwds []string) []string

DiscoverRepos resolves each cwd to its enclosing git repository toplevel and returns the deduplicated list. Cwds with no enclosing repo (or whose resolution fails) are silently dropped. Order follows first-seen order in the input.

Resolution prefers `git rev-parse --show-toplevel`, which handles standard `.git` directories, linked worktrees (`.git` is a file pointing at the shared gitdir), and submodules. When the cwd no longer exists on disk, the helper falls back to walking upward from the nearest existing ancestor and invoking `git rev-parse` from there — that mirrors how the parser package recovers repo roots for archived sessions whose cwd has been deleted.

Types

type Cache

type Cache struct {
	// contains filtered or unexported fields
}

Cache is a small TTL-backed key-value store for git aggregation results.

Reads and writes go through the provided *sql.DB. The caller is expected to have created the `git_cache` table (see internal/db/schema.sql) before using the cache; Cache itself never issues DDL.

func NewCache

func NewCache(db *sql.DB) *Cache

NewCache wraps db as a git TTL cache. db must be a handle on a SQLite database that already contains the `git_cache` table.

func (*Cache) GetOrCompute

func (c *Cache) GetOrCompute(
	ctx context.Context,
	key, kind string,
	ttl time.Duration,
	compute func() ([]byte, error),
) ([]byte, error)

GetOrCompute returns the cached payload for key when present and within ttl. On miss or stale entry, compute is invoked and its result is stored with INSERT OR REPLACE. compute is called at most once per invocation, and only on miss. Errors from compute propagate unchanged and do NOT write a cache row.

kind is persisted alongside the payload as a debugging aid; it is not used for lookup (the key already encodes kind).

type LogResult

type LogResult struct {
	Commits      int
	LOCAdded     int
	LOCRemoved   int
	FilesChanged int
}

LogResult aggregates author-filtered counts from `git log --numstat` output.

func AggregateLog

func AggregateLog(
	ctx context.Context, repo, authorEmail, since, until string,
) (LogResult, error)

AggregateLog runs `git log --numstat` filtered by author and window and returns total commits, lines added, lines removed, and files changed.

The since/until timestamps should be RFC3339 strings; git accepts them directly via `--since`/`--until`. LOC counts from binary files (which numstat represents as `-\t-\t<path>`) are skipped, but the file still counts toward FilesChanged.

If the window is empty or the author matches nothing, a zero-valued LogResult is returned with no error. Exec failures (bad repo path, git missing from PATH) are surfaced as errors.

func AggregateLogCached

func AggregateLogCached(
	ctx context.Context,
	cache *Cache,
	repo, author, since, until string,
	ttl time.Duration,
) (LogResult, error)

AggregateLogCached wraps AggregateLog with a TTL-bounded read-through cache. The cache key is derived from ("log", repo, author, since, until). On a cache miss, AggregateLog is invoked; its LogResult is JSON-encoded before being stored. Errors from AggregateLog propagate unchanged.

type PRResult

type PRResult struct {
	Opened int
	Merged int
}

PRResult holds pull-request counts for a window. Opened counts PRs created in [since, until]; Merged counts PRs merged in [since, until] regardless of when they were created.

func AggregatePRs

func AggregatePRs(
	ctx context.Context, repo, since, until, ghToken string,
) (*PRResult, error)

AggregatePRs queries the `gh` CLI twice per repo — once for PRs created in the window, once for PRs merged in the window — and returns the counts.

since/until are formatted into gh's `--search=created:SINCE..UNTIL` (and `merged:...`) range expressions. GitHub search treats `>=A..B` as malformed — the colon-and-double-dot range syntax already implies an inclusive closed window, so the bounds must be plain dates or RFC3339 timestamps. The repo argument sets the working directory for `gh` so it picks up the correct remote.

When ghToken is empty this returns (nil, nil): the caller distinguishes "unknown — gh not configured" from a legitimate zero count. GH_TOKEN is injected via the exec environment so it never appears in argv or logs.

Any failure to invoke `gh` or parse its output is surfaced as an error; callers should log and continue rather than fail the whole aggregation.

func AggregatePRsCached

func AggregatePRsCached(
	ctx context.Context,
	cache *Cache,
	repo, since, until, ghToken string,
	ttl time.Duration,
) (*PRResult, error)

AggregatePRsCached wraps AggregatePRs with a TTL-bounded cache.

`--author=@me` resolves against the GitHub identity behind ghToken, so the token effectively partitions the result set. To prevent one account's PR counts from leaking into another's cache (after `gh auth switch` or a token swap), the cache key includes a SHA-256 digest of the token. The token itself never lands on disk — only its digest appears in the key, which is itself hashed again by CacheKey.

When ghToken == "", AggregatePRs returns (nil, nil) and this wrapper mirrors that behavior without touching the cache — a nil PRResult is ambiguous ("gh unavailable") and we don't want to memoize it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL