vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
Add repository settings for description, branch, and visibility
1948358f9719cd0e5a15bd75a5d5dd3640e4ea82 · Keenan Nemetz · 15d ago · parent e84a66f5
Add repository settings for description, branch, and visibility The Settings tab is shown only to repository admins and edits the facts that repository owns: description, default branch (validated and required to exist), and public/private visibility. Visibility toggles the ACL default between none and read and leaves explicit entries alone; access rules stay an instance-admin operation. The page is read-gated before it is admin-gated, so a private repository still answers 404 rather than confirming that settings exist. Saves carry CSRF, are audited, and refresh the repository index. Adds Meta setters for the description file and HEAD, plus git helpers to validate a branch and point HEAD at it.
forge/repo/repo.go +38
| @@ -148,6 +148,44 @@ func (s *Store) Open(name string) (*Meta, error) { | |||
| 148 | 148 | return m, nil | |
| 149 | 149 | } | |
| 150 | 150 | ||
| 151 | // SetDescription writes the repository's description beside the bare repo. An | ||
| 152 | // empty description removes the file, so a later Open cannot resurrect a value | ||
| 153 | // the operator cleared. | ||
| 154 | func (m *Meta) SetDescription(description string) error { | ||
| 155 | description = strings.TrimSpace(description) | ||
| 156 | path := filepath.Join(m.Dir, descFile) | ||
| 157 | if description == "" { | ||
| 158 | if err := os.Remove(path); err != nil && !os.IsNotExist(err) { | ||
| 159 | return err | ||
| 160 | } | ||
| 161 | } else if err := os.WriteFile(path, []byte(description+"\n"), 0o644); err != nil { | ||
| 162 | return err | ||
| 163 | } | ||
| 164 | m.Description = description | ||
| 165 | return nil | ||
| 166 | } | ||
| 167 | |||
| 168 | // SetDefaultBranch points HEAD at a branch that already exists. It validates the | ||
| 169 | // name and the ref before touching HEAD, so a rejected branch changes nothing. | ||
| 170 | func (m *Meta) SetDefaultBranch(branch string) error { | ||
| 171 | branch = strings.TrimSpace(branch) | ||
| 172 | if branch == "" { | ||
| 173 | return fmt.Errorf("default branch is required") | ||
| 174 | } | ||
| 175 | g := m.Git() | ||
| 176 | if !g.ValidBranch(branch) { | ||
| 177 | return fmt.Errorf("%q is not a valid branch name", branch) | ||
| 178 | } | ||
| 179 | if sha, err := g.RevParse("refs/heads/" + branch); err != nil || sha == "" { | ||
| 180 | return fmt.Errorf("branch %q does not exist", branch) | ||
| 181 | } | ||
| 182 | if err := g.SetHEAD(branch); err != nil { | ||
| 183 | return err | ||
| 184 | } | ||
| 185 | m.DefaultBranch = branch | ||
| 186 | return nil | ||
| 187 | } | ||
| 188 | |||
| 151 | 189 | // List returns every repo in the store, sorted by name. | |
| 152 | 190 | func (s *Store) List() ([]*Meta, error) { | |
| 153 | 191 | ents, err := os.ReadDir(s.Root) | |