Files
RenewCMS/internal/infrastructure/update/giteaReleaseFeed.go
T

80 lines
2.0 KiB
Go

package update
import (
domain "RenewCMS/internal/domain/update"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"time"
)
const (
releasesPath = "/api/v1/repos/fsylvain/RenewCMS/releases"
feedRequestTimeout = 10 * time.Second
maxFeedBodyBytes = 4 << 20
)
type GiteaReleaseFeed struct {
baseURL string
client *http.Client
}
var _ domain.ReleaseFeed = &GiteaReleaseFeed{}
type giteaRelease struct {
TagName string `json:"tag_name"`
HTMLURL string `json:"html_url"`
Body string `json:"body"`
Draft bool `json:"draft"`
PublishedAt time.Time `json:"published_at"`
}
func NewGiteaReleaseFeed(baseURL string) *GiteaReleaseFeed {
return &GiteaReleaseFeed{
baseURL: strings.TrimRight(baseURL, "/"),
client: &http.Client{Timeout: feedRequestTimeout},
}
}
func (g *GiteaReleaseFeed) Latest() (domain.Release, error) {
releases, err := g.fetch()
if err != nil {
return domain.Release{}, err
}
return domain.Newest(releases)
}
func (g *GiteaReleaseFeed) fetch() ([]domain.Release, error) {
response, err := g.client.Get(g.baseURL + releasesPath)
if err != nil {
return nil, fmt.Errorf("%w: %v", domain.ErrFeedUnavailable, err)
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%w: status %d", domain.ErrFeedUnavailable, response.StatusCode)
}
var raw []giteaRelease
if err := json.NewDecoder(io.LimitReader(response.Body, maxFeedBodyBytes)).Decode(&raw); err != nil {
return nil, fmt.Errorf("%w: %v", domain.ErrFeedUnavailable, err)
}
return toReleases(raw), nil
}
func toReleases(raw []giteaRelease) []domain.Release {
releases := make([]domain.Release, 0, len(raw))
for _, item := range raw {
if item.Draft {
continue
}
releases = append(releases, domain.Release{
Tag: item.TagName,
URL: item.HTMLURL,
PublishedAt: item.PublishedAt,
Notes: domain.BuildNotes(item.TagName, item.PublishedAt, item.Body),
})
}
return releases
}