package xrpc import ( "net/http" "strconv" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" "tangled.org/core/knotserver/vcs" "tangled.org/core/types" xrpcerr "tangled.org/core/xrpc/errors" ) func (x *Xrpc) RepoLog(w http.ResponseWriter, r *http.Request) { repo := r.URL.Query().Get("repo") repoPath, err := x.parseRepoParam(repo) if err != nil { writeError(w, err.(xrpcerr.XrpcError), http.StatusBadRequest) return } ref := r.URL.Query().Get("ref") path := r.URL.Query().Get("path") cursor := r.URL.Query().Get("cursor") limit := 50 // default if limitStr := r.URL.Query().Get("limit"); limitStr != "" { if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 100 { limit = l } } rv, err := vcs.Open(repoPath, ref) if err != nil { writeError(w, xrpcerr.RefNotFoundError, http.StatusNotFound) return } // If ref was empty, resolve the actual default branch name if ref == "" { if defaultBranch, err := rv.DefaultBranch(); err == nil { ref = defaultBranch } } offset := 0 if cursor != "" { if o, err := strconv.Atoi(cursor); err == nil && o >= 0 { offset = o } } entries, err := rv.History(offset, limit) if err != nil { x.Logger.Error("fetching history", "error", err.Error()) writeError(w, xrpcerr.NewXrpcError( xrpcerr.WithTag("PathNotFound"), xrpcerr.WithMessage("failed to read commit log"), ), http.StatusNotFound) return } total, err := rv.TotalHistoryEntries() if err != nil { x.Logger.Error("fetching total history entries", "error", err.Error()) writeError(w, xrpcerr.NewXrpcError( xrpcerr.WithTag("InternalServerError"), xrpcerr.WithMessage("failed to fetch total commits"), ), http.StatusInternalServerError) return } tcommits := make([]types.Commit, len(entries)) for i, e := range entries { parents := make([]plumbing.Hash, 0, len(e.Parents)) for _, p := range e.Parents { parents = append(parents, plumbing.NewHash(p)) } tcommits[i] = types.Commit{ Hash: plumbing.NewHash(e.Hash), Author: object.Signature{ Name: e.Author.Name, Email: e.Author.Email, When: e.Author.When, }, Committer: object.Signature{ Name: e.Committer.Name, Email: e.Committer.Email, When: e.Committer.When, }, Message: e.Message, ParentHashes: parents, } } response := types.RepoLogResponse{ Commits: tcommits, Ref: ref, Page: (offset / limit) + 1, PerPage: limit, Total: total, } if path != "" { response.Description = path } response.Log = true writeJson(w, response) }