-
Notifications
You must be signed in to change notification settings - Fork 37
Add user contribution stats table #533
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| --- | ||
| title: "Steampipe Table: github_user_contribution_stats - Query GitHub user contributions summary using SQL" | ||
| description: "Query GitHub user contribution summaries and calendar data from the GraphQL ContributionsCollection." | ||
| folder: "User" | ||
| --- | ||
|
|
||
| ## Table: github_user_contribution_stats - Query GitHub user contributions summary using SQL | ||
|
|
||
| The `github_user_contribution_stats` table provides access to GitHub's ContributionsCollection data for a user, including total contribution counts and the contribution calendar (weeks/days). This makes it possible to build dashboards and reports similar to a user's public contribution graph. | ||
|
|
||
| ## Table Usage Guide | ||
|
|
||
| The table is scoped to a single user per query. Optionally specify `from_date` and `to_date` to constrain the contribution window, and `max_repositories` to control how many repositories are returned for commit contributions by repository. | ||
|
|
||
| ## Important Notes | ||
|
|
||
| - You must specify the `login` column in the `where` clause. | ||
| - The `commit_contributions_by_repository` field returns at most 100 repositories (default 100). | ||
|
|
||
| ## Examples | ||
|
|
||
| ### Get contribution summary for a user | ||
|
|
||
| ```sql+postgres | ||
| select | ||
| total_commit_contributions, | ||
| total_issue_contributions, | ||
| total_pull_request_contributions, | ||
| total_pull_request_review_contributions, | ||
| total_repositories_with_contributed_commits | ||
| from | ||
| github_user_contribution_stats | ||
| where | ||
| login = 'octocat'; | ||
| ``` | ||
|
|
||
| ```sql+sqlite | ||
| select | ||
| total_commit_contributions, | ||
| total_issue_contributions, | ||
| total_pull_request_contributions, | ||
| total_pull_request_review_contributions, | ||
| total_repositories_with_contributed_commits | ||
| from | ||
| github_user_contribution_stats | ||
| where | ||
| login = 'octocat'; | ||
| ``` | ||
|
|
||
| ### Get contribution calendar for a date range | ||
|
|
||
| ```sql+postgres | ||
| select | ||
| contribution_calendar | ||
| from | ||
| github_user_contribution_stats | ||
| where | ||
| login = 'octocat' | ||
| and from_date = '2025-01-01' | ||
| and to_date = '2025-12-31'; | ||
| ``` | ||
|
|
||
| ```sql+sqlite | ||
| select | ||
| contribution_calendar | ||
| from | ||
| github_user_contribution_stats | ||
| where | ||
| login = 'octocat' | ||
| and from_date = '2025-01-01' | ||
| and to_date = '2025-12-31'; | ||
| ``` | ||
|
|
||
| ### Limit repositories in commit contributions breakdown | ||
|
|
||
| ```sql+postgres | ||
| select | ||
| commit_contributions_by_repository | ||
| from | ||
| github_user_contribution_stats | ||
| where | ||
| login = 'octocat' | ||
| and max_repositories = 100; | ||
| ``` | ||
|
|
||
| ```sql+sqlite | ||
| select | ||
| commit_contributions_by_repository | ||
| from | ||
| github_user_contribution_stats | ||
| where | ||
| login = 'octocat' | ||
| and max_repositories = 100; | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package github | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "slices" | ||
|
|
||
| "github.com/shurcooL/githubv4" | ||
| "github.com/turbot/steampipe-plugin-github/github/models" | ||
| "github.com/turbot/steampipe-plugin-sdk/v5/plugin" | ||
| ) | ||
|
|
||
| func appendContributionColumnIncludes(m *map[string]interface{}, cols []string) { | ||
| (*m)["includeContributionCalendar"] = githubv4.Boolean(slices.Contains(cols, "contribution_calendar")) | ||
| (*m)["includeCommitContributionsByRepository"] = githubv4.Boolean(slices.Contains(cols, "commit_contributions_by_repository")) | ||
| } | ||
|
|
||
| func extractContributionsCollectionFromHydrateItem(h *plugin.HydrateData) (models.ContributionsCollection, error) { | ||
| if collection, ok := h.Item.(models.ContributionsCollection); ok { | ||
| return collection, nil | ||
| } | ||
| return models.ContributionsCollection{}, fmt.Errorf("unable to parse hydrate item %v as ContributionsCollection", h.Item) | ||
| } | ||
|
|
||
| func contributionHydrateCalendar(_ context.Context, _ *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { | ||
| collection, err := extractContributionsCollectionFromHydrateItem(h) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return collection.ContributionCalendar, nil | ||
| } | ||
|
|
||
| func contributionHydrateCommitContributionsByRepository(_ context.Context, _ *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { | ||
| collection, err := extractContributionsCollectionFromHydrateItem(h) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return collection.CommitContributionsByRepository, nil | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package models | ||
|
|
||
| import "github.com/shurcooL/githubv4" | ||
|
|
||
| type ContributionCalendar struct { | ||
| TotalContributions int `graphql:"totalContributions" json:"total_contributions"` | ||
| Weeks []ContributionWeek `graphql:"weeks" json:"weeks"` | ||
| } | ||
|
|
||
| type ContributionWeek struct { | ||
| ContributionDays []ContributionDay `graphql:"contributionDays" json:"contribution_days"` | ||
| FirstDay githubv4.Date `graphql:"firstDay" json:"first_day"` | ||
| } | ||
|
|
||
| type ContributionDay struct { | ||
| Color string `graphql:"color" json:"color"` | ||
| ContributionCount int `graphql:"contributionCount" json:"contribution_count"` | ||
| ContributionLevel githubv4.ContributionLevel `graphql:"contributionLevel" json:"contribution_level"` | ||
| Date githubv4.Date `graphql:"date" json:"date"` | ||
| Weekday int `graphql:"weekday" json:"weekday"` | ||
| } | ||
|
|
||
| type CommitContributionsByRepository struct { | ||
| Repository struct { | ||
| NameWithOwner string `graphql:"nameWithOwner" json:"name_with_owner"` | ||
| Url string `graphql:"url" json:"url"` | ||
| } `graphql:"repository" json:"repository"` | ||
| Contributions struct { | ||
| TotalCount int `graphql:"totalCount" json:"total_count"` | ||
| } `graphql:"contributions" json:"contributions"` | ||
| } | ||
|
|
||
| type ContributionsCollection struct { | ||
| TotalCommitContributions int `graphql:"totalCommitContributions" json:"total_commit_contributions"` | ||
| TotalIssueContributions int `graphql:"totalIssueContributions" json:"total_issue_contributions"` | ||
| TotalPullRequestContributions int `graphql:"totalPullRequestContributions" json:"total_pull_request_contributions"` | ||
| TotalPullRequestReviewContributions int `graphql:"totalPullRequestReviewContributions" json:"total_pull_request_review_contributions"` | ||
| TotalRepositoriesWithContributedCommits int `graphql:"totalRepositoriesWithContributedCommits" json:"total_repositories_with_contributed_commits"` | ||
| ContributionCalendar ContributionCalendar `graphql:"contributionCalendar @include(if:$includeContributionCalendar)" json:"contribution_calendar,omitempty"` | ||
| CommitContributionsByRepository []CommitContributionsByRepository `graphql:"commitContributionsByRepository(maxRepositories: $maxRepositories) @include(if:$includeCommitContributionsByRepository)" json:"commit_contributions_by_repository,omitempty"` | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,113 @@ | ||||||
| package github | ||||||
|
|
||||||
| import ( | ||||||
| "context" | ||||||
| "fmt" | ||||||
| "strings" | ||||||
|
|
||||||
| "github.com/shurcooL/githubv4" | ||||||
| "github.com/turbot/steampipe-plugin-github/github/models" | ||||||
| "github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto" | ||||||
| "github.com/turbot/steampipe-plugin-sdk/v5/plugin" | ||||||
| "github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform" | ||||||
| ) | ||||||
|
|
||||||
| const maxCommitContributionsRepositories = 100 | ||||||
|
|
||||||
| func tableGitHubUserContributionStats() *plugin.Table { | ||||||
| return &plugin.Table{ | ||||||
| Name: "github_user_contribution_stats", | ||||||
| Description: "Contribution summary and calendar data for a GitHub user.", | ||||||
| List: &plugin.ListConfig{ | ||||||
| KeyColumns: []*plugin.KeyColumn{ | ||||||
| {Name: "login", Require: plugin.Required}, | ||||||
| {Name: "from_date", Require: plugin.Optional, Operators: []string{"="}}, | ||||||
| {Name: "to_date", Require: plugin.Optional, Operators: []string{"="}}, | ||||||
| {Name: "max_repositories", Require: plugin.Optional}, | ||||||
| }, | ||||||
| ShouldIgnoreError: isNotFoundError([]string{"404"}), | ||||||
| Hydrate: tableGitHubUserContributionStatsList, | ||||||
| }, | ||||||
| Columns: commonColumns([]*plugin.Column{ | ||||||
| {Name: "login", Type: proto.ColumnType_STRING, Description: "The login name of the user.", Transform: transform.FromQual("login")}, | ||||||
| {Name: "from_date", Type: proto.ColumnType_TIMESTAMP, Description: "Start date for the contribution window.", Transform: transform.FromQual("from_date")}, | ||||||
| {Name: "to_date", Type: proto.ColumnType_TIMESTAMP, Description: "End date for the contribution window.", Transform: transform.FromQual("to_date")}, | ||||||
| {Name: "max_repositories", Type: proto.ColumnType_INT, Description: "Maximum repositories returned for commit contributions by repository.", Transform: transform.FromQual("max_repositories")}, | ||||||
|
||||||
| {Name: "max_repositories", Type: proto.ColumnType_INT, Description: "Maximum repositories returned for commit contributions by repository.", Transform: transform.FromQual("max_repositories")}, | |
| {Name: "max_repositories", Type: proto.ColumnType_INT, Description: "Maximum repositories returned for commit contributions by repository. This column reflects only the provided qualifier value; when omitted, a default of 100 is used internally and this column will be NULL.", Transform: transform.FromQual("max_repositories")}, |
Uh oh!
There was an error while loading. Please reload this page.