+230
-85
appview/pulls/pulls.go
+230
-85
appview/pulls/pulls.go
···
2
2
3
3
import (
4
4
"database/sql"
5
+
"encoding/json"
5
6
"errors"
6
7
"fmt"
7
8
"log"
···
21
22
"tangled.sh/tangled.sh/core/appview/reporesolver"
22
23
"tangled.sh/tangled.sh/core/appview/xrpcclient"
23
24
"tangled.sh/tangled.sh/core/idresolver"
24
-
"tangled.sh/tangled.sh/core/knotclient"
25
25
"tangled.sh/tangled.sh/core/patchutil"
26
26
"tangled.sh/tangled.sh/core/tid"
27
27
"tangled.sh/tangled.sh/core/types"
···
99
99
mergeCheckResponse := s.mergeCheck(r, f, pull, stack)
100
100
resubmitResult := pages.Unknown
101
101
if user.Did == pull.OwnerDid {
102
-
resubmitResult = s.resubmitCheck(f, pull, stack)
102
+
resubmitResult = s.resubmitCheck(r, f, pull, stack)
103
103
}
104
104
105
105
s.pages.PullActionsFragment(w, pages.PullActionsParams{
···
154
154
mergeCheckResponse := s.mergeCheck(r, f, pull, stack)
155
155
resubmitResult := pages.Unknown
156
156
if user != nil && user.Did == pull.OwnerDid {
157
-
resubmitResult = s.resubmitCheck(f, pull, stack)
157
+
resubmitResult = s.resubmitCheck(r, f, pull, stack)
158
158
}
159
159
160
160
repoInfo := f.RepoInfo(user)
···
282
282
return result
283
283
}
284
284
285
-
func (s *Pulls) resubmitCheck(f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) pages.ResubmitResult {
285
+
func (s *Pulls) resubmitCheck(r *http.Request, f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) pages.ResubmitResult {
286
286
if pull.State == db.PullMerged || pull.State == db.PullDeleted || pull.PullSource == nil {
287
287
return pages.Unknown
288
288
}
···
307
307
repoName = f.Name
308
308
}
309
309
310
-
us, err := knotclient.NewUnsignedClient(knot, s.config.Core.Dev)
311
-
if err != nil {
312
-
log.Printf("failed to setup client for %s; ignoring: %v", knot, err)
313
-
return pages.Unknown
310
+
scheme := "http"
311
+
if !s.config.Core.Dev {
312
+
scheme = "https"
313
+
}
314
+
host := fmt.Sprintf("%s://%s", scheme, knot)
315
+
xrpcc := &indigoxrpc.Client{
316
+
Host: host,
314
317
}
315
318
316
-
result, err := us.Branch(ownerDid, repoName, pull.PullSource.Branch)
319
+
repo := fmt.Sprintf("%s/%s", ownerDid, repoName)
320
+
branchResp, err := tangled.RepoBranch(r.Context(), xrpcc, pull.PullSource.Branch, repo)
317
321
if err != nil {
322
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
323
+
log.Println("failed to call XRPC repo.branches", xrpcerr)
324
+
return pages.Unknown
325
+
}
318
326
log.Println("failed to reach knotserver", err)
319
327
return pages.Unknown
320
328
}
321
329
330
+
targetBranch := branchResp
331
+
322
332
latestSourceRev := pull.Submissions[pull.LastRoundNumber()].SourceRev
323
333
324
334
if pull.IsStacked() && stack != nil {
···
326
336
latestSourceRev = top.Submissions[top.LastRoundNumber()].SourceRev
327
337
}
328
338
329
-
if latestSourceRev != result.Branch.Hash {
339
+
if latestSourceRev != targetBranch.Hash {
330
340
return pages.ShouldResubmit
331
341
}
332
342
···
678
688
679
689
switch r.Method {
680
690
case http.MethodGet:
681
-
us, err := knotclient.NewUnsignedClient(f.Knot, s.config.Core.Dev)
691
+
scheme := "http"
692
+
if !s.config.Core.Dev {
693
+
scheme = "https"
694
+
}
695
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
696
+
xrpcc := &indigoxrpc.Client{
697
+
Host: host,
698
+
}
699
+
700
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
701
+
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
682
702
if err != nil {
683
-
log.Printf("failed to create unsigned client for %s", f.Knot)
684
-
s.pages.Error503(w)
703
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
704
+
log.Println("failed to call XRPC repo.branches", xrpcerr)
705
+
s.pages.Error503(w)
706
+
return
707
+
}
708
+
log.Println("failed to fetch branches", err)
685
709
return
686
710
}
687
711
688
-
result, err := us.Branches(f.OwnerDid(), f.Name)
689
-
if err != nil {
690
-
log.Println("failed to fetch branches", err)
712
+
var result types.RepoBranchesResponse
713
+
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
714
+
log.Println("failed to decode XRPC response", err)
715
+
s.pages.Error503(w)
691
716
return
692
717
}
693
718
···
752
777
return
753
778
}
754
779
755
-
us, err := knotclient.NewUnsignedClient(f.Knot, s.config.Core.Dev)
756
-
if err != nil {
757
-
log.Printf("failed to create unsigned client to %s: %v", f.Knot, err)
758
-
s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.")
759
-
return
760
-
}
780
+
// us, err := knotclient.NewUnsignedClient(f.Knot, s.config.Core.Dev)
781
+
// if err != nil {
782
+
// log.Printf("failed to create unsigned client to %s: %v", f.Knot, err)
783
+
// s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.")
784
+
// return
785
+
// }
761
786
762
-
caps, err := us.Capabilities()
763
-
if err != nil {
764
-
log.Println("error fetching knot caps", f.Knot, err)
765
-
s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.")
766
-
return
787
+
// TODO: make capabilities an xrpc call
788
+
caps := struct {
789
+
PullRequests struct {
790
+
FormatPatch bool
791
+
BranchSubmissions bool
792
+
ForkSubmissions bool
793
+
PatchSubmissions bool
794
+
}
795
+
}{
796
+
PullRequests: struct {
797
+
FormatPatch bool
798
+
BranchSubmissions bool
799
+
ForkSubmissions bool
800
+
PatchSubmissions bool
801
+
}{
802
+
FormatPatch: true,
803
+
BranchSubmissions: true,
804
+
ForkSubmissions: true,
805
+
PatchSubmissions: true,
806
+
},
767
807
}
808
+
809
+
// caps, err := us.Capabilities()
810
+
// if err != nil {
811
+
// log.Println("error fetching knot caps", f.Knot, err)
812
+
// s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.")
813
+
// return
814
+
// }
768
815
769
816
if !caps.PullRequests.FormatPatch {
770
817
s.pages.Notice(w, "pull", "This knot doesn't support format-patch. Unfortunately, there is no fallback for now.")
···
806
853
sourceBranch string,
807
854
isStacked bool,
808
855
) {
809
-
// Generate a patch using /compare
810
-
ksClient, err := knotclient.NewUnsignedClient(f.Knot, s.config.Core.Dev)
811
-
if err != nil {
812
-
log.Printf("failed to create signed client for %s: %s", f.Knot, err)
813
-
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
814
-
return
856
+
scheme := "http"
857
+
if !s.config.Core.Dev {
858
+
scheme = "https"
859
+
}
860
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
861
+
xrpcc := &indigoxrpc.Client{
862
+
Host: host,
815
863
}
816
864
817
-
comparison, err := ksClient.Compare(f.OwnerDid(), f.Name, targetBranch, sourceBranch)
865
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
866
+
xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, targetBranch, sourceBranch)
818
867
if err != nil {
868
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
869
+
log.Println("failed to call XRPC repo.compare", xrpcerr)
870
+
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
871
+
return
872
+
}
819
873
log.Println("failed to compare", err)
820
874
s.pages.Notice(w, "pull", err.Error())
875
+
return
876
+
}
877
+
878
+
var comparison types.RepoFormatPatchResponse
879
+
if err := json.Unmarshal(xrpcBytes, &comparison); err != nil {
880
+
log.Println("failed to decode XRPC compare response", err)
881
+
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
821
882
return
822
883
}
823
884
···
869
930
oauth.WithLxm(tangled.RepoHiddenRefNSID),
870
931
oauth.WithDev(s.config.Core.Dev),
871
932
)
872
-
if err != nil {
873
-
log.Printf("failed to connect to knot server: %v", err)
874
-
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
875
-
return
876
-
}
877
-
878
-
us, err := knotclient.NewUnsignedClient(fork.Knot, s.config.Core.Dev)
879
-
if err != nil {
880
-
log.Println("failed to create unsigned client:", err)
881
-
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
882
-
return
883
-
}
884
933
885
934
resp, err := tangled.RepoHiddenRef(
886
935
r.Context(),
···
911
960
// hiddenRef: hidden/feature-1/main (on repo-fork)
912
961
// targetBranch: main (on repo-1)
913
962
// sourceBranch: feature-1 (on repo-fork)
914
-
comparison, err := us.Compare(fork.Did, fork.Name, hiddenRef, sourceBranch)
963
+
forkScheme := "http"
964
+
if !s.config.Core.Dev {
965
+
forkScheme = "https"
966
+
}
967
+
forkHost := fmt.Sprintf("%s://%s", forkScheme, fork.Knot)
968
+
forkXrpcc := &indigoxrpc.Client{
969
+
Host: forkHost,
970
+
}
971
+
972
+
forkRepoId := fmt.Sprintf("%s/%s", fork.Did, fork.Name)
973
+
forkXrpcBytes, err := tangled.RepoCompare(r.Context(), forkXrpcc, forkRepoId, hiddenRef, sourceBranch)
915
974
if err != nil {
975
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
976
+
log.Println("failed to call XRPC repo.compare for fork", xrpcerr)
977
+
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
978
+
return
979
+
}
916
980
log.Println("failed to compare across branches", err)
917
981
s.pages.Notice(w, "pull", err.Error())
918
982
return
919
983
}
920
984
985
+
var comparison types.RepoFormatPatchResponse
986
+
if err := json.Unmarshal(forkXrpcBytes, &comparison); err != nil {
987
+
log.Println("failed to decode XRPC compare response for fork", err)
988
+
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
989
+
return
990
+
}
991
+
921
992
sourceRev := comparison.Rev2
922
993
patch := comparison.Patch
923
994
···
1211
1282
return
1212
1283
}
1213
1284
1214
-
us, err := knotclient.NewUnsignedClient(f.Knot, s.config.Core.Dev)
1285
+
scheme := "http"
1286
+
if !s.config.Core.Dev {
1287
+
scheme = "https"
1288
+
}
1289
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
1290
+
xrpcc := &indigoxrpc.Client{
1291
+
Host: host,
1292
+
}
1293
+
1294
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
1295
+
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
1215
1296
if err != nil {
1216
-
log.Printf("failed to create unsigned client for %s", f.Knot)
1217
-
s.pages.Error503(w)
1297
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1298
+
log.Println("failed to call XRPC repo.branches", xrpcerr)
1299
+
s.pages.Error503(w)
1300
+
return
1301
+
}
1302
+
log.Println("failed to fetch branches", err)
1218
1303
return
1219
1304
}
1220
1305
1221
-
result, err := us.Branches(f.OwnerDid(), f.Name)
1222
-
if err != nil {
1223
-
log.Println("failed to reach knotserver", err)
1306
+
var result types.RepoBranchesResponse
1307
+
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
1308
+
log.Println("failed to decode XRPC response", err)
1309
+
s.pages.Error503(w)
1224
1310
return
1225
1311
}
1226
1312
···
1284
1370
return
1285
1371
}
1286
1372
1287
-
sourceBranchesClient, err := knotclient.NewUnsignedClient(repo.Knot, s.config.Core.Dev)
1373
+
sourceScheme := "http"
1374
+
if !s.config.Core.Dev {
1375
+
sourceScheme = "https"
1376
+
}
1377
+
sourceHost := fmt.Sprintf("%s://%s", sourceScheme, repo.Knot)
1378
+
sourceXrpcc := &indigoxrpc.Client{
1379
+
Host: sourceHost,
1380
+
}
1381
+
1382
+
sourceRepo := fmt.Sprintf("%s/%s", forkOwnerDid, repo.Name)
1383
+
sourceXrpcBytes, err := tangled.RepoBranches(r.Context(), sourceXrpcc, "", 0, sourceRepo)
1288
1384
if err != nil {
1289
-
log.Printf("failed to create unsigned client for %s", repo.Knot)
1290
-
s.pages.Error503(w)
1385
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1386
+
log.Println("failed to call XRPC repo.branches for source", xrpcerr)
1387
+
s.pages.Error503(w)
1388
+
return
1389
+
}
1390
+
log.Println("failed to fetch source branches", err)
1291
1391
return
1292
1392
}
1293
1393
1294
-
sourceResult, err := sourceBranchesClient.Branches(forkOwnerDid, repo.Name)
1295
-
if err != nil {
1296
-
log.Println("failed to reach knotserver for source branches", err)
1394
+
// Decode source branches
1395
+
var sourceBranches types.RepoBranchesResponse
1396
+
if err := json.Unmarshal(sourceXrpcBytes, &sourceBranches); err != nil {
1397
+
log.Println("failed to decode source branches XRPC response", err)
1398
+
s.pages.Error503(w)
1297
1399
return
1298
1400
}
1299
1401
1300
-
targetBranchesClient, err := knotclient.NewUnsignedClient(f.Knot, s.config.Core.Dev)
1402
+
targetScheme := "http"
1403
+
if !s.config.Core.Dev {
1404
+
targetScheme = "https"
1405
+
}
1406
+
targetHost := fmt.Sprintf("%s://%s", targetScheme, f.Knot)
1407
+
targetXrpcc := &indigoxrpc.Client{
1408
+
Host: targetHost,
1409
+
}
1410
+
1411
+
targetRepo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
1412
+
targetXrpcBytes, err := tangled.RepoBranches(r.Context(), targetXrpcc, "", 0, targetRepo)
1301
1413
if err != nil {
1302
-
log.Printf("failed to create unsigned client for target knot %s", f.Knot)
1303
-
s.pages.Error503(w)
1414
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1415
+
log.Println("failed to call XRPC repo.branches for target", xrpcerr)
1416
+
s.pages.Error503(w)
1417
+
return
1418
+
}
1419
+
log.Println("failed to fetch target branches", err)
1304
1420
return
1305
1421
}
1306
1422
1307
-
targetResult, err := targetBranchesClient.Branches(f.OwnerDid(), f.Name)
1308
-
if err != nil {
1309
-
log.Println("failed to reach knotserver for target branches", err)
1423
+
// Decode target branches
1424
+
var targetBranches types.RepoBranchesResponse
1425
+
if err := json.Unmarshal(targetXrpcBytes, &targetBranches); err != nil {
1426
+
log.Println("failed to decode target branches XRPC response", err)
1427
+
s.pages.Error503(w)
1310
1428
return
1311
1429
}
1312
1430
1313
-
sourceBranches := sourceResult.Branches
1314
-
sort.Slice(sourceBranches, func(i int, j int) bool {
1315
-
return sourceBranches[i].Commit.Committer.When.After(sourceBranches[j].Commit.Committer.When)
1431
+
sort.Slice(sourceBranches.Branches, func(i int, j int) bool {
1432
+
return sourceBranches.Branches[i].Commit.Committer.When.After(sourceBranches.Branches[j].Commit.Committer.When)
1316
1433
})
1317
1434
1318
1435
s.pages.PullCompareForkBranchesFragment(w, pages.PullCompareForkBranchesParams{
1319
1436
RepoInfo: f.RepoInfo(user),
1320
-
SourceBranches: sourceBranches,
1321
-
TargetBranches: targetResult.Branches,
1437
+
SourceBranches: sourceBranches.Branches,
1438
+
TargetBranches: targetBranches.Branches,
1322
1439
})
1323
1440
}
1324
1441
···
1413
1530
return
1414
1531
}
1415
1532
1416
-
ksClient, err := knotclient.NewUnsignedClient(f.Knot, s.config.Core.Dev)
1417
-
if err != nil {
1418
-
log.Printf("failed to create client for %s: %s", f.Knot, err)
1419
-
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1420
-
return
1533
+
scheme := "http"
1534
+
if !s.config.Core.Dev {
1535
+
scheme = "https"
1536
+
}
1537
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
1538
+
xrpcc := &indigoxrpc.Client{
1539
+
Host: host,
1421
1540
}
1422
1541
1423
-
comparison, err := ksClient.Compare(f.OwnerDid(), f.Name, pull.TargetBranch, pull.PullSource.Branch)
1542
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
1543
+
xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, pull.TargetBranch, pull.PullSource.Branch)
1424
1544
if err != nil {
1545
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1546
+
log.Println("failed to call XRPC repo.compare", xrpcerr)
1547
+
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1548
+
return
1549
+
}
1425
1550
log.Printf("compare request failed: %s", err)
1426
1551
s.pages.Notice(w, "resubmit-error", err.Error())
1552
+
return
1553
+
}
1554
+
1555
+
var comparison types.RepoFormatPatchResponse
1556
+
if err := json.Unmarshal(xrpcBytes, &comparison); err != nil {
1557
+
log.Println("failed to decode XRPC compare response", err)
1558
+
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1427
1559
return
1428
1560
}
1429
1561
···
1463
1595
}
1464
1596
1465
1597
// extract patch by performing compare
1466
-
ksClient, err := knotclient.NewUnsignedClient(forkRepo.Knot, s.config.Core.Dev)
1598
+
forkScheme := "http"
1599
+
if !s.config.Core.Dev {
1600
+
forkScheme = "https"
1601
+
}
1602
+
forkHost := fmt.Sprintf("%s://%s", forkScheme, forkRepo.Knot)
1603
+
forkRepoId := fmt.Sprintf("%s/%s", forkRepo.Did, forkRepo.Name)
1604
+
forkXrpcBytes, err := tangled.RepoCompare(r.Context(), &indigoxrpc.Client{Host: forkHost}, forkRepoId, pull.TargetBranch, pull.PullSource.Branch)
1467
1605
if err != nil {
1468
-
log.Printf("failed to create client for %s: %s", forkRepo.Knot, err)
1606
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1607
+
log.Println("failed to call XRPC repo.compare for fork", xrpcerr)
1608
+
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1609
+
return
1610
+
}
1611
+
log.Printf("failed to compare branches: %s", err)
1612
+
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1613
+
return
1614
+
}
1615
+
1616
+
var forkComparison types.RepoFormatPatchResponse
1617
+
if err := json.Unmarshal(forkXrpcBytes, &forkComparison); err != nil {
1618
+
log.Println("failed to decode XRPC compare response for fork", err)
1469
1619
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1470
1620
return
1471
1621
}
···
1501
1651
return
1502
1652
}
1503
1653
1504
-
hiddenRef := fmt.Sprintf("hidden/%s/%s", pull.PullSource.Branch, pull.TargetBranch)
1505
-
comparison, err := ksClient.Compare(forkRepo.Did, forkRepo.Name, hiddenRef, pull.PullSource.Branch)
1506
-
if err != nil {
1507
-
log.Printf("failed to compare branches: %s", err)
1508
-
s.pages.Notice(w, "resubmit-error", err.Error())
1509
-
return
1510
-
}
1654
+
// Use the fork comparison we already made
1655
+
comparison := forkComparison
1511
1656
1512
1657
sourceRev := comparison.Rev2
1513
1658
patch := comparison.Patch