Mirror of @tangled.org/core. Running on a Raspberry Pi Zero 2 (Please be gentle).
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

appview: state: introduce get route to check if fork is syncable

authored by

BrookJeynes and committed by
Tangled
65defd9c a26ee40d

+80 -73
+23 -2
appview/knotclient/signer.go
··· 106 106 return s.client.Do(req) 107 107 } 108 108 109 + func (s *SignedClient) RepoForkAheadBehind(ownerDid, source, name, branch, hiddenRef string) (*http.Response, error) { 110 + const ( 111 + Method = "GET" 112 + ) 113 + endpoint := fmt.Sprintf("/repo/fork/sync/%s", url.PathEscape(branch)) 114 + 115 + body, _ := json.Marshal(map[string]any{ 116 + "did": ownerDid, 117 + "source": source, 118 + "name": name, 119 + "hiddenref": hiddenRef, 120 + }) 121 + 122 + req, err := s.newRequest(Method, endpoint, body) 123 + if err != nil { 124 + return nil, err 125 + } 126 + 127 + return s.client.Do(req) 128 + } 129 + 109 130 func (s *SignedClient) SyncRepoFork(ownerDid, source, name, branch string) (*http.Response, error) { 110 131 const ( 111 - Method = "POST" 132 + Method = "POST" 112 133 ) 113 - endpoint := fmt.Sprintf("/repo/fork/sync/%s", branch) 134 + endpoint := fmt.Sprintf("/repo/fork/sync/%s", url.PathEscape(branch)) 114 135 115 136 body, _ := json.Marshal(map[string]any{ 116 137 "did": ownerDid,
+1 -15
appview/pages/pages.go
··· 402 402 return p.executePlain("repo/fragments/repoDescription", w, params) 403 403 } 404 404 405 - type ForkStatus int 406 - 407 - const ( 408 - UpToDate ForkStatus = 0 409 - FastForwardable = 1 410 - Conflict = 2 411 - MissingBranch = 3 412 - ) 413 - 414 - type ForkInfo struct { 415 - IsFork bool 416 - Status ForkStatus 417 - } 418 - 419 405 type RepoIndexParams struct { 420 406 LoggedInUser *oauth.User 421 407 RepoInfo repoinfo.RepoInfo ··· 410 424 CommitsTrunc []*object.Commit 411 425 TagsTrunc []*types.TagReference 412 426 BranchesTrunc []types.Branch 413 - ForkInfo ForkInfo 427 + ForkInfo types.ForkInfo 414 428 types.RepoIndexResponse 415 429 HTMLReadme template.HTML 416 430 Raw bool
+22 -47
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" 29 28 "tangled.sh/tangled.sh/core/types" 30 29 31 30 "github.com/bluesky-social/indigo/atproto/data" ··· 123 124 user := s.oauth.GetUser(r) 124 125 repoInfo := f.RepoInfo(s, user) 125 126 126 - forkInfo, err := GetForkInfo(repoInfo, s, f, us, w, user) 127 + forkInfo, err := getForkInfo(repoInfo, s, f, us, w, user) 127 128 if err != nil { 128 129 log.Printf("Failed to fetch fork information: %v", err) 129 130 return ··· 143 144 return 144 145 } 145 146 146 - func GetForkInfo( 147 + func getForkInfo( 147 148 repoInfo repoinfo.RepoInfo, 148 149 s *State, 149 150 f *FullyResolvedRepo, 150 151 us *knotclient.UnsignedClient, 151 152 w http.ResponseWriter, 152 153 user *oauth.User, 153 - ) (*pages.ForkInfo, error) { 154 - forkInfo := pages.ForkInfo{ 154 + ) (*types.ForkInfo, error) { 155 + forkInfo := types.ForkInfo{ 155 156 IsFork: repoInfo.Source != nil, 156 - Status: pages.UpToDate, 157 + Status: types.UpToDate, 157 158 } 158 159 159 160 secret, err := db.GetRegistrationKey(s.db, f.Knot) ··· 186 187 return nil, err 187 188 } 188 189 189 - var contains = false 190 - for _, branch := range result.Branches { 191 - if branch.Name == f.Ref { 192 - contains = true 193 - break 194 - } 195 - } 196 - 197 - if contains == false { 198 - forkInfo.Status = pages.MissingBranch 190 + if !slices.ContainsFunc(result.Branches, func(branch types.Branch) bool { 191 + return branch.Name == f.Ref 192 + }) { 193 + forkInfo.Status = types.MissingBranch 199 194 return &forkInfo, nil 200 195 } 201 196 ··· 206 213 } 207 214 208 215 hiddenRef := fmt.Sprintf("hidden/%s/%s", f.Ref, f.Ref) 209 - comparison, err := us.Compare(user.Did, repoInfo.Name, f.Ref, hiddenRef) 216 + 217 + var status types.AncestorCheckResponse 218 + forkSyncableResp, err := signedClient.RepoForkAheadBehind(user.Did, string(f.RepoAt), repoInfo.Name, f.Ref, hiddenRef) 210 219 if err != nil { 211 - log.Printf("failed to compare branches '%s' and '%s': %s", f.Ref, hiddenRef, err) 220 + log.Printf("failed to check if fork is ahead/behind: %s", err) 212 221 return nil, err 213 222 } 214 223 215 - if len(comparison.FormatPatch) == 0 { 216 - return &forkInfo, nil 217 - } 218 - 219 - var isAncestor types.AncestorCheckResponse 220 - forkSyncableResp, err := signedClient.RepoForkSyncable(user.Did, string(f.RepoAt), repoInfo.Name, f.Ref, hiddenRef) 221 - if err != nil { 222 - log.Printf("failed to check if fork is syncable: %s", err) 224 + if err := json.NewDecoder(forkSyncableResp.Body).Decode(&status); err != nil { 225 + log.Printf("failed to decode fork status: %s", err) 223 226 return nil, err 224 227 } 225 228 226 - if err := json.NewDecoder(forkSyncableResp.Body).Decode(&isAncestor); err != nil { 227 - log.Printf("failed to decode 'isAncestor': %s", err) 228 - return nil, err 229 - } 230 - 231 - if isAncestor.IsAncestor { 232 - forkInfo.Status = pages.FastForwardable 233 - } else { 234 - forkInfo.Status = pages.Conflict 235 - } 236 - 229 + forkInfo.Status = status.Status 237 230 return &forkInfo, nil 238 231 } 239 232 ··· 1895 1916 } 1896 1917 1897 1918 func (s *State) SyncRepoFork(w http.ResponseWriter, r *http.Request) { 1898 - user := s.auth.GetUser(r) 1919 + user := s.oauth.GetUser(r) 1899 1920 f, err := s.fullyResolvedRepo(r) 1900 1921 if err != nil { 1901 1922 log.Printf("failed to resolve source repo: %v", err) 1902 1923 return 1903 1924 } 1904 1925 1905 - params := r.URL.Query() 1906 - knot := params.Get("knot") 1907 - branch := params.Get("branch") 1908 - 1909 1926 switch r.Method { 1910 1927 case http.MethodPost: 1911 - secret, err := db.GetRegistrationKey(s.db, knot) 1928 + secret, err := db.GetRegistrationKey(s.db, f.Knot) 1912 1929 if err != nil { 1913 - s.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", knot)) 1930 + s.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", f.Knot)) 1914 1931 return 1915 1932 } 1916 1933 1917 - client, err := NewSignedClient(knot, secret, s.config.Dev) 1934 + client, err := knotclient.NewSignedClient(f.Knot, secret, s.config.Core.Dev) 1918 1935 if err != nil { 1919 1936 s.pages.Notice(w, "repo", "Failed to reach knot server.") 1920 1937 return 1921 1938 } 1922 1939 1923 1940 var uri string 1924 - if s.config.Dev { 1941 + if s.config.Core.Dev { 1925 1942 uri = "http" 1926 1943 } else { 1927 1944 uri = "https" ··· 1925 1950 forkName := fmt.Sprintf("%s", f.RepoName) 1926 1951 forkSourceUrl := fmt.Sprintf("%s://%s/%s/%s", uri, f.Knot, f.OwnerDid(), f.RepoName) 1927 1952 1928 - _, err = client.SyncRepoFork(user.Did, forkSourceUrl, forkName, branch) 1953 + _, err = client.SyncRepoFork(user.Did, forkSourceUrl, forkName, f.Ref) 1929 1954 if err != nil { 1930 1955 s.pages.Notice(w, "repo", "Failed to sync repository fork.") 1931 1956 return
+3 -1
appview/state/router.go
··· 113 113 r.Use(middleware.AuthMiddleware(s.oauth)) 114 114 r.Get("/", s.ForkRepo) 115 115 r.Post("/", s.ForkRepo) 116 - r.Post("/sync", s.SyncRepoFork) 116 + r.With(RepoPermissionMiddleware(s, "repo:owner")).Route("/sync", func(r chi.Router) { 117 + r.Post("/", s.SyncRepoFork) 118 + }) 117 119 }) 118 120 119 121 r.Route("/pulls", func(r chi.Router) {
+1 -1
knotserver/handler.go
··· 129 129 r.Route("/fork", func(r chi.Router) { 130 130 r.Post("/", h.RepoFork) 131 131 r.Post("/sync/{branch}", h.RepoForkSync) 132 - r.Get("/sync/{branch}", h.RepoForkSyncable) 132 + r.Get("/sync/{branch}", h.RepoForkAheadBehind) 133 133 }) 134 134 }) 135 135
+15 -6
knotserver/routes.go
··· 631 631 w.WriteHeader(http.StatusNoContent) 632 632 } 633 633 634 - func (h *Handle) RepoForkSyncable(w http.ResponseWriter, r *http.Request) { 634 + func (h *Handle) RepoForkAheadBehind(w http.ResponseWriter, r *http.Request) { 635 635 l := h.l.With("handler", "RepoForkSync") 636 636 637 637 data := struct { ··· 689 689 return 690 690 } 691 691 692 - isAncestor, err := forkCommit.IsAncestor(sourceCommit) 693 - if err != nil { 694 - log.Printf("error resolving whether %s is ancestor of %s: %s", branch, data.HiddenRef, err) 695 - return 692 + status := types.UpToDate 693 + if forkCommit.Hash.String() != sourceCommit.Hash.String() { 694 + isAncestor, err := forkCommit.IsAncestor(sourceCommit) 695 + if err != nil { 696 + log.Printf("error resolving whether %s is ancestor of %s: %s", branch, data.HiddenRef, err) 697 + return 698 + } 699 + 700 + if isAncestor { 701 + status = types.FastForwardable 702 + } else { 703 + status = types.Conflict 704 + } 696 705 } 697 706 698 707 w.Header().Set("Content-Type", "application/json") 699 - json.NewEncoder(w).Encode(types.AncestorCheckResponse{IsAncestor: isAncestor}) 708 + json.NewEncoder(w).Encode(types.AncestorCheckResponse{Status: status}) 700 709 } 701 710 702 711 func (h *Handle) RepoForkSync(w http.ResponseWriter, r *http.Request) {
+15 -1
types/repo.go
··· 91 91 SizeHint uint64 `json:"size_hint,omitempty"` 92 92 } 93 93 94 + type ForkStatus int 95 + 96 + const ( 97 + UpToDate ForkStatus = 0 98 + FastForwardable = 1 99 + Conflict = 2 100 + MissingBranch = 3 101 + ) 102 + 103 + type ForkInfo struct { 104 + IsFork bool 105 + Status ForkStatus 106 + } 107 + 94 108 type AncestorCheckResponse struct { 95 - IsAncestor bool `json:"isAncestor"` 109 + Status ForkStatus `json:"status"` 96 110 }