Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ Stale trays (no heartbeat for 2+ minutes) are automatically cleaned up.
## Prerequisites

- Go 1.25+
- MongoDB
- A [GitHub App](https://docs.github.com/en/apps/creating-github-apps) with Actions read/write permissions, installed on your organization
- Docker and/or GCP credentials depending on your provider choice
- A database: **SQLite** (no external dependencies) or **MongoDB**

## Quick start

Expand All @@ -71,8 +71,8 @@ server:
advertiseUrl: https://cattery.example.com

database:
uri: mongodb://localhost:27017/
database: cattery
type: sqlite
path: /var/lib/cattery/cattery.db

github:
- name: my-org
Expand Down
21 changes: 15 additions & 6 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,16 @@ server:
advertiseUrl: https://example.org
agentSecret: my-secret-token

# SQLite (default):
database:
uri: mongodb://localhost:27017/
database: cattery
type: sqlite
path: /var/lib/cattery/cattery.db

# Or MongoDB:
# database:
# type: mongodb
# uri: mongodb://localhost:27017/
# database: cattery

github:
- name: my-org
Expand Down Expand Up @@ -74,10 +81,12 @@ trayTypes:

#### database

| Key | Type | Required | Description |
|----------|--------|----------|---------------------------------------------------------------|
| uri | string | yes | MongoDB connection string (e.g., mongodb://localhost:27017/). |
| database | string | yes | Database name (e.g., cattery). |
| Key | Type | Required | Description |
|----------|--------|-------------------|----------------------------------------------------------------------|
| type | string | no | Database backend: `sqlite` (default) or `mongodb`. |
| path | string | yes (for sqlite) | Path to the SQLite database file (e.g., /var/lib/cattery/cattery.db) |
| uri | string | yes (for mongodb) | MongoDB connection string (e.g., mongodb://localhost:27017/). |
| database | string | yes (for mongodb) | MongoDB database name (e.g., cattery). |

#### github
A list of GitHub organizations/accounts the server manages via a GitHub App.
Expand Down
11 changes: 9 additions & 2 deletions examples/example-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@ server:
listenAddress: "0.0.0.0:5137"
advertiseUrl: https://cattery.my-org.com

# SQLite (default, zero external dependencies):
database:
uri: mongodb://localhost:27017/cattery
database: cattery
type: sqlite
path: /var/lib/cattery/cattery.db

# MongoDB (uncomment to use instead of SQLite):
# database:
# type: mongodb
# uri: mongodb://localhost:27017/cattery
# database: cattery

github:
- name: paritytech-stg
Expand Down
10 changes: 9 additions & 1 deletion src/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
Expand All @@ -45,12 +46,15 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.18.2 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/procfs v0.19.2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/sagikazarmark/locafero v0.12.0 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
Expand All @@ -71,12 +75,16 @@ require (
golang.org/x/net v0.48.0 // indirect
golang.org/x/oauth2 v0.34.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/text v0.33.0 // indirect
google.golang.org/genproto v0.0.0-20251222181119-0a764e51fe1b // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect
google.golang.org/grpc v1.78.0 // indirect
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.70.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
modernc.org/sqlite v1.48.2 // indirect
)
17 changes: 17 additions & 0 deletions src/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
Expand Down Expand Up @@ -89,6 +91,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand All @@ -102,6 +106,8 @@ github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTU
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
Expand Down Expand Up @@ -181,8 +187,11 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down Expand Up @@ -217,3 +226,11 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw=
modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/sqlite v1.48.2 h1:5CnW4uP8joZtA0LedVqLbZV5GD7F/0x91AXeSyjoh5c=
modernc.org/sqlite v1.48.2/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
24 changes: 22 additions & 2 deletions src/lib/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,24 @@ func LoadConfig(configPath *string) (*CatteryConfig, error) {
return nil, fmt.Errorf("failed to unmarshal config file: %w", err)
}

switch cfg.Database.Type {
case "":
return nil, fmt.Errorf("database.type is required (supported: sqlite, mongodb)")
case "mongodb":
if cfg.Database.Uri == "" {
return nil, fmt.Errorf("database.uri is required for mongodb")
}
if cfg.Database.Database == "" {
return nil, fmt.Errorf("database.database is required for mongodb")
}
case "sqlite":
if cfg.Database.Path == "" {
return nil, fmt.Errorf("database.path is required for sqlite")
}
default:
return nil, fmt.Errorf("unsupported database type: %s", cfg.Database.Type)
}

cfg.githubMap = make(map[string]*GitHubOrganization)
for _, organization := range cfg.Github {
cfg.githubMap[organization.Name] = organization
Expand Down Expand Up @@ -185,8 +203,10 @@ type ServerConfig struct {
}

type DatabaseConfig struct {
Uri string `yaml:"uri" validate:"required"`
Database string `yaml:"database" validate:"required"`
Type string `yaml:"type"` // "mongodb" (default) or "sqlite"
Uri string `yaml:"uri"`
Database string `yaml:"database"`
Path string `yaml:"path"` // SQLite file path
}

type GitHubOrganization struct {
Expand Down
8 changes: 6 additions & 2 deletions src/lib/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ server:
listenAddress: ":8080"
advertiseUrl: "http://localhost:8080"
database:
type: mongodb
uri: "mongodb://localhost:27017"
database: "cattery"
github:
Expand Down Expand Up @@ -113,8 +114,8 @@ server:
listenAddress: ":8080"
# Missing advertiseUrl
database:
uri: "mongodb://localhost:27017"
database: "cattery"
type: sqlite
path: ":memory:"
# Missing github section
providers:
- name: "docker"
Expand Down Expand Up @@ -313,6 +314,7 @@ server:
listenAddress: ":8080"
advertiseUrl: "http://localhost:8080"
database:
type: mongodb
uri: "mongodb://localhost:27017"
database: "cattery"
github:
Expand Down Expand Up @@ -371,6 +373,7 @@ server:
listenAddress: ":8080"
advertiseUrl: "http://localhost:8080"
database:
type: mongodb
uri: "mongodb://localhost:27017"
database: "cattery"
github:
Expand Down Expand Up @@ -413,6 +416,7 @@ server:
advertiseUrl: "http://localhost:8080"
agentSecret: "my-secret-token"
database:
type: mongodb
uri: "mongodb://localhost:27017"
database: "cattery"
github:
Expand Down
63 changes: 63 additions & 0 deletions src/lib/restarter/repositories/sqliteRestarterRepository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package repositories

import (
"context"
"database/sql"
"time"
)

type SqliteRestarterRepository struct {
db *sql.DB
}

func NewSqliteRestarterRepository(db *sql.DB) (*SqliteRestarterRepository, error) {
_, err := db.Exec(`
CREATE TABLE IF NOT EXISTS restart_requests (
workflow_run_id INTEGER PRIMARY KEY,
org_name TEXT NOT NULL,
repo_name TEXT NOT NULL,
created_at TEXT NOT NULL
)`)
if err != nil {
return nil, err
}
return &SqliteRestarterRepository{db: db}, nil
}

func (s *SqliteRestarterRepository) SaveRestartRequest(ctx context.Context, workflowRunId int64, orgName string, repoName string) error {
_, err := s.db.ExecContext(ctx,
`INSERT INTO restart_requests (workflow_run_id, org_name, repo_name, created_at)
VALUES (?, ?, ?, ?)
ON CONFLICT(workflow_run_id) DO UPDATE SET
org_name = excluded.org_name,
repo_name = excluded.repo_name,
created_at = excluded.created_at`,
workflowRunId, orgName, repoName, time.Now().UTC().Format(time.RFC3339Nano))
return err
}

func (s *SqliteRestarterRepository) DeleteRestartRequest(ctx context.Context, workflowRunId int64) error {
_, err := s.db.ExecContext(ctx, `DELETE FROM restart_requests WHERE workflow_run_id = ?`, workflowRunId)
return err
}

func (s *SqliteRestarterRepository) GetAllPendingRestartRequests(ctx context.Context) ([]RestartRequest, error) {
rows, err := s.db.QueryContext(ctx, `SELECT workflow_run_id, org_name, repo_name, created_at FROM restart_requests`)
if err != nil {
return nil, err
}
defer rows.Close()

var result []RestartRequest
for rows.Next() {
var r RestartRequest
var createdAt string
err := rows.Scan(&r.WorkflowRunId, &r.OrgName, &r.RepoName, &createdAt)
if err != nil {
return nil, err
}
r.CreatedAt, _ = time.Parse(time.RFC3339Nano, createdAt)
result = append(result, r)
}
return result, rows.Err()
}
Loading
Loading