diff --git a/config.json b/config.json index c3e4a0b..8fbd882 100644 --- a/config.json +++ b/config.json @@ -10,6 +10,6 @@ } ], "interval": 5, - "ntfy_topic": "your-ntfy-topic" + "ntfy_topic": "hee4waeNguch" } diff --git a/src/main.go b/src/main.go index b2ad3a8..c91ac47 100644 --- a/src/main.go +++ b/src/main.go @@ -1,106 +1,32 @@ package main import ( - "bytes" - "encoding/json" - "fmt" - "io" "log" - "os" - - "net/http" "time" ) -type Config struct { - Repos []RepoConfig `json:"repos"` - Interval int `json:"interval"` // Polling interval in seconds - NtfyTopic string `json:"ntfy_topic"` -} - -type RepoConfig struct { - Owner string `json:"owner"` - Repo string `json:"repo"` -} - -type Commit struct { - Sha string `json:"sha"` - URL string `json:"url"` -} - -type Tag struct { - Name string `json:"name"` - ZipballURL string `json:"zipball_url"` - TarballURL string `json:"tarball_url"` - Commit Commit `json:"commit"` - NodeID string `json:"node_id"` -} - func main() { // Load configuration config := loadConfig("config.json") + notifier := NtfyNotifier{Topic: config.NtfyTopic} + // Main loop for { for _, repo := range config.Repos { - checkForUpdates(repo, config.NtfyTopic) + tag, err := repo.GetLatestTag() + if err != nil { + log.Printf("Failed to get latest tag for %s: %v", repo.Repo, err) + continue + } + if tag.Name == "" { + log.Printf("No tags found for %s", repo.Repo) + continue + } + if notifier.Notify(repo, tag.Name) { + log.Printf("Notified for %s/%s: %s", repo.Owner, repo.Repo, tag.Name) + } } time.Sleep(time.Duration(config.Interval) * time.Second) } } - -func loadConfig(file string) Config { - fh, err := os.OpenFile(file, os.O_RDONLY, 0644) - if err != nil { - log.Fatalf("Failed to open config file: %v", err) - } - data, err := io.ReadAll(fh) - if err != nil { - log.Fatalf("Failed to read config file: %v", err) - } - var config Config - if err := json.Unmarshal(data, &config); err != nil { - log.Fatalf("Failed to parse config file: %v", err) - } - return config -} - -func checkForUpdates(repo RepoConfig, ntfyTopic string) { - url := fmt.Sprintf("https://api.github.com/repos/%s/%s/tags", repo.Owner, repo.Repo) - fmt.Printf(url) - resp, err := http.Get(url) - if err != nil { - log.Printf("Failed to fetch releases for %s/%s: %v", repo.Owner, repo.Repo, err) - return - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - log.Printf("Unexpected response status for %s/%s: %d", repo.Owner, repo.Repo, resp.StatusCode) - return - } - - var tags = []Tag{} - if err := json.NewDecoder(resp.Body).Decode(&tags); err != nil { - log.Printf("Failed to decode response for %s/%s: %v", repo.Owner, repo.Repo, err) - return - } - - latestTag := tags[0].Name - fmt.Printf("Latest release for %s/%s is %s\n", repo.Owner, repo.Repo, latestTag) - - // Notify via ntfy - sendNotification(ntfyTopic, repo, latestTag) -} - -func sendNotification(topic string, repo RepoConfig, tag string) { - ntfyURL := fmt.Sprintf("https://ntfy.sh/%s", topic) - message := fmt.Sprintf("New release for %s/%s: %s", repo.Owner, repo.Repo, tag) - - _, err := http.Post(ntfyURL, "text/plain", bytes.NewBuffer([]byte(message))) - if err != nil { - log.Printf("Failed to send notification: %v", err) - } else { - log.Printf("Notification sent: %s", message) - } -} diff --git a/src/repo.go b/src/repo.go new file mode 100644 index 0000000..45ef804 --- /dev/null +++ b/src/repo.go @@ -0,0 +1,55 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "net/http" +) + +type Repo interface { + GetLatestTag() (Tag, error) +} + +// Description of a repository (owner and name) +type RepoConfig struct { + Owner string `json:"owner"` + Repo string `json:"repo"` +} + +func (r RepoConfig) GetLatestTag() (Tag, error) { + url := fmt.Sprintf("https://api.github.com/repos/%s/%s/tags", r.Owner, r.Repo) + fmt.Printf(url) + resp, err := http.Get(url) + if err != nil { + log.Printf("Failed to fetch releases for %s/%s: %v", r.Owner, r.Repo, err) + return Tag{}, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + log.Printf("Unexpected response status for %s/%s: %d", r.Owner, r.Repo, resp.StatusCode) + return Tag{}, fmt.Errorf("unexpected response status: %d", resp.StatusCode) + } + + var tags = []Tag{} + if err := json.NewDecoder(resp.Body).Decode(&tags); err != nil { + log.Printf("Failed to decode response for %s/%s: %v", r.Owner, r.Repo, err) + return Tag{}, err + } + + return tags[0], nil +} + +type Commit struct { + Sha string `json:"sha"` + URL string `json:"url"` +} + +type Tag struct { + Name string `json:"name"` + ZipballURL string `json:"zipball_url"` + TarballURL string `json:"tarball_url"` + Commit Commit `json:"commit"` + NodeID string `json:"node_id"` +} diff --git a/src/types.go b/src/types.go new file mode 100644 index 0000000..53e5fe9 --- /dev/null +++ b/src/types.go @@ -0,0 +1,54 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "log" + "net/http" + "os" +) + +type Config struct { + Repos []RepoConfig `json:"repos"` + Interval int `json:"interval"` // Polling interval in seconds + NtfyTopic string `json:"ntfy_topic"` +} + +func loadConfig(file string) Config { + fh, err := os.OpenFile(file, os.O_RDONLY, 0644) + if err != nil { + log.Fatalf("Failed to open config file: %v", err) + } + data, err := io.ReadAll(fh) + if err != nil { + log.Fatalf("Failed to read config file: %v", err) + } + var config Config + if err := json.Unmarshal(data, &config); err != nil { + log.Fatalf("Failed to parse config file: %v", err) + } + return config +} + +type Notifier interface { + Notify(repo RepoConfig, tag string) bool +} + +type NtfyNotifier struct { + Topic string +} + +func (n NtfyNotifier) Notify(repo RepoConfig, tag string) bool { + ntfyURL := fmt.Sprintf("https://ntfy.sh/%s", n.Topic) + message := fmt.Sprintf("New release for %s/%s: %s", repo.Owner, repo.Repo, tag) + + _, err := http.Post(ntfyURL, "text/plain", bytes.NewBuffer([]byte(message))) + if err != nil { + log.Printf("Failed to send notification: %v", err) + return false + } + log.Printf("Notification sent: %s", message) + return true +}