autobrr/pkg/version/version.go
soup 0391629862
chore(license): update copyright year in headers (#1929)
* chore: update copyright year in license headers

* Revert "chore: update copyright year in license headers"

This reverts commit 3e58129c431b9a491089ce36b908f9bb6ba38ed3.

* chore: update copyright year in license headers

* fix: sort go imports

* fix: add missing license headers
2025-01-06 22:23:19 +01:00

182 lines
4.6 KiB
Go

// Copyright (c) 2021 - 2025, Ludvig Lundgren and the autobrr contributors.
// SPDX-License-Identifier: GPL-2.0-or-later
package version
import (
"context"
"encoding/json"
"fmt"
"net/http"
"runtime"
"time"
"github.com/autobrr/autobrr/pkg/errors"
"github.com/autobrr/autobrr/pkg/sharedhttp"
goversion "github.com/hashicorp/go-version"
)
// Release is a GitHub release
type Release struct {
ID int64 `json:"id,omitempty"`
NodeID string `json:"node_id,omitempty"`
URL string `json:"url,omitempty"`
HtmlURL string `json:"html_url,omitempty"`
TagName string `json:"tag_name,omitempty"`
TargetCommitish string `json:"target_commitish,omitempty"`
Name *string `json:"name,omitempty"`
Body *string `json:"body,omitempty"`
Draft bool `json:"draft,omitempty"`
Prerelease bool `json:"prerelease,omitempty"`
CreatedAt time.Time `json:"created_at"`
PublishedAt time.Time `json:"published_at"`
Author Author `json:"author"`
Assets []Asset `json:"assets"`
}
type Author struct {
Login string `json:"login"`
Id int64 `json:"id"`
NodeId string `json:"node_id"`
AvatarUrl string `json:"avatar_url"`
GravatarId string `json:"gravatar_id"`
Url string `json:"url"`
HtmlUrl string `json:"html_url"`
Type string `json:"type"`
}
type Asset struct {
Url string `json:"url"`
Id int64 `json:"id"`
NodeId string `json:"node_id"`
Name string `json:"name"`
Label string `json:"label"`
Uploader Author `json:"uploader"`
ContentType string `json:"content_type"`
State string `json:"state"`
Size int64 `json:"size"`
DownloadCount int64 `json:"download_count"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
BrowserDownloadUrl string `json:"browser_download_url"`
}
func (r *Release) IsPreOrDraft() bool {
if r.Draft || r.Prerelease {
return true
}
return false
}
type Checker struct {
// user/repo-name or org/repo-name
Owner string
Repo string
CurrentVersion string
httpClient *http.Client
}
func NewChecker(owner, repo, currentVersion string) *Checker {
return &Checker{
Owner: owner,
Repo: repo,
CurrentVersion: currentVersion,
httpClient: &http.Client{
Timeout: time.Second * 30,
Transport: sharedhttp.Transport,
},
}
}
func (c *Checker) get(ctx context.Context) (*Release, error) {
url := fmt.Sprintf("https://api.autobrr.com/repos/%s/%s/releases/latest", c.Owner, c.Repo)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
}
req.Header.Set("Accept", "application/vnd.github.v3+json")
req.Header.Set("User-Agent", c.buildUserAgent())
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("error getting releases for %v: %s", c.Repo, resp.Status)
}
var release Release
dec := json.NewDecoder(resp.Body)
if err := dec.Decode(&release); err != nil {
return nil, err
}
return &release, nil
}
func (c *Checker) CheckNewVersion(ctx context.Context, version string) (bool, *Release, error) {
if isDevelop(version) {
return false, nil, nil
}
release, err := c.get(ctx)
if err != nil {
return false, nil, err
}
newAvailable, _, err := c.checkNewVersion(version, release)
if err != nil {
return false, nil, err
}
if !newAvailable {
return false, nil, nil
}
return true, release, nil
}
func (c *Checker) checkNewVersion(version string, release *Release) (bool, string, error) {
currentVersion, err := goversion.NewVersion(version)
if err != nil {
return false, "", errors.Wrap(err, "error parsing current version")
}
releaseVersion, err := goversion.NewVersion(release.TagName)
if err != nil {
return false, "", errors.Wrap(err, "error parsing release version")
}
if len(currentVersion.Prerelease()) == 0 && len(releaseVersion.Prerelease()) > 0 {
return false, "", nil
}
if releaseVersion.GreaterThan(currentVersion) {
// new update available
return true, releaseVersion.String(), nil
}
return false, "", nil
}
func (c *Checker) buildUserAgent() string {
return fmt.Sprintf("autobrr/%s (%s %s)", c.CurrentVersion, runtime.GOOS, runtime.GOARCH)
}
func isDevelop(version string) bool {
tags := []string{"dev", "develop", "master", "latest", ""}
for _, tag := range tags {
if version == tag {
return true
}
}
return false
}