mirror of
https://github.com/lukaszraczylo/git-velocity.git
synced 2026-06-06 22:49:27 +00:00
455 lines
14 KiB
Go
455 lines
14 KiB
Go
package config
|
|
|
|
import "time"
|
|
|
|
// Config represents the main configuration structure
|
|
type Config struct {
|
|
Version string `yaml:"version"`
|
|
Auth AuthConfig `yaml:"auth"`
|
|
Repositories []RepositoryConfig `yaml:"repositories"`
|
|
DateRange DateRangeConfig `yaml:"date_range"`
|
|
Granularity []string `yaml:"granularity"`
|
|
CustomPeriods []CustomPeriod `yaml:"custom_periods,omitempty"`
|
|
Teams []TeamConfig `yaml:"teams,omitempty"`
|
|
Scoring ScoringConfig `yaml:"scoring"`
|
|
Output OutputConfig `yaml:"output"`
|
|
Cache CacheConfig `yaml:"cache"`
|
|
Options OptionsConfig `yaml:"options"`
|
|
}
|
|
|
|
// AuthConfig holds authentication configuration
|
|
type AuthConfig struct {
|
|
// Token-based authentication
|
|
GithubToken string `yaml:"github_token,omitempty"`
|
|
|
|
// GitHub App authentication
|
|
GithubApp *GithubAppConfig `yaml:"github_app,omitempty"`
|
|
}
|
|
|
|
// GithubAppConfig holds GitHub App authentication details
|
|
type GithubAppConfig struct {
|
|
AppID int64 `yaml:"app_id"`
|
|
InstallationID int64 `yaml:"installation_id"`
|
|
PrivateKeyPath string `yaml:"private_key_path,omitempty"`
|
|
PrivateKey string `yaml:"private_key,omitempty"`
|
|
}
|
|
|
|
// RepositoryConfig defines a repository to analyze
|
|
type RepositoryConfig struct {
|
|
Owner string `yaml:"owner"`
|
|
Name string `yaml:"name,omitempty"`
|
|
Pattern string `yaml:"pattern,omitempty"` // For wildcard matching
|
|
}
|
|
|
|
// DateRangeConfig specifies the analysis time range
|
|
type DateRangeConfig struct {
|
|
Start string `yaml:"start,omitempty"` // ISO 8601 format
|
|
End string `yaml:"end,omitempty"` // ISO 8601 format
|
|
}
|
|
|
|
// CustomPeriod defines a custom time period for analysis
|
|
type CustomPeriod struct {
|
|
Name string `yaml:"name"`
|
|
Start string `yaml:"start"`
|
|
End string `yaml:"end"`
|
|
}
|
|
|
|
// TeamConfig defines a team and its members
|
|
type TeamConfig struct {
|
|
Name string `yaml:"name"`
|
|
Members []string `yaml:"members"`
|
|
Color string `yaml:"color,omitempty"`
|
|
}
|
|
|
|
// ScoringConfig holds gamification scoring configuration
|
|
type ScoringConfig struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
Points PointsConfig `yaml:"points"`
|
|
Achievements []AchievementConfig `yaml:"achievements,omitempty"`
|
|
}
|
|
|
|
// PointsConfig defines point values for various activities
|
|
type PointsConfig struct {
|
|
Commit int `yaml:"commit"`
|
|
CommitWithTests int `yaml:"commit_with_tests"`
|
|
LinesAdded float64 `yaml:"lines_added"`
|
|
LinesDeleted float64 `yaml:"lines_deleted"`
|
|
PROpened int `yaml:"pr_opened"`
|
|
PRMerged int `yaml:"pr_merged"`
|
|
PRReviewed int `yaml:"pr_reviewed"`
|
|
ReviewComment int `yaml:"review_comment"` // PR review comments (not code comments)
|
|
IssueOpened int `yaml:"issue_opened"`
|
|
IssueClosed int `yaml:"issue_closed"`
|
|
FastReview1h int `yaml:"fast_review_1h"`
|
|
FastReview4h int `yaml:"fast_review_4h"`
|
|
FastReview24h int `yaml:"fast_review_24h"`
|
|
}
|
|
|
|
// AchievementConfig defines an achievement badge
|
|
type AchievementConfig struct {
|
|
ID string `yaml:"id"`
|
|
Name string `yaml:"name"`
|
|
Description string `yaml:"description"`
|
|
Icon string `yaml:"icon"`
|
|
Condition AchievementCondition `yaml:"condition"`
|
|
}
|
|
|
|
// AchievementCondition defines when an achievement is earned
|
|
type AchievementCondition struct {
|
|
Type string `yaml:"type"` // commit_count, pr_count, review_count, avg_review_time, etc.
|
|
Threshold float64 `yaml:"threshold"`
|
|
}
|
|
|
|
// TierFromThreshold returns the tier level (1-11) based on threshold value
|
|
// Tiers: 1=1, 2=10, 3=25, 4=50, 5=100, 6=250, 7=500, 8=1000, 9=5000, 10=10000, 11=25000+
|
|
func TierFromThreshold(threshold float64) int {
|
|
tiers := []float64{1, 10, 25, 50, 100, 250, 500, 1000, 5000, 10000, 25000}
|
|
for i := len(tiers) - 1; i >= 0; i-- {
|
|
if threshold >= tiers[i] {
|
|
return i + 1
|
|
}
|
|
}
|
|
return 1
|
|
}
|
|
|
|
// OutputConfig specifies output generation settings
|
|
type OutputConfig struct {
|
|
Directory string `yaml:"directory"`
|
|
Format []string `yaml:"format"` // html, json
|
|
Deploy DeployConfig `yaml:"deploy"`
|
|
}
|
|
|
|
// DeployConfig specifies deployment options
|
|
type DeployConfig struct {
|
|
GHPages bool `yaml:"gh_pages"`
|
|
Artifact bool `yaml:"artifact"`
|
|
}
|
|
|
|
// CacheConfig holds caching configuration
|
|
type CacheConfig struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
Directory string `yaml:"directory"`
|
|
TTL string `yaml:"ttl"` // Duration string like "24h"
|
|
}
|
|
|
|
// OptionsConfig holds advanced options
|
|
type OptionsConfig struct {
|
|
ConcurrentRequests int `yaml:"concurrent_requests"`
|
|
IncludeBots bool `yaml:"include_bots"`
|
|
BotPatterns []string `yaml:"bot_patterns"`
|
|
CloneDirectory string `yaml:"clone_directory"` // Directory for local git clones
|
|
UseLocalGit bool `yaml:"use_local_git"` // Use local git for commits (faster)
|
|
UserAliases []UserAlias `yaml:"user_aliases,omitempty"` // Manual email/name to login mappings
|
|
}
|
|
|
|
// UserAlias maps git emails or names to a GitHub login
|
|
type UserAlias struct {
|
|
GithubLogin string `yaml:"github_login"` // The canonical GitHub username
|
|
Emails []string `yaml:"emails,omitempty"` // Git commit emails to map
|
|
Names []string `yaml:"names,omitempty"` // Git commit author names to map
|
|
}
|
|
|
|
// ParsedDateRange holds parsed date range values
|
|
type ParsedDateRange struct {
|
|
Start *time.Time
|
|
End *time.Time
|
|
}
|
|
|
|
// DefaultConfig returns a configuration with sensible defaults
|
|
func DefaultConfig() *Config {
|
|
return &Config{
|
|
Version: "1.0",
|
|
Granularity: []string{"daily", "weekly", "monthly"},
|
|
Scoring: ScoringConfig{
|
|
Enabled: true,
|
|
Points: PointsConfig{
|
|
Commit: 10,
|
|
CommitWithTests: 15,
|
|
LinesAdded: 0.1,
|
|
LinesDeleted: 0.05,
|
|
PROpened: 25,
|
|
PRMerged: 50,
|
|
PRReviewed: 30,
|
|
ReviewComment: 5,
|
|
IssueOpened: 15,
|
|
IssueClosed: 20,
|
|
FastReview1h: 50,
|
|
FastReview4h: 25,
|
|
FastReview24h: 10,
|
|
},
|
|
Achievements: defaultAchievements(),
|
|
},
|
|
Output: OutputConfig{
|
|
Directory: "./dist",
|
|
Format: []string{"html", "json"},
|
|
Deploy: DeployConfig{
|
|
GHPages: true,
|
|
Artifact: true,
|
|
},
|
|
},
|
|
Cache: CacheConfig{
|
|
Enabled: true,
|
|
Directory: "./.cache",
|
|
TTL: "24h",
|
|
},
|
|
Options: OptionsConfig{
|
|
ConcurrentRequests: 5,
|
|
IncludeBots: false,
|
|
BotPatterns: []string{
|
|
"*[bot]",
|
|
"dependabot*",
|
|
"renovate*",
|
|
"github-actions*",
|
|
},
|
|
CloneDirectory: "./.repos",
|
|
UseLocalGit: true, // Default to faster local git analysis
|
|
},
|
|
}
|
|
}
|
|
|
|
// defaultAchievements returns the default achievement badges
|
|
func defaultAchievements() []AchievementConfig {
|
|
return []AchievementConfig{
|
|
{
|
|
ID: "first-commit",
|
|
Name: "First Steps",
|
|
Description: "Made your first commit",
|
|
Icon: "fa-baby",
|
|
Condition: AchievementCondition{Type: "commit_count", Threshold: 1},
|
|
},
|
|
{
|
|
ID: "commit-10",
|
|
Name: "Getting Started",
|
|
Description: "Made 10 commits",
|
|
Icon: "fa-seedling",
|
|
Condition: AchievementCondition{Type: "commit_count", Threshold: 10},
|
|
},
|
|
{
|
|
ID: "commit-100",
|
|
Name: "Committed",
|
|
Description: "Made 100 commits",
|
|
Icon: "fa-fire",
|
|
Condition: AchievementCondition{Type: "commit_count", Threshold: 100},
|
|
},
|
|
{
|
|
ID: "commit-500",
|
|
Name: "Code Machine",
|
|
Description: "Made 500 commits",
|
|
Icon: "fa-robot",
|
|
Condition: AchievementCondition{Type: "commit_count", Threshold: 500},
|
|
},
|
|
{
|
|
ID: "commit-1000",
|
|
Name: "Code Warrior",
|
|
Description: "Made 1000 commits",
|
|
Icon: "fa-crown",
|
|
Condition: AchievementCondition{Type: "commit_count", Threshold: 1000},
|
|
},
|
|
{
|
|
ID: "pr-opener",
|
|
Name: "PR Pioneer",
|
|
Description: "Opened your first pull request",
|
|
Icon: "fa-code-pull-request",
|
|
Condition: AchievementCondition{Type: "pr_opened_count", Threshold: 1},
|
|
},
|
|
{
|
|
ID: "pr-10",
|
|
Name: "Pull Request Pro",
|
|
Description: "Opened 10 pull requests",
|
|
Icon: "fa-code-branch",
|
|
Condition: AchievementCondition{Type: "pr_opened_count", Threshold: 10},
|
|
},
|
|
{
|
|
ID: "pr-50",
|
|
Name: "Merge Master",
|
|
Description: "Opened 50 pull requests",
|
|
Icon: "fa-code-merge",
|
|
Condition: AchievementCondition{Type: "pr_opened_count", Threshold: 50},
|
|
},
|
|
{
|
|
ID: "reviewer",
|
|
Name: "Code Reviewer",
|
|
Description: "Reviewed your first pull request",
|
|
Icon: "fa-magnifying-glass-chart",
|
|
Condition: AchievementCondition{Type: "review_count", Threshold: 1},
|
|
},
|
|
{
|
|
ID: "reviewer-25",
|
|
Name: "Review Regular",
|
|
Description: "Reviewed 25 pull requests",
|
|
Icon: "fa-eye",
|
|
Condition: AchievementCondition{Type: "review_count", Threshold: 25},
|
|
},
|
|
{
|
|
ID: "reviewer-100",
|
|
Name: "Review Guru",
|
|
Description: "Reviewed 100 pull requests",
|
|
Icon: "fa-user-graduate",
|
|
Condition: AchievementCondition{Type: "review_count", Threshold: 100},
|
|
},
|
|
{
|
|
ID: "speed-demon",
|
|
Name: "Speed Demon",
|
|
Description: "Average review response under 1 hour",
|
|
Icon: "fa-bolt",
|
|
Condition: AchievementCondition{Type: "avg_review_time_hours", Threshold: 1},
|
|
},
|
|
{
|
|
ID: "quick-responder",
|
|
Name: "Quick Responder",
|
|
Description: "Average review response under 4 hours",
|
|
Icon: "fa-clock",
|
|
Condition: AchievementCondition{Type: "avg_review_time_hours", Threshold: 4},
|
|
},
|
|
{
|
|
ID: "commentator",
|
|
Name: "Commentator",
|
|
Description: "Left 50 PR review comments",
|
|
Icon: "fa-comments",
|
|
Condition: AchievementCondition{Type: "comment_count", Threshold: 50},
|
|
},
|
|
{
|
|
ID: "lines-1000",
|
|
Name: "Thousand Lines",
|
|
Description: "Added 1000 lines of code",
|
|
Icon: "fa-layer-group",
|
|
Condition: AchievementCondition{Type: "lines_added", Threshold: 1000},
|
|
},
|
|
{
|
|
ID: "lines-10000",
|
|
Name: "Ten Thousand",
|
|
Description: "Added 10000 lines of code",
|
|
Icon: "fa-mountain",
|
|
Condition: AchievementCondition{Type: "lines_added", Threshold: 10000},
|
|
},
|
|
{
|
|
ID: "cleaner",
|
|
Name: "Code Cleaner",
|
|
Description: "Deleted 1000 lines of code",
|
|
Icon: "fa-broom",
|
|
Condition: AchievementCondition{Type: "lines_deleted", Threshold: 1000},
|
|
},
|
|
{
|
|
ID: "refactorer",
|
|
Name: "Refactoring Champion",
|
|
Description: "Deleted 10000 lines of code",
|
|
Icon: "fa-recycle",
|
|
Condition: AchievementCondition{Type: "lines_deleted", Threshold: 10000},
|
|
},
|
|
{
|
|
ID: "multi-repo",
|
|
Name: "Multi-Repo Master",
|
|
Description: "Contributed to 5 repositories",
|
|
Icon: "fa-folder-tree",
|
|
Condition: AchievementCondition{Type: "repo_count", Threshold: 5},
|
|
},
|
|
{
|
|
ID: "team-player",
|
|
Name: "Team Player",
|
|
Description: "Reviewed PRs from 10 different contributors",
|
|
Icon: "fa-people-group",
|
|
Condition: AchievementCondition{Type: "unique_reviewees", Threshold: 10},
|
|
},
|
|
// PR Quality achievements
|
|
{
|
|
ID: "big-pr",
|
|
Name: "Heavy Lifter",
|
|
Description: "Merged a PR with 1000+ lines changed",
|
|
Icon: "fa-weight-hanging",
|
|
Condition: AchievementCondition{Type: "largest_pr_size", Threshold: 1000},
|
|
},
|
|
{
|
|
ID: "mega-pr",
|
|
Name: "Mega Merge",
|
|
Description: "Merged a PR with 5000+ lines changed",
|
|
Icon: "fa-dumbbell",
|
|
Condition: AchievementCondition{Type: "largest_pr_size", Threshold: 5000},
|
|
},
|
|
{
|
|
ID: "small-pr-10",
|
|
Name: "Small PR Advocate",
|
|
Description: "Merged 10 PRs under 100 lines",
|
|
Icon: "fa-compress",
|
|
Condition: AchievementCondition{Type: "small_pr_count", Threshold: 10},
|
|
},
|
|
{
|
|
ID: "small-pr-50",
|
|
Name: "Atomic Commits Hero",
|
|
Description: "Merged 50 PRs under 100 lines",
|
|
Icon: "fa-atom",
|
|
Condition: AchievementCondition{Type: "small_pr_count", Threshold: 50},
|
|
},
|
|
{
|
|
ID: "perfect-pr-5",
|
|
Name: "Clean Code",
|
|
Description: "5 PRs merged without changes requested",
|
|
Icon: "fa-check-double",
|
|
Condition: AchievementCondition{Type: "perfect_prs", Threshold: 5},
|
|
},
|
|
{
|
|
ID: "perfect-pr-25",
|
|
Name: "Flawless",
|
|
Description: "25 PRs merged without changes requested",
|
|
Icon: "fa-gem",
|
|
Condition: AchievementCondition{Type: "perfect_prs", Threshold: 25},
|
|
},
|
|
// Activity pattern achievements
|
|
{
|
|
ID: "streak-7",
|
|
Name: "Week Warrior",
|
|
Description: "7 day contribution streak",
|
|
Icon: "fa-calendar-week",
|
|
Condition: AchievementCondition{Type: "longest_streak", Threshold: 7},
|
|
},
|
|
{
|
|
ID: "streak-30",
|
|
Name: "Month Master",
|
|
Description: "30 day contribution streak",
|
|
Icon: "fa-calendar-check",
|
|
Condition: AchievementCondition{Type: "longest_streak", Threshold: 30},
|
|
},
|
|
{
|
|
ID: "early-bird",
|
|
Name: "Early Bird",
|
|
Description: "50 commits before 9am",
|
|
Icon: "fa-sun",
|
|
Condition: AchievementCondition{Type: "early_bird_count", Threshold: 50},
|
|
},
|
|
{
|
|
ID: "night-owl",
|
|
Name: "Night Owl",
|
|
Description: "50 commits after 9pm",
|
|
Icon: "fa-moon",
|
|
Condition: AchievementCondition{Type: "night_owl_count", Threshold: 50},
|
|
},
|
|
{
|
|
ID: "nosferatu",
|
|
Name: "Nosferatu",
|
|
Description: "25 commits between midnight and 4am",
|
|
Icon: "fa-skull",
|
|
Condition: AchievementCondition{Type: "midnight_count", Threshold: 25},
|
|
},
|
|
{
|
|
ID: "weekend-warrior",
|
|
Name: "Weekend Warrior",
|
|
Description: "25 weekend commits",
|
|
Icon: "fa-couch",
|
|
Condition: AchievementCondition{Type: "weekend_warrior", Threshold: 25},
|
|
},
|
|
{
|
|
ID: "active-30",
|
|
Name: "Consistent Contributor",
|
|
Description: "Active on 30 different days",
|
|
Icon: "fa-chart-line",
|
|
Condition: AchievementCondition{Type: "active_days", Threshold: 30},
|
|
},
|
|
{
|
|
ID: "active-100",
|
|
Name: "Dedicated Developer",
|
|
Description: "Active on 100 different days",
|
|
Icon: "fa-fire-flame-curved",
|
|
Condition: AchievementCondition{Type: "active_days", Threshold: 100},
|
|
},
|
|
}
|
|
}
|