147 lines
3.2 KiB
Go
147 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"code.gitea.io/sdk/gitea"
|
|
)
|
|
|
|
func main() {
|
|
url := os.Getenv("GITEA_URL")
|
|
token := os.Getenv("GITEA_TOKEN")
|
|
repoFullName := os.Getenv("GITEA_REPO") // format: owner/repo
|
|
orgName := os.Getenv("GITEA_ORG")
|
|
|
|
if url == "" || token == "" {
|
|
log.Fatal("Missing required environment variables: GITEA_URL, GITEA_TOKEN")
|
|
}
|
|
|
|
if repoFullName == "" && orgName == "" {
|
|
log.Fatal("Either GITEA_REPO or GITEA_ORG must be set")
|
|
}
|
|
|
|
client, err := gitea.NewClient(url, gitea.SetToken(token))
|
|
if err != nil {
|
|
log.Fatalf("Failed to create Gitea client: %v", err)
|
|
}
|
|
|
|
var repos []*gitea.Repository
|
|
if orgName != "" {
|
|
fmt.Printf("Fetching all repositories for organization: %s\n", orgName)
|
|
page := 1
|
|
for {
|
|
orgRepos, _, err := client.ListOrgRepos(orgName, gitea.ListOrgReposOptions{
|
|
ListOptions: gitea.ListOptions{Page: page, PageSize: 50},
|
|
})
|
|
if err != nil {
|
|
log.Fatalf("Failed to fetch organization repositories: %v", err)
|
|
}
|
|
if len(orgRepos) == 0 {
|
|
break
|
|
}
|
|
repos = append(repos, orgRepos...)
|
|
page++
|
|
}
|
|
} else {
|
|
parts := strings.Split(repoFullName, "/")
|
|
if len(parts) != 2 {
|
|
log.Fatal("GITEA_REPO must be in format 'owner/repo'")
|
|
}
|
|
repo, _, err := client.GetRepo(parts[0], parts[1])
|
|
if err != nil {
|
|
log.Fatalf("Failed to fetch repository: %v", err)
|
|
}
|
|
repos = append(repos, repo)
|
|
}
|
|
|
|
// Start date for Sprint 1 (2024-10-02)
|
|
startDate := time.Date(2025, 5, 2, 0, 0, 0, 0, time.Local)
|
|
|
|
// user -> bucketIndex -> hours
|
|
data := make(map[string]map[int]float64)
|
|
maxBucket := 0
|
|
|
|
for _, r := range repos {
|
|
fmt.Printf("Processing repository: %s/%s\n", r.Owner.UserName, r.Name)
|
|
page := 1
|
|
for {
|
|
times, _, err := client.ListRepoTrackedTimes(r.Owner.UserName, r.Name, gitea.ListTrackedTimesOptions{
|
|
ListOptions: gitea.ListOptions{Page: page, PageSize: 50},
|
|
})
|
|
if err != nil {
|
|
fmt.Printf("Warning: Failed to fetch time tracking for %s (page %d): %v\n", r.Name, page, err)
|
|
break
|
|
}
|
|
if len(times) == 0 {
|
|
break
|
|
}
|
|
|
|
for _, t := range times {
|
|
if t.Created.Before(startDate) {
|
|
continue
|
|
}
|
|
|
|
daysSinceStart := int(t.Created.Sub(startDate).Hours() / 24)
|
|
bucketIndex := daysSinceStart / 14
|
|
if bucketIndex < 0 {
|
|
continue
|
|
}
|
|
|
|
if bucketIndex > maxBucket {
|
|
maxBucket = bucketIndex
|
|
}
|
|
|
|
userName := t.UserName
|
|
if data[userName] == nil {
|
|
data[userName] = make(map[int]float64)
|
|
}
|
|
|
|
hours := float64(t.Time) / 3600.0
|
|
data[userName][bucketIndex] += hours
|
|
}
|
|
page++
|
|
}
|
|
}
|
|
|
|
if len(data) == 0 {
|
|
fmt.Println("No time tracking entries found.")
|
|
return
|
|
}
|
|
|
|
// Print Table
|
|
users := make([]string, 0, len(data))
|
|
for u := range data {
|
|
users = append(users, u)
|
|
}
|
|
sort.Strings(users)
|
|
|
|
// Header
|
|
fmt.Print("\nNutzer ")
|
|
for i := 0; i <= maxBucket; i++ {
|
|
start := startDate.AddDate(0, 0, i*14)
|
|
fmt.Printf("| %s ", start.Format("02.01."))
|
|
}
|
|
fmt.Println("| Gesamt")
|
|
fmt.Println(strings.Repeat("-", 14+(maxBucket+1)*10+8))
|
|
|
|
for _, u := range users {
|
|
fmt.Printf("%-12s ", u)
|
|
total := 0.0
|
|
for i := 0; i <= maxBucket; i++ {
|
|
h := data[u][i]
|
|
total += h
|
|
if h > 0 {
|
|
fmt.Printf("| %7.1fh ", h)
|
|
} else {
|
|
fmt.Printf("| %8s ", "-")
|
|
}
|
|
}
|
|
fmt.Printf("| %7.1fh\n", total)
|
|
}
|
|
}
|