Skip to content

fix(contributors): show real GitHub commits per contributor#302

Merged
ambicuity merged 1 commit into
mainfrom
fix/contributors-real-recent-commits
May 26, 2026
Merged

fix(contributors): show real GitHub commits per contributor#302
ambicuity merged 1 commit into
mainfrom
fix/contributors-real-recent-commits

Conversation

@ambicuity
Copy link
Copy Markdown
Owner

Why

The "RECENT COMMITS" panel in the right-side detail of #contributors was rendering deterministic mock SHAs and made-up messages like refactor(ui): keyboard nav for every selected dev. Anyone landing on jobs.riteshrana.engineer/#contributors and clicking a contributor saw fabricated history that had nothing to do with that person.

What

Replaces the local mock generator in docs/terminal/contributors.jsx with a useRecentCommits() hook that fetches GET /repos/{repo}/commits?author={handle} from the GitHub REST API on selection. A module-level cache keyed by handle dedupes within a session so re-clicking a contributor doesn't re-hit the API.

Each row now shows:

  • real 7-char SHA
  • actual commit subject (first line, truncated to 80 chars)
  • human-readable "ago" derived from the commit author date
  • linked to the commit on GitHub

States surfaced explicitly (no silent failures):

Cache-bust ?v=7?v=8 on all docs/index.html bundles so existing visitors pick up the new code.

Verification (local — python3 -m http.server 8765, Playwright)

Contributor Result
@ambicuity Real commits — #299, #300, #301 (19m, 27m, 42m ago)
@rvac-bucky Real commits — #265, #247, #166, #193 (2h, 2mo …)
@15045 Empty-state message (co-author only)
@mitre88 Empty-state message (no direct authored commits)

Screenshot saved to contributors-real-commits.png (not committed).

The "RECENT COMMITS" panel in the contributor detail (right side of the
#contributors view) was rendering deterministic mock SHAs and made-up
messages like `refactor(ui): keyboard nav` for every selected dev. Users
landing on jobs.riteshrana.engineer/#contributors and clicking a name
saw fabricated history.

Replaces the local `recentCommits(c)` stub with a `useRecentCommits()`
hook that lazily fetches `GET /repos/{repo}/commits?author={handle}` from
the GitHub REST API when a contributor is selected, with a module-level
session cache keyed by handle so repeated clicks don't re-hit the API.

Each row now shows the real 7-char SHA, the actual commit subject (first
line of the message, truncated to 80 chars), and a human-readable "ago"
derived from the commit author date. Rows link to the commit on GitHub.

Loading / empty / error states are surfaced explicitly:
- "loading from github…" while in-flight
- "no commits authored by @{handle} in this repo" when the user is only
  a co-author (e.g. @15045 / 小吴 on #296) — verified locally.
- "could not load commits (…)" with the failure reason on rate-limit or
  network failure (graceful degradation).

Bumps the `?v=7` cache-bust on all bundles in docs/index.html to `?v=8`
so existing visitors fetch the new contributors.jsx.

Verified against http://localhost:8765/#contributors:
- @ambicuity → shows #299, #300, #301 etc. with correct ages (19m, 27m, …).
- @rvac-bucky → shows #265, #247, #166, #193.
- @15045 → empty-state message (co-author only, never the author).
Copilot AI review requested due to automatic review settings May 26, 2026 19:28
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Warning

Review limit reached

@ambicuity, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 12 minutes and 40 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3ac9626e-9da3-47cd-98f6-0f54a0be4a62

📥 Commits

Reviewing files that changed from the base of the PR and between 8ee4268 and 0eaf049.

📒 Files selected for processing (2)
  • docs/index.html
  • docs/terminal/contributors.jsx
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/contributors-real-recent-commits

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@ambicuity ambicuity merged commit 535f25c into main May 26, 2026
7 of 8 checks passed
@ambicuity ambicuity deleted the fix/contributors-real-recent-commits branch May 26, 2026 19:29
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces the deterministic mock commits with live data fetched from the GitHub API for each contributor. It introduces a session-scoped cache, a custom React hook useRecentCommits, and a relative time formatter. The review feedback highlights two key improvement opportunities: allowing retries when a fetch request fails instead of permanently caching the error state, and using Math.floor instead of Math.round in the relative time formatter to prevent awkward boundary values like '60s' or '60m'.

Comment on lines +572 to +573
if (!RECENT_COMMITS_CACHE.has(handle)) {
RECENT_COMMITS_CACHE.set(handle, { state: 'loading', commits: [] });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Currently, if a request to fetch recent commits fails (e.g., due to a temporary network issue or rate limit), the error state is cached in RECENT_COMMITS_CACHE. Because RECENT_COMMITS_CACHE.has(handle) is used to check for cached entries, the application will never attempt to refetch the commits for that contributor during the session, even if the user clicks away and clicks back. Allowing a retry when the cached state is 'error' improves usability and resilience against temporary network glitches.

    const cached = RECENT_COMMITS_CACHE.get(handle);
    if (!cached || cached.state === 'error') {
      RECENT_COMMITS_CACHE.set(handle, { state: 'loading', commits: [] });

Comment on lines +539 to +545
if (diffSec < 60) return `${Math.round(diffSec)}s`;
if (diffSec < 3600) return `${Math.round(diffSec / 60)}m`;
if (diffSec < 86400) return `${Math.round(diffSec / 3600)}h`;
if (diffSec < 86400 * 7) return `${Math.round(diffSec / 86400)}d`;
if (diffSec < 86400 * 30) return `${Math.round(diffSec / (86400 * 7))}w`;
if (diffSec < 86400 * 365) return `${Math.round(diffSec / (86400 * 30))}mo`;
return `${Math.round(diffSec / (86400 * 365))}y`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using Math.round for relative time formatting can lead to awkward boundary values such as 60s, 60m, or 24h (e.g., when diffSec is 59.6 seconds, it is less than 60, so it rounds to 60s instead of transitioning to 1m). Using Math.floor ensures standard relative time intervals (e.g., 59s, 59m, 23h) and a smoother transition between units.

Suggested change
if (diffSec < 60) return `${Math.round(diffSec)}s`;
if (diffSec < 3600) return `${Math.round(diffSec / 60)}m`;
if (diffSec < 86400) return `${Math.round(diffSec / 3600)}h`;
if (diffSec < 86400 * 7) return `${Math.round(diffSec / 86400)}d`;
if (diffSec < 86400 * 30) return `${Math.round(diffSec / (86400 * 7))}w`;
if (diffSec < 86400 * 365) return `${Math.round(diffSec / (86400 * 30))}mo`;
return `${Math.round(diffSec / (86400 * 365))}y`;
if (diffSec < 60) return Math.floor(diffSec) + "s";
if (diffSec < 3600) return Math.floor(diffSec / 60) + "m";
if (diffSec < 86400) return Math.floor(diffSec / 3600) + "h";
if (diffSec < 86400 * 7) return Math.floor(diffSec / 86400) + "d";
if (diffSec < 86400 * 30) return Math.floor(diffSec / (86400 * 7)) + "w";
if (diffSec < 86400 * 365) return Math.floor(diffSec / (86400 * 30)) + "mo";
return Math.floor(diffSec / (86400 * 365)) + "y";

@ambicuity ambicuity review requested due to automatic review settings May 26, 2026 19:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant