multiple content per fetcher

This commit is contained in:
2026-01-20 18:10:26 +01:00
parent 4f168197b8
commit 76933a04d8
7 changed files with 129 additions and 99 deletions

View File

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

View File

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

View File

@@ -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.

View File

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

View File

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

View File

@@ -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()