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.
Name the instance in the tab and the brand link
3d707ea78961adff55cb7b3cb8a61c5697e726a4 · Keenan Nemetz · 19h ago · parent 2c988ecd
Name the instance in the tab and the brand link instance_name reached the home heading only, so a renamed instance still put "Vole" in the one place a reader always looks and in the brand link's accessible name. Put the name on the shared page data and read it in the chrome. An instance that never set one still says Vole, and the separator never renders on its own. Prose about the software, such as the status page's restart instruction, keeps the product name: it names the program, not the organisation's forge.
server/ui_test.go +41
| @@ -9,6 +9,8 @@ import ( | |||
| 9 | 9 | "strings" | |
| 10 | 10 | "testing" | |
| 11 | 11 | "time" | |
| 12 | |||
| 13 | "github.com/rodent-software/vole/forge/config" | ||
| 12 | 14 | ) | |
| 13 | 15 | ||
| 14 | 16 | func TestUnknownPathIsAVolePage(t *testing.T) { | |
| @@ -23,6 +25,45 @@ func TestUnknownPathIsAVolePage(t *testing.T) { | |||
| 23 | 25 | } | |
| 24 | 26 | } | |
| 25 | 27 | ||
| 28 | // The instance name is the product an organisation runs: it belongs in the one | ||
| 29 | // place a reader always looks, the tab, and in the brand link's accessible name. | ||
| 30 | func TestInstanceNameReachesThePageChrome(t *testing.T) { | ||
| 31 | t.Parallel() | ||
| 32 | f := newFixtureWith(t, func(c *config.Config) { c.InstanceName = "Acme Forge" }) | ||
| 33 | f.publish(f.repo) | ||
| 34 | for _, path := range []string{"/", "/r/" + f.repo, "/r/" + f.repo + "/issues", "/no/such/page"} { | ||
| 35 | code, body := f.get(path) | ||
| 36 | if code != 200 && code != 404 { | ||
| 37 | t.Fatalf("%s = %d", path, code) | ||
| 38 | } | ||
| 39 | if !strings.Contains(body, " · Acme Forge</title>") { | ||
| 40 | t.Fatalf("%s does not name the instance in its tab title:\n%s", path, body) | ||
| 41 | } | ||
| 42 | if !strings.Contains(body, `aria-label="Acme Forge home"`) { | ||
| 43 | t.Fatalf("%s does not name the instance in the brand link:\n%s", path, body) | ||
| 44 | } | ||
| 45 | if strings.Contains(body, "· Vole</title>") || strings.Contains(body, `aria-label="Vole home"`) { | ||
| 46 | t.Fatalf("%s still calls the instance Vole:\n%s", path, body) | ||
| 47 | } | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | // An instance that never set a name is Vole, and the shell must not render the | ||
| 52 | // separator on its own when a page has no title to put in front of it. | ||
| 53 | func TestChromeDoesNotDangleASeparatorWithoutAName(t *testing.T) { | ||
| 54 | t.Parallel() | ||
| 55 | f := newFixture(t) | ||
| 56 | for _, path := range []string{"/", "/no/such/page"} { | ||
| 57 | _, body := f.get(path) | ||
| 58 | if !strings.Contains(body, "· Vole</title>") { | ||
| 59 | t.Fatalf("%s does not fall back to Vole in the tab title:\n%s", path, body) | ||
| 60 | } | ||
| 61 | if strings.Contains(body, "<title>· ") || strings.Contains(body, `aria-label=" home"`) { | ||
| 62 | t.Fatalf("%s renders a dangling separator or an empty label:\n%s", path, body) | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 26 | 67 | func TestRepositoryPagesShareTheTabHeader(t *testing.T) { | |
| 27 | 68 | t.Parallel() | |
| 28 | 69 | f := newFixture(t) | |