Initial commit on Forgejo
Some checks failed
CI and releases / Test and vet (push) Failing after 1s
CI and releases / Build release binaries (push) Has been skipped
CI and releases / Publish GitHub release (push) Has been skipped

Fresh repository history for elektrine/tarakan-client hosted at
https://git.elektrine.com/elektrine/tarakan-client.
This commit is contained in:
Maxfield Luke 2026-07-29 04:56:36 -04:00
commit 58b29a7f84
70 changed files with 12994 additions and 0 deletions

240
internal/context/context.go Normal file
View file

@ -0,0 +1,240 @@
package repoctx
import (
"net/url"
"os"
"os/exec"
"path/filepath"
"strings"
)
// Info is the repository context attached to an agent session.
type Info struct {
Root string `json:"root"`
Name string `json:"name"`
Branch string `json:"branch,omitempty"`
Commit string `json:"commit,omitempty"`
CommitSHA string `json:"commit_sha,omitempty"`
IsGit bool `json:"is_git"`
Dirty bool `json:"dirty"`
Origin string `json:"origin,omitempty"`
// Remote identity (any supported host).
Host string `json:"host,omitempty"` // e.g. github.com, tarakan.lol
Owner string `json:"owner,omitempty"` // remote owner / handle
Repo string `json:"repo,omitempty"` // remote repository name
// GitHubOwner/GitHubName are kept for older call sites; set when Host is GitHub,
// and also mirrored from Owner/Repo for convenience when matching jobs.
GitHubOwner string `json:"github_owner,omitempty"`
GitHubName string `json:"github_name,omitempty"`
}
// Discover finds the Git repository containing path. Outside a Git repository,
// it still returns useful directory context.
func Discover(path string) Info {
absolute, err := filepath.Abs(path)
if err != nil {
absolute = path
}
info := Info{
Root: absolute,
Name: filepath.Base(absolute),
}
if root, ok := gitOutput(absolute, "rev-parse", "--show-toplevel"); ok {
info.Root = root
info.Name = filepath.Base(root)
info.IsGit = true
info.Branch, _ = gitOutput(root, "branch", "--show-current")
info.Commit, _ = gitOutput(root, "rev-parse", "--short", "HEAD")
info.CommitSHA, _ = gitOutput(root, "rev-parse", "HEAD")
if status, found := gitOutput(root, "status", "--porcelain", "--untracked-files=normal"); found {
info.Dirty = status != ""
}
if origin, found := gitOutput(root, "remote", "get-url", "origin"); found {
if host, owner, repo, ok := ParseRemote(origin); ok {
info.Host = host
info.Owner = owner
info.Repo = repo
info.Origin = redactRemote(origin)
if isGitHubHost(host) {
info.GitHubOwner = owner
info.GitHubName = repo
info.Origin = "https://github.com/" + owner + "/" + repo + ".git"
}
} else {
info.Origin = redactRemote(origin)
}
}
}
return info
}
func redactRemote(remote string) string {
parsed, err := url.Parse(remote)
if err != nil || parsed.Scheme == "" {
if separator := strings.IndexByte(remote, ':'); separator >= 0 {
host := remote[:separator]
if at := strings.LastIndexByte(host, '@'); at >= 0 {
host = host[at+1:]
}
return host + ":" + remote[separator+1:]
}
return ""
}
parsed.User = nil
parsed.RawQuery = ""
parsed.Fragment = ""
return parsed.String()
}
// GitHubRepository returns origin's owner/name pair when origin points to
// GitHub. The second result is false for non-GitHub or malformed remotes.
func (i Info) GitHubRepository() (string, bool) {
if i.GitHubOwner == "" || i.GitHubName == "" {
return "", false
}
return i.GitHubOwner + "/" + i.GitHubName, true
}
// RemoteSlug is host-less owner/name when known.
func (i Info) RemoteSlug() (owner, name string, ok bool) {
if i.Owner != "" && i.Repo != "" {
return i.Owner, i.Repo, true
}
if i.GitHubOwner != "" && i.GitHubName != "" {
return i.GitHubOwner, i.GitHubName, true
}
return "", "", false
}
// ParseGitHubRemote accepts GitHub HTTPS, SSH URL, and SCP-like remote forms.
func ParseGitHubRemote(remote string) (owner, name string, ok bool) {
host, owner, name, ok := ParseRemote(remote)
if !ok || !isGitHubHost(host) {
return "", "", false
}
return owner, name, true
}
// ParseRemote extracts host, owner, and repo from common git remote URLs
// (HTTPS, SSH, SCP-like) for GitHub, Tarakan-hosted, and similar forges.
func ParseRemote(remote string) (host, owner, name string, ok bool) {
remote = strings.TrimSpace(remote)
if remote == "" {
return "", "", "", false
}
// SCP-like: git@github.com:owner/repo.git or git@tarakan.lol:owner/repo.git
if !strings.Contains(remote, "://") {
if separator := strings.IndexByte(remote, ':'); separator >= 0 {
hostPart := remote[:separator]
if at := strings.LastIndexByte(hostPart, '@'); at >= 0 {
hostPart = hostPart[at+1:]
}
owner, name, pathOK := parseOwnerRepoPath(remote[separator+1:])
if !pathOK || !supportedHost(hostPart) {
return "", "", "", false
}
return normalizeHost(hostPart), owner, name, true
}
return "", "", "", false
}
parsed, err := url.Parse(remote)
if err != nil || !remoteScheme(parsed.Scheme) {
return "", "", "", false
}
hostPart := parsed.Hostname()
if !supportedHost(hostPart) {
return "", "", "", false
}
owner, name, pathOK := parseOwnerRepoPath(parsed.Path)
if !pathOK {
return "", "", "", false
}
return normalizeHost(hostPart), owner, name, true
}
func remoteScheme(scheme string) bool {
switch strings.ToLower(scheme) {
case "http", "https", "ssh", "git":
return true
default:
return false
}
}
func supportedHost(host string) bool {
host = strings.ToLower(strings.TrimSpace(host))
if host == "" {
return false
}
// Explicit forges + loopback (local Tarakan-hosted clones).
if isGitHubHost(host) || isTarakanHost(host) || isLoopbackHost(host) {
return true
}
// Generic host.tld/owner/repo for future forges.
return strings.Contains(host, ".")
}
func isGitHubHost(host string) bool {
h := strings.ToLower(host)
return h == "github.com" || h == "www.github.com"
}
func isTarakanHost(host string) bool {
h := strings.ToLower(host)
return h == "tarakan.lol" || h == "www.tarakan.lol" || h == "tarakan"
}
func isLoopbackHost(host string) bool {
h := strings.ToLower(host)
return h == "localhost" || h == "127.0.0.1" || h == "::1"
}
func normalizeHost(host string) string {
h := strings.ToLower(strings.TrimSpace(host))
switch h {
case "www.github.com", "github":
return "github.com"
case "www.tarakan.lol", "tarakan":
return "tarakan.lol"
default:
return h
}
}
func parseOwnerRepoPath(path string) (owner, name string, ok bool) {
parts := strings.Split(strings.Trim(path, "/"), "/")
if len(parts) != 2 {
return "", "", false
}
owner = strings.TrimSpace(parts[0])
name = strings.TrimSuffix(strings.TrimSpace(parts[1]), ".git")
if owner == "" || name == "" || owner == "." || name == "." {
return "", "", false
}
return owner, name, true
}
// Current discovers context from the process working directory.
func Current() (Info, error) {
workingDirectory, err := os.Getwd()
if err != nil {
return Info{}, err
}
return Discover(workingDirectory), nil
}
func gitOutput(directory string, args ...string) (string, bool) {
commandArgs := append([]string{"-C", directory}, args...)
output, err := exec.Command("git", commandArgs...).Output()
if err != nil {
return "", false
}
return strings.TrimSpace(string(output)), true
}