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.
Make the run list say what triggered each run
57dc79afa8097830de03fc2fc2c19561470b6d36 · Keenan Nemetz · 6d ago · parent 338a19dd
Make the run list say what triggered each run The runs table said only which ref a run used, so a push, an issue event and a manual dispatch looked alike. Give each run a TriggerTitle and show it in a "Triggered by" column; the run page uses the same words. Drop the separate workflows page. The run list is where a job is found, and the run page now links the workflow definition it ran, so a second page listing the same jobs only split the answer. Show the full log viewer only while a run is going. A finished run has per-step logs, and the full log is a download rather than a second copy of every step's output.
server/web/workflows.go −110
| @@ -1,110 +0,0 @@ | |||
| 1 | package web | ||
| 2 | |||
| 3 | // Workflows are read from the default branch's tree, with the same validator the | ||
| 4 | // push boundary uses. The page is a view of what is configured, not a second | ||
| 5 | // scheduler: a run still happens when a matching push arrives. | ||
| 6 | |||
| 7 | import ( | ||
| 8 | "net/http" | ||
| 9 | |||
| 10 | "github.com/rodent-software/vole/ci" | ||
| 11 | "github.com/rodent-software/vole/ci/runs" | ||
| 12 | ) | ||
| 13 | |||
| 14 | type workflowJobView struct { | ||
| 15 | ID string | ||
| 16 | Name string | ||
| 17 | Description string | ||
| 18 | Labels []string | ||
| 19 | Image string | ||
| 20 | Network string | ||
| 21 | Steps int | ||
| 22 | Artifacts int | ||
| 23 | Pages bool | ||
| 24 | Last *runs.Run | ||
| 25 | } | ||
| 26 | |||
| 27 | type workflowView struct { | ||
| 28 | Path string | ||
| 29 | Name string | ||
| 30 | Description string | ||
| 31 | Branches []string | ||
| 32 | Tags []string | ||
| 33 | ChangeRequest []string | ||
| 34 | Issues []string | ||
| 35 | Comments []string | ||
| 36 | Schedules []string | ||
| 37 | Dispatch bool | ||
| 38 | Jobs []workflowJobView | ||
| 39 | } | ||
| 40 | |||
| 41 | func (w *Web) WorkflowsPage(rw http.ResponseWriter, r *http.Request) { | ||
| 42 | m, ok := w.open(rw, r) | ||
| 43 | if !ok { | ||
| 44 | return | ||
| 45 | } | ||
| 46 | commit, _ := m.Git().RevParse(m.DefaultBranch) | ||
| 47 | workflows, problems := ci.At(m.Git(), commit) | ||
| 48 | |||
| 49 | var recent []*runs.Run | ||
| 50 | if w.Runs != nil { | ||
| 51 | recent, _ = w.Runs.Recent(m.Name, 100) | ||
| 52 | } | ||
| 53 | latest := map[string]*runs.Run{} | ||
| 54 | for _, run := range recent { | ||
| 55 | key := run.Workflow + "\x00" + run.Job | ||
| 56 | if latest[key] == nil { | ||
| 57 | latest[key] = run | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | views := make([]workflowView, 0, len(workflows)) | ||
| 62 | for _, wf := range workflows { | ||
| 63 | view := workflowView{ | ||
| 64 | Path: wf.Path, Name: wf.Name, Description: wf.Description, | ||
| 65 | Branches: wf.Branches, Tags: wf.Tags, Dispatch: wf.Dispatch != nil, | ||
| 66 | } | ||
| 67 | if wf.ChangeRequest != nil { | ||
| 68 | view.ChangeRequest = wf.ChangeRequest.Types | ||
| 69 | } | ||
| 70 | if wf.Issues != nil { | ||
| 71 | view.Issues = wf.Issues.Types | ||
| 72 | } | ||
| 73 | if wf.Comments != nil { | ||
| 74 | view.Comments = wf.Comments.Types | ||
| 75 | } | ||
| 76 | for _, schedule := range wf.Schedules { | ||
| 77 | view.Schedules = append(view.Schedules, schedule.Cron) | ||
| 78 | } | ||
| 79 | for _, job := range wf.Jobs { | ||
| 80 | image := job.Image | ||
| 81 | if job.ImageFile != "" { | ||
| 82 | image = "file:" + job.ImageFile | ||
| 83 | } | ||
| 84 | view.Jobs = append(view.Jobs, workflowJobView{ | ||
| 85 | ID: job.ID, Name: job.Name, Description: job.Description, | ||
| 86 | Labels: job.Labels, Image: image, Network: job.Network, | ||
| 87 | Steps: len(job.Steps), Artifacts: len(job.Artifacts), | ||
| 88 | Pages: job.Pages != nil, | ||
| 89 | Last: latest[wf.Path+"\x00"+job.ID], | ||
| 90 | }) | ||
| 91 | } | ||
| 92 | views = append(views, view) | ||
| 93 | } | ||
| 94 | |||
| 95 | w.render(rw, "workflows", struct { | ||
| 96 | Page | ||
| 97 | Name string | ||
| 98 | Ref string | ||
| 99 | Workflows []workflowView | ||
| 100 | Problems []string | ||
| 101 | HasCommit bool | ||
| 102 | }{ | ||
| 103 | Page: w.page(r, m.Name+" · workflows"), | ||
| 104 | Name: m.Name, | ||
| 105 | Ref: m.DefaultBranch, | ||
| 106 | Workflows: views, | ||
| 107 | Problems: problems, | ||
| 108 | HasCommit: commit != "", | ||
| 109 | }, 0) | ||
| 110 | } | ||