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/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.

Compact the change request target controls

41d1fee900568b1bff5c7cff3b4c52942f47fabd · Keenan Nemetz · 13d ago · parent e050e14a

Compact the change request target controls

Replace the separate base and head forms and the duplicated labels with one
row: base picker, head picker, update. The pickers preselect the current
targets, and a pinned head appears as the current commit. Collapse the help
text to one line.

Post both targets to one /target handler and write them in one metadata
commit. Either change invalidates approvals; keeping the current value is
allowed even if its branch has gone missing so the other side can still be
repaired.

metadata/request_write.go +44

@@ -236,6 +236,50 @@ func SetRequestBase(g *git.Repo, id, newBase, actor string) (*Request, error) {
236 236 return out, err
237 237 }
238 238
239 // SetRequestTarget moves an open request's base and the branch it follows in one
240 // metadata commit. It is the writer behind the request page's single target control:
241 // changing both together avoids a request that briefly points at a base it was never
242 // reviewed against. Approvals name the old base and commit, so either change makes
243 // them stale.
244 func SetRequestTarget(g *git.Repo, id, newBase, newHead, newHeadRef, actor string) (*Request, error) {
245 var out *Request
246 dir := fmt.Sprintf("%s/%s/", RequestsDir, id)
247 target := newHeadRef
248 if target == "" {
249 target = format.SHA(newHead)
250 }
251 _, err := git.CommitFiles(g, Ref, func(files map[string][]byte) error {
252 r, err := loadFrom(files, id)
253 if err != nil {
254 return err
255 }
256 if r.State != "open" {
257 return fmt.Errorf("requests: %s is %s, so its target cannot move", id, r.State)
258 }
259 if r.Base == newBase && r.Head == newHead && r.HeadRef == newHeadRef {
260 out = r
261 return ErrNoChange
262 }
263 r.Base = newBase
264 r.Head = newHead
265 r.HeadRef = newHeadRef
266 if err := validateRequestForWrite(r); err != nil {
267 return err
268 }
269 raw, err := renderRequest(r)
270 if err != nil {
271 return err
272 }
273 files[dir+requestName] = raw
274 out = r
275 return nil
276 }, fmt.Sprintf("request: %s target %s <- %s", id, newBase, target), actor)
277 if errors.Is(err, ErrNoChange) {
278 return out, nil
279 }
280 return out, err
281 }
282
239 283 // SyncBranchHead moves every open request that follows branch to head. It is the
240 284 // server-side half of following a branch: post-receive calls it after the ref has
241 285 // moved, so the request names the tip a reviewer will see. It changes only head;