+14
appview/state/signer.go
+14
appview/state/signer.go
···
243
243
return s.client.Do(req)
244
244
}
245
245
246
+
func (s *SignedClient) NewHiddenRef(ownerDid, targetRepo, forkBranch, remoteBranch string) (*http.Response, error) {
247
+
const (
248
+
Method = "POST"
249
+
)
250
+
endpoint := fmt.Sprintf("/%s/%s/hidden-ref/%s/%s", ownerDid, targetRepo, forkBranch, remoteBranch)
251
+
252
+
req, err := s.newRequest(Method, endpoint, nil)
253
+
if err != nil {
254
+
return nil, err
255
+
}
256
+
257
+
return s.client.Do(req)
258
+
}
259
+
246
260
type UnsignedClient struct {
247
261
Url *url.URL
248
262
client *http.Client
+28
-1
knotserver/git/fork.go
+28
-1
knotserver/git/fork.go
···
2
2
3
3
import (
4
4
"fmt"
5
+
"os/exec"
5
6
6
7
"github.com/go-git/go-git/v5"
8
+
"github.com/go-git/go-git/v5/config"
7
9
)
8
10
9
11
func Fork(repoPath, source string) error {
10
12
_, err := git.PlainClone(repoPath, true, &git.CloneOptions{
11
13
URL: source,
12
-
Depth: 1,
13
14
SingleBranch: false,
14
15
})
15
16
16
17
if err != nil {
17
18
return fmt.Errorf("failed to bare clone repository: %w", err)
19
+
}
20
+
21
+
err = exec.Command("git", "-C", repoPath, "config", "receive.hideRefs", "refs/hidden").Run()
22
+
if err != nil {
23
+
return fmt.Errorf("failed to configure hidden refs: %w", err)
24
+
}
25
+
26
+
return nil
27
+
}
28
+
29
+
// TrackHiddenRemoteRef tracks a hidden remote in the repository. For example,
30
+
// if the feature branch on the fork (forkRef) is feature-1, and the remoteRef,
31
+
// i.e. the branch we want to merge into, is main, this will result in a refspec:
32
+
//
33
+
// +refs/heads/main:refs/hidden/feature-1/main
34
+
func (g *GitRepo) TrackHiddenRemoteRef(forkRef, remoteRef string) error {
35
+
fetchOpts := &git.FetchOptions{
36
+
RefSpecs: []config.RefSpec{
37
+
config.RefSpec(fmt.Sprintf("+refs/heads/%s:refs/hidden/%s/%s", forkRef, forkRef, remoteRef)),
38
+
},
39
+
RemoteName: "origin",
40
+
}
41
+
42
+
err := g.r.Fetch(fetchOpts)
43
+
if err != nil {
44
+
return fmt.Errorf("failed to fetch hidden remote: %s: %w", forkRef, err)
18
45
}
19
46
return nil
20
47
}
+2
knotserver/handler.go
+2
knotserver/handler.go
···
85
85
r.Post("/git-upload-pack", h.UploadPack)
86
86
r.Get("/compare/{rev1}/{rev2}", h.Compare) // git diff-tree compare of two objects
87
87
88
+
r.With(h.VerifySignature).Post("/hidden-ref/{forkRef}/{remoteRef}", h.NewHiddenRef)
89
+
88
90
r.Route("/merge", func(r chi.Router) {
89
91
r.With(h.VerifySignature)
90
92
r.Post("/", h.Merge)
+23
knotserver/routes.go
+23
knotserver/routes.go
···
786
786
return
787
787
}
788
788
789
+
func (h *Handle) NewHiddenRef(w http.ResponseWriter, r *http.Request) {
790
+
l := h.l.With("handler", "NewHiddenRef")
791
+
792
+
forkRef := chi.URLParam(r, "forkRef")
793
+
remoteRef := chi.URLParam(r, "remoteRef")
794
+
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
795
+
gr, err := git.PlainOpen(path)
796
+
if err != nil {
797
+
notFound(w)
798
+
return
799
+
}
800
+
801
+
err = gr.TrackHiddenRemoteRef(forkRef, remoteRef)
802
+
if err != nil {
803
+
l.Error("error tracking hidden remote ref", "msg", err.Error())
804
+
writeError(w, "error tracking hidden remote ref", http.StatusBadRequest)
805
+
return
806
+
}
807
+
808
+
w.WriteHeader(http.StatusNoContent)
809
+
return
810
+
}
811
+
789
812
func (h *Handle) AddMember(w http.ResponseWriter, r *http.Request) {
790
813
l := h.l.With("handler", "AddMember")
791
814