MVP
This commit is contained in:
parent
72177679f4
commit
05127ef72b
9 changed files with 97 additions and 7 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.db
|
2
Justfile
Normal file
2
Justfile
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
run:
|
||||||
|
go run src/*.go
|
5
go.mod
Normal file
5
go.mod
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module beretta
|
||||||
|
|
||||||
|
go 1.22.7
|
||||||
|
|
||||||
|
require github.com/mattn/go-sqlite3 v1.14.23 // indirect
|
2
go.sum
Normal file
2
go.sum
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.23 h1:gbShiuAP1W5j9UOksQ06aiiqPMxYecovVGwmTxWtuw0=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.23/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
49
src/db.go
Normal file
49
src/db.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed init.sql
|
||||||
|
var initSQL string
|
||||||
|
|
||||||
|
type Db interface {
|
||||||
|
// CheckAndStore checks if the tag is already stored in the database and stores it if it's not.
|
||||||
|
CheckAndStore(repo, tag string) (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SQLiteDb struct {
|
||||||
|
DB *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SQLiteDb) CheckAndStore(repo, tag string) (bool, error) {
|
||||||
|
var count int
|
||||||
|
err := s.DB.QueryRow("SELECT COUNT(*) FROM tags WHERE repo = ? AND tag = ?", repo, tag).Scan(&count)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if count > 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
_, err = s.DB.Exec("INSERT INTO tags (repo, tag) VALUES (?, ?)", repo, tag)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSQLiteDb creates a new SQLite database connection.
|
||||||
|
// The database is created if it doesn't exist.
|
||||||
|
func NewSQLiteDb(file string) (SQLiteDb, error) {
|
||||||
|
db, err := sql.Open("sqlite3", file)
|
||||||
|
if err != nil {
|
||||||
|
return SQLiteDb{}, err
|
||||||
|
}
|
||||||
|
_, err = db.Exec(initSQL)
|
||||||
|
if err != nil {
|
||||||
|
return SQLiteDb{}, err
|
||||||
|
}
|
||||||
|
return SQLiteDb{DB: db}, nil
|
||||||
|
}
|
5
src/init.sql
Normal file
5
src/init.sql
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS tags (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
repo TEXT NOT NULL,
|
||||||
|
tag TEXT NOT NULL
|
||||||
|
);
|
27
src/main.go
27
src/main.go
|
@ -7,7 +7,17 @@ import (
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Load configuration
|
// Load configuration
|
||||||
config := loadConfig("config.json")
|
config, err := loadConfig("config.json")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to load configuration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create database
|
||||||
|
db, err := NewSQLiteDb("tags.db")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to create database: %v", err)
|
||||||
|
}
|
||||||
|
_ = db
|
||||||
|
|
||||||
notifier := NtfyNotifier{Topic: config.NtfyTopic}
|
notifier := NtfyNotifier{Topic: config.NtfyTopic}
|
||||||
|
|
||||||
|
@ -22,9 +32,20 @@ func main() {
|
||||||
if tag.Name == "" {
|
if tag.Name == "" {
|
||||||
log.Printf("No tags found for %s", repo.Repo)
|
log.Printf("No tags found for %s", repo.Repo)
|
||||||
continue
|
continue
|
||||||
|
_ = notifier
|
||||||
}
|
}
|
||||||
if notifier.Notify(repo, tag.Name) {
|
|
||||||
log.Printf("Notified for %s/%s: %s", repo.Owner, repo.Repo, tag.Name)
|
// Check and store tag
|
||||||
|
stored, err := db.CheckAndStore(repo.Repo, tag.Name)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to store tag for %s: %v", repo.Repo, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if stored {
|
||||||
|
log.Printf("New tag stored for %s: %s", repo.Repo, tag.Name)
|
||||||
|
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)
|
time.Sleep(time.Duration(config.Interval) * time.Second)
|
||||||
|
|
|
@ -19,7 +19,7 @@ type RepoConfig struct {
|
||||||
|
|
||||||
func (r RepoConfig) GetLatestTag() (Tag, error) {
|
func (r RepoConfig) GetLatestTag() (Tag, error) {
|
||||||
url := fmt.Sprintf("https://api.github.com/repos/%s/%s/tags", r.Owner, r.Repo)
|
url := fmt.Sprintf("https://api.github.com/repos/%s/%s/tags", r.Owner, r.Repo)
|
||||||
fmt.Printf(url)
|
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to fetch releases for %s/%s: %v", r.Owner, r.Repo, err)
|
log.Printf("Failed to fetch releases for %s/%s: %v", r.Owner, r.Repo, err)
|
||||||
|
|
11
src/types.go
11
src/types.go
|
@ -16,20 +16,25 @@ type Config struct {
|
||||||
NtfyTopic string `json:"ntfy_topic"`
|
NtfyTopic string `json:"ntfy_topic"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadConfig(file string) Config {
|
func loadConfig(file string) (Config, error) {
|
||||||
|
var config Config
|
||||||
fh, err := os.OpenFile(file, os.O_RDONLY, 0644)
|
fh, err := os.OpenFile(file, os.O_RDONLY, 0644)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to open config file: %v", err)
|
log.Fatalf("Failed to open config file: %v", err)
|
||||||
|
return Config{}, err
|
||||||
}
|
}
|
||||||
data, err := io.ReadAll(fh)
|
data, err := io.ReadAll(fh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to read config file: %v", err)
|
log.Fatalf("Failed to read config file: %v", err)
|
||||||
|
return Config{}, err
|
||||||
}
|
}
|
||||||
var config Config
|
|
||||||
if err := json.Unmarshal(data, &config); err != nil {
|
if err := json.Unmarshal(data, &config); err != nil {
|
||||||
log.Fatalf("Failed to parse config file: %v", err)
|
log.Fatalf("Failed to parse config file: %v", err)
|
||||||
|
return Config{}, err
|
||||||
}
|
}
|
||||||
return config
|
|
||||||
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Notifier interface {
|
type Notifier interface {
|
||||||
|
|
Loading…
Reference in a new issue