multiple content per fetcher
This commit is contained in:
@@ -1,12 +1,18 @@
|
|||||||
WIKI_BASE_URL=
|
WIKI_BASE_URL=
|
||||||
WIKI_TOKEN=
|
WIKI_TOKEN=
|
||||||
|
WIKI_CONTENT_LIMIT=10
|
||||||
|
|
||||||
|
|
||||||
REDMINE_BASE_URL=
|
REDMINE_BASE_URL=
|
||||||
REDMINE_KEY=
|
REDMINE_KEY=
|
||||||
|
REDMINE_CONTENT_LIMIT=10
|
||||||
|
|
||||||
GITEA_TOKEN=
|
GITEA_TOKEN=
|
||||||
GITEA_BASE_URL=
|
GITEA_BASE_URL=
|
||||||
GITEA_REPOS=org/repo1,org/repo2
|
GITEA_REPOS=org/repo1,org/repo2
|
||||||
|
GITEA_CONTENT_LIMIT=10
|
||||||
|
|
||||||
|
|
||||||
DISCORD_WEBHOOK=
|
DISCORD_WEBHOOK=
|
||||||
INTERVAL_MINUTES=5
|
|
||||||
|
INTERVAL_MINUTES=5
|
||||||
|
|||||||
@@ -1,16 +1,45 @@
|
|||||||
package lib
|
package lib
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
WikiBaseURL string
|
WikiBaseURL string
|
||||||
WikiToken string
|
WikiToken string
|
||||||
RedmineBaseURL string
|
WikiContentLimit int
|
||||||
RedmineKey string
|
RedmineBaseURL string
|
||||||
GiteaToken string
|
RedmineKey string
|
||||||
GiteaBaseURL string
|
RedmineContentLimit int
|
||||||
GiteaRepos []string
|
GiteaToken string
|
||||||
DiscordWebhook string
|
GiteaBaseURL string
|
||||||
DiscordFake bool
|
GiteaRepos []string
|
||||||
Interval time.Duration
|
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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,41 +33,37 @@ func (f *GiteaFetcher) Fetch() []Entry {
|
|||||||
continue
|
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{
|
req := FetcherRequest{
|
||||||
BaseURL: f.BaseURL,
|
BaseURL: f.BaseURL,
|
||||||
Path: path,
|
Path: fmt.Sprintf("/api/v1/repos/%s/commits?limit=%d", repo, f.ContentLimit),
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Headers: headers,
|
Headers: map[string]string{
|
||||||
|
"Authorization": "token " + f.Token,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp GiteaResponse
|
var response GiteaResponse
|
||||||
if err := req.Run(&resp); err != nil {
|
if err := req.Run(&response); err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(resp) == 0 {
|
if len(response) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
commit := resp[0]
|
for _, content := range response {
|
||||||
cacheKey := "gitea_" + url.QueryEscape(f.BaseURL+path)
|
cacheKey := "gitea_commit_" + url.QueryEscape(f.BaseURL+repo+"_"+content.Sha)
|
||||||
|
|
||||||
entry := f.TryCreateEntry(
|
entry := f.TryCreateEntry(
|
||||||
cacheKey,
|
cacheKey,
|
||||||
commit.Sha,
|
content.Sha,
|
||||||
fmt.Sprintf("📝 [%s] - (%s) %s", f.Name(), repo, commit.Commit.Message),
|
fmt.Sprintf("📝 [%s] - (%s) %s", f.Name(), repo, content.Commit.Message),
|
||||||
commit.HTMLURL,
|
content.HTMLURL,
|
||||||
)
|
)
|
||||||
|
|
||||||
if entry != nil {
|
if entry != nil {
|
||||||
entries = append(entries, *entry)
|
entries = append(entries, *entry)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ type Fetcher interface {
|
|||||||
|
|
||||||
// BaseFetcher contains common fields for all fetchers.
|
// BaseFetcher contains common fields for all fetchers.
|
||||||
type BaseFetcher struct {
|
type BaseFetcher struct {
|
||||||
BaseURL string
|
BaseURL string
|
||||||
Token string
|
Token string
|
||||||
Cache *Cache
|
Cache *Cache
|
||||||
|
ContentLimit int
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryCreateEntry checks the cache and creates an Entry if the value has changed.
|
// TryCreateEntry checks the cache and creates an Entry if the value has changed.
|
||||||
|
|||||||
@@ -22,34 +22,37 @@ func (f *RedmineFetcher) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *RedmineFetcher) Fetch() []Entry {
|
func (f *RedmineFetcher) Fetch() []Entry {
|
||||||
|
var entries []Entry
|
||||||
|
path := fmt.Sprintf("/issues.json?limit=%d&sort=updated_on:desc", f.ContentLimit)
|
||||||
req := FetcherRequest{
|
req := FetcherRequest{
|
||||||
BaseURL: f.BaseURL,
|
BaseURL: f.BaseURL,
|
||||||
Path: "/issues.json?limit=1&sort=updated_on:desc",
|
Path: path,
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
"X-Redmine-API-Key": f.Token,
|
"X-Redmine-API-Key": f.Token,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp RedmineResponse
|
var response RedmineResponse
|
||||||
if err := req.Run(&resp); err != nil {
|
if err := req.Run(&response); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(resp.Issues) == 0 {
|
if len(response.Issues) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
issue := resp.Issues[0]
|
for _, content := range response.Issues {
|
||||||
entry := f.TryCreateEntry(
|
entry := f.TryCreateEntry(
|
||||||
"redmine",
|
fmt.Sprintf("redmine_%d", content.ID),
|
||||||
issue.UpdatedOn,
|
content.UpdatedOn,
|
||||||
fmt.Sprintf("🎫 [%s] - #%d %s", f.Name(), issue.ID, issue.Subject),
|
fmt.Sprintf("🎫 [%s] - #%d %s", f.Name(), content.ID, content.Subject),
|
||||||
fmt.Sprintf("%s/issues/%d", f.BaseURL, issue.ID),
|
fmt.Sprintf("%s/issues/%d", f.BaseURL, content.ID),
|
||||||
)
|
)
|
||||||
|
if entry != nil {
|
||||||
if entry != nil {
|
entries = append(entries, *entry)
|
||||||
return []Entry{*entry}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
return entries
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ func (f *WikiFetcher) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *WikiFetcher) Fetch() []Entry {
|
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{
|
req := FetcherRequest{
|
||||||
BaseURL: f.BaseURL,
|
BaseURL: f.BaseURL,
|
||||||
@@ -39,25 +40,27 @@ func (f *WikiFetcher) Fetch() []Entry {
|
|||||||
Body: []byte(query),
|
Body: []byte(query),
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp WikiResponse
|
var response WikiResponse
|
||||||
if err := req.Run(&resp); err != nil {
|
if err := req.Run(&response); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(resp.Data.Pages.List) == 0 {
|
if len(response.Data.Pages.List) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
page := resp.Data.Pages.List[0]
|
for _, content := range response.Data.Pages.List {
|
||||||
entry := f.TryCreateEntry(
|
entry := f.TryCreateEntry(
|
||||||
"wiki",
|
"wiki_"+content.Path,
|
||||||
page.UpdatedAt,
|
content.UpdatedAt,
|
||||||
fmt.Sprintf("📖 [%s] - %s", f.Name(), page.Title),
|
fmt.Sprintf("📖 [%s] - %s", f.Name(), content.Title),
|
||||||
fmt.Sprintf("%s/%s", f.BaseURL, page.Path),
|
fmt.Sprintf("%s/%s", f.BaseURL, content.Path),
|
||||||
)
|
)
|
||||||
|
|
||||||
if entry != nil {
|
if entry != nil {
|
||||||
return []Entry{*entry}
|
entries = append(entries, *entry)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
return entries
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,30 +4,25 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getConfig() Config {
|
func getConfig() Config {
|
||||||
intervalMinutes, err := strconv.Atoi(os.Getenv("INTERVAL_MINUTES"))
|
|
||||||
if err != nil {
|
|
||||||
intervalMinutes = 5
|
|
||||||
}
|
|
||||||
|
|
||||||
return Config{
|
return Config{
|
||||||
WikiBaseURL: os.Getenv("WIKI_BASE_URL"),
|
WikiBaseURL: os.Getenv("WIKI_BASE_URL"),
|
||||||
WikiToken: os.Getenv("WIKI_TOKEN"),
|
WikiToken: os.Getenv("WIKI_TOKEN"),
|
||||||
RedmineBaseURL: os.Getenv("REDMINE_BASE_URL"),
|
WikiContentLimit: envToInteger("WIKI_CONTENT_LIMIT", 10),
|
||||||
RedmineKey: os.Getenv("REDMINE_KEY"),
|
RedmineBaseURL: os.Getenv("REDMINE_BASE_URL"),
|
||||||
GiteaToken: os.Getenv("GITEA_TOKEN"),
|
RedmineKey: os.Getenv("REDMINE_KEY"),
|
||||||
GiteaBaseURL: os.Getenv("GITEA_BASE_URL"),
|
RedmineContentLimit: envToInteger("REDMINE_CONTENT_LIMIT", 10),
|
||||||
GiteaRepos: strings.Split(os.Getenv("GITEA_REPOS"), ","),
|
GiteaToken: os.Getenv("GITEA_TOKEN"),
|
||||||
DiscordWebhook: os.Getenv("DISCORD_WEBHOOK"),
|
GiteaBaseURL: os.Getenv("GITEA_BASE_URL"),
|
||||||
DiscordFake: os.Getenv("DISCORD_FAKE") == "true",
|
GiteaRepos: strings.Split(os.Getenv("GITEA_REPOS"), ","),
|
||||||
Interval: time.Duration(intervalMinutes) * time.Minute,
|
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{
|
return []Fetcher{
|
||||||
&GiteaFetcher{
|
&GiteaFetcher{
|
||||||
BaseFetcher: BaseFetcher{
|
BaseFetcher: BaseFetcher{
|
||||||
BaseURL: config.GiteaBaseURL,
|
BaseURL: config.GiteaBaseURL,
|
||||||
Token: config.GiteaToken,
|
Token: config.GiteaToken,
|
||||||
Cache: cache,
|
Cache: cache,
|
||||||
|
ContentLimit: config.GiteaContentLimit,
|
||||||
},
|
},
|
||||||
Repos: config.GiteaRepos,
|
Repos: config.GiteaRepos,
|
||||||
},
|
},
|
||||||
&WikiFetcher{
|
&WikiFetcher{
|
||||||
BaseFetcher: BaseFetcher{
|
BaseFetcher: BaseFetcher{
|
||||||
BaseURL: config.WikiBaseURL,
|
BaseURL: config.WikiBaseURL,
|
||||||
Token: config.WikiToken,
|
Token: config.WikiToken,
|
||||||
Cache: cache,
|
Cache: cache,
|
||||||
|
ContentLimit: config.WikiContentLimit,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&RedmineFetcher{
|
&RedmineFetcher{
|
||||||
BaseFetcher: BaseFetcher{
|
BaseFetcher: BaseFetcher{
|
||||||
BaseURL: config.RedmineBaseURL,
|
BaseURL: config.RedmineBaseURL,
|
||||||
Token: config.RedmineKey,
|
Token: config.RedmineKey,
|
||||||
Cache: cache,
|
Cache: cache,
|
||||||
|
ContentLimit: config.RedmineContentLimit,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -82,12 +80,6 @@ func getMessages(fetchers []Fetcher) []string {
|
|||||||
return messages
|
return messages
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadEnv() {
|
|
||||||
if err := godotenv.Load(); err != nil {
|
|
||||||
log.Println("Warning: .env file not found, using environment variables")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Runner() {
|
func Runner() {
|
||||||
loadEnv()
|
loadEnv()
|
||||||
config := getConfig()
|
config := getConfig()
|
||||||
|
|||||||
Reference in New Issue
Block a user