this repo has no description
1package repo 2 3import ( 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 23func (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 pipelines, err := rp.getPipelineStatuses(repoInfo, commitsTrunc) 131 if err != nil { 132 log.Printf("failed to fetch pipeline statuses: %s", err) 133 // non-fatal 134 } 135 136 rp.pages.RepoIndexPage(w, pages.RepoIndexParams{ 137 LoggedInUser: user, 138 RepoInfo: repoInfo, 139 TagMap: tagMap, 140 RepoIndexResponse: *result, 141 CommitsTrunc: commitsTrunc, 142 TagsTrunc: tagsTrunc, 143 ForkInfo: forkInfo, 144 BranchesTrunc: branchesTrunc, 145 EmailToDidOrHandle: emailToDidOrHandle(rp, emailToDidMap), 146 VerifiedCommits: vc, 147 Languages: repoLanguages, 148 Pipelines: pipelines, 149 }) 150 return 151} 152 153func getForkInfo( 154 repoInfo repoinfo.RepoInfo, 155 rp *Repo, 156 f *reporesolver.ResolvedRepo, 157 user *oauth.User, 158 signedClient *knotclient.SignedClient, 159) (*types.ForkInfo, error) { 160 if user == nil { 161 return nil, nil 162 } 163 164 forkInfo := types.ForkInfo{ 165 IsFork: repoInfo.Source != nil, 166 Status: types.UpToDate, 167 } 168 169 if !forkInfo.IsFork { 170 forkInfo.IsFork = false 171 return &forkInfo, nil 172 } 173 174 us, err := knotclient.NewUnsignedClient(repoInfo.Source.Knot, rp.config.Core.Dev) 175 if err != nil { 176 log.Printf("failed to create unsigned client for %s", repoInfo.Source.Knot) 177 return nil, err 178 } 179 180 result, err := us.Branches(repoInfo.Source.Did, repoInfo.Source.Name) 181 if err != nil { 182 log.Println("failed to reach knotserver", err) 183 return nil, err 184 } 185 186 if !slices.ContainsFunc(result.Branches, func(branch types.Branch) bool { 187 return branch.Name == f.Ref 188 }) { 189 forkInfo.Status = types.MissingBranch 190 return &forkInfo, nil 191 } 192 193 newHiddenRefResp, err := signedClient.NewHiddenRef(user.Did, repoInfo.Name, f.Ref, f.Ref) 194 if err != nil || newHiddenRefResp.StatusCode != http.StatusNoContent { 195 log.Printf("failed to update tracking branch: %s", err) 196 return nil, err 197 } 198 199 hiddenRef := fmt.Sprintf("hidden/%s/%s", f.Ref, f.Ref) 200 201 var status types.AncestorCheckResponse 202 forkSyncableResp, err := signedClient.RepoForkAheadBehind(user.Did, string(f.RepoAt), repoInfo.Name, f.Ref, hiddenRef) 203 if err != nil { 204 log.Printf("failed to check if fork is ahead/behind: %s", err) 205 return nil, err 206 } 207 208 if err := json.NewDecoder(forkSyncableResp.Body).Decode(&status); err != nil { 209 log.Printf("failed to decode fork status: %s", err) 210 return nil, err 211 } 212 213 forkInfo.Status = status.Status 214 return &forkInfo, nil 215}