···4647// DefaultSize returns the default size for a card
48func DefaultSize() (int, int) {
49- return 1200, 630
50}
5152// NewCard creates a new card with the given dimensions in pixels
···4647// DefaultSize returns the default size for a card
48func DefaultSize() (int, int) {
49+ return 1200, 600
50}
5152// NewCard creates a new card with the given dimensions in pixels
+28-54
appview/repo/opengraph.go
···35 // Split content horizontally: main content (80%) and avatar area (20%)
36 mainContent, avatarArea := contentCard.Split(true, 80)
3738- // Use main content area for both repo name and description to allow dynamic wrapping.
39- mainContent.SetMargin(10)
000400041 var ownerHandle string
42 owner, err := rp.idResolver.ResolveIdent(context.Background(), repo.Did)
43 if err != nil {
···46 ownerHandle = "@" + owner.Handle.String()
47 }
4849- bounds := mainContent.Img.Bounds()
50- startX := bounds.Min.X + mainContent.Margin
51- startY := bounds.Min.Y + mainContent.Margin
0052 currentX := startX
53- currentY := startY
54- lineHeight := 64 // Font size 54 + padding
55 textColor := color.RGBA{88, 96, 105, 255}
5657- // Draw owner handle
58- ownerWidth, err := mainContent.DrawTextAtWithWidth(ownerHandle, currentX, currentY, textColor, 54, ogcard.Top, ogcard.Left)
59 if err != nil {
60 return nil, err
61 }
62 currentX += ownerWidth
6364 // Draw separator
65- sepWidth, err := mainContent.DrawTextAtWithWidth(" / ", currentX, currentY, textColor, 54, ogcard.Top, ogcard.Left)
66 if err != nil {
67 return nil, err
68 }
69 currentX += sepWidth
7071- words := strings.Fields(repo.Name)
72- spaceWidth, _ := mainContent.DrawTextAtWithWidth(" ", -1000, -1000, color.Black, 54, ogcard.Top, ogcard.Left)
73- if spaceWidth == 0 {
74- spaceWidth = 15
75 }
7677- for _, word := range words {
78- // estimate bold width by measuring regular width and adding a multiplier
79- regularWidth, _ := mainContent.DrawTextAtWithWidth(word, -1000, -1000, color.Black, 54, ogcard.Top, ogcard.Left)
80- estimatedBoldWidth := int(float64(regularWidth) * 1.15) // Heuristic for bold text
81-82- if currentX+estimatedBoldWidth > (bounds.Max.X - mainContent.Margin) {
83- currentX = startX
84- currentY += lineHeight
85- }
86-87- _, err := mainContent.DrawBoldText(word, currentX, currentY, color.Black, 54, ogcard.Top, ogcard.Left)
88- if err != nil {
89- return nil, err
90- }
91- currentX += estimatedBoldWidth + spaceWidth
92 }
9394- // update Y position for the description
95- currentY += lineHeight
96-97- // draw description
98- if currentY < bounds.Max.Y-mainContent.Margin {
99- totalHeight := float64(bounds.Dy())
100- repoNameHeight := float64(currentY - bounds.Min.Y)
101-102- if totalHeight > 0 && repoNameHeight < totalHeight {
103- repoNamePercent := (repoNameHeight / totalHeight) * 100
104- if repoNamePercent < 95 { // Ensure there's space left for description
105- _, descriptionCard := mainContent.Split(false, int(repoNamePercent))
106- descriptionCard.SetMargin(8)
107-108- description := repo.Description
109- if len(description) > 70 {
110- description = description[:70] + "…"
111- }
112-113- _, err = descriptionCard.DrawText(description, color.RGBA{88, 96, 105, 255}, 36, ogcard.Top, ogcard.Left)
114- if err != nil {
115- log.Printf("failed to draw description: %v", err)
116- }
117- }
118- }
119 }
120121 // Draw avatar circle on the right side
···35 // Split content horizontally: main content (80%) and avatar area (20%)
36 mainContent, avatarArea := contentCard.Split(true, 80)
3738+ // Split main content: 50% for name/description, 50% for spacing
39+ topSection, _ := mainContent.Split(false, 50)
40+41+ // Split top section: 40% for repo name, 60% for description
42+ repoNameCard, descriptionCard := topSection.Split(false, 50)
4344+ // Draw repo name with owner in regular and repo name in bold
45+ repoNameCard.SetMargin(10)
46 var ownerHandle string
47 owner, err := rp.idResolver.ResolveIdent(context.Background(), repo.Did)
48 if err != nil {
···51 ownerHandle = "@" + owner.Handle.String()
52 }
5354+ // Draw repo name with wrapping support
55+ repoNameCard.SetMargin(10)
56+ bounds := repoNameCard.Img.Bounds()
57+ startX := bounds.Min.X + repoNameCard.Margin
58+ startY := bounds.Min.Y + repoNameCard.Margin
59 currentX := startX
0060 textColor := color.RGBA{88, 96, 105, 255}
6162+ // Draw owner handle in gray
63+ ownerWidth, err := repoNameCard.DrawTextAtWithWidth(ownerHandle, currentX, startY, textColor, 54, ogcard.Top, ogcard.Left)
64 if err != nil {
65 return nil, err
66 }
67 currentX += ownerWidth
6869 // Draw separator
70+ sepWidth, err := repoNameCard.DrawTextAtWithWidth(" / ", currentX, startY, textColor, 54, ogcard.Top, ogcard.Left)
71 if err != nil {
72 return nil, err
73 }
74 currentX += sepWidth
7576+ // Draw repo name in bold
77+ _, err = repoNameCard.DrawBoldText(repo.Name, currentX, startY, color.Black, 54, ogcard.Top, ogcard.Left)
78+ if err != nil {
79+ return nil, err
80 }
8182+ // Draw description (DrawText handles multi-line wrapping automatically)
83+ descriptionCard.SetMargin(10)
84+ description := repo.Description
85+ if len(description) > 70 {
86+ description = description[:70] + "…"
000000000087 }
8889+ _, err = descriptionCard.DrawText(description, color.RGBA{88, 96, 105, 255}, 36, ogcard.Top, ogcard.Left)
90+ if err != nil {
91+ log.Printf("failed to draw description: %v", err)
92+ return nil, err
00000000000000000000093 }
9495 // Draw avatar circle on the right side
+130-92
appview/repo/repo.go
···7 "errors"
8 "fmt"
9 "io"
10- "log"
11 "log/slog"
12 "net/http"
13 "net/url"
···90}
9192func (rp *Repo) DownloadArchive(w http.ResponseWriter, r *http.Request) {
0093 ref := chi.URLParam(r, "ref")
94 ref, _ = url.PathUnescape(ref)
9596 f, err := rp.repoResolver.Resolve(r)
97 if err != nil {
98- log.Println("failed to get repo and knot", err)
99 return
100 }
101···111 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
112 archiveBytes, err := tangled.RepoArchive(r.Context(), xrpcc, "tar.gz", "", ref, repo)
113 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
114- log.Println("failed to call XRPC repo.archive", xrpcerr)
115 rp.pages.Error503(w)
116 return
117 }
···128}
129130func (rp *Repo) RepoLog(w http.ResponseWriter, r *http.Request) {
00131 f, err := rp.repoResolver.Resolve(r)
132 if err != nil {
133- log.Println("failed to fully resolve repo", err)
134 return
135 }
136···165 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
166 xrpcBytes, err := tangled.RepoLog(r.Context(), xrpcc, cursor, limit, "", ref, repo)
167 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
168- log.Println("failed to call XRPC repo.log", xrpcerr)
169 rp.pages.Error503(w)
170 return
171 }
172173 var xrpcResp types.RepoLogResponse
174 if err := json.Unmarshal(xrpcBytes, &xrpcResp); err != nil {
175- log.Println("failed to decode XRPC response", err)
176 rp.pages.Error503(w)
177 return
178 }
179180 tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
181 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
182- log.Println("failed to call XRPC repo.tags", xrpcerr)
183 rp.pages.Error503(w)
184 return
185 }
···196197 branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
198 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
199- log.Println("failed to call XRPC repo.branches", xrpcerr)
200 rp.pages.Error503(w)
201 return
202 }
···214215 emailToDidMap, err := db.GetEmailToDid(rp.db, uniqueEmails(xrpcResp.Commits), true)
216 if err != nil {
217- log.Println("failed to fetch email to did mapping", err)
218 }
219220 vc, err := commitverify.GetVerifiedObjectCommits(rp.db, emailToDidMap, xrpcResp.Commits)
221 if err != nil {
222- log.Println(err)
223 }
224225 repoInfo := f.RepoInfo(user)
···230 }
231 pipelines, err := getPipelineStatuses(rp.db, repoInfo, shas)
232 if err != nil {
233- log.Println(err)
234 // non-fatal
235 }
236···246}
247248func (rp *Repo) RepoDescriptionEdit(w http.ResponseWriter, r *http.Request) {
00249 f, err := rp.repoResolver.Resolve(r)
250 if err != nil {
251- log.Println("failed to get repo and knot", err)
252 w.WriteHeader(http.StatusBadRequest)
253 return
254 }
···260}
261262func (rp *Repo) RepoDescription(w http.ResponseWriter, r *http.Request) {
00263 f, err := rp.repoResolver.Resolve(r)
264 if err != nil {
265- log.Println("failed to get repo and knot", err)
266 w.WriteHeader(http.StatusBadRequest)
267 return
268 }
···270 repoAt := f.RepoAt()
271 rkey := repoAt.RecordKey().String()
272 if rkey == "" {
273- log.Println("invalid aturi for repo", err)
274 w.WriteHeader(http.StatusInternalServerError)
275 return
276 }
···287 newDescription := r.FormValue("description")
288 client, err := rp.oauth.AuthorizedClient(r)
289 if err != nil {
290- log.Println("failed to get client")
291 rp.pages.Notice(w, "repo-notice", "Failed to update description, try again later.")
292 return
293 }
···295 // optimistic update
296 err = db.UpdateDescription(rp.db, string(repoAt), newDescription)
297 if err != nil {
298- log.Println("failed to perferom update-description query", err)
299 rp.pages.Notice(w, "repo-notice", "Failed to update description, try again later.")
300 return
301 }
···324 })
325326 if err != nil {
327- log.Println("failed to perferom update-description query", err)
328 // failed to get record
329 rp.pages.Notice(w, "repo-notice", "Failed to update description, unable to save to PDS.")
330 return
···341}
342343func (rp *Repo) RepoCommit(w http.ResponseWriter, r *http.Request) {
00344 f, err := rp.repoResolver.Resolve(r)
345 if err != nil {
346- log.Println("failed to fully resolve repo", err)
347 return
348 }
349 ref := chi.URLParam(r, "ref")
···371 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
372 xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, repo)
373 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
374- log.Println("failed to call XRPC repo.diff", xrpcerr)
375 rp.pages.Error503(w)
376 return
377 }
378379 var result types.RepoCommitResponse
380 if err := json.Unmarshal(xrpcBytes, &result); err != nil {
381- log.Println("failed to decode XRPC response", err)
382 rp.pages.Error503(w)
383 return
384 }
385386 emailToDidMap, err := db.GetEmailToDid(rp.db, []string{result.Diff.Commit.Committer.Email, result.Diff.Commit.Author.Email}, true)
387 if err != nil {
388- log.Println("failed to get email to did mapping:", err)
389 }
390391 vc, err := commitverify.GetVerifiedCommits(rp.db, emailToDidMap, []types.NiceDiff{*result.Diff})
392 if err != nil {
393- log.Println(err)
394 }
395396 user := rp.oauth.GetUser(r)
397 repoInfo := f.RepoInfo(user)
398 pipelines, err := getPipelineStatuses(rp.db, repoInfo, []string{result.Diff.Commit.This})
399 if err != nil {
400- log.Println(err)
401 // non-fatal
402 }
403 var pipeline *models.Pipeline
···417}
418419func (rp *Repo) RepoTree(w http.ResponseWriter, r *http.Request) {
00420 f, err := rp.repoResolver.Resolve(r)
421 if err != nil {
422- log.Println("failed to fully resolve repo", err)
423 return
424 }
425···444 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
445 xrpcResp, err := tangled.RepoTree(r.Context(), xrpcc, treePath, ref, repo)
446 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
447- log.Println("failed to call XRPC repo.tree", xrpcerr)
448 rp.pages.Error503(w)
449 return
450 }
···519}
520521func (rp *Repo) RepoTags(w http.ResponseWriter, r *http.Request) {
00522 f, err := rp.repoResolver.Resolve(r)
523 if err != nil {
524- log.Println("failed to get repo and knot", err)
525 return
526 }
527···537 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
538 xrpcBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
539 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
540- log.Println("failed to call XRPC repo.tags", xrpcerr)
541 rp.pages.Error503(w)
542 return
543 }
544545 var result types.RepoTagsResponse
546 if err := json.Unmarshal(xrpcBytes, &result); err != nil {
547- log.Println("failed to decode XRPC response", err)
548 rp.pages.Error503(w)
549 return
550 }
551552 artifacts, err := db.GetArtifact(rp.db, db.FilterEq("repo_at", f.RepoAt()))
553 if err != nil {
554- log.Println("failed grab artifacts", err)
555 return
556 }
557···588}
589590func (rp *Repo) RepoBranches(w http.ResponseWriter, r *http.Request) {
00591 f, err := rp.repoResolver.Resolve(r)
592 if err != nil {
593- log.Println("failed to get repo and knot", err)
594 return
595 }
596···606 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
607 xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
608 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
609- log.Println("failed to call XRPC repo.branches", xrpcerr)
610 rp.pages.Error503(w)
611 return
612 }
613614 var result types.RepoBranchesResponse
615 if err := json.Unmarshal(xrpcBytes, &result); err != nil {
616- log.Println("failed to decode XRPC response", err)
617 rp.pages.Error503(w)
618 return
619 }
···629}
630631func (rp *Repo) DeleteBranch(w http.ResponseWriter, r *http.Request) {
00632 f, err := rp.repoResolver.Resolve(r)
633 if err != nil {
634- log.Println("failed to get repo and knot", err)
635 return
636 }
637638 noticeId := "delete-branch-error"
639 fail := func(msg string, err error) {
640- log.Println(msg, "err", err)
641 rp.pages.Notice(w, noticeId, msg)
642 }
643···670 fail(fmt.Sprintf("Failed to delete branch: %s", err), err)
671 return
672 }
673- log.Println("deleted branch from knot", "branch", branch, "repo", f.RepoAt())
674675 rp.pages.HxRefresh(w)
676}
677678func (rp *Repo) RepoBlob(w http.ResponseWriter, r *http.Request) {
00679 f, err := rp.repoResolver.Resolve(r)
680 if err != nil {
681- log.Println("failed to get repo and knot", err)
682 return
683 }
684···700 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Repo.Name)
701 resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, repo)
702 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
703- log.Println("failed to call XRPC repo.blob", xrpcerr)
704 rp.pages.Error503(w)
705 return
706 }
···800}
801802func (rp *Repo) RepoBlobRaw(w http.ResponseWriter, r *http.Request) {
00803 f, err := rp.repoResolver.Resolve(r)
804 if err != nil {
805- log.Println("failed to get repo and knot", err)
806 w.WriteHeader(http.StatusBadRequest)
807 return
808 }
···834835 req, err := http.NewRequest("GET", blobURL, nil)
836 if err != nil {
837- log.Println("failed to create request", err)
838 return
839 }
840···846 client := &http.Client{}
847 resp, err := client.Do(req)
848 if err != nil {
849- log.Println("failed to reach knotserver", err)
850 rp.pages.Error503(w)
851 return
852 }
···859 }
860861 if resp.StatusCode != http.StatusOK {
862- log.Printf("knotserver returned non-OK status for raw blob %s: %d", blobURL, resp.StatusCode)
863 w.WriteHeader(resp.StatusCode)
864 _, _ = io.Copy(w, resp.Body)
865 return
···868 contentType := resp.Header.Get("Content-Type")
869 body, err := io.ReadAll(resp.Body)
870 if err != nil {
871- log.Printf("error reading response body from knotserver: %v", err)
872 w.WriteHeader(http.StatusInternalServerError)
873 return
874 }
···1443 db.FilterContains("scope", subject.Collection().String()),
1444 )
1445 if err != nil {
1446- log.Println("failed to fetch label defs", err)
1447 return
1448 }
1449···14541455 states, err := db.GetLabels(rp.db, db.FilterEq("subject", subject))
1456 if err != nil {
1457- log.Println("failed to build label state", err)
1458 return
1459 }
1460 state := states[subject]
···1491 db.FilterContains("scope", subject.Collection().String()),
1492 )
1493 if err != nil {
1494- log.Println("failed to fetch labels", err)
1495 return
1496 }
1497···15021503 states, err := db.GetLabels(rp.db, db.FilterEq("subject", subject))
1504 if err != nil {
1505- log.Println("failed to build label state", err)
1506 return
1507 }
1508 state := states[subject]
···16491650func (rp *Repo) DeleteRepo(w http.ResponseWriter, r *http.Request) {
1651 user := rp.oauth.GetUser(r)
016521653 noticeId := "operation-error"
1654 f, err := rp.repoResolver.Resolve(r)
1655 if err != nil {
1656- log.Println("failed to get repo and knot", err)
1657 return
1658 }
16591660 // remove record from pds
1661 atpClient, err := rp.oauth.AuthorizedClient(r)
1662 if err != nil {
1663- log.Println("failed to get authorized client", err)
1664 return
1665 }
1666 _, err = comatproto.RepoDeleteRecord(r.Context(), atpClient, &comatproto.RepoDeleteRecord_Input{
···1669 Rkey: f.Rkey,
1670 })
1671 if err != nil {
1672- log.Printf("failed to delete record: %s", err)
1673 rp.pages.Notice(w, noticeId, "Failed to delete repository from PDS.")
1674 return
1675 }
1676- log.Println("removed repo record ", f.RepoAt().String())
16771678 client, err := rp.oauth.ServiceClient(
1679 r,
···1682 oauth.WithDev(rp.config.Core.Dev),
1683 )
1684 if err != nil {
1685- log.Println("failed to connect to knot server:", err)
1686 return
1687 }
1688···1699 rp.pages.Notice(w, noticeId, err.Error())
1700 return
1701 }
1702- log.Println("deleted repo from knot")
17031704 tx, err := rp.db.BeginTx(r.Context(), nil)
1705 if err != nil {
1706- log.Println("failed to start tx")
1707 w.Write(fmt.Append(nil, "failed to add collaborator: ", err))
1708 return
1709 }
···1711 tx.Rollback()
1712 err = rp.enforcer.E.LoadPolicy()
1713 if err != nil {
1714- log.Println("failed to rollback policies")
1715 }
1716 }()
1717···1725 did := c[0]
1726 rp.enforcer.RemoveCollaborator(did, f.Knot, f.DidSlashRepo())
1727 }
1728- log.Println("removed collaborators")
17291730 // remove repo RBAC
1731 err = rp.enforcer.RemoveRepo(f.OwnerDid(), f.Knot, f.DidSlashRepo())
···1740 rp.pages.Notice(w, noticeId, "Failed to update appview")
1741 return
1742 }
1743- log.Println("removed repo from db")
17441745 err = tx.Commit()
1746 if err != nil {
1747- log.Println("failed to commit changes", err)
1748 http.Error(w, err.Error(), http.StatusInternalServerError)
1749 return
1750 }
17511752 err = rp.enforcer.E.SavePolicy()
1753 if err != nil {
1754- log.Println("failed to update ACLs", err)
1755 http.Error(w, err.Error(), http.StatusInternalServerError)
1756 return
1757 }
···1760}
17611762func (rp *Repo) SetDefaultBranch(w http.ResponseWriter, r *http.Request) {
001763 f, err := rp.repoResolver.Resolve(r)
1764 if err != nil {
1765- log.Println("failed to get repo and knot", err)
1766 return
1767 }
1768···1780 oauth.WithDev(rp.config.Core.Dev),
1781 )
1782 if err != nil {
1783- log.Println("failed to connect to knot server:", err)
1784 rp.pages.Notice(w, noticeId, "Failed to connect to knot server.")
1785 return
1786 }
···1794 },
1795 )
1796 if err := xrpcclient.HandleXrpcErr(xe); err != nil {
1797- log.Println("xrpc failed", "err", xe)
1798 rp.pages.Notice(w, noticeId, err.Error())
1799 return
1800 }
···18091810 f, err := rp.repoResolver.Resolve(r)
1811 if err != nil {
1812- log.Println("failed to get repo and knot", err)
1813 return
1814 }
18151816 if f.Spindle == "" {
1817- log.Println("empty spindle cannot add/rm secret", err)
1818 return
1819 }
1820···1831 oauth.WithDev(rp.config.Core.Dev),
1832 )
1833 if err != nil {
1834- log.Println("failed to create spindle client", err)
1835 return
1836 }
1837···1917}
19181919func (rp *Repo) generalSettings(w http.ResponseWriter, r *http.Request) {
001920 f, err := rp.repoResolver.Resolve(r)
1921 user := rp.oauth.GetUser(r)
1922···1932 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
1933 xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
1934 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1935- log.Println("failed to call XRPC repo.branches", xrpcerr)
1936 rp.pages.Error503(w)
1937 return
1938 }
19391940 var result types.RepoBranchesResponse
1941 if err := json.Unmarshal(xrpcBytes, &result); err != nil {
1942- log.Println("failed to decode XRPC response", err)
1943 rp.pages.Error503(w)
1944 return
1945 }
19461947 defaultLabels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", models.DefaultLabelDefs()))
1948 if err != nil {
1949- log.Println("failed to fetch labels", err)
1950 rp.pages.Error503(w)
1951 return
1952 }
19531954 labels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", f.Repo.Labels))
1955 if err != nil {
1956- log.Println("failed to fetch labels", err)
1957 rp.pages.Error503(w)
1958 return
1959 }
···2001}
20022003func (rp *Repo) accessSettings(w http.ResponseWriter, r *http.Request) {
002004 f, err := rp.repoResolver.Resolve(r)
2005 user := rp.oauth.GetUser(r)
20062007 repoCollaborators, err := f.Collaborators(r.Context())
2008 if err != nil {
2009- log.Println("failed to get collaborators", err)
2010 }
20112012 rp.pages.RepoAccessSettings(w, pages.RepoAccessSettingsParams{
···2019}
20202021func (rp *Repo) pipelineSettings(w http.ResponseWriter, r *http.Request) {
002022 f, err := rp.repoResolver.Resolve(r)
2023 user := rp.oauth.GetUser(r)
20242025 // all spindles that the repo owner is a member of
2026 spindles, err := rp.enforcer.GetSpindlesForUser(f.OwnerDid())
2027 if err != nil {
2028- log.Println("failed to fetch spindles", err)
2029 return
2030 }
2031···2038 oauth.WithExp(60),
2039 oauth.WithDev(rp.config.Core.Dev),
2040 ); err != nil {
2041- log.Println("failed to create spindle client", err)
2042 } else if resp, err := tangled.RepoListSecrets(r.Context(), spindleClient, f.RepoAt().String()); err != nil {
2043- log.Println("failed to fetch secrets", err)
2044 } else {
2045 secrets = resp.Secrets
2046 }
···2080}
20812082func (rp *Repo) SyncRepoFork(w http.ResponseWriter, r *http.Request) {
002083 ref := chi.URLParam(r, "ref")
2084 ref, _ = url.PathUnescape(ref)
20852086 user := rp.oauth.GetUser(r)
2087 f, err := rp.repoResolver.Resolve(r)
2088 if err != nil {
2089- log.Printf("failed to resolve source repo: %v", err)
2090 return
2091 }
2092···2130}
21312132func (rp *Repo) ForkRepo(w http.ResponseWriter, r *http.Request) {
002133 user := rp.oauth.GetUser(r)
2134 f, err := rp.repoResolver.Resolve(r)
2135 if err != nil {
2136- log.Printf("failed to resolve source repo: %v", err)
2137 return
2138 }
2139···2184 )
2185 if err != nil {
2186 if !errors.Is(err, sql.ErrNoRows) {
2187- log.Println("error fetching existing repo from db", "err", err)
2188 rp.pages.Notice(w, "repo", "Failed to fork this repository. Try again later.")
2189 return
2190 }
···22992300 err = db.AddRepo(tx, repo)
2301 if err != nil {
2302- log.Println(err)
2303 rp.pages.Notice(w, "repo", "Failed to save repository information.")
2304 return
2305 }
···2308 p, _ := securejoin.SecureJoin(user.Did, forkName)
2309 err = rp.enforcer.AddRepo(user.Did, targetKnot, p)
2310 if err != nil {
2311- log.Println(err)
2312 rp.pages.Notice(w, "repo", "Failed to set up repository permissions.")
2313 return
2314 }
23152316 err = tx.Commit()
2317 if err != nil {
2318- log.Println("failed to commit changes", err)
2319 http.Error(w, err.Error(), http.StatusInternalServerError)
2320 return
2321 }
23222323 err = rp.enforcer.E.SavePolicy()
2324 if err != nil {
2325- log.Println("failed to update ACLs", err)
2326 http.Error(w, err.Error(), http.StatusInternalServerError)
2327 return
2328 }
···2358}
23592360func (rp *Repo) RepoCompareNew(w http.ResponseWriter, r *http.Request) {
002361 user := rp.oauth.GetUser(r)
2362 f, err := rp.repoResolver.Resolve(r)
2363 if err != nil {
2364- log.Println("failed to get repo and knot", err)
2365 return
2366 }
2367···2377 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
2378 branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
2379 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2380- log.Println("failed to call XRPC repo.branches", xrpcerr)
2381 rp.pages.Error503(w)
2382 return
2383 }
23842385 var branchResult types.RepoBranchesResponse
2386 if err := json.Unmarshal(branchBytes, &branchResult); err != nil {
2387- log.Println("failed to decode XRPC branches response", err)
2388 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
2389 return
2390 }
···24142415 tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
2416 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2417- log.Println("failed to call XRPC repo.tags", xrpcerr)
2418 rp.pages.Error503(w)
2419 return
2420 }
24212422 var tags types.RepoTagsResponse
2423 if err := json.Unmarshal(tagBytes, &tags); err != nil {
2424- log.Println("failed to decode XRPC tags response", err)
2425 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
2426 return
2427 }
···2439}
24402441func (rp *Repo) RepoCompare(w http.ResponseWriter, r *http.Request) {
002442 user := rp.oauth.GetUser(r)
2443 f, err := rp.repoResolver.Resolve(r)
2444 if err != nil {
2445- log.Println("failed to get repo and knot", err)
2446 return
2447 }
2448···2469 head, _ = url.PathUnescape(head)
24702471 if base == "" || head == "" {
2472- log.Printf("invalid comparison")
2473 rp.pages.Error404(w)
2474 return
2475 }
···24872488 branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
2489 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2490- log.Println("failed to call XRPC repo.branches", xrpcerr)
2491 rp.pages.Error503(w)
2492 return
2493 }
24942495 var branches types.RepoBranchesResponse
2496 if err := json.Unmarshal(branchBytes, &branches); err != nil {
2497- log.Println("failed to decode XRPC branches response", err)
2498 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
2499 return
2500 }
25012502 tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
2503 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2504- log.Println("failed to call XRPC repo.tags", xrpcerr)
2505 rp.pages.Error503(w)
2506 return
2507 }
25082509 var tags types.RepoTagsResponse
2510 if err := json.Unmarshal(tagBytes, &tags); err != nil {
2511- log.Println("failed to decode XRPC tags response", err)
2512 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
2513 return
2514 }
25152516 compareBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, base, head)
2517 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2518- log.Println("failed to call XRPC repo.compare", xrpcerr)
2519 rp.pages.Error503(w)
2520 return
2521 }
25222523 var formatPatch types.RepoFormatPatchResponse
2524 if err := json.Unmarshal(compareBytes, &formatPatch); err != nil {
2525- log.Println("failed to decode XRPC compare response", err)
2526 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
2527 return
2528 }
···7 "errors"
8 "fmt"
9 "io"
010 "log/slog"
11 "net/http"
12 "net/url"
···89}
9091func (rp *Repo) DownloadArchive(w http.ResponseWriter, r *http.Request) {
92+ l := rp.logger.With("handler", "DownloadArchive")
93+94 ref := chi.URLParam(r, "ref")
95 ref, _ = url.PathUnescape(ref)
9697 f, err := rp.repoResolver.Resolve(r)
98 if err != nil {
99+ l.Error("failed to get repo and knot", "err", err)
100 return
101 }
102···112 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
113 archiveBytes, err := tangled.RepoArchive(r.Context(), xrpcc, "tar.gz", "", ref, repo)
114 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
115+ l.Error("failed to call XRPC repo.archive", "err", xrpcerr)
116 rp.pages.Error503(w)
117 return
118 }
···129}
130131func (rp *Repo) RepoLog(w http.ResponseWriter, r *http.Request) {
132+ l := rp.logger.With("handler", "RepoLog")
133+134 f, err := rp.repoResolver.Resolve(r)
135 if err != nil {
136+ l.Error("failed to fully resolve repo", "err", err)
137 return
138 }
139···168 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
169 xrpcBytes, err := tangled.RepoLog(r.Context(), xrpcc, cursor, limit, "", ref, repo)
170 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
171+ l.Error("failed to call XRPC repo.log", "err", xrpcerr)
172 rp.pages.Error503(w)
173 return
174 }
175176 var xrpcResp types.RepoLogResponse
177 if err := json.Unmarshal(xrpcBytes, &xrpcResp); err != nil {
178+ l.Error("failed to decode XRPC response", "err", err)
179 rp.pages.Error503(w)
180 return
181 }
182183 tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
184 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
185+ l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
186 rp.pages.Error503(w)
187 return
188 }
···199200 branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
201 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
202+ l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
203 rp.pages.Error503(w)
204 return
205 }
···217218 emailToDidMap, err := db.GetEmailToDid(rp.db, uniqueEmails(xrpcResp.Commits), true)
219 if err != nil {
220+ l.Error("failed to fetch email to did mapping", "err", err)
221 }
222223 vc, err := commitverify.GetVerifiedObjectCommits(rp.db, emailToDidMap, xrpcResp.Commits)
224 if err != nil {
225+ l.Error("failed to GetVerifiedObjectCommits", "err", err)
226 }
227228 repoInfo := f.RepoInfo(user)
···233 }
234 pipelines, err := getPipelineStatuses(rp.db, repoInfo, shas)
235 if err != nil {
236+ l.Error("failed to getPipelineStatuses", "err", err)
237 // non-fatal
238 }
239···249}
250251func (rp *Repo) RepoDescriptionEdit(w http.ResponseWriter, r *http.Request) {
252+ l := rp.logger.With("handler", "RepoDescriptionEdit")
253+254 f, err := rp.repoResolver.Resolve(r)
255 if err != nil {
256+ l.Error("failed to get repo and knot", "err", err)
257 w.WriteHeader(http.StatusBadRequest)
258 return
259 }
···265}
266267func (rp *Repo) RepoDescription(w http.ResponseWriter, r *http.Request) {
268+ l := rp.logger.With("handler", "RepoDescription")
269+270 f, err := rp.repoResolver.Resolve(r)
271 if err != nil {
272+ l.Error("failed to get repo and knot", "err", err)
273 w.WriteHeader(http.StatusBadRequest)
274 return
275 }
···277 repoAt := f.RepoAt()
278 rkey := repoAt.RecordKey().String()
279 if rkey == "" {
280+ l.Error("invalid aturi for repo", "err", err)
281 w.WriteHeader(http.StatusInternalServerError)
282 return
283 }
···294 newDescription := r.FormValue("description")
295 client, err := rp.oauth.AuthorizedClient(r)
296 if err != nil {
297+ l.Error("failed to get client")
298 rp.pages.Notice(w, "repo-notice", "Failed to update description, try again later.")
299 return
300 }
···302 // optimistic update
303 err = db.UpdateDescription(rp.db, string(repoAt), newDescription)
304 if err != nil {
305+ l.Error("failed to perform update-description query", "err", err)
306 rp.pages.Notice(w, "repo-notice", "Failed to update description, try again later.")
307 return
308 }
···331 })
332333 if err != nil {
334+ l.Error("failed to perferom update-description query", "err", err)
335 // failed to get record
336 rp.pages.Notice(w, "repo-notice", "Failed to update description, unable to save to PDS.")
337 return
···348}
349350func (rp *Repo) RepoCommit(w http.ResponseWriter, r *http.Request) {
351+ l := rp.logger.With("handler", "RepoCommit")
352+353 f, err := rp.repoResolver.Resolve(r)
354 if err != nil {
355+ l.Error("failed to fully resolve repo", "err", err)
356 return
357 }
358 ref := chi.URLParam(r, "ref")
···380 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
381 xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, repo)
382 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
383+ l.Error("failed to call XRPC repo.diff", "err", xrpcerr)
384 rp.pages.Error503(w)
385 return
386 }
387388 var result types.RepoCommitResponse
389 if err := json.Unmarshal(xrpcBytes, &result); err != nil {
390+ l.Error("failed to decode XRPC response", "err", err)
391 rp.pages.Error503(w)
392 return
393 }
394395 emailToDidMap, err := db.GetEmailToDid(rp.db, []string{result.Diff.Commit.Committer.Email, result.Diff.Commit.Author.Email}, true)
396 if err != nil {
397+ l.Error("failed to get email to did mapping", "err", err)
398 }
399400 vc, err := commitverify.GetVerifiedCommits(rp.db, emailToDidMap, []types.NiceDiff{*result.Diff})
401 if err != nil {
402+ l.Error("failed to GetVerifiedCommits", "err", err)
403 }
404405 user := rp.oauth.GetUser(r)
406 repoInfo := f.RepoInfo(user)
407 pipelines, err := getPipelineStatuses(rp.db, repoInfo, []string{result.Diff.Commit.This})
408 if err != nil {
409+ l.Error("failed to getPipelineStatuses", "err", err)
410 // non-fatal
411 }
412 var pipeline *models.Pipeline
···426}
427428func (rp *Repo) RepoTree(w http.ResponseWriter, r *http.Request) {
429+ l := rp.logger.With("handler", "RepoTree")
430+431 f, err := rp.repoResolver.Resolve(r)
432 if err != nil {
433+ l.Error("failed to fully resolve repo", "err", err)
434 return
435 }
436···455 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
456 xrpcResp, err := tangled.RepoTree(r.Context(), xrpcc, treePath, ref, repo)
457 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
458+ l.Error("failed to call XRPC repo.tree", "err", xrpcerr)
459 rp.pages.Error503(w)
460 return
461 }
···530}
531532func (rp *Repo) RepoTags(w http.ResponseWriter, r *http.Request) {
533+ l := rp.logger.With("handler", "RepoTags")
534+535 f, err := rp.repoResolver.Resolve(r)
536 if err != nil {
537+ l.Error("failed to get repo and knot", "err", err)
538 return
539 }
540···550 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
551 xrpcBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
552 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
553+ l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
554 rp.pages.Error503(w)
555 return
556 }
557558 var result types.RepoTagsResponse
559 if err := json.Unmarshal(xrpcBytes, &result); err != nil {
560+ l.Error("failed to decode XRPC response", "err", err)
561 rp.pages.Error503(w)
562 return
563 }
564565 artifacts, err := db.GetArtifact(rp.db, db.FilterEq("repo_at", f.RepoAt()))
566 if err != nil {
567+ l.Error("failed grab artifacts", "err", err)
568 return
569 }
570···601}
602603func (rp *Repo) RepoBranches(w http.ResponseWriter, r *http.Request) {
604+ l := rp.logger.With("handler", "RepoBranches")
605+606 f, err := rp.repoResolver.Resolve(r)
607 if err != nil {
608+ l.Error("failed to get repo and knot", "err", err)
609 return
610 }
611···621 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
622 xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
623 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
624+ l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
625 rp.pages.Error503(w)
626 return
627 }
628629 var result types.RepoBranchesResponse
630 if err := json.Unmarshal(xrpcBytes, &result); err != nil {
631+ l.Error("failed to decode XRPC response", "err", err)
632 rp.pages.Error503(w)
633 return
634 }
···644}
645646func (rp *Repo) DeleteBranch(w http.ResponseWriter, r *http.Request) {
647+ l := rp.logger.With("handler", "DeleteBranch")
648+649 f, err := rp.repoResolver.Resolve(r)
650 if err != nil {
651+ l.Error("failed to get repo and knot", "err", err)
652 return
653 }
654655 noticeId := "delete-branch-error"
656 fail := func(msg string, err error) {
657+ l.Error(msg, "err", err)
658 rp.pages.Notice(w, noticeId, msg)
659 }
660···687 fail(fmt.Sprintf("Failed to delete branch: %s", err), err)
688 return
689 }
690+ l.Error("deleted branch from knot", "branch", branch, "repo", f.RepoAt())
691692 rp.pages.HxRefresh(w)
693}
694695func (rp *Repo) RepoBlob(w http.ResponseWriter, r *http.Request) {
696+ l := rp.logger.With("handler", "RepoBlob")
697+698 f, err := rp.repoResolver.Resolve(r)
699 if err != nil {
700+ l.Error("failed to get repo and knot", "err", err)
701 return
702 }
703···719 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Repo.Name)
720 resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, repo)
721 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
722+ l.Error("failed to call XRPC repo.blob", "err", xrpcerr)
723 rp.pages.Error503(w)
724 return
725 }
···819}
820821func (rp *Repo) RepoBlobRaw(w http.ResponseWriter, r *http.Request) {
822+ l := rp.logger.With("handler", "RepoBlobRaw")
823+824 f, err := rp.repoResolver.Resolve(r)
825 if err != nil {
826+ l.Error("failed to get repo and knot", err)
827 w.WriteHeader(http.StatusBadRequest)
828 return
829 }
···855856 req, err := http.NewRequest("GET", blobURL, nil)
857 if err != nil {
858+ l.Error("failed to create request", "err", err)
859 return
860 }
861···867 client := &http.Client{}
868 resp, err := client.Do(req)
869 if err != nil {
870+ l.Error("failed to reach knotserver", "err", err)
871 rp.pages.Error503(w)
872 return
873 }
···880 }
881882 if resp.StatusCode != http.StatusOK {
883+ l.Error("knotserver returned non-OK status for raw blob", "url", blobURL, "statuscode", resp.StatusCode)
884 w.WriteHeader(resp.StatusCode)
885 _, _ = io.Copy(w, resp.Body)
886 return
···889 contentType := resp.Header.Get("Content-Type")
890 body, err := io.ReadAll(resp.Body)
891 if err != nil {
892+ l.Error("error reading response body from knotserver", "err", err)
893 w.WriteHeader(http.StatusInternalServerError)
894 return
895 }
···1464 db.FilterContains("scope", subject.Collection().String()),
1465 )
1466 if err != nil {
1467+ l.Error("failed to fetch label defs", "err", err)
1468 return
1469 }
1470···14751476 states, err := db.GetLabels(rp.db, db.FilterEq("subject", subject))
1477 if err != nil {
1478+ l.Error("failed to build label state", "err", err)
1479 return
1480 }
1481 state := states[subject]
···1512 db.FilterContains("scope", subject.Collection().String()),
1513 )
1514 if err != nil {
1515+ l.Error("failed to fetch labels", "err", err)
1516 return
1517 }
1518···15231524 states, err := db.GetLabels(rp.db, db.FilterEq("subject", subject))
1525 if err != nil {
1526+ l.Error("failed to build label state", "err", err)
1527 return
1528 }
1529 state := states[subject]
···16701671func (rp *Repo) DeleteRepo(w http.ResponseWriter, r *http.Request) {
1672 user := rp.oauth.GetUser(r)
1673+ l := rp.logger.With("handler", "DeleteRepo")
16741675 noticeId := "operation-error"
1676 f, err := rp.repoResolver.Resolve(r)
1677 if err != nil {
1678+ l.Error("failed to get repo and knot", "err", err)
1679 return
1680 }
16811682 // remove record from pds
1683 atpClient, err := rp.oauth.AuthorizedClient(r)
1684 if err != nil {
1685+ l.Error("failed to get authorized client", "err", err)
1686 return
1687 }
1688 _, err = comatproto.RepoDeleteRecord(r.Context(), atpClient, &comatproto.RepoDeleteRecord_Input{
···1691 Rkey: f.Rkey,
1692 })
1693 if err != nil {
1694+ l.Error("failed to delete record", "err", err)
1695 rp.pages.Notice(w, noticeId, "Failed to delete repository from PDS.")
1696 return
1697 }
1698+ l.Info("removed repo record", "aturi", f.RepoAt().String())
16991700 client, err := rp.oauth.ServiceClient(
1701 r,
···1704 oauth.WithDev(rp.config.Core.Dev),
1705 )
1706 if err != nil {
1707+ l.Error("failed to connect to knot server", "err", err)
1708 return
1709 }
1710···1721 rp.pages.Notice(w, noticeId, err.Error())
1722 return
1723 }
1724+ l.Info("deleted repo from knot")
17251726 tx, err := rp.db.BeginTx(r.Context(), nil)
1727 if err != nil {
1728+ l.Error("failed to start tx")
1729 w.Write(fmt.Append(nil, "failed to add collaborator: ", err))
1730 return
1731 }
···1733 tx.Rollback()
1734 err = rp.enforcer.E.LoadPolicy()
1735 if err != nil {
1736+ l.Error("failed to rollback policies")
1737 }
1738 }()
1739···1747 did := c[0]
1748 rp.enforcer.RemoveCollaborator(did, f.Knot, f.DidSlashRepo())
1749 }
1750+ l.Info("removed collaborators")
17511752 // remove repo RBAC
1753 err = rp.enforcer.RemoveRepo(f.OwnerDid(), f.Knot, f.DidSlashRepo())
···1762 rp.pages.Notice(w, noticeId, "Failed to update appview")
1763 return
1764 }
1765+ l.Info("removed repo from db")
17661767 err = tx.Commit()
1768 if err != nil {
1769+ l.Error("failed to commit changes", "err", err)
1770 http.Error(w, err.Error(), http.StatusInternalServerError)
1771 return
1772 }
17731774 err = rp.enforcer.E.SavePolicy()
1775 if err != nil {
1776+ l.Error("failed to update ACLs", "err", err)
1777 http.Error(w, err.Error(), http.StatusInternalServerError)
1778 return
1779 }
···1782}
17831784func (rp *Repo) SetDefaultBranch(w http.ResponseWriter, r *http.Request) {
1785+ l := rp.logger.With("handler", "SetDefaultBranch")
1786+1787 f, err := rp.repoResolver.Resolve(r)
1788 if err != nil {
1789+ l.Error("failed to get repo and knot", "err", err)
1790 return
1791 }
1792···1804 oauth.WithDev(rp.config.Core.Dev),
1805 )
1806 if err != nil {
1807+ l.Error("failed to connect to knot server", "err", err)
1808 rp.pages.Notice(w, noticeId, "Failed to connect to knot server.")
1809 return
1810 }
···1818 },
1819 )
1820 if err := xrpcclient.HandleXrpcErr(xe); err != nil {
1821+ l.Error("xrpc failed", "err", xe)
1822 rp.pages.Notice(w, noticeId, err.Error())
1823 return
1824 }
···18331834 f, err := rp.repoResolver.Resolve(r)
1835 if err != nil {
1836+ l.Error("failed to get repo and knot", "err", err)
1837 return
1838 }
18391840 if f.Spindle == "" {
1841+ l.Error("empty spindle cannot add/rm secret", "err", err)
1842 return
1843 }
1844···1855 oauth.WithDev(rp.config.Core.Dev),
1856 )
1857 if err != nil {
1858+ l.Error("failed to create spindle client", "err", err)
1859 return
1860 }
1861···1941}
19421943func (rp *Repo) generalSettings(w http.ResponseWriter, r *http.Request) {
1944+ l := rp.logger.With("handler", "generalSettings")
1945+1946 f, err := rp.repoResolver.Resolve(r)
1947 user := rp.oauth.GetUser(r)
1948···1958 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
1959 xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
1960 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1961+ l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
1962 rp.pages.Error503(w)
1963 return
1964 }
19651966 var result types.RepoBranchesResponse
1967 if err := json.Unmarshal(xrpcBytes, &result); err != nil {
1968+ l.Error("failed to decode XRPC response", "err", err)
1969 rp.pages.Error503(w)
1970 return
1971 }
19721973 defaultLabels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", models.DefaultLabelDefs()))
1974 if err != nil {
1975+ l.Error("failed to fetch labels", "err", err)
1976 rp.pages.Error503(w)
1977 return
1978 }
19791980 labels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", f.Repo.Labels))
1981 if err != nil {
1982+ l.Error("failed to fetch labels", "err", err)
1983 rp.pages.Error503(w)
1984 return
1985 }
···2027}
20282029func (rp *Repo) accessSettings(w http.ResponseWriter, r *http.Request) {
2030+ l := rp.logger.With("handler", "accessSettings")
2031+2032 f, err := rp.repoResolver.Resolve(r)
2033 user := rp.oauth.GetUser(r)
20342035 repoCollaborators, err := f.Collaborators(r.Context())
2036 if err != nil {
2037+ l.Error("failed to get collaborators", "err", err)
2038 }
20392040 rp.pages.RepoAccessSettings(w, pages.RepoAccessSettingsParams{
···2047}
20482049func (rp *Repo) pipelineSettings(w http.ResponseWriter, r *http.Request) {
2050+ l := rp.logger.With("handler", "pipelineSettings")
2051+2052 f, err := rp.repoResolver.Resolve(r)
2053 user := rp.oauth.GetUser(r)
20542055 // all spindles that the repo owner is a member of
2056 spindles, err := rp.enforcer.GetSpindlesForUser(f.OwnerDid())
2057 if err != nil {
2058+ l.Error("failed to fetch spindles", "err", err)
2059 return
2060 }
2061···2068 oauth.WithExp(60),
2069 oauth.WithDev(rp.config.Core.Dev),
2070 ); err != nil {
2071+ l.Error("failed to create spindle client", "err", err)
2072 } else if resp, err := tangled.RepoListSecrets(r.Context(), spindleClient, f.RepoAt().String()); err != nil {
2073+ l.Error("failed to fetch secrets", "err", err)
2074 } else {
2075 secrets = resp.Secrets
2076 }
···2110}
21112112func (rp *Repo) SyncRepoFork(w http.ResponseWriter, r *http.Request) {
2113+ l := rp.logger.With("handler", "SyncRepoFork")
2114+2115 ref := chi.URLParam(r, "ref")
2116 ref, _ = url.PathUnescape(ref)
21172118 user := rp.oauth.GetUser(r)
2119 f, err := rp.repoResolver.Resolve(r)
2120 if err != nil {
2121+ l.Error("failed to resolve source repo", "err", err)
2122 return
2123 }
2124···2162}
21632164func (rp *Repo) ForkRepo(w http.ResponseWriter, r *http.Request) {
2165+ l := rp.logger.With("handler", "ForkRepo")
2166+2167 user := rp.oauth.GetUser(r)
2168 f, err := rp.repoResolver.Resolve(r)
2169 if err != nil {
2170+ l.Error("failed to resolve source repo", "err", err)
2171 return
2172 }
2173···2218 )
2219 if err != nil {
2220 if !errors.Is(err, sql.ErrNoRows) {
2221+ l.Error("error fetching existing repo from db", "err", err)
2222 rp.pages.Notice(w, "repo", "Failed to fork this repository. Try again later.")
2223 return
2224 }
···23332334 err = db.AddRepo(tx, repo)
2335 if err != nil {
2336+ l.Error("failed to AddRepo", "err", err)
2337 rp.pages.Notice(w, "repo", "Failed to save repository information.")
2338 return
2339 }
···2342 p, _ := securejoin.SecureJoin(user.Did, forkName)
2343 err = rp.enforcer.AddRepo(user.Did, targetKnot, p)
2344 if err != nil {
2345+ l.Error("failed to add ACLs", "err", err)
2346 rp.pages.Notice(w, "repo", "Failed to set up repository permissions.")
2347 return
2348 }
23492350 err = tx.Commit()
2351 if err != nil {
2352+ l.Error("failed to commit changes", "err", err)
2353 http.Error(w, err.Error(), http.StatusInternalServerError)
2354 return
2355 }
23562357 err = rp.enforcer.E.SavePolicy()
2358 if err != nil {
2359+ l.Error("failed to update ACLs", "err", err)
2360 http.Error(w, err.Error(), http.StatusInternalServerError)
2361 return
2362 }
···2392}
23932394func (rp *Repo) RepoCompareNew(w http.ResponseWriter, r *http.Request) {
2395+ l := rp.logger.With("handler", "RepoCompareNew")
2396+2397 user := rp.oauth.GetUser(r)
2398 f, err := rp.repoResolver.Resolve(r)
2399 if err != nil {
2400+ l.Error("failed to get repo and knot", "err", err)
2401 return
2402 }
2403···2413 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
2414 branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
2415 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2416+ l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
2417 rp.pages.Error503(w)
2418 return
2419 }
24202421 var branchResult types.RepoBranchesResponse
2422 if err := json.Unmarshal(branchBytes, &branchResult); err != nil {
2423+ l.Error("failed to decode XRPC branches response", "err", err)
2424 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
2425 return
2426 }
···24502451 tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
2452 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2453+ l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
2454 rp.pages.Error503(w)
2455 return
2456 }
24572458 var tags types.RepoTagsResponse
2459 if err := json.Unmarshal(tagBytes, &tags); err != nil {
2460+ l.Error("failed to decode XRPC tags response", "err", err)
2461 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
2462 return
2463 }
···2475}
24762477func (rp *Repo) RepoCompare(w http.ResponseWriter, r *http.Request) {
2478+ l := rp.logger.With("handler", "RepoCompare")
2479+2480 user := rp.oauth.GetUser(r)
2481 f, err := rp.repoResolver.Resolve(r)
2482 if err != nil {
2483+ l.Error("failed to get repo and knot", "err", err)
2484 return
2485 }
2486···2507 head, _ = url.PathUnescape(head)
25082509 if base == "" || head == "" {
2510+ l.Error("invalid comparison")
2511 rp.pages.Error404(w)
2512 return
2513 }
···25252526 branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
2527 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2528+ l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
2529 rp.pages.Error503(w)
2530 return
2531 }
25322533 var branches types.RepoBranchesResponse
2534 if err := json.Unmarshal(branchBytes, &branches); err != nil {
2535+ l.Error("failed to decode XRPC branches response", "err", err)
2536 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
2537 return
2538 }
25392540 tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
2541 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2542+ l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
2543 rp.pages.Error503(w)
2544 return
2545 }
25462547 var tags types.RepoTagsResponse
2548 if err := json.Unmarshal(tagBytes, &tags); err != nil {
2549+ l.Error("failed to decode XRPC tags response", "err", err)
2550 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
2551 return
2552 }
25532554 compareBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, base, head)
2555 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2556+ l.Error("failed to call XRPC repo.compare", "err", xrpcerr)
2557 rp.pages.Error503(w)
2558 return
2559 }
25602561 var formatPatch types.RepoFormatPatchResponse
2562 if err := json.Unmarshal(compareBytes, &formatPatch); err != nil {
2563+ l.Error("failed to decode XRPC compare response", "err", err)
2564 rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
2565 return
2566 }