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 2 3 3 import ( 4 4 "database/sql" 5 - "encoding/json" 6 5 "errors" 7 6 "fmt" 8 - "io" 9 7 "log" 10 8 "net/http" 11 9 "sort" ··· 96 94 return 97 95 } 98 96 99 - mergeCheckResponse := s.mergeCheck(f, pull, stack) 97 + mergeCheckResponse := s.mergeCheck(r, f, pull, stack) 100 98 resubmitResult := pages.Unknown 101 99 if user.Did == pull.OwnerDid { 102 100 resubmitResult = s.resubmitCheck(f, pull, stack) ··· 151 149 } 152 150 } 153 151 154 - mergeCheckResponse := s.mergeCheck(f, pull, stack) 152 + mergeCheckResponse := s.mergeCheck(r, f, pull, stack) 155 153 resubmitResult := pages.Unknown 156 154 if user != nil && user.Did == pull.OwnerDid { 157 155 resubmitResult = s.resubmitCheck(f, pull, stack) ··· 215 213 }) 216 214 } 217 215 218 - func (s *Pulls) mergeCheck(f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) types.MergeCheckResponse { 216 + func (s *Pulls) mergeCheck(r *http.Request, f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) types.MergeCheckResponse { 219 217 if pull.State == db.PullMerged { 220 218 return types.MergeCheckResponse{} 221 219 } 222 220 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) 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 + ) 232 227 if err != nil { 233 - log.Printf("failed to setup signed client for %s; ignoring: %v", f.Knot, err) 228 + log.Printf("failed to connect to knot server: %v", err) 234 229 return types.MergeCheckResponse{ 235 - Error: "failed to check merge status", 230 + Error: "failed to check merge status: could not connect to knot server", 236 231 } 237 232 } 238 233 ··· 246 241 patch = mergeable.CombinedPatch() 247 242 } 248 243 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) 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) 252 256 return types.MergeCheckResponse{ 253 - Error: "failed to check merge status", 257 + Error: fmt.Sprintf("failed to check merge status: %s", err.Error()), 254 258 } 255 259 } 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?", 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, 264 267 } 265 268 } 266 269 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 - } 270 + result := types.MergeCheckResponse{ 271 + IsConflicted: resp.Is_conflicted, 272 + Conflicts: conflicts, 273 + } 274 + 275 + if resp.Message != nil { 276 + result.Message = *resp.Message 273 277 } 274 - defer resp.Body.Close() 275 278 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 - } 279 + if resp.Error != nil { 280 + result.Error = *resp.Error 283 281 } 284 282 285 - return mergeCheckResponse 283 + return result 286 284 } 287 285 288 286 func (s *Pulls) resubmitCheck(f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) pages.ResubmitResult { ··· 867 865 return 868 866 } 869 867 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) 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 + ) 878 874 if err != nil { 879 - log.Println("failed to create signed client:", err) 875 + log.Printf("failed to connect to knot server: %v", err) 880 876 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 881 877 return 882 878 } ··· 888 884 return 889 885 } 890 886 891 - resp, err := sc.NewHiddenRef(user.Did, fork.Name, sourceBranch, targetBranch) 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 + ) 892 896 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.") 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 + } 895 909 return 896 910 } 897 911 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.") 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) 902 918 return 903 919 } 904 920 ··· 1464 1480 return 1465 1481 } 1466 1482 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 1483 // update the hidden tracking branch to latest 1475 - signedClient, err := knotclient.NewSignedClient(forkRepo.Knot, secret, s.config.Core.Dev) 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 + ) 1476 1490 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.") 1491 + log.Printf("failed to connect to knot server: %v", err) 1479 1492 return 1480 1493 } 1481 1494 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) 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 + } 1485 1510 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") 1486 1511 return 1487 1512 } ··· 1908 1933 1909 1934 patch := pullsToMerge.CombinedPatch() 1910 1935 1911 - secret, err := db.GetRegistrationKey(s.db, f.Knot) 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 + ) 1912 1942 if err != nil { 1913 - log.Printf("no registration key found for domain %s: %s\n", f.Knot, err) 1943 + log.Printf("failed to connect to knot server: %v", err) 1914 1944 s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") 1915 1945 return 1916 1946 } ··· 1927 1957 log.Printf("failed to get primary email: %s", err) 1928 1958 } 1929 1959 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 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, 1935 1968 } 1936 1969 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) 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 + ) 1939 1984 if err != nil { 1940 - log.Printf("failed to merge pull request: %s", err) 1985 + log.Printf("failed to connect to knot server: %v", err) 1941 1986 s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") 1942 1987 return 1943 1988 } 1944 1989 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.") 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()) 1948 1993 return 1949 1994 } 1950 1995
+28 -4
appview/repo/index.go
··· 119 119 120 120 var forkInfo *types.ForkInfo 121 121 if user != nil && (repoInfo.Roles.IsOwner() || repoInfo.Roles.IsCollaborator()) { 122 - forkInfo, err = getForkInfo(repoInfo, rp, f, result.Ref, user, signedClient) 122 + forkInfo, err = getForkInfo(r, repoInfo, rp, f, result.Ref, user, signedClient) 123 123 if err != nil { 124 124 log.Printf("Failed to fetch fork information: %v", err) 125 125 return ··· 233 233 } 234 234 235 235 func getForkInfo( 236 + r *http.Request, 236 237 repoInfo repoinfo.RepoInfo, 237 238 rp *Repo, 238 239 f *reporesolver.ResolvedRepo, ··· 273 274 return &forkInfo, nil 274 275 } 275 276 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) 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) 279 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") 280 304 } 281 305 282 306 hiddenRef := fmt.Sprintf("hidden/%s/%s", currentRef, currentRef)
+99 -67
appview/repo/repo.go
··· 17 17 "strings" 18 18 "time" 19 19 20 + comatproto "github.com/bluesky-social/indigo/api/atproto" 21 + lexutil "github.com/bluesky-social/indigo/lex/util" 20 22 "tangled.sh/tangled.sh/core/api/tangled" 21 23 "tangled.sh/tangled.sh/core/appview/commitverify" 22 24 "tangled.sh/tangled.sh/core/appview/config" ··· 33 35 "tangled.sh/tangled.sh/core/rbac" 34 36 "tangled.sh/tangled.sh/core/tid" 35 37 "tangled.sh/tangled.sh/core/types" 38 + "tangled.sh/tangled.sh/core/xrpc/serviceauth" 36 39 37 40 securejoin "github.com/cyphar/filepath-securejoin" 38 41 "github.com/go-chi/chi/v5" 39 42 "github.com/go-git/go-git/v5/plumbing" 40 43 41 - comatproto "github.com/bluesky-social/indigo/api/atproto" 42 44 "github.com/bluesky-social/indigo/atproto/syntax" 43 - lexutil "github.com/bluesky-social/indigo/lex/util" 44 45 ) 45 46 46 47 type Repo struct { ··· 54 55 enforcer *rbac.Enforcer 55 56 notifier notify.Notifier 56 57 logger *slog.Logger 58 + serviceAuth *serviceauth.ServiceAuth 57 59 } 58 60 59 61 func New( ··· 960 962 } 961 963 log.Println("removed repo record ", f.RepoAt().String()) 962 964 963 - secret, err := db.GetRegistrationKey(rp.db, f.Knot) 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 + ) 964 971 if err != nil { 965 - log.Printf("no key found for domain %s: %s\n", f.Knot, err) 972 + log.Println("failed to connect to knot server:", err) 966 973 return 967 974 } 968 975 969 - ksClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev) 976 + err = tangled.RepoDelete( 977 + r.Context(), 978 + client, 979 + &tangled.RepoDelete_Input{ 980 + Did: f.OwnerDid(), 981 + Name: f.Name, 982 + }, 983 + ) 970 984 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) 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 983 992 } else { 984 993 log.Println("removed repo from knot ", f.Knot) 985 994 } ··· 1055 1064 return 1056 1065 } 1057 1066 1058 - secret, err := db.GetRegistrationKey(rp.db, f.Knot) 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 + ) 1059 1073 if err != nil { 1060 - log.Printf("no key found for domain %s: %s\n", f.Knot, err) 1074 + log.Println("failed to connect to knot server:", err) 1075 + rp.pages.Notice(w, noticeId, "Failed to connect to knot server.") 1061 1076 return 1062 1077 } 1063 1078 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.") 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()) 1078 1090 return 1079 1091 } 1080 1092 ··· 1373 1385 1374 1386 switch r.Method { 1375 1387 case http.MethodPost: 1376 - secret, err := db.GetRegistrationKey(rp.db, f.Knot) 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 + ) 1377 1394 if err != nil { 1378 - rp.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", f.Knot)) 1395 + rp.pages.Notice(w, "repo", "Failed to connect to knot server.") 1379 1396 return 1380 1397 } 1381 1398 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.") 1399 + repoInfo := f.RepoInfo(user) 1400 + if repoInfo.Source == nil { 1401 + rp.pages.Notice(w, "repo", "This repository is not a fork.") 1385 1402 return 1386 1403 } 1387 1404 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) 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 + ) 1398 1415 if err != nil { 1399 - rp.pages.Notice(w, "repo", "Failed to sync repository fork.") 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 + } 1400 1424 return 1401 1425 } 1402 1426 ··· 1459 1483 // repo with this name already exists, append random string 1460 1484 forkName = fmt.Sprintf("%s-%s", forkName, randomString(3)) 1461 1485 } 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 - } 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 + ) 1467 1492 1468 - client, err := knotclient.NewSignedClient(knot, secret, rp.config.Core.Dev) 1469 1493 if err != nil { 1470 - rp.pages.Notice(w, "repo", "Failed to reach knot server.") 1494 + log.Printf("error creating client for knot server: %v", err) 1495 + rp.pages.Notice(w, "repo", "Failed to connect to knot server.") 1471 1496 return 1472 1497 } 1473 1498 ··· 1503 1528 } 1504 1529 }() 1505 1530 1506 - resp, err := client.ForkRepo(user.Did, forkSourceUrl, forkName) 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 + 1507 1541 if err != nil { 1508 - rp.pages.Notice(w, "repo", "Failed to create repository on knot server.") 1509 - return 1510 - } 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 + } 1511 1548 1512 - switch resp.StatusCode { 1513 - case http.StatusConflict: 1514 - rp.pages.Notice(w, "repo", "A repository with that name already exists.") 1549 + log.Println(xe.Error()) 1550 + rp.pages.Notice(w, "repo", fmt.Sprintf("Failed to create repository on knot server: %s.", xe.Message)) 1515 1551 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 1552 } 1521 1553 1522 1554 xrpcClient, err := rp.oauth.AuthorizedClient(r)
+24 -19
appview/state/state.go
··· 28 28 "tangled.sh/tangled.sh/core/eventconsumer" 29 29 "tangled.sh/tangled.sh/core/idresolver" 30 30 "tangled.sh/tangled.sh/core/jetstream" 31 - "tangled.sh/tangled.sh/core/knotclient" 32 31 tlog "tangled.sh/tangled.sh/core/log" 33 32 "tangled.sh/tangled.sh/core/rbac" 34 33 "tangled.sh/tangled.sh/core/tid" 34 + // xrpcerr "tangled.sh/tangled.sh/core/xrpc/errors" 35 35 ) 36 36 37 37 type State struct { ··· 327 327 328 328 existingRepo, err := db.GetRepo(s.db, user.Did, repoName) 329 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)) 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)) 331 332 return 332 333 } 333 334 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 - } 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 + ) 339 341 340 - client, err := knotclient.NewSignedClient(domain, secret, s.config.Core.Dev) 341 342 if err != nil { 342 343 s.pages.Notice(w, "repo", "Failed to connect to knot server.") 343 344 return ··· 392 393 } 393 394 }() 394 395 395 - resp, err := client.NewRepo(user.Did, repoName, defaultBranch) 396 + xe := tangled.RepoCreate( 397 + r.Context(), 398 + client, 399 + &tangled.RepoCreate_Input{ 400 + Rkey: rkey, 401 + }, 402 + ) 396 403 if err != nil { 397 - s.pages.Notice(w, "repo", "Failed to create repository on knot server.") 398 - return 399 - } 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 + } 400 410 401 - switch resp.StatusCode { 402 - case http.StatusConflict: 403 - s.pages.Notice(w, "repo", "A repository with that name already exists.") 411 + log.Println(xe.Error()) 412 + s.pages.Notice(w, "repo", fmt.Sprintf("Failed to create repository on knot server: %s.", xe.Message)) 404 413 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 414 } 410 415 411 416 err = db.AddRepo(tx, repo)