config loading fixtures ======================= Each case pairs a `config.yaml` input with the `result` of loading it: either the normalized repo listing, or the startup error. Paths are shown with the config file's directory as `$BASE`. Regenerate the result hunks with `go test -run TestLoadConfig . -testmark.regen`. Good configs ------------ The minimal config: one repo, and the `%` placeholder saying its path matches its name. [testmark]:# (good-minimal/config.yaml) ```yaml repos: parnass: path: "%" ``` [testmark]:# (good-minimal/result) ```text repo parnass: path=$BASE/parnass ``` Names may be slash-nested to arbitrary depth; paths may be relative (resolved against the config file's directory, even pointing outside it) or absolute; descriptions are optional. [testmark]:# (good-varied/config.yaml) ```yaml repos: parnass: path: "%" description: "the showcase repo" work/infra/deploy: path: ../deploy elsewhere: path: /srv/git/elsewhere ``` [testmark]:# (good-varied/result) ```text repo elsewhere: path=/srv/git/elsewhere repo parnass: path=$BASE/parnass description="the showcase repo" repo work/infra/deploy: path=$PARENT/deploy ``` Trailing slashes on paths are normalized away. [testmark]:# (good-trailing-slash-path/config.yaml) ```yaml repos: tidy: path: "sub/dir/" ``` [testmark]:# (good-trailing-slash-path/result) ```text repo tidy: path=$BASE/sub/dir ``` The base URL ------------ `baseurl` names the canonical outside address of this socle: it becomes the displayed clone URL and enables the go-get vanity-import answers. It is optional; without it, clone URLs derive from each request and go-get is not served. [testmark]:# (good-baseurl/config.yaml) ```yaml baseurl: https://code.example repos: parnass: path: "%" ``` [testmark]:# (good-baseurl/result) ```text baseurl=https://code.example repo parnass: path=$BASE/parnass ``` One trailing slash is tolerated and trimmed. [testmark]:# (good-baseurl-trailing-slash/config.yaml) ```yaml baseurl: https://code.example/ repos: parnass: path: "%" ``` [testmark]:# (good-baseurl-trailing-slash/result) ```text baseurl=https://code.example repo parnass: path=$BASE/parnass ``` It must be an absolute http(s) URL naming only a host: no bare hostnames, no other schemes, and no path -- socle's URL space is rooted at `/`, so a path prefix would promise routing it can't deliver. [testmark]:# (err-baseurl-relative/config.yaml) ```yaml baseurl: code.example repos: parnass: path: "%" ``` [testmark]:# (err-baseurl-relative/result) ```text error: config $BASE/config.yaml: baseurl "code.example": must be an absolute URL with scheme http or https ``` [testmark]:# (err-baseurl-scheme/config.yaml) ```yaml baseurl: ssh://code.example repos: parnass: path: "%" ``` [testmark]:# (err-baseurl-scheme/result) ```text error: config $BASE/config.yaml: baseurl "ssh://code.example": must be an absolute URL with scheme http or https ``` [testmark]:# (err-baseurl-path/config.yaml) ```yaml baseurl: https://code.example/git repos: parnass: path: "%" ``` [testmark]:# (err-baseurl-path/result) ```text error: config $BASE/config.yaml: baseurl "https://code.example/git": must name only a host, with no path, query, fragment, or userinfo ``` Bad configs ----------- Every problem below is a startup error: socle refuses to run on a config it can't fully honor. Unknown keys are errors, not silence; typos should not quietly change meaning. [testmark]:# (err-unknown-key/config.yaml) ```yaml repos: parnass: path: "%" exposed: true ``` [testmark]:# (err-unknown-key/result) ```text error: config $BASE/config.yaml: yaml: unmarshal errors: line 4: field exposed not found in type main.repoConfig ``` A config with nothing to serve is a misconfiguration. [testmark]:# (err-no-repos/config.yaml) ```yaml repos: {} ``` [testmark]:# (err-no-repos/result) ```text error: config $BASE/config.yaml: no repos configured; a socle with nothing on display is a misconfiguration ``` Repo names are validated: segments of `[A-Za-z0-9._-]`, no leading dot or dash. [testmark]:# (err-bad-name/config.yaml) ```yaml repos: .hidden: path: "%" ``` [testmark]:# (err-bad-name/result) ```text error: config $BASE/config.yaml: invalid: repo name ".hidden": segment ".hidden" starts with "." ``` Names ending in `.git` are rejected: URLs treat a trailing `.git` as an alias for the plain name, and configuring one would make that alias ambiguous. [testmark]:# (err-git-suffix-name/config.yaml) ```yaml repos: parnass.git: path: "%" ``` [testmark]:# (err-git-suffix-name/result) ```text error: config $BASE/config.yaml: invalid: repo name "parnass.git": segment "parnass.git" ends in .git (reserved as a URL alias for the plain name) ``` No repo name may be a path-prefix of another; nested names would make URL dispatch ambiguous. [testmark]:# (err-prefix-collision/config.yaml) ```yaml repos: work: path: "%" work/deploy: path: "%" ``` [testmark]:# (err-prefix-collision/result) ```text error: config $BASE/config.yaml: repo "work" is a path-prefix of repo "work/deploy"; nested names would make URL dispatch ambiguous ``` The path field is required; an empty entry is probably an accident, so there is no default. [testmark]:# (err-missing-path/config.yaml) ```yaml repos: parnass: description: "all description, no substance" ``` [testmark]:# (err-missing-path/result) ```text error: config $BASE/config.yaml: repo "parnass": missing required field "path" (use "path: %" to serve the path matching the repo name) ``` Serving the filesystem root is refused outright. [testmark]:# (err-root-path/config.yaml) ```yaml repos: everything: path: "/" ``` [testmark]:# (err-root-path/result) ```text error: config $BASE/config.yaml: repo "everything": path "/" is the filesystem root; refusing ``` The accent knobs: a hue must be on the wheel. [testmark]:# (err-hue-range/config.yaml) ```yaml hue: 3600 repos: parnass: path: "%" ``` [testmark]:# (err-hue-range/result) ```text error: config $BASE/config.yaml: hue 3600 is not on the wheel (0..359) ``` Hue and accent together is an ambiguity, so it is refused. [testmark]:# (err-hue-and-accent/config.yaml) ```yaml hue: 150 accent: "#7a5af5" repos: parnass: path: "%" ``` [testmark]:# (err-hue-and-accent/result) ```text error: config $BASE/config.yaml: hue and accent are both set; pick one (hue keeps the stock tuning, accent takes the wheel) ``` An accent map must carry both schemes. [testmark]:# (err-accent-half/config.yaml) ```yaml accent: light: "#7a5af5" repos: parnass: path: "%" ``` [testmark]:# (err-accent-half/result) ```text error: config $BASE/config.yaml: accent is missing its "dark" color (a bare string sets both schemes; a map needs both) ``` Accent colors are charset-checked, so a typo cannot break the stylesheet they land in. [testmark]:# (err-accent-charset/config.yaml) ```yaml accent: "#7a5af5; } body { display: none" repos: parnass: path: "%" ``` [testmark]:# (err-accent-charset/result) ```text error: config $BASE/config.yaml: accent light color "#7a5af5; } body { display: none" contains characters that have no business in a CSS color ``` A good accent, in the map form. [testmark]:# (good-accent-map/config.yaml) ```yaml accent: light: "hsl(260 60% 35%)" dark: "hsl(260 70% 75%)" repos: parnass: path: "%" ``` [testmark]:# (good-accent-map/result) ```text repo parnass: path=$BASE/parnass ```