Skip to content

Repository files navigation

GitHub Profiler

A Go CLI that analyzes a GitHub account via the GitHub REST API and produces a JSON evidence document describing the authenticated user's engineering activity. It is useful for building an engineering CV, portfolio, or profile: for every repository the user has contributed to, it records commit activity, programming languages, permissions, and links back to the actual commits.

Features

  • Authenticates against GitHub and scans every repository the token can access (owned, collaborated, and organization membership).
  • Per repository, captures:
    • Metadata: URL, visibility, description, default branch, fork/archived flags
    • Your permissions (admin, maintain, push, triage, pull)
    • Activity: total commit count, first and last contribution dates
    • Language breakdown with byte counts and percentages
    • The 20 most recent commits (SHA, message, author, date, URL)
    • A human-readable safe_summary line suitable for a CV
  • Aggregate totals across all scanned repositories.
  • Concurrent scanning (worker pool) for speed.
  • Skips forked repositories by default; optionally includes them.
  • Optional -since filter to count only commits after a given date.

Requirements

  • Go 1.25 or newer (go.mod declares go 1.25.0)
  • A GitHub personal access token (classic or fine-grained) with read access to the repositories you want to scan. A classic token with the repo scope works for private repositories; a public-only token covers public contributions.

Installation

go build -o github-profiler .

Create a GitHub token

The CLI requires a token in GITHUB_TOKEN. Keep it private: do not commit it, add it to a source file, or share it in screenshots.

Option 1: GitHub CLI (recommended)

Install GitHub CLI, then authenticate in your browser:

gh auth login

Choose GitHub.com, HTTPS, then Login with a web browser. Confirm the authorization, then use the token GitHub CLI stores securely for the current shell:

export GITHUB_TOKEN="$(gh auth token)"
./github-profiler

Verify the account at any time with:

gh auth status

Option 2: GitHub website

Open GitHub SettingsDeveloper settingsPersonal access tokensFine-grained tokensGenerate new token. Give it a descriptive name, short expiration, and access to the repositories you want to scan. Grant repository Contents: Read-only, generate the token, copy it immediately, then run:

export GITHUB_TOKEN='github_pat_...'
./github-profiler

For private repositories across multiple organizations, a fine-grained token may not cover every resource owner. If your organization allows it, create a classic token with the repo scope instead. See GitHub's official personal access token guide for current permission and organization-approval requirements.

Usage

The token is read from the GITHUB_TOKEN environment variable; it is required.

export GITHUB_TOKEN=ghp_xxx
./github-profiler

The tool logs its progress to stderr and writes the evidence document to a timestamped filename by default, such as evidence-20260806T120000.123456789Z.json. Set -file-name-with-timestamp=false to write to the exact -output path.

Flags

FlagDefaultDescriptionToken permission when enabled
-outputevidence.jsonOutput JSON file path.
-file-name-with-timestamptrueAppend a UTC timestamp to the output filename.
-with-toonfalseWrite TOON output with a .toon extension.
-since(none)Only count commits since this date.
-concurrency4Number of repositories scanned concurrently.
-max-recent-commits20Maximum recent commits recorded per repository.
-max-repositories0Maximum contributed repositories in final output.
-max-repository-scans0Maximum eligible repositories to scan.
-include-forksfalseInclude forked repositories in the scan.
-exclude-privatefalseExclude private repositories from the scan.
-include-pull-requestsfalseInclude pull requests authored by you.Classic: repo; fine-grained: Pull requests: Read-only
-include-reviewsfalseInclude pull request reviews submitted by you.Classic: repo; fine-grained: Pull requests: Read-only
-include-issuesfalseInclude issues authored by you.Classic: repo; fine-grained: Issues: Read-only
-include-discussionsfalseInclude discussions created by you.Classic: repo; fine-grained: Discussions: Read-only
-exclude-repo(none)Exclude an owner/name repository; may be repeated.
-exclude-org(none)Exclude repositories owned by an organization; may be repeated.
-sort-repo-bylast-contribution-date-descRepository sort criterion; may be repeated.

For example, to skip a private repository and a fork:

./github-profiler \
-max-repository-scans 50 \
-max-repositories 20 \
-max-recent-commits 10 \
-exclude-repo your-account/private-project \
-exclude-repo upstream/example-fork \
-exclude-org example-organization

Exclusions are applied before -max-repository-scans, so it caps the number of repositories actually scanned. Repositories are considered in GitHub's full-name sort order. -max-repositories is applied afterwards: it limits the final sorted contributed-repository results and recalculates their totals.

Optional contribution evidence

Commits are always included. The following flags add opt-in evidence and allow a repository to appear when it contains one of these contributions but no attributed commit:

./github-profiler \
-include-pull-requests \
-include-reviews \
-include-issues \
-include-discussions

For a fine-grained token, grant read access to Pull requests, Issues, and Discussions for the selected repositories. Reviews can generate substantially more API requests because GitHub exposes them per pull request.

A classic token with repo covers all private-repository features above. For public repositories, GitHub permits many endpoints without those private-repository scopes.

