From 76933a04d8cc49b88fade7f36d6ffd158cc6da48 Mon Sep 17 00:00:00 2001 From: Zsolt Tasnadi Date: Tue, 20 Jan 2026 18:10:26 +0100 Subject: [PATCH] multiple content per fetcher --- env-example | 8 +++++- lib/config.go | 51 +++++++++++++++++++++++++++++-------- lib/fetcher.gitea.go | 40 +++++++++++++---------------- lib/fetcher.go | 7 ++--- lib/fetcher.redmine.go | 33 +++++++++++++----------- lib/fetcher.wikijs.go | 31 ++++++++++++---------- lib/runner.go | 58 ++++++++++++++++++------------------------ 7 files changed, 129 insertions(+), 99 deletions(-) diff --git a/env-example b/env-example index 5a96df4..3e2ee34 100644 --- a/env-example +++ b/env-example @@ -1,12 +1,18 @@ WIKI_BASE_URL= WIKI_TOKEN= +WIKI_CONTENT_LIMIT=10 + REDMINE_BASE_URL= REDMINE_KEY= +REDMINE_CONTENT_LIMIT=10 GITEA_TOKEN= GITEA_BASE_URL= GITEA_REPOS=org/repo1,org/repo2 +GITEA_CONTENT_LIMIT=10 + DISCORD_WEBHOOK= -INTERVAL_MINUTES=5 \ No newline at end of file + +INTERVAL_MINUTES=5 diff --git a/lib/config.go b/lib/config.go index 52ea8df..01c0a59 100644 --- a/lib/config.go +++ b/lib/config.go @@ -1,16 +1,45 @@ package lib -import "time" +import ( + "log" + "os" + "strconv" + "time" + + "github.com/joho/godotenv" +) type Config struct { - WikiBaseURL string - WikiToken string - RedmineBaseURL string - RedmineKey string - GiteaToken string - GiteaBaseURL string - GiteaRepos []string - DiscordWebhook string - DiscordFake bool - Interval time.Duration + WikiBaseURL string + WikiToken string + WikiContentLimit int + RedmineBaseURL string + RedmineKey string + RedmineContentLimit int + GiteaToken string + GiteaBaseURL string + GiteaRepos []string + GiteaContentLimit int + DiscordWebhook string + DiscordFake bool + Interval time.Duration +} + +func envToInteger(key string, defaultValue int) int { + valueStr := os.Getenv(key) + if valueStr == "" { + return defaultValue + } + value, err := strconv.Atoi(valueStr) + if err != nil { + return defaultValue + } + return value + +} + +func loadEnv() { + if err := godotenv.Load(); err != nil { + log.Println("Warning: .env file not found, using environment variables") + } } diff --git a/lib/fetcher.gitea.go b/lib/fetcher.gitea.go index 383048a..ef1f01a 100644 --- a/lib/fetcher.gitea.go +++ b/lib/fetcher.gitea.go @@ -33,41 +33,37 @@ func (f *GiteaFetcher) Fetch() []Entry { continue } - path := fmt.Sprintf("/api/v1/repos/%s/commits?limit=1", repo) - - headers := map[string]string{} - if f.Token != "" { - headers["Authorization"] = "token " + f.Token - } - req := FetcherRequest{ BaseURL: f.BaseURL, - Path: path, + Path: fmt.Sprintf("/api/v1/repos/%s/commits?limit=%d", repo, f.ContentLimit), Method: http.MethodGet, - Headers: headers, + Headers: map[string]string{ + "Authorization": "token " + f.Token, + }, } - var resp GiteaResponse - if err := req.Run(&resp); err != nil { + var response GiteaResponse + if err := req.Run(&response); err != nil { continue } - if len(resp) == 0 { + if len(response) == 0 { continue } - commit := resp[0] - cacheKey := "gitea_" + url.QueryEscape(f.BaseURL+path) + for _, content := range response { + cacheKey := "gitea_commit_" + url.QueryEscape(f.BaseURL+repo+"_"+content.Sha) - entry := f.TryCreateEntry( - cacheKey, - commit.Sha, - fmt.Sprintf("📝 [%s] - (%s) %s", f.Name(), repo, commit.Commit.Message), - commit.HTMLURL, - ) + entry := f.TryCreateEntry( + cacheKey, + content.Sha, + fmt.Sprintf("📝 [%s] - (%s) %s", f.Name(), repo, content.Commit.Message), + content.HTMLURL, + ) - if entry != nil { - entries = append(entries, *entry) + if entry != nil { + entries = append(entries, *entry) + } } } diff --git a/lib/fetcher.go b/lib/fetcher.go index c55d3c9..0d1f23a 100644 --- a/lib/fetcher.go +++ b/lib/fetcher.go @@ -21,9 +21,10 @@ type Fetcher interface { // BaseFetcher contains common fields for all fetchers. type BaseFetcher struct { - BaseURL string - Token string - Cache *Cache + BaseURL string + Token string + Cache *Cache + ContentLimit int } // TryCreateEntry checks the cache and creates an Entry if the value has changed. diff --git a/lib/fetcher.redmine.go b/lib/fetcher.redmine.go index cfc287c..b5c521f 100644 --- a/lib/fetcher.redmine.go +++ b/lib/fetcher.redmine.go @@ -22,34 +22,37 @@ func (f *RedmineFetcher) Name() string { } func (f *RedmineFetcher) Fetch() []Entry { + var entries []Entry + path := fmt.Sprintf("/issues.json?limit=%d&sort=updated_on:desc", f.ContentLimit) req := FetcherRequest{ BaseURL: f.BaseURL, - Path: "/issues.json?limit=1&sort=updated_on:desc", + Path: path, Method: http.MethodGet, Headers: map[string]string{ "X-Redmine-API-Key": f.Token, }, } - var resp RedmineResponse - if err := req.Run(&resp); err != nil { + var response RedmineResponse + if err := req.Run(&response); err != nil { return nil } - if len(resp.Issues) == 0 { + if len(response.Issues) == 0 { return nil } - issue := resp.Issues[0] - entry := f.TryCreateEntry( - "redmine", - issue.UpdatedOn, - fmt.Sprintf("🎫 [%s] - #%d %s", f.Name(), issue.ID, issue.Subject), - fmt.Sprintf("%s/issues/%d", f.BaseURL, issue.ID), - ) - - if entry != nil { - return []Entry{*entry} + for _, content := range response.Issues { + entry := f.TryCreateEntry( + fmt.Sprintf("redmine_%d", content.ID), + content.UpdatedOn, + fmt.Sprintf("🎫 [%s] - #%d %s", f.Name(), content.ID, content.Subject), + fmt.Sprintf("%s/issues/%d", f.BaseURL, content.ID), + ) + if entry != nil { + entries = append(entries, *entry) + } } - return nil + + return entries } diff --git a/lib/fetcher.wikijs.go b/lib/fetcher.wikijs.go index ee6fe2a..7b8c927 100644 --- a/lib/fetcher.wikijs.go +++ b/lib/fetcher.wikijs.go @@ -26,7 +26,8 @@ func (f *WikiFetcher) Name() string { } func (f *WikiFetcher) Fetch() []Entry { - query := `{"query":"{ pages { list(orderBy: UPDATED, orderByDirection: DESC, limit: 1){ path, updatedAt, title }}}"}` + var entries []Entry + query := fmt.Sprintf(`{"query":"{ pages { list(orderBy: UPDATED, orderByDirection: DESC, limit: %d){ path, updatedAt, title }}}"}`, f.ContentLimit) req := FetcherRequest{ BaseURL: f.BaseURL, @@ -39,25 +40,27 @@ func (f *WikiFetcher) Fetch() []Entry { Body: []byte(query), } - var resp WikiResponse - if err := req.Run(&resp); err != nil { + var response WikiResponse + if err := req.Run(&response); err != nil { return nil } - if len(resp.Data.Pages.List) == 0 { + if len(response.Data.Pages.List) == 0 { return nil } - page := resp.Data.Pages.List[0] - entry := f.TryCreateEntry( - "wiki", - page.UpdatedAt, - fmt.Sprintf("📖 [%s] - %s", f.Name(), page.Title), - fmt.Sprintf("%s/%s", f.BaseURL, page.Path), - ) + for _, content := range response.Data.Pages.List { + entry := f.TryCreateEntry( + "wiki_"+content.Path, + content.UpdatedAt, + fmt.Sprintf("📖 [%s] - %s", f.Name(), content.Title), + fmt.Sprintf("%s/%s", f.BaseURL, content.Path), + ) - if entry != nil { - return []Entry{*entry} + if entry != nil { + entries = append(entries, *entry) + } } - return nil + + return entries } diff --git a/lib/runner.go b/lib/runner.go index 98f132a..f0538d1 100644 --- a/lib/runner.go +++ b/lib/runner.go @@ -4,30 +4,25 @@ import ( "fmt" "log" "os" - "strconv" "strings" "time" - - "github.com/joho/godotenv" ) func getConfig() Config { - intervalMinutes, err := strconv.Atoi(os.Getenv("INTERVAL_MINUTES")) - if err != nil { - intervalMinutes = 5 - } - return Config{ - WikiBaseURL: os.Getenv("WIKI_BASE_URL"), - WikiToken: os.Getenv("WIKI_TOKEN"), - RedmineBaseURL: os.Getenv("REDMINE_BASE_URL"), - RedmineKey: os.Getenv("REDMINE_KEY"), - GiteaToken: os.Getenv("GITEA_TOKEN"), - GiteaBaseURL: os.Getenv("GITEA_BASE_URL"), - GiteaRepos: strings.Split(os.Getenv("GITEA_REPOS"), ","), - DiscordWebhook: os.Getenv("DISCORD_WEBHOOK"), - DiscordFake: os.Getenv("DISCORD_FAKE") == "true", - Interval: time.Duration(intervalMinutes) * time.Minute, + WikiBaseURL: os.Getenv("WIKI_BASE_URL"), + WikiToken: os.Getenv("WIKI_TOKEN"), + WikiContentLimit: envToInteger("WIKI_CONTENT_LIMIT", 10), + RedmineBaseURL: os.Getenv("REDMINE_BASE_URL"), + RedmineKey: os.Getenv("REDMINE_KEY"), + RedmineContentLimit: envToInteger("REDMINE_CONTENT_LIMIT", 10), + GiteaToken: os.Getenv("GITEA_TOKEN"), + GiteaBaseURL: os.Getenv("GITEA_BASE_URL"), + GiteaRepos: strings.Split(os.Getenv("GITEA_REPOS"), ","), + GiteaContentLimit: envToInteger("GITEA_CONTENT_LIMIT", 10), + DiscordWebhook: os.Getenv("DISCORD_WEBHOOK"), + DiscordFake: os.Getenv("DISCORD_FAKE") == "true", + Interval: time.Duration(envToInteger("INTERVAL_MINUTES", 5)) * time.Minute, } } @@ -35,24 +30,27 @@ func getFetchers(config *Config, cache *Cache) []Fetcher { return []Fetcher{ &GiteaFetcher{ BaseFetcher: BaseFetcher{ - BaseURL: config.GiteaBaseURL, - Token: config.GiteaToken, - Cache: cache, + BaseURL: config.GiteaBaseURL, + Token: config.GiteaToken, + Cache: cache, + ContentLimit: config.GiteaContentLimit, }, Repos: config.GiteaRepos, }, &WikiFetcher{ BaseFetcher: BaseFetcher{ - BaseURL: config.WikiBaseURL, - Token: config.WikiToken, - Cache: cache, + BaseURL: config.WikiBaseURL, + Token: config.WikiToken, + Cache: cache, + ContentLimit: config.WikiContentLimit, }, }, &RedmineFetcher{ BaseFetcher: BaseFetcher{ - BaseURL: config.RedmineBaseURL, - Token: config.RedmineKey, - Cache: cache, + BaseURL: config.RedmineBaseURL, + Token: config.RedmineKey, + Cache: cache, + ContentLimit: config.RedmineContentLimit, }, }, } @@ -82,12 +80,6 @@ func getMessages(fetchers []Fetcher) []string { return messages } -func loadEnv() { - if err := godotenv.Load(); err != nil { - log.Println("Warning: .env file not found, using environment variables") - } -} - func Runner() { loadEnv() config := getConfig()