Monorepo for Tangled

knotserver/{git,xrpc}: last commit for specific file path

RepoBlob now also includes the last commit for the blob.

Signed-off-by: Anirudh Oppiliappan <anirudh@tangled.org>

authored by

Anirudh Oppiliappan and committed by tangled.org 94340f70 e3285ce3

+61
+36
knotserver/git/last_commit.go
··· 14 14 "github.com/dgraph-io/ristretto" 15 15 "github.com/go-git/go-git/v5/plumbing" 16 16 "github.com/go-git/go-git/v5/plumbing/object" 17 + "tangled.org/core/types" 17 18 ) 18 19 19 20 var ( ··· 185 186 } 186 187 return ancestors 187 188 } 189 + 190 + // GetLastCommitForPath returns the last commit information for a specific file path 191 + func (g *GitRepo) GetLastCommitForPath(ctx context.Context, filePath string) (*types.LastCommitInfo, error) { 192 + c, err := g.r.CommitObject(g.h) 193 + if err != nil { 194 + return nil, fmt.Errorf("commit object: %w", err) 195 + } 196 + 197 + tree, err := c.Tree() 198 + if err != nil { 199 + return nil, fmt.Errorf("file tree: %w", err) 200 + } 201 + 202 + // parent directory for calculateCommitTime 203 + parent := path.Dir(filePath) 204 + if parent == "." { 205 + parent = "" 206 + } 207 + 208 + times, err := g.calculateCommitTimeIn(ctx, tree, parent, 2*time.Second) 209 + if err != nil { 210 + return nil, fmt.Errorf("calculate commit time: %w", err) 211 + } 212 + 213 + commitInfo, ok := times[filePath] 214 + if !ok { 215 + return nil, fmt.Errorf("no commit found for path: %s", filePath) 216 + } 217 + 218 + return &types.LastCommitInfo{ 219 + Hash: commitInfo.hash, 220 + Message: commitInfo.message, 221 + When: commitInfo.when, 222 + }, nil 223 + }
+25
knotserver/xrpc/repo_blob.go
··· 1 1 package xrpc 2 2 3 3 import ( 4 + "context" 4 5 "crypto/sha256" 5 6 "encoding/base64" 6 7 "fmt" ··· 8 9 "path/filepath" 9 10 "slices" 10 11 "strings" 12 + "time" 11 13 12 14 "tangled.org/core/api/tangled" 13 15 "tangled.org/core/knotserver/git" ··· 140 142 141 143 if mimeType != "" { 142 144 response.MimeType = &mimeType 145 + } 146 + 147 + ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second) 148 + defer cancel() 149 + 150 + lastCommit, err := gr.GetLastCommitForPath(ctx, treePath) 151 + if err == nil && lastCommit != nil { 152 + shortHash := lastCommit.Hash.String()[:8] 153 + response.LastCommit = &tangled.RepoBlob_LastCommit{ 154 + Hash: lastCommit.Hash.String(), 155 + ShortHash: &shortHash, 156 + Message: lastCommit.Message, 157 + When: lastCommit.When.Format(time.RFC3339), 158 + } 159 + 160 + // try to get author information 161 + commit, err := gr.Commit(lastCommit.Hash) 162 + if err == nil { 163 + response.LastCommit.Author = &tangled.RepoBlob_Signature{ 164 + Name: commit.Author.Name, 165 + Email: commit.Author.Email, 166 + } 167 + } 143 168 } 144 169 145 170 writeJson(w, response)