vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Show every run in the runs list
a72e39d5b08fa4285bc78ccd6a6b1b3ca992d823 · Keenan Nemetz · 10d ago · parent 1b1fa7a5
Show every run in the runs list The list still asked each row for Log and LogOID, fields the run no longer has now that logs live in run_logs. html/template stops at the first execution error and keeps the bytes it already wrote, so the page looked complete through the first run and silently dropped the rest. Recent and Get now carry HasLog from the same query, the list links a log only when one exists, and a failed render is a 500 rather than a short page.
ci/runs/runs.go +16−10
| @@ -116,8 +116,18 @@ type Run struct { | |||
| 116 | 116 | // Runtime is the container runtime the newest attempt ran in, mirrored from its | |
| 117 | 117 | // record. Empty for records written before the environment was recorded. | |
| 118 | 118 | Runtime string | |
| 119 | // HasLog says a streamed log exists for at least one attempt. It is a display | ||
| 120 | // hint for lists that would otherwise need a query per row; the run page reads | ||
| 121 | // AttemptLogs when it needs the attempts themselves. | ||
| 122 | HasLog bool | ||
| 119 | 123 | } | |
| 120 | 124 | ||
| 125 | // runColumns is the column list scanRun reads, in order. HasLog is an EXISTS rather | ||
| 126 | // than a stored column so a list of runs stays one query as logs come and go. | ||
| 127 | const runColumns = `id, repo, ref, branch, sha, workflow, workflow_sha, job, steps, steps_sha, | ||
| 128 | artifacts, release_artifacts, pages_path, tag, tag_annotated, status, attempts, lease_owner, lease_until, created, started, finished, exit_code, os, arch, image, image_file, image_definition, image_sha, runtime, env, | ||
| 129 | EXISTS (SELECT 1 FROM run_logs WHERE run_logs.run_id = runs.id)` | ||
| 130 | |||
| 121 | 131 | // Duration is the wall-clock time from the first lease to the finish. A queued run | |
| 122 | 132 | // has no duration yet; a running one is measured to now so a page can show that it | |
| 123 | 133 | // is still going rather than a stale zero. | |
| @@ -1431,18 +1441,15 @@ func (s *Store) RequeueExpired(now time.Time) (requeued, failed int, err error) | |||
| 1431 | 1441 | ||
| 1432 | 1442 | // Get returns one run. | |
| 1433 | 1443 | func (s *Store) Get(id string) (*Run, error) { | |
| 1434 | row := s.db.QueryRow(`SELECT id, repo, ref, branch, sha, workflow, workflow_sha, job, steps, steps_sha, | ||
| 1435 | artifacts, release_artifacts, pages_path, tag, tag_annotated, status, attempts, lease_owner, lease_until, created, started, finished, exit_code, os, arch, image, image_file, image_definition, image_sha, runtime, env | ||
| 1436 | FROM runs WHERE id = ?`, id) | ||
| 1444 | row := s.db.QueryRow(`SELECT `+runColumns+` FROM runs WHERE id = ?`, id) | ||
| 1437 | 1445 | return scanRun(row) | |
| 1438 | 1446 | } | |
| 1439 | 1447 | ||
| 1440 | 1448 | // ForSHA returns the newest run per (workflow, job) for a commit, so a gate can | |
| 1441 | 1449 | // ask "did every job pass for this exact sha". | |
| 1442 | 1450 | func (s *Store) ForSHA(repo, sha string) (map[string]*Run, error) { | |
| 1443 | rows, err := s.db.Query(`SELECT id, repo, ref, branch, sha, workflow, workflow_sha, job, steps, steps_sha, | ||
| 1444 | artifacts, release_artifacts, pages_path, tag, tag_annotated, status, attempts, lease_owner, lease_until, created, started, finished, exit_code, os, arch, image, image_file, image_definition, image_sha, runtime, env | ||
| 1445 | FROM runs WHERE repo = ? AND sha = ? AND (ref LIKE 'refs/heads/%' OR ref LIKE 'refs/vole/candidates/%') ORDER BY created`, repo, sha) | ||
| 1451 | rows, err := s.db.Query(`SELECT `+runColumns+` FROM runs | ||
| 1452 | WHERE repo = ? AND sha = ? AND (ref LIKE 'refs/heads/%' OR ref LIKE 'refs/vole/candidates/%') ORDER BY created`, repo, sha) | ||
| 1446 | 1453 | if err != nil { | |
| 1447 | 1454 | return nil, err | |
| 1448 | 1455 | } | |
| @@ -1536,9 +1543,8 @@ func (s *Store) HasPending(repo, sha string) (bool, error) { | |||
| 1536 | 1543 | ||
| 1537 | 1544 | // Recent returns the newest runs for a repository. | |
| 1538 | 1545 | func (s *Store) Recent(repo string, limit int) ([]*Run, error) { | |
| 1539 | rows, err := s.db.Query(`SELECT id, repo, ref, branch, sha, workflow, workflow_sha, job, steps, steps_sha, | ||
| 1540 | artifacts, release_artifacts, pages_path, tag, tag_annotated, status, attempts, lease_owner, lease_until, created, started, finished, exit_code, os, arch, image, image_file, image_definition, image_sha, runtime, env | ||
| 1541 | FROM runs WHERE repo = ? ORDER BY created DESC LIMIT ?`, repo, limit) | ||
| 1546 | rows, err := s.db.Query(`SELECT `+runColumns+` FROM runs | ||
| 1547 | WHERE repo = ? ORDER BY created DESC LIMIT ?`, repo, limit) | ||
| 1542 | 1548 | if err != nil { | |
| 1543 | 1549 | return nil, err | |
| 1544 | 1550 | } | |
| @@ -1575,7 +1581,7 @@ func scanRun(row scannable) (*Run, error) { | |||
| 1575 | 1581 | &r.Job, &steps, &r.StepsSHA, &artifacts, &releaseArtifacts, &r.PagesPath, &r.Tag, &tagAnnotated, | |
| 1576 | 1582 | &r.Status, &r.Attempts, &r.LeaseOwner, &leaseUntil, | |
| 1577 | 1583 | &created, &started, &finished, &r.ExitCode, &r.OS, &r.Arch, | |
| 1578 | &r.Image, &r.ImageFile, &r.ImageDefinition, &r.ImageSHA, &r.Runtime, &env); err != nil { | ||
| 1584 | &r.Image, &r.ImageFile, &r.ImageDefinition, &r.ImageSHA, &r.Runtime, &env, &r.HasLog); err != nil { | ||
| 1579 | 1585 | return nil, err | |
| 1580 | 1586 | } | |
| 1581 | 1587 | if env != "" { | |