Monorepo for Tangled tangled.org

appview: refactor RepoIndex into separate file

Signed-off-by: oppiliappan <me@oppi.li>

oppi.li 1ac0de7c 02cf40bd

verified
Changed files
+208 -188
appview
+208
appview/repo/index.go
··· 1 + package repo 2 + 3 + import ( 4 + "encoding/json" 5 + "fmt" 6 + "log" 7 + "net/http" 8 + "slices" 9 + "strings" 10 + 11 + "tangled.sh/tangled.sh/core/appview/commitverify" 12 + "tangled.sh/tangled.sh/core/appview/db" 13 + "tangled.sh/tangled.sh/core/appview/oauth" 14 + "tangled.sh/tangled.sh/core/appview/pages" 15 + "tangled.sh/tangled.sh/core/appview/pages/repoinfo" 16 + "tangled.sh/tangled.sh/core/appview/reporesolver" 17 + "tangled.sh/tangled.sh/core/knotclient" 18 + "tangled.sh/tangled.sh/core/types" 19 + 20 + "github.com/go-chi/chi/v5" 21 + ) 22 + 23 + func (rp *Repo) RepoIndex(w http.ResponseWriter, r *http.Request) { 24 + ref := chi.URLParam(r, "ref") 25 + f, err := rp.repoResolver.Resolve(r) 26 + if err != nil { 27 + log.Println("failed to fully resolve repo", err) 28 + return 29 + } 30 + 31 + us, err := knotclient.NewUnsignedClient(f.Knot, rp.config.Core.Dev) 32 + if err != nil { 33 + log.Printf("failed to create unsigned client for %s", f.Knot) 34 + rp.pages.Error503(w) 35 + return 36 + } 37 + 38 + result, err := us.Index(f.OwnerDid(), f.RepoName, ref) 39 + if err != nil { 40 + rp.pages.Error503(w) 41 + log.Println("failed to reach knotserver", err) 42 + return 43 + } 44 + 45 + tagMap := make(map[string][]string) 46 + for _, tag := range result.Tags { 47 + hash := tag.Hash 48 + if tag.Tag != nil { 49 + hash = tag.Tag.Target.String() 50 + } 51 + tagMap[hash] = append(tagMap[hash], tag.Name) 52 + } 53 + 54 + for _, branch := range result.Branches { 55 + hash := branch.Hash 56 + tagMap[hash] = append(tagMap[hash], branch.Name) 57 + } 58 + 59 + slices.SortFunc(result.Branches, func(a, b types.Branch) int { 60 + if a.Name == result.Ref { 61 + return -1 62 + } 63 + if a.IsDefault { 64 + return -1 65 + } 66 + if b.IsDefault { 67 + return 1 68 + } 69 + if a.Commit != nil && b.Commit != nil { 70 + if a.Commit.Committer.When.Before(b.Commit.Committer.When) { 71 + return 1 72 + } else { 73 + return -1 74 + } 75 + } 76 + return strings.Compare(a.Name, b.Name) * -1 77 + }) 78 + 79 + commitCount := len(result.Commits) 80 + branchCount := len(result.Branches) 81 + tagCount := len(result.Tags) 82 + fileCount := len(result.Files) 83 + 84 + commitCount, branchCount, tagCount = balanceIndexItems(commitCount, branchCount, tagCount, fileCount) 85 + commitsTrunc := result.Commits[:min(commitCount, len(result.Commits))] 86 + tagsTrunc := result.Tags[:min(tagCount, len(result.Tags))] 87 + branchesTrunc := result.Branches[:min(branchCount, len(result.Branches))] 88 + 89 + emails := uniqueEmails(commitsTrunc) 90 + emailToDidMap, err := db.GetEmailToDid(rp.db, emails, true) 91 + if err != nil { 92 + log.Println("failed to get email to did map", err) 93 + } 94 + 95 + vc, err := commitverify.GetVerifiedObjectCommits(rp.db, emailToDidMap, commitsTrunc) 96 + if err != nil { 97 + log.Println(err) 98 + } 99 + 100 + user := rp.oauth.GetUser(r) 101 + repoInfo := f.RepoInfo(user) 102 + 103 + secret, err := db.GetRegistrationKey(rp.db, f.Knot) 104 + if err != nil { 105 + log.Printf("failed to get registration key for %s: %s", f.Knot, err) 106 + rp.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") 107 + } 108 + 109 + signedClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev) 110 + if err != nil { 111 + log.Printf("failed to create signed client for %s: %s", f.Knot, err) 112 + return 113 + } 114 + 115 + var forkInfo *types.ForkInfo 116 + if user != nil && (repoInfo.Roles.IsOwner() || repoInfo.Roles.IsCollaborator()) { 117 + forkInfo, err = getForkInfo(repoInfo, rp, f, user, signedClient) 118 + if err != nil { 119 + log.Printf("Failed to fetch fork information: %v", err) 120 + return 121 + } 122 + } 123 + 124 + repoLanguages, err := signedClient.RepoLanguages(f.OwnerDid(), f.RepoName, ref) 125 + if err != nil { 126 + log.Printf("failed to compute language percentages: %s", err) 127 + // non-fatal 128 + } 129 + 130 + rp.pages.RepoIndexPage(w, pages.RepoIndexParams{ 131 + LoggedInUser: user, 132 + RepoInfo: repoInfo, 133 + TagMap: tagMap, 134 + RepoIndexResponse: *result, 135 + CommitsTrunc: commitsTrunc, 136 + TagsTrunc: tagsTrunc, 137 + ForkInfo: forkInfo, 138 + BranchesTrunc: branchesTrunc, 139 + EmailToDidOrHandle: emailToDidOrHandle(rp, emailToDidMap), 140 + VerifiedCommits: vc, 141 + Languages: repoLanguages, 142 + }) 143 + return 144 + } 145 + 146 + func getForkInfo( 147 + repoInfo repoinfo.RepoInfo, 148 + rp *Repo, 149 + f *reporesolver.ResolvedRepo, 150 + user *oauth.User, 151 + signedClient *knotclient.SignedClient, 152 + ) (*types.ForkInfo, error) { 153 + if user == nil { 154 + return nil, nil 155 + } 156 + 157 + forkInfo := types.ForkInfo{ 158 + IsFork: repoInfo.Source != nil, 159 + Status: types.UpToDate, 160 + } 161 + 162 + if !forkInfo.IsFork { 163 + forkInfo.IsFork = false 164 + return &forkInfo, nil 165 + } 166 + 167 + us, err := knotclient.NewUnsignedClient(repoInfo.Source.Knot, rp.config.Core.Dev) 168 + if err != nil { 169 + log.Printf("failed to create unsigned client for %s", repoInfo.Source.Knot) 170 + return nil, err 171 + } 172 + 173 + result, err := us.Branches(repoInfo.Source.Did, repoInfo.Source.Name) 174 + if err != nil { 175 + log.Println("failed to reach knotserver", err) 176 + return nil, err 177 + } 178 + 179 + if !slices.ContainsFunc(result.Branches, func(branch types.Branch) bool { 180 + return branch.Name == f.Ref 181 + }) { 182 + forkInfo.Status = types.MissingBranch 183 + return &forkInfo, nil 184 + } 185 + 186 + newHiddenRefResp, err := signedClient.NewHiddenRef(user.Did, repoInfo.Name, f.Ref, f.Ref) 187 + if err != nil || newHiddenRefResp.StatusCode != http.StatusNoContent { 188 + log.Printf("failed to update tracking branch: %s", err) 189 + return nil, err 190 + } 191 + 192 + hiddenRef := fmt.Sprintf("hidden/%s/%s", f.Ref, f.Ref) 193 + 194 + var status types.AncestorCheckResponse 195 + forkSyncableResp, err := signedClient.RepoForkAheadBehind(user.Did, string(f.RepoAt), repoInfo.Name, f.Ref, hiddenRef) 196 + if err != nil { 197 + log.Printf("failed to check if fork is ahead/behind: %s", err) 198 + return nil, err 199 + } 200 + 201 + if err := json.NewDecoder(forkSyncableResp.Body).Decode(&status); err != nil { 202 + log.Printf("failed to decode fork status: %s", err) 203 + return nil, err 204 + } 205 + 206 + forkInfo.Status = status.Status 207 + return &forkInfo, nil 208 + }
-188
appview/repo/repo.go
··· 26 26 "tangled.sh/tangled.sh/core/appview/oauth" 27 27 "tangled.sh/tangled.sh/core/appview/pages" 28 28 "tangled.sh/tangled.sh/core/appview/pages/markup" 29 - "tangled.sh/tangled.sh/core/appview/pages/repoinfo" 30 29 "tangled.sh/tangled.sh/core/appview/reporesolver" 31 30 "tangled.sh/tangled.sh/core/eventconsumer" 32 31 "tangled.sh/tangled.sh/core/knotclient" ··· 76 75 posthog: posthog, 77 76 enforcer: enforcer, 78 77 } 79 - } 80 - 81 - func (rp *Repo) RepoIndex(w http.ResponseWriter, r *http.Request) { 82 - ref := chi.URLParam(r, "ref") 83 - f, err := rp.repoResolver.Resolve(r) 84 - if err != nil { 85 - log.Println("failed to fully resolve repo", err) 86 - return 87 - } 88 - 89 - us, err := knotclient.NewUnsignedClient(f.Knot, rp.config.Core.Dev) 90 - if err != nil { 91 - log.Printf("failed to create unsigned client for %s", f.Knot) 92 - rp.pages.Error503(w) 93 - return 94 - } 95 - 96 - result, err := us.Index(f.OwnerDid(), f.RepoName, ref) 97 - if err != nil { 98 - rp.pages.Error503(w) 99 - log.Println("failed to reach knotserver", err) 100 - return 101 - } 102 - 103 - tagMap := make(map[string][]string) 104 - for _, tag := range result.Tags { 105 - hash := tag.Hash 106 - if tag.Tag != nil { 107 - hash = tag.Tag.Target.String() 108 - } 109 - tagMap[hash] = append(tagMap[hash], tag.Name) 110 - } 111 - 112 - for _, branch := range result.Branches { 113 - hash := branch.Hash 114 - tagMap[hash] = append(tagMap[hash], branch.Name) 115 - } 116 - 117 - slices.SortFunc(result.Branches, func(a, b types.Branch) int { 118 - if a.Name == result.Ref { 119 - return -1 120 - } 121 - if a.IsDefault { 122 - return -1 123 - } 124 - if b.IsDefault { 125 - return 1 126 - } 127 - if a.Commit != nil && b.Commit != nil { 128 - if a.Commit.Committer.When.Before(b.Commit.Committer.When) { 129 - return 1 130 - } else { 131 - return -1 132 - } 133 - } 134 - return strings.Compare(a.Name, b.Name) * -1 135 - }) 136 - 137 - commitCount := len(result.Commits) 138 - branchCount := len(result.Branches) 139 - tagCount := len(result.Tags) 140 - fileCount := len(result.Files) 141 - 142 - commitCount, branchCount, tagCount = balanceIndexItems(commitCount, branchCount, tagCount, fileCount) 143 - commitsTrunc := result.Commits[:min(commitCount, len(result.Commits))] 144 - tagsTrunc := result.Tags[:min(tagCount, len(result.Tags))] 145 - branchesTrunc := result.Branches[:min(branchCount, len(result.Branches))] 146 - 147 - emails := uniqueEmails(commitsTrunc) 148 - emailToDidMap, err := db.GetEmailToDid(rp.db, emails, true) 149 - if err != nil { 150 - log.Println("failed to get email to did map", err) 151 - } 152 - 153 - vc, err := commitverify.GetVerifiedObjectCommits(rp.db, emailToDidMap, commitsTrunc) 154 - if err != nil { 155 - log.Println(err) 156 - } 157 - 158 - user := rp.oauth.GetUser(r) 159 - repoInfo := f.RepoInfo(user) 160 - 161 - secret, err := db.GetRegistrationKey(rp.db, f.Knot) 162 - if err != nil { 163 - log.Printf("failed to get registration key for %s: %s", f.Knot, err) 164 - rp.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") 165 - } 166 - 167 - signedClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev) 168 - if err != nil { 169 - log.Printf("failed to create signed client for %s: %s", f.Knot, err) 170 - return 171 - } 172 - 173 - var forkInfo *types.ForkInfo 174 - if user != nil && (repoInfo.Roles.IsOwner() || repoInfo.Roles.IsCollaborator()) { 175 - forkInfo, err = getForkInfo(repoInfo, rp, f, user, signedClient) 176 - if err != nil { 177 - log.Printf("Failed to fetch fork information: %v", err) 178 - return 179 - } 180 - } 181 - 182 - repoLanguages, err := signedClient.RepoLanguages(f.OwnerDid(), f.RepoName, ref) 183 - if err != nil { 184 - log.Printf("failed to compute language percentages: %s", err) 185 - // non-fatal 186 - } 187 - 188 - rp.pages.RepoIndexPage(w, pages.RepoIndexParams{ 189 - LoggedInUser: user, 190 - RepoInfo: repoInfo, 191 - TagMap: tagMap, 192 - RepoIndexResponse: *result, 193 - CommitsTrunc: commitsTrunc, 194 - TagsTrunc: tagsTrunc, 195 - ForkInfo: forkInfo, 196 - BranchesTrunc: branchesTrunc, 197 - EmailToDidOrHandle: emailToDidOrHandle(rp, emailToDidMap), 198 - VerifiedCommits: vc, 199 - Languages: repoLanguages, 200 - }) 201 - return 202 - } 203 - 204 - func getForkInfo( 205 - repoInfo repoinfo.RepoInfo, 206 - rp *Repo, 207 - f *reporesolver.ResolvedRepo, 208 - user *oauth.User, 209 - signedClient *knotclient.SignedClient, 210 - ) (*types.ForkInfo, error) { 211 - if user == nil { 212 - return nil, nil 213 - } 214 - 215 - forkInfo := types.ForkInfo{ 216 - IsFork: repoInfo.Source != nil, 217 - Status: types.UpToDate, 218 - } 219 - 220 - if !forkInfo.IsFork { 221 - forkInfo.IsFork = false 222 - return &forkInfo, nil 223 - } 224 - 225 - us, err := knotclient.NewUnsignedClient(repoInfo.Source.Knot, rp.config.Core.Dev) 226 - if err != nil { 227 - log.Printf("failed to create unsigned client for %s", repoInfo.Source.Knot) 228 - return nil, err 229 - } 230 - 231 - result, err := us.Branches(repoInfo.Source.Did, repoInfo.Source.Name) 232 - if err != nil { 233 - log.Println("failed to reach knotserver", err) 234 - return nil, err 235 - } 236 - 237 - if !slices.ContainsFunc(result.Branches, func(branch types.Branch) bool { 238 - return branch.Name == f.Ref 239 - }) { 240 - forkInfo.Status = types.MissingBranch 241 - return &forkInfo, nil 242 - } 243 - 244 - newHiddenRefResp, err := signedClient.NewHiddenRef(user.Did, repoInfo.Name, f.Ref, f.Ref) 245 - if err != nil || newHiddenRefResp.StatusCode != http.StatusNoContent { 246 - log.Printf("failed to update tracking branch: %s", err) 247 - return nil, err 248 - } 249 - 250 - hiddenRef := fmt.Sprintf("hidden/%s/%s", f.Ref, f.Ref) 251 - 252 - var status types.AncestorCheckResponse 253 - forkSyncableResp, err := signedClient.RepoForkAheadBehind(user.Did, string(f.RepoAt), repoInfo.Name, f.Ref, hiddenRef) 254 - if err != nil { 255 - log.Printf("failed to check if fork is ahead/behind: %s", err) 256 - return nil, err 257 - } 258 - 259 - if err := json.NewDecoder(forkSyncableResp.Body).Decode(&status); err != nil { 260 - log.Printf("failed to decode fork status: %s", err) 261 - return nil, err 262 - } 263 - 264 - forkInfo.Status = status.Status 265 - return &forkInfo, nil 266 78 } 267 79 268 80 func (rp *Repo) RepoLog(w http.ResponseWriter, r *http.Request) {