internal/store/runners.go
59 lines · 2321 bytes
1package store
2
3// Runner is one runner account as the instance admin sees it.
4type Runner struct {
5 Username string `json:"username"`
6 LastSeen string `json:"last_seen"`
7 Scope string `json:"scope,omitempty"` // comma-joined owner/name, "" for any
8 // The build it holds, if any.
9 BuildRepo string `json:"build_repo,omitempty"`
10 BuildNumber int64 `json:"build_number,omitempty"`
11 BuildJob string `json:"build_job,omitempty"`
12 StartedAt string `json:"started_at,omitempty"`
13}
14
15// TouchRunner records a poll: the time, the scope the runner asked for,
16// and the build it just claimed (0 for none).
17func (s *Store) TouchRunner(userID int64, scope string, buildID int64) error {
18 _, err := s.DB.Exec(`INSERT INTO runner_seen (user_id, last_seen, scope, build_id)
19 VALUES (?1, strftime('%Y-%m-%dT%H:%M:%fZ','now'), ?2, NULLIF(?3, 0))
20 ON CONFLICT (user_id) DO UPDATE SET
21 last_seen = excluded.last_seen, scope = excluded.scope,
22 build_id = COALESCE(excluded.build_id, runner_seen.build_id)`,
23 userID, scope, buildID)
24 return err
25}
26
27// RunnerDone records that the runner reported and holds nothing now.
28func (s *Store) RunnerDone(userID int64) error {
29 _, err := s.DB.Exec(`UPDATE runner_seen SET last_seen = strftime('%Y-%m-%dT%H:%M:%fZ','now'),
30 build_id = NULL WHERE user_id = ?`, userID)
31 return err
32}
33
34// ListRunners lists every account that has ever polled as a runner,
35// most recently seen first.
36func (s *Store) ListRunners() ([]Runner, error) {
37 rows, err := s.DB.Query(`SELECT u.username, r.last_seen, r.scope,
38 COALESCE(COALESCE(bu.username, bo.name) || '/' || br.name, ''),
39 COALESCE(b.number, 0), COALESCE(b.job, ''), COALESCE(b.started_at, '')
40 FROM runner_seen r JOIN users u ON u.id = r.user_id
41 LEFT JOIN builds b ON b.id = r.build_id AND b.status = 'running'
42 LEFT JOIN repos br ON br.id = b.repo_id
43 LEFT JOIN users bu ON br.owner_kind = 'user' AND bu.id = br.owner_id
44 LEFT JOIN orgs bo ON br.owner_kind = 'org' AND bo.id = br.owner_id
45 ORDER BY r.last_seen DESC`)
46 if err != nil {
47 return nil, err
48 }
49 defer rows.Close()
50 var out []Runner
51 for rows.Next() {
52 var r Runner
53 if err := rows.Scan(&r.Username, &r.LastSeen, &r.Scope, &r.BuildRepo, &r.BuildNumber, &r.BuildJob, &r.StartedAt); err != nil {
54 return nil, err
55 }
56 out = append(out, r)
57 }
58 return out, rows.Err()
59}