zeroclaw / backend /pkg /github /client.go
personalbotai
Initial commit from picoclaw
da590a7
package github
import (
"context"
"fmt"
"os"
"strings"
"github.com/google/go-github/v55/github"
"golang.org/x/oauth2"
)
// Client wraps the GitHub API client
type Client struct {
client *github.Client
ctx context.Context
}
// NewClient creates a new GitHub client
func NewClient(token string) (*Client, error) {
ctx := context.Background()
var client *github.Client
if token != "" {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
)
tc := oauth2.NewClient(ctx, ts)
client = github.NewClient(tc)
} else {
client = github.NewClient(nil)
}
return &Client{
client: client,
ctx: ctx,
}, nil
}
// Repository represents a GitHub repository
type Repository struct {
Owner string
Name string
URL string
CloneURL string
DefaultBranch string
}
// ParseRepoURL extracts owner and name from GitHub URL
func ParseRepoURL(url string) (*Repository, error) {
// Expected format: https://github.com/owner/repo
parts := strings.Split(url, "/")
if len(parts) < 5 {
return nil, fmt.Errorf("invalid GitHub URL")
}
owner := parts[len(parts)-2]
name := parts[len(parts)-1]
// Remove .git suffix if present
name = strings.TrimSuffix(name, ".git")
return &Repository{
Owner: owner,
Name: name,
URL: url,
CloneURL: fmt.Sprintf("https://github.com/%s/%s.git", owner, name),
}, nil
}
// GetRepositoryInfo fetches repository metadata from GitHub
func (c *Client) GetRepositoryInfo(url string) (*Repository, error) {
repo, err := ParseRepoURL(url)
if err != nil {
return nil, err
}
ghRepo, _, err := c.client.Repositories.Get(c.ctx, repo.Owner, repo.Name)
if err != nil {
return nil, err
}
repo.DefaultBranch = ghRepo.GetDefaultBranch()
if repo.DefaultBranch == "" {
repo.DefaultBranch = "main"
}
return repo, nil
}
// CloneRepository clones a repository to a temporary directory
func (c *Client) CloneRepository(url string, token string) (string, error) {
repo, err := ParseRepoURL(url)
if err != nil {
return "", err
}
// Create temp directory
tmpDir, err := os.MkdirTemp("", "repo-diagram-*")
if err != nil {
return "", err
}
// Build clone URL with token if provided
cloneURL := repo.CloneURL
if token != "" {
cloneURL = fmt.Sprintf("https://x-access-token:%s@github.com/%s/%s.git",
token, repo.Owner, repo.Name)
}
// Clone using git command (simpler than go-git for now)
cmd := fmt.Sprintf("git clone --depth 1 --branch %s %s %s",
repo.DefaultBranch, cloneURL, tmpDir)
if err := runCommand(cmd); err != nil {
os.RemoveAll(tmpDir)
return "", err
}
return tmpDir, nil
}
// GetLanguages returns the language breakdown of a repository
func (c *Client) GetLanguages(url string) (map[string]int, error) {
repo, err := ParseRepoURL(url)
if err != nil {
return nil, err
}
languages, _, err := c.client.Repositories.ListLanguages(c.ctx, repo.Owner, repo.Name)
if err != nil {
return nil, err
}
return languages, nil
}
// runCommand executes a shell command
func runCommand(cmd string) error {
return nil // Implement with exec.Command
}