Skip to content

Release Notes v0.8.0

This release adds comprehensive user profile statistics, a new CLI tool, and contributor statistics functionality.

New Features

Profile Package

The new profile package provides comprehensive GitHub user contribution statistics that mirror what GitHub shows on profile pages:

import "github.com/grokify/gogithub/profile"

ctx := context.Background()
restClient := github.NewClient(nil).WithAuthToken(token)
gqlClient := graphql.NewClient(ctx, token)

// Fetch profile for last year
from := time.Now().AddDate(-1, 0, 0)
to := time.Now()

p, err := profile.GetUserProfile(ctx, restClient, gqlClient, "octocat", from, to, nil)
if err != nil {
    panic(err)
}

fmt.Println(p.Summary())
// octocat: 150 commits (+10000/-3000) in 12 repos, 25 PRs, 10 issues, 50 reviews

UserProfile Type

type UserProfile struct {
    Username    string
    From        time.Time
    To          time.Time

    // GitHub official counts (from contributionsCollection)
    TotalCommits            int
    TotalIssues             int
    TotalPRs                int
    TotalReviews            int
    TotalReposCreated       int
    RestrictedContributions int

    // From default branch traversal (includes additions/deletions)
    CommitsDefaultBranch int
    TotalAdditions       int
    TotalDeletions       int

    // Repository data
    ReposContributedTo int
    RepoStats          []RepoContribution

    // Time-series data
    Calendar *ContributionCalendar
    Activity *ActivityTimeline
}

Contribution Calendar

Track contribution patterns with streak calculations:

cal := p.Calendar

fmt.Printf("Total contributions: %d\n", cal.TotalContributions)
fmt.Printf("Days with activity: %d\n", cal.DaysWithContributions())
fmt.Printf("Longest streak: %d days\n", cal.LongestStreak())
fmt.Printf("Current streak: %d days\n", cal.CurrentStreak())

// Contribution levels (0-4) for visualization
day := cal.GetDay(time.Now())
if day != nil {
    fmt.Printf("Today: %d contributions (level %d)\n", day.ContributionCount, day.Level)
}

Activity Timeline

Monthly activity breakdown with GitHub-style summaries:

for _, m := range p.Activity.Months {
    fmt.Printf("%s %d:\n", m.MonthName(), m.Year)
    if s := m.CommitSummary(); s != "" {
        fmt.Printf("  - %s\n", s)  // "Created 42 commits in 5 repositories"
    }
    if s := m.PRSummary(); s != "" {
        fmt.Printf("  - %s\n", s)  // "Opened 3 pull requests in 2 repositories"
    }
}

Progress Reporting

Long-running operations support progress callbacks:

opts := &profile.Options{
    Progress: func(info profile.ProgressInfo) {
        fmt.Printf("[%d/%d] %s (%d%%)\n",
            info.Stage, info.TotalStages, info.Description,
            (info.Current * 100) / info.Total)
    },
}

Contributor Statistics

New functions in the repo package for per-repository contributor statistics:

import "github.com/grokify/gogithub/repo"

// Get all contributors for a repository
stats, err := repo.ListContributorStats(ctx, client, "owner", "repo")

// Get stats for a specific user
userStats, err := repo.GetContributorStats(ctx, client, "owner", "repo", "username")

// Get summarized stats
summary, err := repo.GetContributorSummary(ctx, client, "owner", "repo", "username")
if summary != nil {
    fmt.Printf("%s: %d commits (+%d/-%d)\n",
        summary.Username, summary.TotalCommits,
        summary.TotalAdditions, summary.TotalDeletions)
    fmt.Printf("First commit: %s\n", summary.FirstCommit.Format("2006-01-02"))
    fmt.Printf("Last commit: %s\n", summary.LastCommit.Format("2006-01-02"))
}

The functions automatically handle GitHub's 202 Accepted responses with exponential backoff retry.

Functions

Function Description
ListContributorStats List all contributors for a repository
GetContributorStats Get stats for a specific contributor
GetContributorSummary Get aggregated summary for a contributor

CLI Tool

New gogithub CLI tool for GitHub operations:

# Install
go install github.com/grokify/gogithub/cmd/gogithub@latest

# Fetch user profile statistics
export GITHUB_TOKEN=your-token
gogithub profile --user grokify --from 2024-01-01 --to 2024-12-31

# Output as JSON
gogithub profile --user grokify --from 2024-01-01 --to 2024-12-31 --format json

# Generate both raw and aggregate JSON files
gogithub profile --user grokify --from 2024-01-01 --to 2024-12-31 \
    --output-raw raw.json --output-aggregate aggregate.json

# Regenerate aggregate from raw file (no API calls)
gogithub profile --input raw.json --output aggregate.json

# Search for open PRs by user
gogithub search-prs --accounts grokify,octocat --outfile prs.xlsx

Progress Display

The CLI shows real-time progress with visual progress bars:

Fetching profile for 'grokify' from 2024-01-01 to 2024-12-31

[1/4] Fetching contribution statistics   [████████████████████] 100%
[2/4] Fetching commit details            [████████████████████] 100%
[3/4] Processing repositories            [██████████░░░░░░░░░░]  50%
[4/4] Building activity timeline         [████████████████████] 100%

Commands

Command Description
profile Fetch comprehensive user contribution statistics
search-prs Search for open pull requests by user

Integration Tests

New integration tests that run against the real GitHub API when GITHUB_TOKEN is set:

# Run unit tests only
go test ./...

# Run with integration tests
GITHUB_TOKEN=your-token go test ./... -v

# Run only integration tests
GITHUB_TOKEN=your-token go test ./... -v -run Integration

Integration tests automatically skip when no token is available.

Commit Count Clarification

The profile package exposes two commit counts:

Field Source Description
TotalCommits contributionsCollection GitHub's official count shown on profile
CommitsDefaultBranch Commit history traversal Commits found on default branches

These may differ because TotalCommits includes all branches while CommitsDefaultBranch only traverses default branch history (but provides additions/deletions data).

Token Requirements

For public data, use a fine-grained token with minimal permissions:

Token Type Configuration
Fine-grained PAT Repository access: "Public Repositories (read-only)", no permissions needed
Classic PAT No scopes required (just a valid token)

See the Authentication Guide for detailed token setup instructions.

Documentation

New documentation added:

Dependencies

  • Added github.com/spf13/cobra v1.10.2 for CLI