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.
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.
cmd/vole/acl.go +30−1
| @@ -24,6 +24,9 @@ const aclUsage = `usage: vole admin acl <command> [options] [args] | |||
| 24 | 24 | checks enable <repo> | |
| 25 | 25 | checks disable <repo> | |
| 26 | 26 | ||
| 27 | require-issues enable <repo> | ||
| 28 | require-issues disable <repo> | ||
| 29 | |||
| 27 | 30 | protect list <repo> | |
| 28 | 31 | protect add <repo> <ref-pattern>... | |
| 29 | 32 | protect remove <repo> <ref-pattern>... | |
| @@ -65,7 +68,7 @@ func cmdACL(args []string) error { | |||
| 65 | 68 | } | |
| 66 | 69 | switch sub { | |
| 67 | 70 | case "show", "set-role", "set-default-role", "set-approvals", | |
| 68 | "checks", "protect", "runners": | ||
| 71 | "checks", "require-issues", "protect", "runners": | ||
| 69 | 72 | default: | |
| 70 | 73 | fmt.Fprintln(os.Stderr, aclUsage) | |
| 71 | 74 | return usagef("unknown acl subcommand %q", sub) | |
| @@ -128,6 +131,15 @@ func cmdACL(args []string) error { | |||
| 128 | 131 | return usagef("checks takes enable or disable, not %q", action) | |
| 129 | 132 | } | |
| 130 | 133 | ||
| 134 | case "require-issues": | ||
| 135 | if len(f.rest) != 2 { | ||
| 136 | return usageErr{msg: "usage: vole admin acl require-issues enable|disable <repo>"} | ||
| 137 | } | ||
| 138 | action, repo = f.rest[0], f.rest[1] | ||
| 139 | if action != "enable" && action != "disable" { | ||
| 140 | return usagef("require-issues takes enable or disable, not %q", action) | ||
| 141 | } | ||
| 142 | |||
| 131 | 143 | case "protect", "runners": | |
| 132 | 144 | if len(f.rest) < 2 { | |
| 133 | 145 | return usageErr{msg: fmt.Sprintf("usage: vole admin acl %s list|add|remove|set|clear <repo> ...", sub)} | |
| @@ -186,6 +198,11 @@ func cmdACL(args []string) error { | |||
| 186 | 198 | if len(a.Protected) > 0 { | |
| 187 | 199 | fmt.Printf("protected: %s\n", strings.Join(a.Protected, ", ")) | |
| 188 | 200 | } | |
| 201 | if a.RequiresLinkedIssue() { | ||
| 202 | fmt.Println("linked issues: required for new change requests") | ||
| 203 | } else { | ||
| 204 | fmt.Println("linked issues: optional for new change requests") | ||
| 205 | } | ||
| 189 | 206 | // Admins are implicit runners, so an empty list is not "nobody": it is | |
| 190 | 207 | // "nobody beyond the people who can edit this file". | |
| 191 | 208 | if len(a.Runners) == 0 { | |
| @@ -246,6 +263,18 @@ func cmdACL(args []string) error { | |||
| 246 | 263 | } | |
| 247 | 264 | return nil | |
| 248 | 265 | ||
| 266 | case "require-issues": | ||
| 267 | a.RequireLinkedIssue = action == "enable" | ||
| 268 | if err := save(); err != nil { | ||
| 269 | return err | ||
| 270 | } | ||
| 271 | if a.RequiresLinkedIssue() { | ||
| 272 | fmt.Println("linked issues: required when a change request is opened") | ||
| 273 | } else { | ||
| 274 | fmt.Println("linked issues: no longer required for new change requests") | ||
| 275 | } | ||
| 276 | return nil | ||
| 277 | |||
| 249 | 278 | case "protect": | |
| 250 | 279 | if action == "list" { | |
| 251 | 280 | printProtected(a, m.Name) | |