refactor(github): attribute commits by repo language byte share

Each commit now contributes a full "vote" partitioned across the repo's
languages proportional to linguist byte counts, instead of crediting only
the primary language. A 60% Go / 40% Python repo adds 0.6 to Go and 0.4
to Python per commit.

- RepoInfo gains []LangEdge capturing the full byte breakdown already
  returned by profileQuery.
- FetchProductive distributes each commit via a fixed-point scaleFactor
  (int64 preserved, percentages unchanged in the card).
- Fallback to primary language only when linguist reports zero bytes
  (empty repo).

Caveat: linguist excludes prose languages (Markdown, AsciiDoc, reST) from
its byte output, so Markdown-heavy repos still skew toward the detected
code fraction. Fixing that case requires per-commit file classification
via REST /commits/{sha} + go-enry — tracked as future work.
This commit is contained in:
tiennm99 committed 2026-04-18 20:50:04 +07:00
1 parent 9c81926c06
commit 9efb912df5
3 files changed
+68 -15

No files matched your search

+9 -5
View File
@@ -116,16 +116,20 @@ func (c *Client) FetchProfile(login string) (*Profile, error) {
langColor[r.PrimaryLanguage.Name] = r.PrimaryLanguage.Color
}
}
p.TopRepos = append(p.TopRepos, info)
// Capture secondary language colors so productive-time's
// per-language aggregation can color them even if that language
// isn't the primary of any other repo.
// Carry the repo's full language-bytes breakdown so commit
// attribution can distribute each commit across all languages
// the repo contains, not just the primary.
for _, e := range r.Languages.Edges {
info.Languages = append(info.Languages, LangEdge{
Name: e.Node.Name,
Color: e.Node.Color,
Bytes: e.Size,
})
if _, ok := langColor[e.Node.Name]; !ok {
langColor[e.Node.Name] = e.Node.Color
}
}
p.TopRepos = append(p.TopRepos, info)
}
if !u.Repositories.PageInfo.HasNextPage {