Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

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.

Publish repositories as Go modules and move the module path to rodent.software

d37d301fd4881ee37855387377db5a7aed843017 · Keenan Nemetz · 17h ago · parent 1c363d53

Publish repositories as Go modules and move the module path to rodent.software

The module named a GitHub repository that does not exist, and a module path
under the forge could not be fetched anyway: the go command resolves an import
path by asking it for a go-import tag first, and the forge served only pages.

Answer the <host>/<repository> discovery probe from the catch-all route with the
repository's tag, naming its Git transport and that prefix, so a public
repository is importable with no vanity service in front of the instance. Only
a repository an anonymous reader can read answers: the tag is fetched without
credentials, so a tag for a private repository would confirm its existence to
anyone who guessed the name. The prefix host comes from public_url, never the
request's Host header, for the same reason the clone URL does.

With the path resolvable, rename the module to rodent.software/vole: imports,
the build line in the getting-started guide, and the packaged units and
metadata follow it. docs/go-modules.md explains the lookup, what the instance
must have, and why a repository named after a route cannot claim the prefix.

docs/go-modules.md +84

@@ -0,0 +1,84 @@
1 # Go modules
2
3 A public repository on a Vole instance is a Go module. The import path is the
4 instance's host and the repository name:
5
6 ```text
7 https://<host>/<repository>
8 ```
9
10 Vole serves the metadata the `go` command looks for, so an import path needs no
11 vanity service, no redirect, and no separate web host in front of the forge.
12 Vole itself is published this way: `rodent.software/vole`.
13
14 ## How the lookup works
15
16 `go get` cannot clone an arbitrary URL from an import path, so it first asks the
17 path for directions: it fetches `https://<host>/<repository>?go-get=1` and reads
18 the `<meta name="go-import">` tag in the answer. Vole answers for a public
19 repository with that repository's Git transport:
20
21 ```console
22 $ curl -s 'https://rodent.software/vole?go-get=1'
23 <!doctype html>
24 ...
25 <meta name="go-import" content="rodent.software/vole git https://rodent.software/git/vole.git">
26 ```
27
28 Then `go` clones the repository over the smart-HTTP transport and resolves the
29 package from the tag it finds there, exactly as it would for a module on any
30 other forge. A package inside the module (`rodent.software/vole/server/web`)
31 resolves from the same tag: the go command asks the full path first, and the tag
32 it gets names the repository prefix.
33
34 Add the repository to a project as usual:
35
36 ```console
37 $ go get rodent.software/vole
38 $ go doc rodent.software/vole/server/web
39 ```
40
41 ## What the instance must have
42
43 - `public_url` set to the origin people use, in `[server]` in the
44 configuration file. The metadata's import prefix is that origin's host name;
45 without `public_url` Vole falls back to the request's host, which is not
46 something the go command's discovery can rely on.
47 - The host in the import path is the host name alone. A module path cannot carry
48 a port, so an instance reached only at `https://forge.example.com:8443` can
49 still serve its pages, but its repositories are not importable paths; clone
50 them by URL instead.
51
52 ## Which repositories answer
53
54 Only a repository an anonymous reader may read, which is the same rule that makes
55 its pages public. The tag is fetched without credentials — that is the discovery
56 protocol — so answering for a private repository would confirm to anyone who
57 guessed the name that it exists. Vole answers 404 for those, like every other
58 private path.
59
60 A private repository is therefore not resolvable from its import path. Clone it
61 where the build runs and point a `replace` at that checkout, or mirror the code in
62 a repository that is public.
63
64 ## Naming
65
66 The import path is `<host>/<repository>`, so the repository name is also the last
67 element of every import path inside the module. A repository named after a page
68 the forge already serves at the top level — `r`, `u`, `admin`, `activity`,
69 `login`, `static`, and so on — keeps its pages and its clone URL but cannot claim
70 that module path; pick another name if the code is meant to be imported.
71
72 ## Vole's own module
73
74 The Vole repository is `rodent.software/vole`, so fetching the source is:
75
76 ```console
77 $ go get rodent.software/vole
78 ```
79
80 and building from a checkout uses the same path:
81
82 ```sh
83 go build -tags libsqlite3,sqlite_fts5 -o vole rodent.software/vole/cmd/vole
84 ```