Repository sorting

Use -sort-repo-by once or multiple times. Criteria are evaluated in the order provided: the first is the primary sort and each later criterion breaks ties.

./github-profiler \
-sort-repo-by=star-count-desc \
-sort-repo-by=project-size-desc

Available criteria:

  • creation-date-desc, creation-date-asc
  • first-contribution-date-desc, first-contribution-date-asc
  • last-contribution-date-desc, last-contribution-date-asc
  • star-count-desc, star-count-asc
  • fork-count-desc, fork-count-asc
  • commit-count-desc, commit-count-asc
  • project-size-desc, project-size-asc

Without this flag, repositories remain sorted by latest contribution first. project-size uses the repository size reported by GitHub, in KB. Each repository also includes its star_count, fork_count, and project_size_kb in the output JSON.

Environment variables

VariableRequiredDefaultDescription
GITHUB_TOKENyesPersonal access token used for API calls.
GITHUB_API_URLnohttps://api.github.comOverride for GitHub Enterprise API base URL.

Output format

The output is a pretty-printed JSON document with the following top-level structure:

{
"profile": {
"github": "octocat",
"name": "The Octocat",
"email": "octocat@example.com",
"generated_at": "2026-08-06T12:00:00Z"
},
"totals": {
"accessible_repositories": 12,
"contributed_repositories": 8,
"public_repositories": 5,
"private_repositories": 3,
"commits": 342
},
"repositories": [
{
"repository": "octocat/hello-world",
"owner": "octocat",
"name": "hello-world",
"url": "https://github.com/octocat/hello-world",
"visibility": "public",
"description": "My first repository",
"default_branch": "main",
"fork": false,
"archived": false,
"star_count": 80,
"fork_count": 9,
"project_size_kb": 108,
"permissions": {
"admin": true,
"maintain": true,
"push": true,
"triage": true,
"pull": true
},
"activity": {
"commit_count": 42,
"first_contribution": "2023-01-15T10:00:00Z",
"last_contribution": "2026-07-30T09:30:00Z"
},
"languages": [
{ "name": "Go", "bytes": 20480, "percentage": 80.0 },
{ "name": "Markdown", "bytes": 5120, "percentage": 20.0 }
],
"recent_commits": [
{
"sha": "abc123",
"message": "Fix flaky test",
"author": "octocat",
"email": "octocat@example.com",
"date": "2026-07-30T09:30:00Z",
"url": "https://github.com/octocat/hello-world/commit/abc123"
}
],
"safe_summary": "Contributed to My first repository, using primarily Go, Markdown."
}
],
"warnings": [
"Only repositories accessible to the supplied token were scanned.",
"Commit attribution depends on GitHub associating commits with the authenticated username.",
"Squashed commits, alternate unverified emails, reviews, issues, discussions, and pair-programming activity may be missing.",
"Private repository names and commit messages must be reviewed before publishing."
]
}

Details worth knowing:

  • Repositories with no commits attributed to the authenticated user are omitted.
  • Repositories are sorted by most recent contribution (descending).
  • Languages are sorted by byte count (descending), with percentages rounded to two decimals.
  • Only the first line of each commit message is included in recent_commits.
  • The output file is written with 0600 permissions to keep private data safe.

How it works

  1. GET /user — identifies the authenticated user.
  2. GET /user/repos (paginated, 100 per page) — lists all accessible repositories, covering owner, collaborator, and organization_member affiliations.
  3. For each repository, concurrently:
    • GET /repos/{owner}/{repo}/commits?author={username} (paginated, optional since)
    • GET /repos/{owner}/{repo}/languages
  4. Results are aggregated into the evidence document and written to the output file.

Project structure

The project stays as a single main package because it is a small, self-contained CLI. Files are separated by responsibility so the application flow and GitHub integration are easy to navigate:

.
├── main.go # CLI orchestration: fetch, analyze, sort, and write
├── config.go # Flags, environment variables, and validation
├── models.go # GitHub API and evidence-document data structures
├── github_client.go # GitHub REST requests, pagination, and API errors
├── analyzer.go # Concurrent repository analysis and commit evidence
├── evidence.go # Evidence-document creation and aggregate totals
├── output.go # JSON serialization and secure file writing
└── helpers.go # Date, repository-name, summary, and rounding helpers

If the CLI gains more commands or integrations, the next step would be to move these concerns into internal/ packages (for example internal/github and internal/evidence) while keeping main.go as the command entry point.

Caveats

  • The scan only sees repositories the supplied token can access. Totals reflect what the token can see, not necessarily the entire account.
  • Commit counts depend on GitHub's author association. Squashed commits, commits made under unverified or alternate emails, reviews, issues, discussions, and pair-programming work are not counted.
  • The output contains private repository names and commit messages — review the JSON before sharing or publishing it.

About

A Go CLI that analyzes a GitHub account via the GitHub REST API and produces a JSON describing the authenticated user's engineering activity. It is useful for building an engineering CV, portfolio, or profile.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages