Files
claude-botandClaude Sonnet 5.5 92cd12f150
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/review-bot-test Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline failed
feat(review-bot): Go service that reviews pull requests with a Mistral agent
Gitea's pull_request webhook (HMAC-checked) queues the review at once; a periodic sweep over the configured repositories catches lost deliveries. The service keeps the listed Mistral agent in sync with the embedded prompt, asks it for a review, refuses answers that called non-read-only tools, cleans the report, derives the review event and posts as the review bot. State is the pr-review:sha marker in the bot's own review. /healthz, /readyz and /metrics. Standard library only, tests against fake Gitea and Mistral servers, built as a scratch image by build-ci-images.yml.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 20:57:13 +02:00

61 lines
1.3 KiB
Go

package main
import (
"fmt"
"io"
"sort"
"strings"
"sync"
)
// Metrics is a small set of counters and gauges rendered in the Prometheus text format.
type Metrics struct {
mu sync.Mutex
vals map[string]float64
}
func newMetrics() *Metrics { return &Metrics{vals: map[string]float64{}} }
func series(name string, labels []string) string {
if len(labels) == 0 {
return "review_bot_" + name
}
var parts []string
for i := 0; i+1 < len(labels); i += 2 {
parts = append(parts, fmt.Sprintf("%s=%q", labels[i], labels[i+1]))
}
return "review_bot_" + name + "{" + strings.Join(parts, ",") + "}"
}
// Inc adds one to a counter; labels are key, value pairs.
func (m *Metrics) Inc(name string, labels ...string) {
m.mu.Lock()
defer m.mu.Unlock()
m.vals[series(name, labels)]++
}
func (m *Metrics) Add(name string, delta float64) {
m.mu.Lock()
defer m.mu.Unlock()
m.vals[series(name, nil)] += delta
}
func (m *Metrics) Set(name string, v float64) {
m.mu.Lock()
defer m.mu.Unlock()
m.vals[series(name, nil)] = v
}
func (m *Metrics) Render(w io.Writer) {
m.mu.Lock()
defer m.mu.Unlock()
keys := make([]string, 0, len(m.vals))
for k := range m.vals {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Fprintf(w, "%s %g\n", k, m.vals[k])
}
}