Commit 9ec11cfbad

9ec11cfbad7b278f891751810eeb08f89f91ae61

parent: 8994b7770e

Verified · cmc ci/build: success ci/test: success

cmc <hello@cleberg.net> · 2026-09-28 22:41 UTC

web: builds page offers an org-mode badge snippet

Closes #299

Layout: unified · split

CHANGELOG.org +2
@@ -6,6 +6,8 @@ anything beyond "replace the binary and restart" is needed.
6 6
7* Unreleased 7* Unreleased
8 8
9- The builds page's status badge section gives an org-mode snippet
10 beside the Markdown one, for a README.org (#299).
9- A wiki link to an existing non-page file (an .svg, .txt, .pdf) now 11- A wiki link to an existing non-page file (an .svg, .txt, .pdf) now
10 resolves to the raw route instead of 404ing against the page route 12 resolves to the raw route instead of 404ing against the page route
11 (#283). 13 (#283).
internal/httpd/buildpages_test.go +32
@@ -120,6 +120,38 @@ func TestBuildsEmptyStateShowsInstructionForWriters(t *testing.T) {
120 } 120 }
121} 121}
122 122
123// The badge section offers the snippet for a README.md and a README.org.
124func TestBuildsPageBadgeSnippetsMarkdownAndOrg(t *testing.T) {
125 var sb strings.Builder
126 rp := testRepoPage()
127 err := web.Render(&sb, "builds.html", struct {
128 repoPage
129 Builds []control.BuildOut
130 Jobs []control.JobOut
131 Runs []buildRun
132 Filter buildFilter
133 Facets []facetGroup
134 Refs []string
135 Older string
136 CanWrite bool
137 Notice string
138 }{
139 rp, nil, nil, nil, buildFilter{}, nil, nil, "", false, "",
140 })
141 if err != nil {
142 t.Fatalf("render: %v", err)
143 }
144 base := "https://" + rp.Host + "/" + rp.Repo.OwnerName + "/" + rp.Repo.Name
145 for _, want := range []string{
146 "[![build](" + base + "/badge/build.svg)](" + base + "/builds)",
147 "[[" + base + "/builds][" + base + "/badge/build.svg]]",
148 } {
149 if !strings.Contains(sb.String(), want) {
150 t.Errorf("badge section lacks %s", want)
151 }
152 }
153}
154
123func TestBuildPageRendersCommandOutput(t *testing.T) { 155func TestBuildPageRendersCommandOutput(t *testing.T) {
124 var sb strings.Builder 156 var sb strings.Builder
125 err := web.Render(&sb, "build.html", buildView{ 157 err := web.Render(&sb, "build.html", buildView{
internal/web/templates/builds.html +3 −1
@@ -34,8 +34,10 @@
34</form> 34</form>
35{{end}} 35{{end}}
36<details class="editbox"><summary>Status badge</summary> 36<details class="editbox"><summary>Status badge</summary>
37<p class="meta">Paste into a README; it shows the newest build's state.</p> 37<p class="meta">Paste into a README; it shows the newest build's state. Markdown:</p>
38<pre class="code" tabindex="0">[![build](https://{{.Host}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/badge/build.svg)](https://{{.Host}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/builds)</pre> 38<pre class="code" tabindex="0">[![build](https://{{.Host}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/badge/build.svg)](https://{{.Host}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/builds)</pre>
39<p class="meta">Org:</p>
40<pre class="code" tabindex="0">[[https://{{.Host}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/builds][https://{{.Host}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/badge/build.svg]]</pre>
39<p class="meta">Add <code>?job=name</code> for one job.</p> 41<p class="meta">Add <code>?job=name</code> for one job.</p>
40</details> 42</details>
41<p class="meta">{{len .Builds}} build{{if ne (len .Builds) 1}}s{{end}} in {{len .Runs}} run{{if ne (len .Runs) 1}}s{{end}}{{if .Older}} on this page{{end}}{{if or .Filter.Ref .Filter.Status .Filter.Job}}, <a href="?">clear filters</a>{{end}}</p> 43<p class="meta">{{len .Builds}} build{{if ne (len .Builds) 1}}s{{end}} in {{len .Runs}} run{{if ne (len .Runs) 1}}s{{end}}{{if .Older}} on this page{{end}}{{if or .Filter.Ref .Filter.Status .Filter.Job}}, <a href="?">clear filters</a>{{end}}</p>