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) } }