+87
knot2/server/handler/xrpc_git_keep_commit.go
+87
knot2/server/handler/xrpc_git_keep_commit.go
···
1
+
package handler
2
+
3
+
import (
4
+
"encoding/json"
5
+
"fmt"
6
+
"net/http"
7
+
"os/exec"
8
+
"path"
9
+
10
+
"github.com/bluesky-social/indigo/atproto/syntax"
11
+
"github.com/go-git/go-git/v5"
12
+
"github.com/go-git/go-git/v5/plumbing"
13
+
"tangled.org/core/api/tangled"
14
+
"tangled.org/core/knot2/config"
15
+
"tangled.org/core/log"
16
+
xrpcerr "tangled.org/core/xrpc/errors"
17
+
)
18
+
19
+
func XrpcGitKeepCommit(cfg *config.Config) http.HandlerFunc {
20
+
return func(w http.ResponseWriter, r *http.Request) {
21
+
ctx := r.Context()
22
+
l := log.FromContext(ctx).With("handler", "XrpcGitKeepCommit")
23
+
24
+
// TODO: get session did
25
+
actorDid := syntax.DID("")
26
+
27
+
var input tangled.GitKeepCommit_Input
28
+
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
29
+
l.Error("failed to decode body", "err", err)
30
+
panic("unimplemented")
31
+
}
32
+
33
+
repoAt, err := syntax.ParseATURI(input.Repo)
34
+
if err != nil {
35
+
l.Error("failed to decode body", "err", err)
36
+
panic("unimplemented")
37
+
}
38
+
repoPath := repoPathFromAtUri(cfg, repoAt)
39
+
40
+
// ensure repo exist (if not, clone it)
41
+
repo, err := git.PlainOpen(repoPath)
42
+
if err != nil {
43
+
// TODO: clone the ref from source repo if repo doesn't exist in this knot yet
44
+
l.Info("repo missing in knot", "err", err)
45
+
panic("unimplemented")
46
+
}
47
+
48
+
commitId, err := repo.ResolveRevision(plumbing.Revision(input.Ref))
49
+
if err != nil {
50
+
l.Error("failed to resolve revision", "ref", input.Ref, "err", err)
51
+
panic("unimplemented")
52
+
}
53
+
54
+
// set keep-ref for given commit
55
+
refspec := fmt.Sprintf("refs/knot/%s/keep/%s", actorDid, commitId)
56
+
updateRefCmd := exec.Command("git", "-C", repoPath, "update-ref", refspec, commitId.String())
57
+
if err := updateRefCmd.Run(); err != nil {
58
+
writeError(w, xrpcerr.GenericError(err), http.StatusBadRequest)
59
+
return
60
+
}
61
+
62
+
output := tangled.GitKeepCommit_Output{
63
+
CommitId: commitId.String(),
64
+
}
65
+
66
+
w.WriteHeader(http.StatusOK)
67
+
writeJson(w, output)
68
+
}
69
+
}
70
+
71
+
func repoPathFromAtUri(cfg *config.Config, repoAt syntax.ATURI) string {
72
+
return path.Join(cfg.RepoDir, repoAt.Authority().String(), repoAt.RecordKey().String())
73
+
}
74
+
75
+
func writeError(w http.ResponseWriter, e xrpcerr.XrpcError, status int) {
76
+
w.Header().Set("Content-Type", "application/json")
77
+
w.WriteHeader(status)
78
+
json.NewEncoder(w).Encode(e)
79
+
}
80
+
81
+
func writeJson(w http.ResponseWriter, response any) {
82
+
w.Header().Set("Content-Type", "application/json")
83
+
if err := json.NewEncoder(w).Encode(response); err != nil {
84
+
writeError(w, xrpcerr.GenericError(err), http.StatusInternalServerError)
85
+
return
86
+
}
87
+
}
+4
-3
knot2/server/routes.go
+4
-3
knot2/server/routes.go
···
7
7
"github.com/bluesky-social/indigo/atproto/auth/oauth"
8
8
"github.com/go-chi/chi/v5"
9
9
"github.com/gorilla/sessions"
10
+
"tangled.org/core/api/tangled"
10
11
"tangled.org/core/knot2/config"
11
12
"tangled.org/core/knot2/server/handler"
12
13
"tangled.org/core/knot2/server/middleware"
···
43
44
44
45
r.Get("/events", handler.Events())
45
46
46
-
// r.Route("/xrpc", func(r chi.Router) {
47
-
// r.Post("/"+tangled.GitKeepRefNSID, handler.GitKeepRef())
48
-
// })
47
+
r.Route("/xrpc", func(r chi.Router) {
48
+
r.Post("/"+tangled.GitKeepCommitNSID, handler.XrpcGitKeepCommit(cfg))
49
+
})
49
50
50
51
return r
51
52
}