Files
ghglance/internal/github/contributions_all_time.go
T
tiennm99 50b29b4a78 feat: add all-time variants of productive, language, contribution cards
Four time-bounded cards ("last year") now have all-time counterparts, and
the stats card gains a lifetime commits row.

New cards:
- 6-most-commit-language-all-time.svg (byte-weighted, all lifetime commits)
- 7-productive-time-all-time.svg       (hour histogram over all lifetime commits)
- 8-contributions-all-time.svg         (area chart spanning every active year)

Data pipeline:
- Drop the "since" filter from commitHistoryQuery; FetchProductive now
  paginates unbounded commits and splits each commit into last-year and
  all-time buckets in a single pass — no extra API calls.
- New contributionYearQuery iterates user.contributionYears to
  concatenate calendar data and accumulate TotalCommitsAllTime.
- -commits-per-repo default bumped 100 → 500 to give all-time depth.

Polish:
- Productive-time title embeds the configured tz as "UTC±N.NN" (e.g.
  UTC+7.00) on both last-year and all-time cards.
- Contribution x-axis flipped to mm/yy with an "mm/yy" footer caption
  paralleling productive-time's "hour of day".
- Contribution x-axis label stride now targets ~6 labels regardless of
  bucket count so the all-time chart (~100 months) stays readable while
  the underlying curve still samples every month.
2026-04-18 21:40:46 +07:00

73 lines
2.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package github
import (
"sort"
"time"
)
// contributionYearGQL mirrors contributionYearQuery.
type contributionYearGQL struct {
User *struct {
ContributionsCollection struct {
TotalCommitContributions int `json:"totalCommitContributions"`
ContributionCalendar struct {
Weeks []struct {
ContributionDays []struct {
ContributionCount int `json:"contributionCount"`
Date string `json:"date"`
} `json:"contributionDays"`
} `json:"weeks"`
} `json:"contributionCalendar"`
} `json:"contributionsCollection"`
} `json:"user"`
}
// FetchContributionsAllTime iterates p.ContributionYears and issues one
// contributionsCollection query per year, concatenating the daily calendar
// into p.DailyContributionsAllTime and accumulating commit counts into
// p.TotalCommitsAllTime.
//
// Cost: one GraphQL call per active year (typically 1–10 per user).
func (c *Client) FetchContributionsAllTime(p *Profile) error {
years := append([]int(nil), p.ContributionYears...)
sort.Ints(years) // ascending so the concatenated series is oldest→newest
for _, y := range years {
from := time.Date(y, 1, 1, 0, 0, 0, 0, time.UTC)
to := time.Date(y, 12, 31, 23, 59, 59, 0, time.UTC)
// Clamp the current year's window to now so GitHub doesn't reject it.
if now := time.Now().UTC(); to.After(now) {
to = now
}
vars := map[string]any{
"login": p.Login,
"from": from.Format(time.RFC3339),
"to": to.Format(time.RFC3339),
}
var resp contributionYearGQL
if err := c.query(contributionYearQuery, vars, &resp); err != nil {
return err
}
if resp.User == nil {
continue
}
cc := resp.User.ContributionsCollection
p.TotalCommitsAllTime += cc.TotalCommitContributions
for _, w := range cc.ContributionCalendar.Weeks {
for _, d := range w.ContributionDays {
t, err := time.Parse("2006-01-02", d.Date)
if err != nil {
continue
}
p.DailyContributionsAllTime = append(p.DailyContributionsAllTime, DailyContribution{
Date: t,
Count: d.ContributionCount,
})
}
}
}
return nil
}