feat: implement Live/Remix filtering and add CI/CD pipeline
Some checks failed
Build and Push Docker Image / build (pull_request) Failing after 38s

This commit includes:

1. Live/Remix Filtering Feature:
   - Added ignore_live and ignore_remix columns to artist_settings table (migration 010)
   - Updated ArtistSettings struct with IgnoreLive and IgnoreRemix fields
   - Modified SaveArtistSettings and UpdateArtistSettings to handle new fields
   - Extended FilterOptions struct with IgnoreLive and IgnoreRemix
   - Updated ApplyTypeToggles and ApplyTypeTogglesToReleaseGroups to filter Live/Remix types
   - Added toggleIgnoreLive and toggleIgnoreRemix handlers in web layer
   - Updated ArtistData view model and artist.html template with new toggle UI
   - Comprehensive test coverage for all new functionality

2. CI/CD Pipeline with Gitea Actions:
   - Added .gitea/workflows/docker-build.yml for automated Docker builds
   - Workflow triggers on pushes to main/master and tags, plus PRs
   - Runs Go tests before building
   - Builds and pushes multi-architecture Docker images to gitea.mrixs.me
   - Includes caching for faster subsequent builds
   - Proper tagging strategy (branch, semver, SHA)
   - CI-CD-GUIDE.md documentation

3. Cleanup:
   - Removed temporary build artifacts and coverage files
This commit is contained in:
2026-08-05 22:55:40 +03:00
parent ca8d503c50
commit e73b17673e
14 changed files with 237 additions and 100 deletions

View File

@@ -7,24 +7,18 @@ import (
"time"
)
// DBer is the minimal query interface satisfied by both *sql.DB and *sql.Tx,
// so callers can run statements inside or outside a transaction.
type DBer interface {
Exec(query string, args ...interface{}) (sql.Result, error)
}
// GetArtistSettings retrieves an artist_settings row by ID.
// Returns sql.ErrNoRows if the artist is not found.
func GetArtistSettings(db *DB, id string) (*ArtistSettings, error) {
var (
s ArtistSettings
mbid sql.NullString
s ArtistSettings
mbid sql.NullString
lastSynced sql.NullTime
)
err := db.Conn().QueryRow(
"SELECT id, name, mbid, ignore_singles, ignore_compilations, monitored, last_synced FROM artist_settings WHERE id = ?",
"SELECT id, name, mbid, ignore_singles, ignore_compilations, ignore_live, ignore_remix, monitored, last_synced FROM artist_settings WHERE id = ?",
id,
).Scan(&s.ID, &s.Name, &mbid, &s.IgnoreSingles, &s.IgnoreCompilations, &s.Monitored, &lastSynced)
).Scan(&s.ID, &s.Name, &mbid, &s.IgnoreSingles, &s.IgnoreCompilations, &s.IgnoreLive, &s.IgnoreRemix, &s.Monitored, &lastSynced)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrArtistNotFound
@@ -60,17 +54,19 @@ func TouchArtistSynced(db DBer, artistID string, syncedAt time.Time) error {
// every periodic artist sync.
func SaveArtistSettings(db *DB, settings *ArtistSettings) error {
_, err := db.Conn().Exec(`
INSERT INTO artist_settings (id, name, mbid, ignore_singles, ignore_compilations, monitored, last_synced)
VALUES (?, ?, ?, ?, ?, ?, ?)
INSERT INTO artist_settings (id, name, mbid, ignore_singles, ignore_compilations, ignore_live, ignore_remix, monitored, last_synced)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(id) DO UPDATE SET
name = excluded.name,
mbid = COALESCE(excluded.mbid, artist_settings.mbid),
ignore_singles = excluded.ignore_singles,
ignore_compilations = excluded.ignore_compilations,
ignore_live = excluded.ignore_live,
ignore_remix = excluded.ignore_remix,
monitored = excluded.monitored,
last_synced = COALESCE(excluded.last_synced, artist_settings.last_synced)
`,
settings.ID, settings.Name, nullIfEmpty(settings.MBID), settings.IgnoreSingles, settings.IgnoreCompilations, settings.Monitored, nullIfEmptyTime(settings.LastSynced),
settings.ID, settings.Name, nullIfEmpty(settings.MBID), settings.IgnoreSingles, settings.IgnoreCompilations, settings.IgnoreLive, settings.IgnoreRemix, settings.Monitored, nullIfEmptyTime(settings.LastSynced),
)
if err != nil {
return fmt.Errorf("save artist settings: %w", err)
@@ -99,7 +95,7 @@ func nullIfEmptyTime(t time.Time) interface{} {
// GetAllArtistSettings returns all rows from artist_settings.
func GetAllArtistSettings(db *DB) ([]ArtistSettings, error) {
rows, err := db.Conn().Query(
"SELECT id, name, mbid, ignore_singles, ignore_compilations, monitored, last_synced FROM artist_settings",
"SELECT id, name, mbid, ignore_singles, ignore_compilations, ignore_live, ignore_remix, monitored, last_synced FROM artist_settings",
)
if err != nil {
return nil, fmt.Errorf("query all artist settings: %w", err)
@@ -111,7 +107,7 @@ func GetAllArtistSettings(db *DB) ([]ArtistSettings, error) {
var s ArtistSettings
var mbid sql.NullString
var lastSynced sql.NullTime
if err := rows.Scan(&s.ID, &s.Name, &mbid, &s.IgnoreSingles, &s.IgnoreCompilations, &s.Monitored, &lastSynced); err != nil {
if err := rows.Scan(&s.ID, &s.Name, &mbid, &s.IgnoreSingles, &s.IgnoreCompilations, &s.IgnoreLive, &s.IgnoreRemix, &s.Monitored, &lastSynced); err != nil {
return nil, fmt.Errorf("scan artist settings: %w", err)
}
s.MBID = mbid.String
@@ -127,7 +123,7 @@ func GetAllArtistSettings(db *DB) ([]ArtistSettings, error) {
}
// UpdateArtistSettings updates specific fields of an artist_settings row by ID.
// The updates map keys must match column names: "name", "ignore_singles", "ignore_compilations", "monitored".
// The updates map keys must match column names: "name", "ignore_singles", "ignore_compilations", "monitored", "ignore_live", "ignore_remix".
func UpdateArtistSettings(db *DB, id string, updates map[string]interface{}) error {
if len(updates) == 0 {
return fmt.Errorf("no updates provided")
@@ -164,6 +160,18 @@ func UpdateArtistSettings(db *DB, id string, updates map[string]interface{}) err
}
setClause += "ignore_compilations = ?"
args = append(args, val)
case "ignore_live":
if setClause != "" {
setClause += ", "
}
setClause += "ignore_live = ?"
args = append(args, val)
case "ignore_remix":
if setClause != "" {
setClause += ", "
}
setClause += "ignore_remix = ?"
args = append(args, val)
case "monitored":
if setClause != "" {
setClause += ", "