forked from tangled.org/core
this repo has no description

appview: repo: retrieve fork info on repo page load

authored by brookjeynes.dev and committed by Tangled 1dc5d2cd a597918f

Changed files
+103 -17
appview
pages
state
types
+1
appview/pages/pages.go
··· 424 424 CommitsTrunc []*object.Commit 425 425 TagsTrunc []*types.TagReference 426 426 BranchesTrunc []types.Branch 427 + ForkInfo ForkInfo 427 428 types.RepoIndexResponse 428 429 HTMLReadme template.HTML 429 430 Raw bool
+98 -17
appview/state/repo.go
··· 25 25 "tangled.sh/tangled.sh/core/appview/pages/markup" 26 26 "tangled.sh/tangled.sh/core/appview/pages/repoinfo" 27 27 "tangled.sh/tangled.sh/core/appview/pagination" 28 + "tangled.sh/tangled.sh/core/knotserver" 28 29 "tangled.sh/tangled.sh/core/types" 29 30 30 31 "github.com/bluesky-social/indigo/atproto/data" ··· 123 124 user := s.oauth.GetUser(r) 124 125 repoInfo := f.RepoInfo(s, user) 125 126 127 + forkInfo, err := GetForkInfo(repoInfo, s, f, us, w, user) 128 + if err != nil { 129 + log.Printf("Failed to fetch fork information: %v", err) 130 + return 131 + } 132 + 133 + s.pages.RepoIndexPage(w, pages.RepoIndexParams{ 134 + LoggedInUser: user, 135 + RepoInfo: repoInfo, 136 + TagMap: tagMap, 137 + RepoIndexResponse: result, 138 + CommitsTrunc: commitsTrunc, 139 + TagsTrunc: tagsTrunc, 140 + ForkInfo: *forkInfo, 141 + BranchesTrunc: branchesTrunc, 142 + EmailToDidOrHandle: EmailToDidOrHandle(s, emails), 143 + }) 144 + return 145 + } 146 + 147 + func GetForkInfo( 148 + repoInfo repoinfo.RepoInfo, 149 + s *State, 150 + f *FullyResolvedRepo, 151 + us *knotclient.UnsignedClient, 152 + w http.ResponseWriter, 153 + user *oauth.User, 154 + ) (*pages.ForkInfo, error) { 155 + forkInfo := pages.ForkInfo{ 156 + IsFork: repoInfo.Source != nil, 157 + Status: pages.UpToDate, 158 + } 159 + 126 160 secret, err := db.GetRegistrationKey(s.db, f.Knot) 127 161 if err != nil { 128 162 log.Printf("failed to get registration key for %s: %s", f.Knot, err) 129 163 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") 130 164 } 131 165 132 - // update the hidden tracking branch to latest 166 + if !forkInfo.IsFork { 167 + forkInfo.IsFork = false 168 + return &forkInfo, nil 169 + } 170 + 171 + resp, err := us.Branches(repoInfo.Source.Did, repoInfo.Source.Name) 172 + if err != nil { 173 + log.Println("failed to reach knotserver", err) 174 + return nil, err 175 + } 176 + 177 + body, err := io.ReadAll(resp.Body) 178 + if err != nil { 179 + log.Printf("Error reading forkResponse forkBody: %v", err) 180 + return nil, err 181 + } 182 + 183 + var result types.RepoBranchesResponse 184 + err = json.Unmarshal(body, &result) 185 + if err != nil { 186 + log.Println("failed to parse forkResponse:", err) 187 + return nil, err 188 + } 189 + 190 + var contains = false 191 + for _, branch := range result.Branches { 192 + if branch.Name == f.Ref { 193 + contains = true 194 + break 195 + } 196 + } 197 + 198 + if contains == false { 199 + forkInfo.Status = pages.MissingBranch 200 + return &forkInfo, nil 201 + } 202 + 133 203 signedClient, err := knotclient.NewSignedClient(f.Knot, secret, s.config.Core.Dev) 134 204 if err != nil { 135 205 log.Printf("failed to create signed client for %s: %s", f.Knot, err) 136 - s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") 206 + return nil, err 137 207 } 138 208 139 209 newHiddenRefResp, err := signedClient.NewHiddenRef(user.Did, repoInfo.Name, f.Ref, f.Ref) 140 210 if err != nil || newHiddenRefResp.StatusCode != http.StatusNoContent { 141 211 log.Printf("failed to update tracking branch: %s", err) 142 - s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") 212 + return nil, err 143 213 } 144 214 145 215 hiddenRef := fmt.Sprintf("hidden/%s/%s", f.Ref, f.Ref) 146 216 comparison, err := us.Compare(user.Did, repoInfo.Name, f.Ref, hiddenRef) 147 217 if err != nil { 148 - log.Printf("failed to compare branches: %s", err) 149 - s.pages.Notice(w, "resubmit-error", err.Error()) 218 + log.Printf("failed to compare branches '%s' and '%s': %s", f.Ref, hiddenRef, err) 219 + return nil, err 220 + } 221 + 222 + if len(comparison.FormatPatch) == 0 { 223 + return &forkInfo, nil 224 + } 225 + 226 + var isAncestor types.AncestorCheckResponse 227 + forkSyncableResp, err := signedClient.RepoForkSyncable(user.Did, string(f.RepoAt), repoInfo.Name, f.Ref, hiddenRef) 228 + if err != nil { 229 + log.Printf("failed to check if fork is syncable: %s", err) 230 + return nil, err 150 231 } 151 - log.Println(comparison) 152 232 153 - s.pages.RepoIndexPage(w, pages.RepoIndexParams{ 154 - LoggedInUser: user, 155 - RepoInfo: repoInfo, 156 - TagMap: tagMap, 157 - RepoIndexResponse: result, 158 - CommitsTrunc: commitsTrunc, 159 - TagsTrunc: tagsTrunc, 160 - BranchesTrunc: branchesTrunc, 161 - EmailToDidOrHandle: EmailToDidOrHandle(s, emails), 162 - }) 163 - return 233 + if err := json.NewDecoder(forkSyncableResp.Body).Decode(&isAncestor); err != nil { 234 + log.Printf("failed to decode 'isAncestor': %s", err) 235 + return nil, err 236 + } 237 + 238 + if isAncestor.IsAncestor { 239 + forkInfo.Status = pages.FastForwardable 240 + } else { 241 + forkInfo.Status = pages.Conflict 242 + } 243 + 244 + return &forkInfo, nil 164 245 } 165 246 166 247 func (s *State) RepoLog(w http.ResponseWriter, r *http.Request) {
+4
types/repo.go
··· 90 90 Lines int `json:"lines,omitempty"` 91 91 SizeHint uint64 `json:"size_hint,omitempty"` 92 92 } 93 + 94 + type AncestorCheckResponse struct { 95 + IsAncestor bool `json:"isAncestor"` 96 + }