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.
Require a linked issue when a change request opens
0789f22ea633bf995417893c0052abb6a36d5520 · Keenan Nemetz · 9d ago · parent 1265ea55
Require a linked issue when a change request opens Add a per-repository policy for teams that want every proposed update to trace back to an issue. The browser marks Closes as required, and the pre-receive hook applies the same rule to requests added through the CLI or a hand-written metadata commit. Existing requests stay editable and landable.
metadata/requests.go +35
| @@ -177,6 +177,41 @@ func LoadRequestAt(g *git.Repo, commit, id string) (*Request, bool, error) { | |||
| 177 | 177 | return list[0], true, nil | |
| 178 | 178 | } | |
| 179 | 179 | ||
| 180 | // NewRequests returns the requests that were added between two commits on the | ||
| 181 | // metadata branch. A missing or zero old commit means the branch is being created, | ||
| 182 | // so every request in it is new. | ||
| 183 | // | ||
| 184 | // Repository policy applies when a request is opened, not to the requests that | ||
| 185 | // were already there. Comparing ids rather than paths is what keeps an edit to an | ||
| 186 | // existing request from being mistaken for a new one. | ||
| 187 | func NewRequests(g *git.Repo, oldCommit, newCommit string) ([]*Request, error) { | ||
| 188 | if newCommit == "" || newCommit == git.ZeroSHA { | ||
| 189 | return nil, nil | ||
| 190 | } | ||
| 191 | current, err := LoadRequestsAt(g, newCommit) | ||
| 192 | if err != nil { | ||
| 193 | return nil, err | ||
| 194 | } | ||
| 195 | if oldCommit == "" || oldCommit == git.ZeroSHA { | ||
| 196 | return current, nil | ||
| 197 | } | ||
| 198 | previous, err := LoadRequestsAt(g, oldCommit) | ||
| 199 | if err != nil { | ||
| 200 | return nil, err | ||
| 201 | } | ||
| 202 | known := make(map[string]bool, len(previous)) | ||
| 203 | for _, req := range previous { | ||
| 204 | known[req.ID] = true | ||
| 205 | } | ||
| 206 | out := make([]*Request, 0, len(current)) | ||
| 207 | for _, req := range current { | ||
| 208 | if !known[req.ID] { | ||
| 209 | out = append(out, req) | ||
| 210 | } | ||
| 211 | } | ||
| 212 | return out, nil | ||
| 213 | } | ||
| 214 | |||
| 180 | 215 | // RequestIDFromPath returns the request a metadata path belongs to. A changed | |
| 181 | 216 | // file names its entity through this, so a comment or an approval updates the | |
| 182 | 217 | // request it belongs to and nothing else. | |