Something went wrong. Try again.
Monorepo for Tangled
Something went wrong. Try again.
Go
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273package repo
import ( "encoding/json" "fmt" "io" "net/http" "net/url" "strconv"
"tangled.org/core/api/tangled" "tangled.org/core/appview/commitverify" "tangled.org/core/appview/db" "tangled.org/core/appview/models" "tangled.org/core/appview/pages" xrpcclient "tangled.org/core/appview/xrpcclient" "tangled.org/core/types"
indigoxrpc "github.com/bluesky-social/indigo/xrpc" "github.com/go-chi/chi/v5" "github.com/go-git/go-git/v5/plumbing")
func (rp *Repo) CommitRawDiff(w http.ResponseWriter, r *http.Request) { rp.serveRawCommit(w, r, "diff")}
func (rp *Repo) CommitRawPatch(w http.ResponseWriter, r *http.Request) { rp.serveRawCommit(w, r, "patch")}
func (rp *Repo) serveRawCommit(w http.ResponseWriter, r *http.Request, format string) { l := rp.logger.With("handler", "CommitRaw", "format", format)
f, err := rp.repoResolver.Resolve(r) if err != nil { l.Error("failed to resolve repo", "err", err) return }
ref := chi.URLParam(r, "ref") ref, _ = url.PathUnescape(ref)
if !plumbing.IsHash(ref) { rp.pages.Error404(w) return }
scheme := "http" if !rp.config.Core.Dev { scheme = "https" }
xrpcc := &indigoxrpc.Client{ Host: fmt.Sprintf("%s://%s", scheme, f.Knot), }
xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, f.RepoIdentifier()) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.diff", "xrpcerr", xrpcerr, "err", err) rp.pages.Error503(w) return }
var result types.RepoCommitResponse if err := json.Unmarshal(xrpcBytes, &result); err != nil { l.Error("failed to decode XRPC response", "err", err) rp.pages.Error503(w) return }
filename := ref[:7] + "." + format w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=%q", filename))
switch format { case "patch": io.WriteString(w, renderFormatPatch(result.Diff)) default: io.WriteString(w, renderUnifiedDiff(result.Diff)) }}
func (rp *Repo) Log(w http.ResponseWriter, r *http.Request) { l := rp.logger.With("handler", "RepoLog")
f, err := rp.repoResolver.Resolve(r) if err != nil { l.Error("failed to fully resolve repo", "err", err) return }
page := 1 if r.URL.Query().Get("page") != "" { page, err = strconv.Atoi(r.URL.Query().Get("page")) if err != nil { page = 1 } }
ref := chi.URLParam(r, "ref") ref, _ = url.PathUnescape(ref)
xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url}
limit := int64(60) cursor := "" if page > 1 { // Convert page number to cursor (offset) offset := (page - 1) * int(limit) cursor = strconv.Itoa(offset) }
xrpcBytes, err := tangled.GitTempListCommits(r.Context(), xrpcc, cursor, limit, ref, f.RepoDid) if err != nil { l.Error("failed to call XRPC repo.log", "err", err) rp.pages.Error503(w) return }
var xrpcResp types.RepoLogResponse if err := json.Unmarshal(xrpcBytes, &xrpcResp); err != nil { l.Error("failed to decode XRPC response", "err", err) rp.pages.Error503(w) return }
tagBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoDid) if err != nil { l.Error("failed to call XRPC repo.tags", "err", err) rp.pages.Error503(w) return }
tagMap := make(map[string][]string) if tagBytes != nil { var tagResp types.RepoTagsResponse if err := json.Unmarshal(tagBytes, &tagResp); err == nil { for _, tag := range tagResp.Tags { hash := tag.Hash if tag.Tag != nil { hash = tag.Tag.Target.String() } tagMap[hash] = append(tagMap[hash], tag.Name) } } }
branchBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoDid) if err != nil { l.Error("failed to call XRPC repo.branches", "err", err) rp.pages.Error503(w) return }
if branchBytes != nil { var branchResp types.RepoBranchesResponse if err := json.Unmarshal(branchBytes, &branchResp); err == nil { for _, branch := range branchResp.Branches { tagMap[branch.Hash] = append(tagMap[branch.Hash], branch.Name) } } }
user := rp.oauth.GetMultiAccountUser(r)
emailToDidMap, err := db.GetEmailToDid(rp.db, uniqueEmails(xrpcResp.Commits), true) if err != nil { l.Error("failed to fetch email to did mapping", "err", err) }
vc, err := commitverify.GetVerifiedCommits(rp.db, emailToDidMap, xrpcResp.Commits) if err != nil { l.Error("failed to GetVerifiedObjectCommits", "err", err) }
var shas []string for _, c := range xrpcResp.Commits { shas = append(shas, c.Hash.String()) } pipelines, err := getPipelineStatuses(rp.db, f, shas) if err != nil { l.Error("failed to getPipelineStatuses", "err", err) // non-fatal }
rp.pages.RepoLog(w, pages.RepoLogParams{ BaseParams: pages.BaseParamsFromContext(r.Context()), TagMap: tagMap, RepoInfo: rp.repoResolver.GetRepoInfo(r, user), RepoLogResponse: xrpcResp, EmailToDid: emailToDidMap, VerifiedCommits: vc, Pipelines: pipelines, })}
func (rp *Repo) Commit(w http.ResponseWriter, r *http.Request) { l := rp.logger.With("handler", "RepoCommit")
f, err := rp.repoResolver.Resolve(r) if err != nil { l.Error("failed to fully resolve repo", "err", err) return } ref := chi.URLParam(r, "ref") ref, _ = url.PathUnescape(ref)
var diffOpts types.DiffOpts if d := r.URL.Query().Get("diff"); d == "split" { diffOpts.Split = true }
if !plumbing.IsHash(ref) { rp.pages.Error404(w) return }
scheme := "http" if !rp.config.Core.Dev { scheme = "https" } host := fmt.Sprintf("%s://%s", scheme, f.Knot) xrpcc := &indigoxrpc.Client{ Host: host, }
xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, f.RepoIdentifier()) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.diff", "xrpcerr", xrpcerr, "err", err) rp.pages.Error503(w) return }
var result types.RepoCommitResponse if err := json.Unmarshal(xrpcBytes, &result); err != nil { l.Error("failed to decode XRPC response", "err", err) rp.pages.Error503(w) return }
emailToDidMap, err := db.GetEmailToDid(rp.db, []string{result.Diff.Commit.Committer.Email, result.Diff.Commit.Author.Email}, true) if err != nil { l.Error("failed to get email to did mapping", "err", err) }
vc, err := commitverify.GetVerifiedCommits(rp.db, emailToDidMap, []types.Commit{result.Diff.Commit}) if err != nil { l.Error("failed to GetVerifiedCommits", "err", err) }
user := rp.oauth.GetMultiAccountUser(r) pipelines, err := getPipelineStatuses(rp.db, f, []string{result.Diff.Commit.This}) if err != nil { l.Error("failed to getPipelineStatuses", "err", err) // non-fatal } var pipeline *models.Pipeline if p, ok := pipelines[result.Diff.Commit.This]; ok { pipeline = &p }
rp.pages.RepoCommit(w, pages.RepoCommitParams{ BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), RepoCommitResponse: result, EmailToDid: emailToDidMap, VerifiedCommit: vc, Pipeline: pipeline, DiffOpts: diffOpts, })}