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

appview/{pulls,repo,state}: use xrpc + service auth for knot requests

This now covers: Fork, ForkSync, NewHiddenRef, Merge, MergeCheck,
and RepoCreate/Delete.

Signed-off-by: Anirudh Oppiliappan <anirudh@tangled.sh>

authored by anirudh.fi and committed by oppi.li a61bacf4 0c03847b

Changed files
+281 -175
appview
pulls
repo
state
+130 -85
appview/pulls/pulls.go
··· 2 3 import ( 4 "database/sql" 5 - "encoding/json" 6 "errors" 7 "fmt" 8 - "io" 9 "log" 10 "net/http" 11 "sort" ··· 96 return 97 } 98 99 - mergeCheckResponse := s.mergeCheck(f, pull, stack) 100 resubmitResult := pages.Unknown 101 if user.Did == pull.OwnerDid { 102 resubmitResult = s.resubmitCheck(f, pull, stack) ··· 151 } 152 } 153 154 - mergeCheckResponse := s.mergeCheck(f, pull, stack) 155 resubmitResult := pages.Unknown 156 if user != nil && user.Did == pull.OwnerDid { 157 resubmitResult = s.resubmitCheck(f, pull, stack) ··· 215 }) 216 } 217 218 - func (s *Pulls) mergeCheck(f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) types.MergeCheckResponse { 219 if pull.State == db.PullMerged { 220 return types.MergeCheckResponse{} 221 } 222 223 - secret, err := db.GetRegistrationKey(s.db, f.Knot) 224 - if err != nil { 225 - log.Printf("failed to get registration key: %v", err) 226 - return types.MergeCheckResponse{ 227 - Error: "failed to check merge status: this knot is unregistered", 228 - } 229 - } 230 - 231 - ksClient, err := knotclient.NewSignedClient(f.Knot, secret, s.config.Core.Dev) 232 if err != nil { 233 - log.Printf("failed to setup signed client for %s; ignoring: %v", f.Knot, err) 234 return types.MergeCheckResponse{ 235 - Error: "failed to check merge status", 236 } 237 } 238 ··· 246 patch = mergeable.CombinedPatch() 247 } 248 249 - resp, err := ksClient.MergeCheck([]byte(patch), f.OwnerDid(), f.Name, pull.TargetBranch) 250 - if err != nil { 251 - log.Println("failed to check for mergeability:", err) 252 return types.MergeCheckResponse{ 253 - Error: "failed to check merge status", 254 } 255 } 256 - switch resp.StatusCode { 257 - case 404: 258 - return types.MergeCheckResponse{ 259 - Error: "failed to check merge status: this knot does not support PRs", 260 - } 261 - case 400: 262 - return types.MergeCheckResponse{ 263 - Error: "failed to check merge status: does this knot support PRs?", 264 } 265 } 266 267 - respBody, err := io.ReadAll(resp.Body) 268 - if err != nil { 269 - log.Println("failed to read merge check response body") 270 - return types.MergeCheckResponse{ 271 - Error: "failed to check merge status: knot is not speaking the right language", 272 - } 273 } 274 - defer resp.Body.Close() 275 276 - var mergeCheckResponse types.MergeCheckResponse 277 - err = json.Unmarshal(respBody, &mergeCheckResponse) 278 - if err != nil { 279 - log.Println("failed to unmarshal merge check response", err) 280 - return types.MergeCheckResponse{ 281 - Error: "failed to check merge status: knot is not speaking the right language", 282 - } 283 } 284 285 - return mergeCheckResponse 286 } 287 288 func (s *Pulls) resubmitCheck(f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) pages.ResubmitResult { ··· 867 return 868 } 869 870 - secret, err := db.GetRegistrationKey(s.db, fork.Knot) 871 - if err != nil { 872 - log.Println("failed to fetch registration key:", err) 873 - s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 874 - return 875 - } 876 - 877 - sc, err := knotclient.NewSignedClient(fork.Knot, secret, s.config.Core.Dev) 878 if err != nil { 879 - log.Println("failed to create signed client:", err) 880 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 881 return 882 } ··· 888 return 889 } 890 891 - resp, err := sc.NewHiddenRef(user.Did, fork.Name, sourceBranch, targetBranch) 892 if err != nil { 893 - log.Println("failed to create hidden ref:", err, resp.StatusCode) 894 - s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 895 return 896 } 897 898 - switch resp.StatusCode { 899 - case 404: 900 - case 400: 901 - s.pages.Notice(w, "pull", "Branch based pull requests are not supported on this knot.") 902 return 903 } 904 ··· 1464 return 1465 } 1466 1467 - secret, err := db.GetRegistrationKey(s.db, forkRepo.Knot) 1468 - if err != nil { 1469 - log.Printf("failed to get registration key for %s: %s", forkRepo.Knot, err) 1470 - s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") 1471 - return 1472 - } 1473 - 1474 // update the hidden tracking branch to latest 1475 - signedClient, err := knotclient.NewSignedClient(forkRepo.Knot, secret, s.config.Core.Dev) 1476 if err != nil { 1477 - log.Printf("failed to create signed client for %s: %s", forkRepo.Knot, err) 1478 - s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") 1479 return 1480 } 1481 1482 - resp, err := signedClient.NewHiddenRef(forkRepo.Did, forkRepo.Name, pull.PullSource.Branch, pull.TargetBranch) 1483 - if err != nil || resp.StatusCode != http.StatusNoContent { 1484 - log.Printf("failed to update tracking branch: %s", err) 1485 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") 1486 return 1487 } ··· 1908 1909 patch := pullsToMerge.CombinedPatch() 1910 1911 - secret, err := db.GetRegistrationKey(s.db, f.Knot) 1912 if err != nil { 1913 - log.Printf("no registration key found for domain %s: %s\n", f.Knot, err) 1914 s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") 1915 return 1916 } ··· 1927 log.Printf("failed to get primary email: %s", err) 1928 } 1929 1930 - ksClient, err := knotclient.NewSignedClient(f.Knot, secret, s.config.Core.Dev) 1931 - if err != nil { 1932 - log.Printf("failed to create signed client for %s: %s", f.Knot, err) 1933 - s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") 1934 - return 1935 } 1936 1937 - // Merge the pull request 1938 - resp, err := ksClient.Merge([]byte(patch), f.OwnerDid(), f.Name, pull.TargetBranch, pull.Title, pull.Body, ident.Handle.String(), email.Address) 1939 if err != nil { 1940 - log.Printf("failed to merge pull request: %s", err) 1941 s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") 1942 return 1943 } 1944 1945 - if resp.StatusCode != http.StatusOK { 1946 - log.Printf("knotserver returned non-OK status code for merge: %d", resp.StatusCode) 1947 - s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") 1948 return 1949 } 1950
··· 2 3 import ( 4 "database/sql" 5 "errors" 6 "fmt" 7 "log" 8 "net/http" 9 "sort" ··· 94 return 95 } 96 97 + mergeCheckResponse := s.mergeCheck(r, f, pull, stack) 98 resubmitResult := pages.Unknown 99 if user.Did == pull.OwnerDid { 100 resubmitResult = s.resubmitCheck(f, pull, stack) ··· 149 } 150 } 151 152 + mergeCheckResponse := s.mergeCheck(r, f, pull, stack) 153 resubmitResult := pages.Unknown 154 if user != nil && user.Did == pull.OwnerDid { 155 resubmitResult = s.resubmitCheck(f, pull, stack) ··· 213 }) 214 } 215 216 + func (s *Pulls) mergeCheck(r *http.Request, f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) types.MergeCheckResponse { 217 if pull.State == db.PullMerged { 218 return types.MergeCheckResponse{} 219 } 220 221 + client, err := s.oauth.ServiceClient( 222 + r, 223 + oauth.WithService(f.Knot), 224 + oauth.WithLxm(tangled.RepoMergeCheckNSID), 225 + oauth.WithDev(s.config.Core.Dev), 226 + ) 227 if err != nil { 228 + log.Printf("failed to connect to knot server: %v", err) 229 return types.MergeCheckResponse{ 230 + Error: "failed to check merge status: could not connect to knot server", 231 } 232 } 233 ··· 241 patch = mergeable.CombinedPatch() 242 } 243 244 + resp, xe := tangled.RepoMergeCheck( 245 + r.Context(), 246 + &xrpcc, 247 + &tangled.RepoMergeCheck_Input{ 248 + Did: f.OwnerDid(), 249 + Name: f.Name, 250 + Branch: pull.TargetBranch, 251 + Patch: patch, 252 + }, 253 + ) 254 + if err := xrpcclient.HandleXrpcErr(xe); err != nil { 255 + log.Println("failed to check for mergeability", "err", err) 256 return types.MergeCheckResponse{ 257 + Error: fmt.Sprintf("failed to check merge status: %s", err.Error()), 258 } 259 } 260 + 261 + // convert xrpc response to internal types 262 + conflicts := make([]types.ConflictInfo, len(resp.Conflicts)) 263 + for i, conflict := range resp.Conflicts { 264 + conflicts[i] = types.ConflictInfo{ 265 + Filename: conflict.Filename, 266 + Reason: conflict.Reason, 267 } 268 } 269 270 + result := types.MergeCheckResponse{ 271 + IsConflicted: resp.Is_conflicted, 272 + Conflicts: conflicts, 273 + } 274 + 275 + if resp.Message != nil { 276 + result.Message = *resp.Message 277 } 278 279 + if resp.Error != nil { 280 + result.Error = *resp.Error 281 } 282 283 + return result 284 } 285 286 func (s *Pulls) resubmitCheck(f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) pages.ResubmitResult { ··· 865 return 866 } 867 868 + client, err := s.oauth.ServiceClient( 869 + r, 870 + oauth.WithService(fork.Knot), 871 + oauth.WithLxm(tangled.RepoHiddenRefNSID), 872 + oauth.WithDev(s.config.Core.Dev), 873 + ) 874 if err != nil { 875 + log.Printf("failed to connect to knot server: %v", err) 876 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 877 return 878 } ··· 884 return 885 } 886 887 + resp, err := tangled.RepoHiddenRef( 888 + r.Context(), 889 + client, 890 + &tangled.RepoHiddenRef_Input{ 891 + ForkRef: sourceBranch, 892 + RemoteRef: targetBranch, 893 + Repo: fork.RepoAt().String(), 894 + }, 895 + ) 896 if err != nil { 897 + xe, parseErr := xrpcerr.Unmarshal(err.Error()) 898 + if parseErr != nil { 899 + log.Printf("failed to create hidden ref: %v", err) 900 + s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 901 + } else { 902 + log.Printf("failed to create hidden ref: %s", xe.Error()) 903 + if xe.Tag == "AccessControl" { 904 + s.pages.Notice(w, "pull", "Branch based pull requests are not supported on this knot.") 905 + } else { 906 + s.pages.Notice(w, "pull", fmt.Sprintf("Failed to create pull request: %s", xe.Message)) 907 + } 908 + } 909 return 910 } 911 912 + if !resp.Success { 913 + errorMsg := "Failed to create pull request" 914 + if resp.Error != nil { 915 + errorMsg = fmt.Sprintf("Failed to create pull request: %s", *resp.Error) 916 + } 917 + s.pages.Notice(w, "pull", errorMsg) 918 return 919 } 920 ··· 1480 return 1481 } 1482 1483 // update the hidden tracking branch to latest 1484 + client, err := s.oauth.ServiceClient( 1485 + r, 1486 + oauth.WithService(forkRepo.Knot), 1487 + oauth.WithLxm(tangled.RepoHiddenRefNSID), 1488 + oauth.WithDev(s.config.Core.Dev), 1489 + ) 1490 if err != nil { 1491 + log.Printf("failed to connect to knot server: %v", err) 1492 return 1493 } 1494 1495 + resp, err := tangled.RepoHiddenRef( 1496 + r.Context(), 1497 + client, 1498 + &tangled.RepoHiddenRef_Input{ 1499 + ForkRef: pull.PullSource.Branch, 1500 + RemoteRef: pull.TargetBranch, 1501 + Repo: forkRepo.RepoAt().String(), 1502 + }, 1503 + ) 1504 + if err != nil || !resp.Success { 1505 + if err != nil { 1506 + log.Printf("failed to update tracking branch: %s", err) 1507 + } else { 1508 + log.Printf("failed to update tracking branch: success=false") 1509 + } 1510 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") 1511 return 1512 } ··· 1933 1934 patch := pullsToMerge.CombinedPatch() 1935 1936 + client, err := s.oauth.ServiceClient( 1937 + r, 1938 + oauth.WithService(f.Knot), 1939 + oauth.WithLxm(tangled.RepoMergeNSID), 1940 + oauth.WithDev(s.config.Core.Dev), 1941 + ) 1942 if err != nil { 1943 + log.Printf("failed to connect to knot server: %v", err) 1944 s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") 1945 return 1946 } ··· 1957 log.Printf("failed to get primary email: %s", err) 1958 } 1959 1960 + authorName := ident.Handle.String() 1961 + mergeInput := &tangled.RepoMerge_Input{ 1962 + Did: f.OwnerDid(), 1963 + Name: f.Name, 1964 + Branch: pull.TargetBranch, 1965 + Patch: patch, 1966 + CommitMessage: &pull.Title, 1967 + AuthorName: &authorName, 1968 } 1969 1970 + if pull.Body != "" { 1971 + mergeInput.CommitBody = &pull.Body 1972 + } 1973 + 1974 + if email.Address != "" { 1975 + mergeInput.AuthorEmail = &email.Address 1976 + } 1977 + 1978 + client, err := s.oauth.ServiceClient( 1979 + r, 1980 + oauth.WithService(f.Knot), 1981 + oauth.WithLxm(tangled.RepoMergeNSID), 1982 + oauth.WithDev(s.config.Core.Dev), 1983 + ) 1984 if err != nil { 1985 + log.Printf("failed to connect to knot server: %v", err) 1986 s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") 1987 return 1988 } 1989 1990 + err = tangled.RepoMerge(r.Context(), client, mergeInput) 1991 + if err := xrpcclient.HandleXrpcErr(err); err != nil { 1992 + s.pages.Notice(w, "pull-merge-error", err.Error()) 1993 return 1994 } 1995
+28 -4
appview/repo/index.go
··· 119 120 var forkInfo *types.ForkInfo 121 if user != nil && (repoInfo.Roles.IsOwner() || repoInfo.Roles.IsCollaborator()) { 122 - forkInfo, err = getForkInfo(repoInfo, rp, f, result.Ref, user, signedClient) 123 if err != nil { 124 log.Printf("Failed to fetch fork information: %v", err) 125 return ··· 233 } 234 235 func getForkInfo( 236 repoInfo repoinfo.RepoInfo, 237 rp *Repo, 238 f *reporesolver.ResolvedRepo, ··· 273 return &forkInfo, nil 274 } 275 276 - newHiddenRefResp, err := signedClient.NewHiddenRef(user.Did, repoInfo.Name, currentRef, currentRef) 277 - if err != nil || newHiddenRefResp.StatusCode != http.StatusNoContent { 278 - log.Printf("failed to update tracking branch: %s", err) 279 return nil, err 280 } 281 282 hiddenRef := fmt.Sprintf("hidden/%s/%s", currentRef, currentRef)
··· 119 120 var forkInfo *types.ForkInfo 121 if user != nil && (repoInfo.Roles.IsOwner() || repoInfo.Roles.IsCollaborator()) { 122 + forkInfo, err = getForkInfo(r, repoInfo, rp, f, result.Ref, user, signedClient) 123 if err != nil { 124 log.Printf("Failed to fetch fork information: %v", err) 125 return ··· 233 } 234 235 func getForkInfo( 236 + r *http.Request, 237 repoInfo repoinfo.RepoInfo, 238 rp *Repo, 239 f *reporesolver.ResolvedRepo, ··· 274 return &forkInfo, nil 275 } 276 277 + client, err := rp.oauth.ServiceClient( 278 + r, 279 + oauth.WithService(f.Knot), 280 + oauth.WithLxm(tangled.RepoHiddenRefNSID), 281 + oauth.WithDev(rp.config.Core.Dev), 282 + ) 283 + if err != nil { 284 + log.Printf("failed to connect to knot server: %v", err) 285 return nil, err 286 + } 287 + 288 + resp, err := tangled.RepoHiddenRef( 289 + r.Context(), 290 + client, 291 + &tangled.RepoHiddenRef_Input{ 292 + ForkRef: currentRef, 293 + RemoteRef: currentRef, 294 + Repo: f.RepoAt().String(), 295 + }, 296 + ) 297 + if err != nil || !resp.Success { 298 + if err != nil { 299 + log.Printf("failed to update tracking branch: %s", err) 300 + } else { 301 + log.Printf("failed to update tracking branch: success=false") 302 + } 303 + return nil, fmt.Errorf("failed to update tracking branch") 304 } 305 306 hiddenRef := fmt.Sprintf("hidden/%s/%s", currentRef, currentRef)
+99 -67
appview/repo/repo.go
··· 17 "strings" 18 "time" 19 20 "tangled.sh/tangled.sh/core/api/tangled" 21 "tangled.sh/tangled.sh/core/appview/commitverify" 22 "tangled.sh/tangled.sh/core/appview/config" ··· 33 "tangled.sh/tangled.sh/core/rbac" 34 "tangled.sh/tangled.sh/core/tid" 35 "tangled.sh/tangled.sh/core/types" 36 37 securejoin "github.com/cyphar/filepath-securejoin" 38 "github.com/go-chi/chi/v5" 39 "github.com/go-git/go-git/v5/plumbing" 40 41 - comatproto "github.com/bluesky-social/indigo/api/atproto" 42 "github.com/bluesky-social/indigo/atproto/syntax" 43 - lexutil "github.com/bluesky-social/indigo/lex/util" 44 ) 45 46 type Repo struct { ··· 54 enforcer *rbac.Enforcer 55 notifier notify.Notifier 56 logger *slog.Logger 57 } 58 59 func New( ··· 960 } 961 log.Println("removed repo record ", f.RepoAt().String()) 962 963 - secret, err := db.GetRegistrationKey(rp.db, f.Knot) 964 if err != nil { 965 - log.Printf("no key found for domain %s: %s\n", f.Knot, err) 966 return 967 } 968 969 - ksClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev) 970 if err != nil { 971 - log.Println("failed to create client to ", f.Knot) 972 - return 973 - } 974 - 975 - ksResp, err := ksClient.RemoveRepo(f.OwnerDid(), f.Name) 976 - if err != nil { 977 - log.Printf("failed to make request to %s: %s", f.Knot, err) 978 - return 979 - } 980 - 981 - if ksResp.StatusCode != http.StatusNoContent { 982 - log.Println("failed to remove repo from knot, continuing anyway ", f.Knot) 983 } else { 984 log.Println("removed repo from knot ", f.Knot) 985 } ··· 1055 return 1056 } 1057 1058 - secret, err := db.GetRegistrationKey(rp.db, f.Knot) 1059 if err != nil { 1060 - log.Printf("no key found for domain %s: %s\n", f.Knot, err) 1061 return 1062 } 1063 1064 - ksClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev) 1065 - if err != nil { 1066 - log.Println("failed to create client to ", f.Knot) 1067 - return 1068 - } 1069 - 1070 - ksResp, err := ksClient.SetDefaultBranch(f.OwnerDid(), f.Name, branch) 1071 - if err != nil { 1072 - log.Printf("failed to make request to %s: %s", f.Knot, err) 1073 - return 1074 - } 1075 - 1076 - if ksResp.StatusCode != http.StatusNoContent { 1077 - rp.pages.Notice(w, "repo-settings", "Failed to set default branch. Try again later.") 1078 return 1079 } 1080 ··· 1373 1374 switch r.Method { 1375 case http.MethodPost: 1376 - secret, err := db.GetRegistrationKey(rp.db, f.Knot) 1377 if err != nil { 1378 - rp.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", f.Knot)) 1379 return 1380 } 1381 1382 - client, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev) 1383 - if err != nil { 1384 - rp.pages.Notice(w, "repo", "Failed to reach knot server.") 1385 return 1386 } 1387 1388 - var uri string 1389 - if rp.config.Core.Dev { 1390 - uri = "http" 1391 - } else { 1392 - uri = "https" 1393 - } 1394 - forkName := fmt.Sprintf("%s", f.Name) 1395 - forkSourceUrl := fmt.Sprintf("%s://%s/%s/%s", uri, f.Knot, f.OwnerDid(), f.Repo.Name) 1396 - 1397 - _, err = client.SyncRepoFork(user.Did, forkSourceUrl, forkName, ref) 1398 if err != nil { 1399 - rp.pages.Notice(w, "repo", "Failed to sync repository fork.") 1400 return 1401 } 1402 ··· 1459 // repo with this name already exists, append random string 1460 forkName = fmt.Sprintf("%s-%s", forkName, randomString(3)) 1461 } 1462 - secret, err := db.GetRegistrationKey(rp.db, knot) 1463 - if err != nil { 1464 - rp.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", knot)) 1465 - return 1466 - } 1467 1468 - client, err := knotclient.NewSignedClient(knot, secret, rp.config.Core.Dev) 1469 if err != nil { 1470 - rp.pages.Notice(w, "repo", "Failed to reach knot server.") 1471 return 1472 } 1473 ··· 1503 } 1504 }() 1505 1506 - resp, err := client.ForkRepo(user.Did, forkSourceUrl, forkName) 1507 if err != nil { 1508 - rp.pages.Notice(w, "repo", "Failed to create repository on knot server.") 1509 - return 1510 - } 1511 1512 - switch resp.StatusCode { 1513 - case http.StatusConflict: 1514 - rp.pages.Notice(w, "repo", "A repository with that name already exists.") 1515 return 1516 - case http.StatusInternalServerError: 1517 - rp.pages.Notice(w, "repo", "Failed to create repository on knot. Try again later.") 1518 - case http.StatusNoContent: 1519 - // continue 1520 } 1521 1522 xrpcClient, err := rp.oauth.AuthorizedClient(r)
··· 17 "strings" 18 "time" 19 20 + comatproto "github.com/bluesky-social/indigo/api/atproto" 21 + lexutil "github.com/bluesky-social/indigo/lex/util" 22 "tangled.sh/tangled.sh/core/api/tangled" 23 "tangled.sh/tangled.sh/core/appview/commitverify" 24 "tangled.sh/tangled.sh/core/appview/config" ··· 35 "tangled.sh/tangled.sh/core/rbac" 36 "tangled.sh/tangled.sh/core/tid" 37 "tangled.sh/tangled.sh/core/types" 38 + "tangled.sh/tangled.sh/core/xrpc/serviceauth" 39 40 securejoin "github.com/cyphar/filepath-securejoin" 41 "github.com/go-chi/chi/v5" 42 "github.com/go-git/go-git/v5/plumbing" 43 44 "github.com/bluesky-social/indigo/atproto/syntax" 45 ) 46 47 type Repo struct { ··· 55 enforcer *rbac.Enforcer 56 notifier notify.Notifier 57 logger *slog.Logger 58 + serviceAuth *serviceauth.ServiceAuth 59 } 60 61 func New( ··· 962 } 963 log.Println("removed repo record ", f.RepoAt().String()) 964 965 + client, err := rp.oauth.ServiceClient( 966 + r, 967 + oauth.WithService(f.Knot), 968 + oauth.WithLxm(tangled.RepoDeleteNSID), 969 + oauth.WithDev(rp.config.Core.Dev), 970 + ) 971 if err != nil { 972 + log.Println("failed to connect to knot server:", err) 973 return 974 } 975 976 + err = tangled.RepoDelete( 977 + r.Context(), 978 + client, 979 + &tangled.RepoDelete_Input{ 980 + Did: f.OwnerDid(), 981 + Name: f.Name, 982 + }, 983 + ) 984 if err != nil { 985 + xe, parseErr := xrpcerr.Unmarshal(err.Error()) 986 + if parseErr != nil { 987 + log.Printf("failed to delete repo from knot %s: %s", f.Knot, err) 988 + } else { 989 + log.Printf("failed to delete repo from knot %s: %s", f.Knot, xe.Error()) 990 + } 991 + // Continue anyway since we want to clean up local state 992 } else { 993 log.Println("removed repo from knot ", f.Knot) 994 } ··· 1064 return 1065 } 1066 1067 + client, err := rp.oauth.ServiceClient( 1068 + r, 1069 + oauth.WithService(f.Knot), 1070 + oauth.WithLxm(tangled.RepoSetDefaultBranchNSID), 1071 + oauth.WithDev(rp.config.Core.Dev), 1072 + ) 1073 if err != nil { 1074 + log.Println("failed to connect to knot server:", err) 1075 + rp.pages.Notice(w, noticeId, "Failed to connect to knot server.") 1076 return 1077 } 1078 1079 + xe := tangled.RepoSetDefaultBranch( 1080 + r.Context(), 1081 + client, 1082 + &tangled.RepoSetDefaultBranch_Input{ 1083 + Repo: f.RepoAt().String(), 1084 + DefaultBranch: branch, 1085 + }, 1086 + ) 1087 + if err := xrpcclient.HandleXrpcErr(xe); err != nil { 1088 + log.Println("xrpc failed", "err", xe) 1089 + rp.pages.Notice(w, noticeId, err.Error()) 1090 return 1091 } 1092 ··· 1385 1386 switch r.Method { 1387 case http.MethodPost: 1388 + client, err := rp.oauth.ServiceClient( 1389 + r, 1390 + oauth.WithService(f.Knot), 1391 + oauth.WithLxm(tangled.RepoForkSyncNSID), 1392 + oauth.WithDev(rp.config.Core.Dev), 1393 + ) 1394 if err != nil { 1395 + rp.pages.Notice(w, "repo", "Failed to connect to knot server.") 1396 return 1397 } 1398 1399 + repoInfo := f.RepoInfo(user) 1400 + if repoInfo.Source == nil { 1401 + rp.pages.Notice(w, "repo", "This repository is not a fork.") 1402 return 1403 } 1404 1405 + err = tangled.RepoForkSync( 1406 + r.Context(), 1407 + client, 1408 + &tangled.RepoForkSync_Input{ 1409 + Did: user.Did, 1410 + Name: f.Name, 1411 + Source: repoInfo.Source.RepoAt().String(), 1412 + Branch: ref, 1413 + }, 1414 + ) 1415 if err != nil { 1416 + xe, parseErr := xrpcerr.Unmarshal(err.Error()) 1417 + if parseErr != nil { 1418 + log.Printf("failed to sync repository fork: %s", err) 1419 + rp.pages.Notice(w, "repo", "Failed to sync repository fork.") 1420 + } else { 1421 + log.Printf("failed to sync repository fork: %s", xe.Error()) 1422 + rp.pages.Notice(w, "repo", fmt.Sprintf("Failed to sync repository fork: %s", xe.Message)) 1423 + } 1424 return 1425 } 1426 ··· 1483 // repo with this name already exists, append random string 1484 forkName = fmt.Sprintf("%s-%s", forkName, randomString(3)) 1485 } 1486 + client, err := rp.oauth.ServiceClient( 1487 + r, 1488 + oauth.WithService(knot), 1489 + oauth.WithLxm(tangled.RepoForkNSID), 1490 + oauth.WithDev(rp.config.Core.Dev), 1491 + ) 1492 1493 if err != nil { 1494 + log.Printf("error creating client for knot server: %v", err) 1495 + rp.pages.Notice(w, "repo", "Failed to connect to knot server.") 1496 return 1497 } 1498 ··· 1528 } 1529 }() 1530 1531 + err = tangled.RepoFork( 1532 + r.Context(), 1533 + client, 1534 + &tangled.RepoFork_Input{ 1535 + Did: user.Did, 1536 + Name: &forkName, 1537 + Source: forkSourceUrl, 1538 + }, 1539 + ) 1540 + 1541 if err != nil { 1542 + xe, err := xrpcerr.Unmarshal(err.Error()) 1543 + if err != nil { 1544 + log.Println(err) 1545 + rp.pages.Notice(w, "repo", "Failed to create repository on knot server.") 1546 + return 1547 + } 1548 1549 + log.Println(xe.Error()) 1550 + rp.pages.Notice(w, "repo", fmt.Sprintf("Failed to create repository on knot server: %s.", xe.Message)) 1551 return 1552 } 1553 1554 xrpcClient, err := rp.oauth.AuthorizedClient(r)
+24 -19
appview/state/state.go
··· 28 "tangled.sh/tangled.sh/core/eventconsumer" 29 "tangled.sh/tangled.sh/core/idresolver" 30 "tangled.sh/tangled.sh/core/jetstream" 31 - "tangled.sh/tangled.sh/core/knotclient" 32 tlog "tangled.sh/tangled.sh/core/log" 33 "tangled.sh/tangled.sh/core/rbac" 34 "tangled.sh/tangled.sh/core/tid" 35 ) 36 37 type State struct { ··· 327 328 existingRepo, err := db.GetRepo(s.db, user.Did, repoName) 329 if err == nil && existingRepo != nil { 330 - s.pages.Notice(w, "repo", fmt.Sprintf("A repo by this name already exists on %s", existingRepo.Knot)) 331 return 332 } 333 334 - secret, err := db.GetRegistrationKey(s.db, domain) 335 - if err != nil { 336 - s.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", domain)) 337 - return 338 - } 339 340 - client, err := knotclient.NewSignedClient(domain, secret, s.config.Core.Dev) 341 if err != nil { 342 s.pages.Notice(w, "repo", "Failed to connect to knot server.") 343 return ··· 392 } 393 }() 394 395 - resp, err := client.NewRepo(user.Did, repoName, defaultBranch) 396 if err != nil { 397 - s.pages.Notice(w, "repo", "Failed to create repository on knot server.") 398 - return 399 - } 400 401 - switch resp.StatusCode { 402 - case http.StatusConflict: 403 - s.pages.Notice(w, "repo", "A repository with that name already exists.") 404 return 405 - case http.StatusInternalServerError: 406 - s.pages.Notice(w, "repo", "Failed to create repository on knot. Try again later.") 407 - case http.StatusNoContent: 408 - // continue 409 } 410 411 err = db.AddRepo(tx, repo)
··· 28 "tangled.sh/tangled.sh/core/eventconsumer" 29 "tangled.sh/tangled.sh/core/idresolver" 30 "tangled.sh/tangled.sh/core/jetstream" 31 tlog "tangled.sh/tangled.sh/core/log" 32 "tangled.sh/tangled.sh/core/rbac" 33 "tangled.sh/tangled.sh/core/tid" 34 + // xrpcerr "tangled.sh/tangled.sh/core/xrpc/errors" 35 ) 36 37 type State struct { ··· 327 328 existingRepo, err := db.GetRepo(s.db, user.Did, repoName) 329 if err == nil && existingRepo != nil { 330 + l.Info("repo exists") 331 + s.pages.Notice(w, "repo", fmt.Sprintf("You already have a repository by this name on %s", existingRepo.Knot)) 332 return 333 } 334 335 + client, err := s.oauth.ServiceClient( 336 + r, 337 + oauth.WithService(domain), 338 + oauth.WithLxm(tangled.RepoCreateNSID), 339 + oauth.WithDev(s.config.Core.Dev), 340 + ) 341 342 if err != nil { 343 s.pages.Notice(w, "repo", "Failed to connect to knot server.") 344 return ··· 393 } 394 }() 395 396 + xe := tangled.RepoCreate( 397 + r.Context(), 398 + client, 399 + &tangled.RepoCreate_Input{ 400 + Rkey: rkey, 401 + }, 402 + ) 403 if err != nil { 404 + xe, err := xrpcerr.Unmarshal(err.Error()) 405 + if err != nil { 406 + log.Println(err) 407 + s.pages.Notice(w, "repo", "Failed to create repository on knot server.") 408 + return 409 + } 410 411 + log.Println(xe.Error()) 412 + s.pages.Notice(w, "repo", fmt.Sprintf("Failed to create repository on knot server: %s.", xe.Message)) 413 return 414 } 415 416 err = db.AddRepo(tx, repo)