mirror of
https://github.com/thegeeklab/github-releases-notifier.git
synced 2024-11-10 23:00:38 +00:00
148 lines
3.9 KiB
Go
148 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/go-kit/kit/log"
|
|
"github.com/go-kit/kit/log/level"
|
|
"github.com/shurcooL/githubv4"
|
|
"github.com/thegeeklab/github-releases-notifier/internal/model"
|
|
)
|
|
|
|
// Checker has a githubv4 client to run queries and also knows about
|
|
// the current repositories releases to compare against.
|
|
type Checker struct {
|
|
logger log.Logger
|
|
client *githubv4.Client
|
|
releases map[string]model.Repository
|
|
}
|
|
|
|
// Run the queries and comparisons for the given repositories in a given interval.
|
|
func (c *Checker) Run(interval time.Duration, repositories []string,
|
|
ignorePre bool, releases chan<- model.Repository) {
|
|
if c.releases == nil {
|
|
c.releases = make(map[string]model.Repository)
|
|
}
|
|
|
|
for {
|
|
for _, repoName := range repositories {
|
|
s := strings.Split(repoName, "/")
|
|
owner, name := s[0], s[1]
|
|
msg := "no new release for repository"
|
|
|
|
nextRepo, err := c.query(owner, name)
|
|
if err != nil {
|
|
level.Warn(c.logger).Log(
|
|
"msg", "failed to query the repository's releases",
|
|
"owner", owner,
|
|
"name", name,
|
|
"err", err,
|
|
)
|
|
continue
|
|
}
|
|
|
|
// For debugging uncomment this next line
|
|
//releases <- nextRepo
|
|
|
|
currRepo, ok := c.releases[repoName]
|
|
|
|
// We've queried the repository for the first time.
|
|
// Saving the current state to compare with the next iteration.
|
|
if !ok {
|
|
c.releases[repoName] = nextRepo
|
|
continue
|
|
}
|
|
|
|
if nextRepo.Release.PublishedAt.After(currRepo.Release.PublishedAt) {
|
|
if !(ignorePre && nextRepo.Release.IsPrerelease) {
|
|
releases <- nextRepo
|
|
c.releases[repoName] = nextRepo
|
|
msg = "found new release for repository"
|
|
} else {
|
|
msg = "ignoring new pre-release for repository"
|
|
}
|
|
}
|
|
|
|
level.Debug(c.logger).Log(
|
|
"msg", msg,
|
|
"owner", owner,
|
|
"name", name,
|
|
)
|
|
}
|
|
time.Sleep(interval)
|
|
}
|
|
}
|
|
|
|
// This should be improved in the future to make batch requests for all watched repositories at once
|
|
// TODO: https://github.com/shurcooL/githubv4/issues/17
|
|
|
|
func (c *Checker) query(owner, name string) (model.Repository, error) {
|
|
var query struct {
|
|
Repository struct {
|
|
ID githubv4.ID
|
|
Name githubv4.String
|
|
Description githubv4.String
|
|
URL githubv4.URI
|
|
|
|
Releases struct {
|
|
Edges []struct {
|
|
Node struct {
|
|
ID githubv4.ID
|
|
Name githubv4.String
|
|
Description githubv4.String
|
|
URL githubv4.URI
|
|
PublishedAt githubv4.DateTime
|
|
IsPrerelease githubv4.Boolean
|
|
}
|
|
}
|
|
} `graphql:"releases(last: 1)"`
|
|
} `graphql:"repository(owner: $owner, name: $name)"`
|
|
}
|
|
|
|
variables := map[string]interface{}{
|
|
"owner": githubv4.String(owner),
|
|
"name": githubv4.String(name),
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
if err := c.client.Query(ctx, &query, variables); err != nil {
|
|
return model.Repository{}, err
|
|
}
|
|
|
|
repositoryID, ok := query.Repository.ID.(string)
|
|
if !ok {
|
|
return model.Repository{}, fmt.Errorf("can't convert repository id to string: %v", query.Repository.ID)
|
|
}
|
|
|
|
if len(query.Repository.Releases.Edges) == 0 {
|
|
return model.Repository{}, fmt.Errorf("can't find any releases for %s/%s", owner, name)
|
|
}
|
|
latestRelease := query.Repository.Releases.Edges[0].Node
|
|
|
|
releaseID, ok := latestRelease.ID.(string)
|
|
if !ok {
|
|
return model.Repository{}, fmt.Errorf("can't convert release id to string: %v", query.Repository.ID)
|
|
}
|
|
|
|
return model.Repository{
|
|
ID: repositoryID,
|
|
Name: string(query.Repository.Name),
|
|
Owner: owner,
|
|
Description: string(query.Repository.Description),
|
|
URL: *query.Repository.URL.URL,
|
|
|
|
Release: model.Release{
|
|
ID: releaseID,
|
|
Name: string(latestRelease.Name),
|
|
Description: string(latestRelease.Description),
|
|
URL: *latestRelease.URL.URL,
|
|
PublishedAt: latestRelease.PublishedAt.Time,
|
|
IsPrerelease: bool(latestRelease.IsPrerelease),
|
|
},
|
|
}, nil
|
|
}
|