+135
-87
appview/pulls/pulls.go
+135
-87
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"
···
25
23
"tangled.sh/tangled.sh/core/patchutil"
26
24
"tangled.sh/tangled.sh/core/tid"
27
25
"tangled.sh/tangled.sh/core/types"
26
+
xrpcerr "tangled.sh/tangled.sh/core/xrpc/errors"
28
27
29
28
"github.com/bluekeyes/go-gitdiff/gitdiff"
30
29
comatproto "github.com/bluesky-social/indigo/api/atproto"
···
96
95
return
97
96
}
98
97
99
-
mergeCheckResponse := s.mergeCheck(f, pull, stack)
98
+
mergeCheckResponse := s.mergeCheck(r, f, pull, stack)
100
99
resubmitResult := pages.Unknown
101
100
if user.Did == pull.OwnerDid {
102
101
resubmitResult = s.resubmitCheck(f, pull, stack)
···
161
160
}
162
161
}
163
162
164
-
mergeCheckResponse := s.mergeCheck(f, pull, stack)
163
+
mergeCheckResponse := s.mergeCheck(r, f, pull, stack)
165
164
resubmitResult := pages.Unknown
166
165
if user != nil && user.Did == pull.OwnerDid {
167
166
resubmitResult = s.resubmitCheck(f, pull, stack)
···
226
225
})
227
226
}
228
227
229
-
func (s *Pulls) mergeCheck(f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) types.MergeCheckResponse {
228
+
func (s *Pulls) mergeCheck(r *http.Request, f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) types.MergeCheckResponse {
230
229
if pull.State == db.PullMerged {
231
230
return types.MergeCheckResponse{}
232
231
}
233
232
234
-
secret, err := db.GetRegistrationKey(s.db, f.Knot)
233
+
client, err := s.oauth.ServiceClient(
234
+
r,
235
+
oauth.WithService(f.Knot),
236
+
oauth.WithLxm(tangled.RepoMergeCheckNSID),
237
+
oauth.WithDev(s.config.Core.Dev),
238
+
)
235
239
if err != nil {
236
-
log.Printf("failed to get registration key: %v", err)
240
+
log.Printf("failed to connect to knot server: %v", err)
237
241
return types.MergeCheckResponse{
238
-
Error: "failed to check merge status: this knot is unregistered",
239
-
}
240
-
}
241
-
242
-
ksClient, err := knotclient.NewSignedClient(f.Knot, secret, s.config.Core.Dev)
243
-
if err != nil {
244
-
log.Printf("failed to setup signed client for %s; ignoring: %v", f.Knot, err)
245
-
return types.MergeCheckResponse{
246
-
Error: "failed to check merge status",
242
+
Error: "failed to check merge status: could not connect to knot server",
247
243
}
248
244
}
249
245
···
257
253
patch = mergeable.CombinedPatch()
258
254
}
259
255
260
-
resp, err := ksClient.MergeCheck([]byte(patch), f.OwnerDid(), f.RepoName, pull.TargetBranch)
256
+
resp, err := tangled.RepoMergeCheck(
257
+
r.Context(),
258
+
client,
259
+
&tangled.RepoMergeCheck_Input{
260
+
Did: f.OwnerDid(),
261
+
Name: f.RepoName,
262
+
Branch: pull.TargetBranch,
263
+
Patch: patch,
264
+
},
265
+
)
261
266
if err != nil {
262
-
log.Println("failed to check for mergeability:", err)
263
-
return types.MergeCheckResponse{
264
-
Error: "failed to check merge status",
265
-
}
266
-
}
267
-
switch resp.StatusCode {
268
-
case 404:
269
-
return types.MergeCheckResponse{
270
-
Error: "failed to check merge status: this knot does not support PRs",
267
+
xe, parseErr := xrpcerr.Unmarshal(err.Error())
268
+
if parseErr != nil {
269
+
log.Printf("failed to check for mergeability: %v", err)
270
+
return types.MergeCheckResponse{
271
+
Error: "failed to check merge status",
272
+
}
271
273
}
272
-
case 400:
274
+
log.Printf("failed to check for mergeability: %s", xe.Error())
273
275
return types.MergeCheckResponse{
274
-
Error: "failed to check merge status: does this knot support PRs?",
276
+
Error: fmt.Sprintf("failed to check merge status: %s", xe.Message),
275
277
}
276
278
}
277
279
278
-
respBody, err := io.ReadAll(resp.Body)
279
-
if err != nil {
280
-
log.Println("failed to read merge check response body")
281
-
return types.MergeCheckResponse{
282
-
Error: "failed to check merge status: knot is not speaking the right language",
280
+
// convert xrpc response to internal types
281
+
conflicts := make([]types.ConflictInfo, len(resp.Conflicts))
282
+
for i, conflict := range resp.Conflicts {
283
+
conflicts[i] = types.ConflictInfo{
284
+
Filename: conflict.Filename,
285
+
Reason: conflict.Reason,
283
286
}
284
287
}
285
-
defer resp.Body.Close()
286
288
287
-
var mergeCheckResponse types.MergeCheckResponse
288
-
err = json.Unmarshal(respBody, &mergeCheckResponse)
289
-
if err != nil {
290
-
log.Println("failed to unmarshal merge check response", err)
291
-
return types.MergeCheckResponse{
292
-
Error: "failed to check merge status: knot is not speaking the right language",
293
-
}
289
+
result := types.MergeCheckResponse{
290
+
IsConflicted: resp.Is_conflicted,
291
+
Conflicts: conflicts,
294
292
}
295
293
296
-
return mergeCheckResponse
294
+
if resp.Message != nil {
295
+
result.Message = *resp.Message
296
+
}
297
+
298
+
if resp.Error != nil {
299
+
result.Error = *resp.Error
300
+
}
301
+
302
+
return result
297
303
}
298
304
299
305
func (s *Pulls) resubmitCheck(f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) pages.ResubmitResult {
···
923
929
return
924
930
}
925
931
926
-
secret, err := db.GetRegistrationKey(s.db, fork.Knot)
932
+
client, err := s.oauth.ServiceClient(
933
+
r,
934
+
oauth.WithService(fork.Knot),
935
+
oauth.WithLxm(tangled.RepoHiddenRefNSID),
936
+
oauth.WithDev(s.config.Core.Dev),
937
+
)
927
938
if err != nil {
928
-
log.Println("failed to fetch registration key:", err)
929
-
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
930
-
return
931
-
}
932
-
933
-
sc, err := knotclient.NewSignedClient(fork.Knot, secret, s.config.Core.Dev)
934
-
if err != nil {
935
-
log.Println("failed to create signed client:", err)
939
+
log.Printf("failed to connect to knot server: %v", err)
936
940
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
937
941
return
938
942
}
···
944
948
return
945
949
}
946
950
947
-
resp, err := sc.NewHiddenRef(user.Did, fork.Name, sourceBranch, targetBranch)
951
+
resp, err := tangled.RepoHiddenRef(
952
+
r.Context(),
953
+
client,
954
+
&tangled.RepoHiddenRef_Input{
955
+
ForkRef: sourceBranch,
956
+
RemoteRef: targetBranch,
957
+
Repo: fork.AtUri,
958
+
},
959
+
)
948
960
if err != nil {
949
-
log.Println("failed to create hidden ref:", err, resp.StatusCode)
950
-
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
961
+
xe, parseErr := xrpcerr.Unmarshal(err.Error())
962
+
if parseErr != nil {
963
+
log.Printf("failed to create hidden ref: %v", err)
964
+
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
965
+
} else {
966
+
log.Printf("failed to create hidden ref: %s", xe.Error())
967
+
if xe.Tag == "AccessControl" {
968
+
s.pages.Notice(w, "pull", "Branch based pull requests are not supported on this knot.")
969
+
} else {
970
+
s.pages.Notice(w, "pull", fmt.Sprintf("Failed to create pull request: %s", xe.Message))
971
+
}
972
+
}
951
973
return
952
974
}
953
975
954
-
switch resp.StatusCode {
955
-
case 404:
956
-
case 400:
957
-
s.pages.Notice(w, "pull", "Branch based pull requests are not supported on this knot.")
976
+
if !resp.Success {
977
+
errorMsg := "Failed to create pull request"
978
+
if resp.Error != nil {
979
+
errorMsg = fmt.Sprintf("Failed to create pull request: %s", *resp.Error)
980
+
}
981
+
s.pages.Notice(w, "pull", errorMsg)
958
982
return
959
983
}
960
984
···
1524
1548
return
1525
1549
}
1526
1550
1527
-
secret, err := db.GetRegistrationKey(s.db, forkRepo.Knot)
1528
-
if err != nil {
1529
-
log.Printf("failed to get registration key for %s: %s", forkRepo.Knot, err)
1530
-
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1531
-
return
1532
-
}
1533
-
1534
1551
// update the hidden tracking branch to latest
1535
-
signedClient, err := knotclient.NewSignedClient(forkRepo.Knot, secret, s.config.Core.Dev)
1552
+
client, err := s.oauth.ServiceClient(
1553
+
r,
1554
+
oauth.WithService(forkRepo.Knot),
1555
+
oauth.WithLxm(tangled.RepoHiddenRefNSID),
1556
+
oauth.WithDev(s.config.Core.Dev),
1557
+
)
1536
1558
if err != nil {
1537
-
log.Printf("failed to create signed client for %s: %s", forkRepo.Knot, err)
1538
-
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1559
+
log.Printf("failed to connect to knot server: %v", err)
1539
1560
return
1540
1561
}
1541
1562
1542
-
resp, err := signedClient.NewHiddenRef(forkRepo.Did, forkRepo.Name, pull.PullSource.Branch, pull.TargetBranch)
1543
-
if err != nil || resp.StatusCode != http.StatusNoContent {
1544
-
log.Printf("failed to update tracking branch: %s", err)
1563
+
resp, err := tangled.RepoHiddenRef(
1564
+
r.Context(),
1565
+
client,
1566
+
&tangled.RepoHiddenRef_Input{
1567
+
ForkRef: pull.PullSource.Branch,
1568
+
RemoteRef: pull.TargetBranch,
1569
+
Repo: forkRepo.AtUri,
1570
+
},
1571
+
)
1572
+
if err != nil || !resp.Success {
1573
+
if err != nil {
1574
+
log.Printf("failed to update tracking branch: %s", err)
1575
+
} else {
1576
+
log.Printf("failed to update tracking branch: success=false")
1577
+
}
1545
1578
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1546
1579
return
1547
1580
}
···
1958
1991
1959
1992
patch := pullsToMerge.CombinedPatch()
1960
1993
1961
-
secret, err := db.GetRegistrationKey(s.db, f.Knot)
1994
+
client, err := s.oauth.ServiceClient(
1995
+
r,
1996
+
oauth.WithService(f.Knot),
1997
+
oauth.WithLxm(tangled.RepoMergeNSID),
1998
+
oauth.WithDev(s.config.Core.Dev),
1999
+
)
1962
2000
if err != nil {
1963
-
log.Printf("no registration key found for domain %s: %s\n", f.Knot, err)
2001
+
log.Printf("failed to connect to knot server: %v", err)
1964
2002
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1965
2003
return
1966
2004
}
···
1977
2015
log.Printf("failed to get primary email: %s", err)
1978
2016
}
1979
2017
1980
-
ksClient, err := knotclient.NewSignedClient(f.Knot, secret, s.config.Core.Dev)
1981
-
if err != nil {
1982
-
log.Printf("failed to create signed client for %s: %s", f.Knot, err)
1983
-
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1984
-
return
2018
+
authorName := ident.Handle.String()
2019
+
mergeInput := &tangled.RepoMerge_Input{
2020
+
Did: f.OwnerDid(),
2021
+
Name: f.RepoName,
2022
+
Branch: pull.TargetBranch,
2023
+
Patch: patch,
2024
+
CommitMessage: &pull.Title,
2025
+
AuthorName: &authorName,
2026
+
}
2027
+
2028
+
if pull.Body != "" {
2029
+
mergeInput.CommitBody = &pull.Body
1985
2030
}
1986
2031
1987
-
// Merge the pull request
1988
-
resp, err := ksClient.Merge([]byte(patch), f.OwnerDid(), f.RepoName, pull.TargetBranch, pull.Title, pull.Body, ident.Handle.String(), email.Address)
1989
-
if err != nil {
1990
-
log.Printf("failed to merge pull request: %s", err)
1991
-
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1992
-
return
2032
+
if email.Address != "" {
2033
+
mergeInput.AuthorEmail = &email.Address
1993
2034
}
1994
2035
1995
-
if resp.StatusCode != http.StatusOK {
1996
-
log.Printf("knotserver returned non-OK status code for merge: %d", resp.StatusCode)
1997
-
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
2036
+
err = tangled.RepoMerge(r.Context(), client, mergeInput)
2037
+
if err != nil {
2038
+
xe, parseErr := xrpcerr.Unmarshal(err.Error())
2039
+
if parseErr != nil {
2040
+
log.Printf("failed to merge pull request: %v", err)
2041
+
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
2042
+
} else {
2043
+
log.Printf("failed to merge pull request: %s", xe.Error())
2044
+
s.pages.Notice(w, "pull-merge-error", fmt.Sprintf("Failed to merge pull request: %s", xe.Message))
2045
+
}
1998
2046
return
1999
2047
}
2000
2048
+29
-4
appview/repo/index.go
+29
-4
appview/repo/index.go
···
9
9
"sort"
10
10
"strings"
11
11
12
+
"tangled.sh/tangled.sh/core/api/tangled"
12
13
"tangled.sh/tangled.sh/core/appview/commitverify"
13
14
"tangled.sh/tangled.sh/core/appview/db"
14
15
"tangled.sh/tangled.sh/core/appview/oauth"
···
118
119
119
120
var forkInfo *types.ForkInfo
120
121
if user != nil && (repoInfo.Roles.IsOwner() || repoInfo.Roles.IsCollaborator()) {
121
-
forkInfo, err = getForkInfo(repoInfo, rp, f, user, signedClient)
122
+
forkInfo, err = getForkInfo(r, repoInfo, rp, f, user, signedClient)
122
123
if err != nil {
123
124
log.Printf("Failed to fetch fork information: %v", err)
124
125
return
···
231
232
}
232
233
233
234
func getForkInfo(
235
+
r *http.Request,
234
236
repoInfo repoinfo.RepoInfo,
235
237
rp *Repo,
236
238
f *reporesolver.ResolvedRepo,
···
270
272
return &forkInfo, nil
271
273
}
272
274
273
-
newHiddenRefResp, err := signedClient.NewHiddenRef(user.Did, repoInfo.Name, f.Ref, f.Ref)
274
-
if err != nil || newHiddenRefResp.StatusCode != http.StatusNoContent {
275
-
log.Printf("failed to update tracking branch: %s", err)
275
+
client, err := rp.oauth.ServiceClient(
276
+
r,
277
+
oauth.WithService(f.Knot),
278
+
oauth.WithLxm(tangled.RepoHiddenRefNSID),
279
+
oauth.WithDev(rp.config.Core.Dev),
280
+
)
281
+
if err != nil {
282
+
log.Printf("failed to connect to knot server: %v", err)
276
283
return nil, err
284
+
}
285
+
286
+
resp, err := tangled.RepoHiddenRef(
287
+
r.Context(),
288
+
client,
289
+
&tangled.RepoHiddenRef_Input{
290
+
ForkRef: f.Ref,
291
+
RemoteRef: f.Ref,
292
+
Repo: string(f.RepoAt),
293
+
},
294
+
)
295
+
if err != nil || !resp.Success {
296
+
if err != nil {
297
+
log.Printf("failed to update tracking branch: %s", err)
298
+
} else {
299
+
log.Printf("failed to update tracking branch: success=false")
300
+
}
301
+
return nil, fmt.Errorf("failed to update tracking branch")
277
302
}
278
303
279
304
hiddenRef := fmt.Sprintf("hidden/%s/%s", f.Ref, f.Ref)
+105
-66
appview/repo/repo.go
+105
-66
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
+
xrpcerr "tangled.sh/tangled.sh/core/xrpc/errors"
39
+
"tangled.sh/tangled.sh/core/xrpc/serviceauth"
36
40
37
41
securejoin "github.com/cyphar/filepath-securejoin"
38
42
"github.com/go-chi/chi/v5"
39
43
"github.com/go-git/go-git/v5/plumbing"
40
44
41
-
comatproto "github.com/bluesky-social/indigo/api/atproto"
42
45
"github.com/bluesky-social/indigo/atproto/syntax"
43
-
lexutil "github.com/bluesky-social/indigo/lex/util"
44
46
)
45
47
46
48
type Repo struct {
···
54
56
enforcer *rbac.Enforcer
55
57
notifier notify.Notifier
56
58
logger *slog.Logger
59
+
serviceAuth *serviceauth.ServiceAuth
57
60
}
58
61
59
62
func New(
···
915
918
}
916
919
log.Println("removed repo record ", f.RepoAt.String())
917
920
918
-
secret, err := db.GetRegistrationKey(rp.db, f.Knot)
921
+
client, err := rp.oauth.ServiceClient(
922
+
r,
923
+
oauth.WithService(f.Knot),
924
+
oauth.WithLxm(tangled.RepoDeleteNSID),
925
+
oauth.WithDev(rp.config.Core.Dev),
926
+
)
919
927
if err != nil {
920
-
log.Printf("no key found for domain %s: %s\n", f.Knot, err)
928
+
log.Println("failed to connect to knot server:", err)
921
929
return
922
930
}
923
931
924
-
ksClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev)
932
+
err = tangled.RepoDelete(
933
+
r.Context(),
934
+
client,
935
+
&tangled.RepoDelete_Input{
936
+
Did: f.OwnerDid(),
937
+
Name: f.RepoName,
938
+
},
939
+
)
925
940
if err != nil {
926
-
log.Println("failed to create client to ", f.Knot)
927
-
return
928
-
}
929
-
930
-
ksResp, err := ksClient.RemoveRepo(f.OwnerDid(), f.RepoName)
931
-
if err != nil {
932
-
log.Printf("failed to make request to %s: %s", f.Knot, err)
933
-
return
934
-
}
935
-
936
-
if ksResp.StatusCode != http.StatusNoContent {
937
-
log.Println("failed to remove repo from knot, continuing anyway ", f.Knot)
941
+
xe, parseErr := xrpcerr.Unmarshal(err.Error())
942
+
if parseErr != nil {
943
+
log.Printf("failed to delete repo from knot %s: %s", f.Knot, err)
944
+
} else {
945
+
log.Printf("failed to delete repo from knot %s: %s", f.Knot, xe.Error())
946
+
}
947
+
// Continue anyway since we want to clean up local state
938
948
} else {
939
949
log.Println("removed repo from knot ", f.Knot)
940
950
}
···
1010
1020
return
1011
1021
}
1012
1022
1013
-
secret, err := db.GetRegistrationKey(rp.db, f.Knot)
1023
+
client, err := rp.oauth.ServiceClient(
1024
+
r,
1025
+
oauth.WithService(f.Knot),
1026
+
oauth.WithLxm(tangled.RepoSetDefaultBranchNSID),
1027
+
oauth.WithDev(rp.config.Core.Dev),
1028
+
)
1014
1029
if err != nil {
1015
-
log.Printf("no key found for domain %s: %s\n", f.Knot, err)
1030
+
log.Println("failed to connect to knot server:", err)
1031
+
rp.pages.Notice(w, "repo-settings", "Failed to connect to knot server.")
1016
1032
return
1017
1033
}
1018
1034
1019
-
ksClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev)
1035
+
err = tangled.RepoSetDefaultBranch(
1036
+
r.Context(),
1037
+
client,
1038
+
&tangled.RepoSetDefaultBranch_Input{
1039
+
Repo: fmt.Sprintf("%s/%s", f.OwnerDid(), f.RepoName),
1040
+
DefaultBranch: branch,
1041
+
},
1042
+
)
1020
1043
if err != nil {
1021
-
log.Println("failed to create client to ", f.Knot)
1022
-
return
1023
-
}
1024
-
1025
-
ksResp, err := ksClient.SetDefaultBranch(f.OwnerDid(), f.RepoName, branch)
1026
-
if err != nil {
1027
-
log.Printf("failed to make request to %s: %s", f.Knot, err)
1028
-
return
1029
-
}
1030
-
1031
-
if ksResp.StatusCode != http.StatusNoContent {
1032
-
rp.pages.Notice(w, "repo-settings", "Failed to set default branch. Try again later.")
1044
+
xe, parseErr := xrpcerr.Unmarshal(err.Error())
1045
+
if parseErr != nil {
1046
+
log.Printf("failed to set default branch: %s", err)
1047
+
rp.pages.Notice(w, "repo-settings", "Failed to set default branch. Try again later.")
1048
+
} else {
1049
+
log.Printf("failed to set default branch: %s", xe.Error())
1050
+
rp.pages.Notice(w, "repo-settings", fmt.Sprintf("Failed to set default branch: %s", xe.Message))
1051
+
}
1033
1052
return
1034
1053
}
1035
1054
···
1323
1342
1324
1343
switch r.Method {
1325
1344
case http.MethodPost:
1326
-
secret, err := db.GetRegistrationKey(rp.db, f.Knot)
1345
+
client, err := rp.oauth.ServiceClient(
1346
+
r,
1347
+
oauth.WithService(f.Knot),
1348
+
oauth.WithLxm(tangled.RepoForkSyncNSID),
1349
+
oauth.WithDev(rp.config.Core.Dev),
1350
+
)
1327
1351
if err != nil {
1328
-
rp.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", f.Knot))
1352
+
rp.pages.Notice(w, "repo", "Failed to connect to knot server.")
1329
1353
return
1330
1354
}
1331
1355
1332
-
client, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev)
1333
-
if err != nil {
1334
-
rp.pages.Notice(w, "repo", "Failed to reach knot server.")
1356
+
repoInfo := f.RepoInfo(user)
1357
+
if repoInfo.Source == nil {
1358
+
rp.pages.Notice(w, "repo", "This repository is not a fork.")
1335
1359
return
1336
1360
}
1337
1361
1338
-
var uri string
1339
-
if rp.config.Core.Dev {
1340
-
uri = "http"
1341
-
} else {
1342
-
uri = "https"
1343
-
}
1344
-
forkName := fmt.Sprintf("%s", f.RepoName)
1345
-
forkSourceUrl := fmt.Sprintf("%s://%s/%s/%s", uri, f.Knot, f.OwnerDid(), f.RepoName)
1346
-
1347
-
_, err = client.SyncRepoFork(user.Did, forkSourceUrl, forkName, f.Ref)
1362
+
err = tangled.RepoForkSync(
1363
+
r.Context(),
1364
+
client,
1365
+
&tangled.RepoForkSync_Input{
1366
+
Did: user.Did,
1367
+
Name: f.RepoName,
1368
+
Source: repoInfo.Source.AtUri,
1369
+
Branch: f.Ref,
1370
+
},
1371
+
)
1348
1372
if err != nil {
1349
-
rp.pages.Notice(w, "repo", "Failed to sync repository fork.")
1373
+
xe, parseErr := xrpcerr.Unmarshal(err.Error())
1374
+
if parseErr != nil {
1375
+
log.Printf("failed to sync repository fork: %s", err)
1376
+
rp.pages.Notice(w, "repo", "Failed to sync repository fork.")
1377
+
} else {
1378
+
log.Printf("failed to sync repository fork: %s", xe.Error())
1379
+
rp.pages.Notice(w, "repo", fmt.Sprintf("Failed to sync repository fork: %s", xe.Message))
1380
+
}
1350
1381
return
1351
1382
}
1352
1383
···
1409
1440
// repo with this name already exists, append random string
1410
1441
forkName = fmt.Sprintf("%s-%s", forkName, randomString(3))
1411
1442
}
1412
-
secret, err := db.GetRegistrationKey(rp.db, knot)
1413
-
if err != nil {
1414
-
rp.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", knot))
1415
-
return
1416
-
}
1443
+
client, err := rp.oauth.ServiceClient(
1444
+
r,
1445
+
oauth.WithService(knot),
1446
+
oauth.WithLxm(tangled.RepoForkNSID),
1447
+
oauth.WithDev(rp.config.Core.Dev),
1448
+
)
1417
1449
1418
-
client, err := knotclient.NewSignedClient(knot, secret, rp.config.Core.Dev)
1419
1450
if err != nil {
1420
-
rp.pages.Notice(w, "repo", "Failed to reach knot server.")
1451
+
log.Printf("error creating client for knot server: %v", err)
1452
+
rp.pages.Notice(w, "repo", "Failed to connect to knot server.")
1421
1453
return
1422
1454
}
1423
1455
···
1453
1485
}
1454
1486
}()
1455
1487
1456
-
resp, err := client.ForkRepo(user.Did, forkSourceUrl, forkName)
1488
+
err = tangled.RepoFork(
1489
+
r.Context(),
1490
+
client,
1491
+
&tangled.RepoFork_Input{
1492
+
Did: user.Did,
1493
+
Name: &forkName,
1494
+
Source: forkSourceUrl,
1495
+
},
1496
+
)
1497
+
1457
1498
if err != nil {
1458
-
rp.pages.Notice(w, "repo", "Failed to create repository on knot server.")
1459
-
return
1460
-
}
1499
+
xe, err := xrpcerr.Unmarshal(err.Error())
1500
+
if err != nil {
1501
+
log.Println(err)
1502
+
rp.pages.Notice(w, "repo", "Failed to create repository on knot server.")
1503
+
return
1504
+
}
1461
1505
1462
-
switch resp.StatusCode {
1463
-
case http.StatusConflict:
1464
-
rp.pages.Notice(w, "repo", "A repository with that name already exists.")
1506
+
log.Println(xe.Error())
1507
+
rp.pages.Notice(w, "repo", fmt.Sprintf("Failed to create repository on knot server: %s.", xe.Message))
1465
1508
return
1466
-
case http.StatusInternalServerError:
1467
-
rp.pages.Notice(w, "repo", "Failed to create repository on knot. Try again later.")
1468
-
case http.StatusNoContent:
1469
-
// continue
1470
1509
}
1471
1510
1472
1511
xrpcClient, err := rp.oauth.AuthorizedClient(r)
+26
-19
appview/state/state.go
+26
-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 {
···
329
329
330
330
existingRepo, err := db.GetRepo(s.db, user.Did, repoName)
331
331
if err == nil && existingRepo != nil {
332
-
s.pages.Notice(w, "repo", fmt.Sprintf("A repo by this name already exists on %s", existingRepo.Knot))
332
+
s.pages.Notice(w, "repo", fmt.Sprintf("You already have a repository by this name on %s", existingRepo.Knot))
333
333
return
334
334
}
335
335
336
-
secret, err := db.GetRegistrationKey(s.db, domain)
337
-
if err != nil {
338
-
s.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", domain))
339
-
return
340
-
}
336
+
client, err := s.oauth.ServiceClient(
337
+
r,
338
+
oauth.WithService(domain),
339
+
oauth.WithLxm(tangled.RepoCreateNSID),
340
+
oauth.WithDev(s.config.Core.Dev),
341
+
)
341
342
342
-
client, err := knotclient.NewSignedClient(domain, secret, s.config.Core.Dev)
343
343
if err != nil {
344
344
s.pages.Notice(w, "repo", "Failed to connect to knot server.")
345
345
return
···
394
394
}
395
395
}()
396
396
397
-
resp, err := client.NewRepo(user.Did, repoName, defaultBranch)
397
+
err = tangled.RepoCreate(
398
+
r.Context(),
399
+
client,
400
+
&tangled.RepoCreate_Input{
401
+
Default_branch: &defaultBranch,
402
+
Did: user.Did,
403
+
Name: repoName,
404
+
},
405
+
)
406
+
398
407
if err != nil {
399
-
s.pages.Notice(w, "repo", "Failed to create repository on knot server.")
400
-
return
401
-
}
408
+
xe, err := xrpcerr.Unmarshal(err.Error())
409
+
if err != nil {
410
+
log.Println(err)
411
+
s.pages.Notice(w, "repo", "Failed to create repository on knot server.")
412
+
return
413
+
}
402
414
403
-
switch resp.StatusCode {
404
-
case http.StatusConflict:
405
-
s.pages.Notice(w, "repo", "A repository with that name already exists.")
415
+
log.Println(xe.Error())
416
+
s.pages.Notice(w, "repo", fmt.Sprintf("Failed to create repository on knot server: %s.", xe.Message))
406
417
return
407
-
case http.StatusInternalServerError:
408
-
s.pages.Notice(w, "repo", "Failed to create repository on knot. Try again later.")
409
-
case http.StatusNoContent:
410
-
// continue
411
418
}
412
419
413
420
repo.AtUri = atresp.Uri