refactor(ci): require the owner in CIConfig and use strconv in the ports
The config is the one place that defaults the owner. ports.itoa was a copy of strconv.FormatInt.
- commit
- 7513520567a99f94a8e3f7a1aed57d7de7623d16
- author
- brice · · 2026-10-12 19:17 UTC
- parent
- 5b299eb
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +7 -19
M internal/ports/ci.go +2 -15
| @@ -5,6 +5,7 @@ package ports | |||
| 5 | 5 | import ( | |
| 6 | 6 | "context" | |
| 7 | 7 | "errors" | |
| 8 | + | "strconv" | |
| 8 | 9 | "time" | |
| 9 | 10 | ||
| 10 | 11 | "bnema.dev/ermite/internal/domain" | |
| @@ -125,26 +126,12 @@ type ErrCILogGap struct{ Count int64 } | |||
| 125 | 126 | ||
| 126 | 127 | // Error implements error. | |
| 127 | 128 | func (e *ErrCILogGap) Error() string { | |
| 128 | - | return "out of range: the log holds lines up to the offset of " + itoa(e.Count) | |
| 129 | + | return "out of range: the log holds lines up to the offset of " + strconv.FormatInt(e.Count, 10) | |
| 129 | 130 | } | |
| 130 | 131 | ||
| 131 | 132 | // Is makes errors.Is(err, domain.ErrOutOfRange) true. | |
| 132 | 133 | func (e *ErrCILogGap) Is(target error) bool { return target == domain.ErrOutOfRange } | |
| 133 | 134 | ||
| 134 | - | func itoa(n int64) string { | |
| 135 | - | if n == 0 { | |
| 136 | - | return "0" | |
| 137 | - | } | |
| 138 | - | var b [20]byte | |
| 139 | - | i := len(b) | |
| 140 | - | for n > 0 { | |
| 141 | - | i-- | |
| 142 | - | b[i] = byte('0' + n%10) | |
| 143 | - | n /= 10 | |
| 144 | - | } | |
| 145 | - | return string(b[i:]) | |
| 146 | - | } | |
| 147 | - | ||
| 148 | 135 | // CILogStore keeps the logs of the jobs: append-only files, one line per log | |
| 149 | 136 | // line, never in the metadata store. Lines are numbered from 0. | |
| 150 | 137 | type CILogStore interface { | |
| @@ -5,6 +5,7 @@ package ports | |||||
| 5 | import ( | 5 | import ( | ||
| 6 | "context" | 6 | "context" | ||
| 7 | "errors" | 7 | "errors" | ||
| 8 | + | "strconv" | |||
| 8 | "time" | 9 | "time" | ||
| 9 | 10 | ||||
| 10 | "bnema.dev/ermite/internal/domain" | 11 | "bnema.dev/ermite/internal/domain" | ||
| @@ -125,26 +126,12 @@ type ErrCILogGap struct{ Count int64 } | |||||
| 125 | 126 | ||||
| 126 | // Error implements error. | 127 | // Error implements error. | ||
| 127 | func (e *ErrCILogGap) Error() string { | 128 | func (e *ErrCILogGap) Error() string { | ||
| 128 | - | return "out of range: the log holds lines up to the offset of " + itoa(e.Count) | 129 | + | return "out of range: the log holds lines up to the offset of " + strconv.FormatInt(e.Count, 10) |
| 129 | } | 130 | } | ||
| 130 | 131 | ||||
| 131 | // Is makes errors.Is(err, domain.ErrOutOfRange) true. | 132 | // Is makes errors.Is(err, domain.ErrOutOfRange) true. | ||
| 132 | func (e *ErrCILogGap) Is(target error) bool { return target == domain.ErrOutOfRange } | 133 | func (e *ErrCILogGap) Is(target error) bool { return target == domain.ErrOutOfRange } | ||
| 133 | 134 | ||||
| 134 | - | func itoa(n int64) string { | |||
| 135 | - | if n == 0 { | |||
| 136 | - | return "0" | |||
| 137 | - | } | |||
| 138 | - | var b [20]byte | |||
| 139 | - | i := len(b) | |||
| 140 | - | for n > 0 { | |||
| 141 | - | i-- | |||
| 142 | - | b[i] = byte('0' + n%10) | |||
| 143 | - | n /= 10 | |||
| 144 | - | } | |||
| 145 | - | return string(b[i:]) | |||
| 146 | - | } | |||
| 147 | - | ||||
| 148 | // CILogStore keeps the logs of the jobs: append-only files, one line per log | 135 | // CILogStore keeps the logs of the jobs: append-only files, one line per log | ||
| 149 | // line, never in the metadata store. Lines are numbered from 0. | 136 | // line, never in the metadata store. Lines are numbered from 0. | ||
| 150 | type CILogStore interface { | 137 | type CILogStore interface { | ||
M internal/usecase/ci.go +5 -4
| @@ -42,7 +42,8 @@ const ( | |||
| 42 | 42 | ) | |
| 43 | 43 | ||
| 44 | 44 | // CIConfig holds what the CI use cases need. Store, Logs, Meta, Repos, Reader, | |
| 45 | - | // Git, Diff, Bus and Clock are required. | |
| 45 | + | // Git, Diff, Bus, Clock, Owner and PublicURL are required (the config supplies | |
| 46 | + | // the defaults of Owner and Retention). | |
| 46 | 47 | type CIConfig struct { | |
| 47 | 48 | Store ports.CIStore | |
| 48 | 49 | Logs ports.CILogStore | |
| @@ -92,9 +93,6 @@ func (c CIConfig) withDefaults() CIConfig { | |||
| 92 | 93 | if c.TriggerQueue <= 0 { | |
| 93 | 94 | c.TriggerQueue = DefaultCITriggerQueue | |
| 94 | 95 | } | |
| 95 | - | if c.Owner == "" { | |
| 96 | - | c.Owner = "owner" | |
| 97 | - | } | |
| 98 | 96 | return c | |
| 99 | 97 | } | |
| 100 | 98 | ||
| @@ -148,6 +146,9 @@ type pollRecord struct { | |||
| 148 | 146 | // NewCI builds the CI use cases. ctx carries the logger; its cancellation is | |
| 149 | 147 | // not followed: call Start to run the workers and Close to stop them. | |
| 150 | 148 | func NewCI(ctx context.Context, cfg CIConfig) *CI { | |
| 149 | + | if cfg.Owner == "" { | |
| 150 | + | panic("usecase: CIConfig.Owner is required") | |
| 151 | + | } | |
| 151 | 152 | cfg = cfg.withDefaults() | |
| 152 | 153 | run, stop := context.WithCancel(context.WithoutCancel(ctx)) | |
| 153 | 154 | return &CI{ | |
| @@ -42,7 +42,8 @@ const ( | |||||
| 42 | ) | 42 | ) | ||
| 43 | 43 | ||||
| 44 | // CIConfig holds what the CI use cases need. Store, Logs, Meta, Repos, Reader, | 44 | // CIConfig holds what the CI use cases need. Store, Logs, Meta, Repos, Reader, | ||
| 45 | - | // Git, Diff, Bus and Clock are required. | 45 | + | // Git, Diff, Bus, Clock, Owner and PublicURL are required (the config supplies |
| 46 | + | // the defaults of Owner and Retention). | |||
| 46 | type CIConfig struct { | 47 | type CIConfig struct { | ||
| 47 | Store ports.CIStore | 48 | Store ports.CIStore | ||
| 48 | Logs ports.CILogStore | 49 | Logs ports.CILogStore | ||
| @@ -92,9 +93,6 @@ func (c CIConfig) withDefaults() CIConfig { | |||||
| 92 | if c.TriggerQueue <= 0 { | 93 | if c.TriggerQueue <= 0 { | ||
| 93 | c.TriggerQueue = DefaultCITriggerQueue | 94 | c.TriggerQueue = DefaultCITriggerQueue | ||
| 94 | } | 95 | } | ||
| 95 | - | if c.Owner == "" { | |||
| 96 | - | c.Owner = "owner" | |||
| 97 | - | } | |||
| 98 | return c | 96 | return c | ||
| 99 | } | 97 | } | ||
| 100 | 98 | ||||
| @@ -148,6 +146,9 @@ type pollRecord struct { | |||||
| 148 | // NewCI builds the CI use cases. ctx carries the logger; its cancellation is | 146 | // NewCI builds the CI use cases. ctx carries the logger; its cancellation is | ||
| 149 | // not followed: call Start to run the workers and Close to stop them. | 147 | // not followed: call Start to run the workers and Close to stop them. | ||
| 150 | func NewCI(ctx context.Context, cfg CIConfig) *CI { | 148 | func NewCI(ctx context.Context, cfg CIConfig) *CI { | ||
| 149 | + | if cfg.Owner == "" { | |||
| 150 | + | panic("usecase: CIConfig.Owner is required") | |||
| 151 | + | } | |||
| 151 | cfg = cfg.withDefaults() | 152 | cfg = cfg.withDefaults() | ||
| 152 | run, stop := context.WithCancel(context.WithoutCancel(ctx)) | 153 | run, stop := context.WithCancel(context.WithoutCancel(ctx)) | ||
| 153 | return &CI{ | 154 | return &CI{ | ||