From a713d72ae60594e7848c3613b6fc5e24dc91aa89 Mon Sep 17 00:00:00 2001 From: Seongmin Lee Date: Tue, 2 Dec 2025 11:55:51 +0900 Subject: [PATCH] wip: knot2: xrpc.git.keepCommit Signed-off-by: Seongmin Lee --- knot2/server/handler/xrpc_git_keep_commit.go | 87 ++++++++++++++++++++ knot2/server/routes.go | 7 +- 2 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 knot2/server/handler/xrpc_git_keep_commit.go diff --git a/knot2/server/handler/xrpc_git_keep_commit.go b/knot2/server/handler/xrpc_git_keep_commit.go new file mode 100644 index 00000000..a7c8ab3e --- /dev/null +++ b/knot2/server/handler/xrpc_git_keep_commit.go @@ -0,0 +1,87 @@ +package handler + +import ( + "encoding/json" + "fmt" + "net/http" + "os/exec" + "path" + + "github.com/bluesky-social/indigo/atproto/syntax" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" + "tangled.org/core/api/tangled" + "tangled.org/core/knot2/config" + "tangled.org/core/log" + xrpcerr "tangled.org/core/xrpc/errors" +) + +func XrpcGitKeepCommit(cfg *config.Config) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + l := log.FromContext(ctx).With("handler", "XrpcGitKeepCommit") + + // TODO: get session did + actorDid := syntax.DID("") + + var input tangled.GitKeepCommit_Input + if err := json.NewDecoder(r.Body).Decode(&input); err != nil { + l.Error("failed to decode body", "err", err) + panic("unimplemented") + } + + repoAt, err := syntax.ParseATURI(input.Repo) + if err != nil { + l.Error("failed to decode body", "err", err) + panic("unimplemented") + } + repoPath := repoPathFromAtUri(cfg, repoAt) + + // ensure repo exist (if not, clone it) + repo, err := git.PlainOpen(repoPath) + if err != nil { + // TODO: clone the ref from source repo if repo doesn't exist in this knot yet + l.Info("repo missing in knot", "err", err) + panic("unimplemented") + } + + commitId, err := repo.ResolveRevision(plumbing.Revision(input.Ref)) + if err != nil { + l.Error("failed to resolve revision", "ref", input.Ref, "err", err) + panic("unimplemented") + } + + // set keep-ref for given commit + refspec := fmt.Sprintf("refs/knot/%s/keep/%s", actorDid, commitId) + updateRefCmd := exec.Command("git", "-C", repoPath, "update-ref", refspec, commitId.String()) + if err := updateRefCmd.Run(); err != nil { + writeError(w, xrpcerr.GenericError(err), http.StatusBadRequest) + return + } + + output := tangled.GitKeepCommit_Output{ + CommitId: commitId.String(), + } + + w.WriteHeader(http.StatusOK) + writeJson(w, output) + } +} + +func repoPathFromAtUri(cfg *config.Config, repoAt syntax.ATURI) string { + return path.Join(cfg.RepoDir, repoAt.Authority().String(), repoAt.RecordKey().String()) +} + +func writeError(w http.ResponseWriter, e xrpcerr.XrpcError, status int) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(status) + json.NewEncoder(w).Encode(e) +} + +func writeJson(w http.ResponseWriter, response any) { + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(response); err != nil { + writeError(w, xrpcerr.GenericError(err), http.StatusInternalServerError) + return + } +} diff --git a/knot2/server/routes.go b/knot2/server/routes.go index cdf28624..0c512170 100644 --- a/knot2/server/routes.go +++ b/knot2/server/routes.go @@ -7,6 +7,7 @@ import ( "github.com/bluesky-social/indigo/atproto/auth/oauth" "github.com/go-chi/chi/v5" "github.com/gorilla/sessions" + "tangled.org/core/api/tangled" "tangled.org/core/knot2/config" "tangled.org/core/knot2/server/handler" "tangled.org/core/knot2/server/middleware" @@ -43,9 +44,9 @@ func Routes( r.Get("/events", handler.Events()) - // r.Route("/xrpc", func(r chi.Router) { - // r.Post("/"+tangled.GitKeepRefNSID, handler.GitKeepRef()) - // }) + r.Route("/xrpc", func(r chi.Router) { + r.Post("/"+tangled.GitKeepCommitNSID, handler.XrpcGitKeepCommit(cfg)) + }) return r } -- 2.51.2