+135
-87
appview/pulls/pulls.go
+135
-87
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"
···
25
"tangled.sh/tangled.sh/core/patchutil"
26
"tangled.sh/tangled.sh/core/tid"
27
"tangled.sh/tangled.sh/core/types"
28
29
"github.com/bluekeyes/go-gitdiff/gitdiff"
30
comatproto "github.com/bluesky-social/indigo/api/atproto"
···
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)
···
161
}
162
}
163
164
-
mergeCheckResponse := s.mergeCheck(f, pull, stack)
165
resubmitResult := pages.Unknown
166
if user != nil && user.Did == pull.OwnerDid {
167
resubmitResult = s.resubmitCheck(f, pull, stack)
···
226
})
227
}
228
229
-
func (s *Pulls) mergeCheck(f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) types.MergeCheckResponse {
230
if pull.State == db.PullMerged {
231
return types.MergeCheckResponse{}
232
}
233
234
-
secret, err := db.GetRegistrationKey(s.db, f.Knot)
235
if err != nil {
236
-
log.Printf("failed to get registration key: %v", err)
237
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",
247
}
248
}
249
···
257
patch = mergeable.CombinedPatch()
258
}
259
260
-
resp, err := ksClient.MergeCheck([]byte(patch), f.OwnerDid(), f.RepoName, pull.TargetBranch)
261
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",
271
}
272
-
case 400:
273
return types.MergeCheckResponse{
274
-
Error: "failed to check merge status: does this knot support PRs?",
275
}
276
}
277
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",
283
}
284
}
285
-
defer resp.Body.Close()
286
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
-
}
294
}
295
296
-
return mergeCheckResponse
297
}
298
299
func (s *Pulls) resubmitCheck(f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) pages.ResubmitResult {
···
923
return
924
}
925
926
-
secret, err := db.GetRegistrationKey(s.db, fork.Knot)
927
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)
936
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
937
return
938
}
···
944
return
945
}
946
947
-
resp, err := sc.NewHiddenRef(user.Did, fork.Name, sourceBranch, targetBranch)
948
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.")
951
return
952
}
953
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.")
958
return
959
}
960
···
1524
return
1525
}
1526
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
// update the hidden tracking branch to latest
1535
-
signedClient, err := knotclient.NewSignedClient(forkRepo.Knot, secret, s.config.Core.Dev)
1536
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.")
1539
return
1540
}
1541
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)
1545
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1546
return
1547
}
···
1958
1959
patch := pullsToMerge.CombinedPatch()
1960
1961
-
secret, err := db.GetRegistrationKey(s.db, f.Knot)
1962
if err != nil {
1963
-
log.Printf("no registration key found for domain %s: %s\n", f.Knot, err)
1964
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1965
return
1966
}
···
1977
log.Printf("failed to get primary email: %s", err)
1978
}
1979
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
1985
}
1986
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
1993
}
1994
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.")
1998
return
1999
}
2000
···
2
3
import (
4
"database/sql"
5
"errors"
6
"fmt"
7
"log"
8
"net/http"
9
"sort"
···
23
"tangled.sh/tangled.sh/core/patchutil"
24
"tangled.sh/tangled.sh/core/tid"
25
"tangled.sh/tangled.sh/core/types"
26
+
xrpcerr "tangled.sh/tangled.sh/core/xrpc/errors"
27
28
"github.com/bluekeyes/go-gitdiff/gitdiff"
29
comatproto "github.com/bluesky-social/indigo/api/atproto"
···
95
return
96
}
97
98
+
mergeCheckResponse := s.mergeCheck(r, f, pull, stack)
99
resubmitResult := pages.Unknown
100
if user.Did == pull.OwnerDid {
101
resubmitResult = s.resubmitCheck(f, pull, stack)
···
160
}
161
}
162
163
+
mergeCheckResponse := s.mergeCheck(r, f, pull, stack)
164
resubmitResult := pages.Unknown
165
if user != nil && user.Did == pull.OwnerDid {
166
resubmitResult = s.resubmitCheck(f, pull, stack)
···
225
})
226
}
227
228
+
func (s *Pulls) mergeCheck(r *http.Request, f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) types.MergeCheckResponse {
229
if pull.State == db.PullMerged {
230
return types.MergeCheckResponse{}
231
}
232
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
+
)
239
if err != nil {
240
+
log.Printf("failed to connect to knot server: %v", err)
241
return types.MergeCheckResponse{
242
+
Error: "failed to check merge status: could not connect to knot server",
243
}
244
}
245
···
253
patch = mergeable.CombinedPatch()
254
}
255
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
+
)
266
if err != nil {
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
+
}
273
}
274
+
log.Printf("failed to check for mergeability: %s", xe.Error())
275
return types.MergeCheckResponse{
276
+
Error: fmt.Sprintf("failed to check merge status: %s", xe.Message),
277
}
278
}
279
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,
286
}
287
}
288
289
+
result := types.MergeCheckResponse{
290
+
IsConflicted: resp.Is_conflicted,
291
+
Conflicts: conflicts,
292
}
293
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
303
}
304
305
func (s *Pulls) resubmitCheck(f *reporesolver.ResolvedRepo, pull *db.Pull, stack db.Stack) pages.ResubmitResult {
···
929
return
930
}
931
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
+
)
938
if err != nil {
939
+
log.Printf("failed to connect to knot server: %v", err)
940
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
941
return
942
}
···
948
return
949
}
950
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
+
)
960
if err != nil {
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
+
}
973
return
974
}
975
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)
982
return
983
}
984
···
1548
return
1549
}
1550
1551
// update the hidden tracking branch to latest
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
+
)
1558
if err != nil {
1559
+
log.Printf("failed to connect to knot server: %v", err)
1560
return
1561
}
1562
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
+
}
1578
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1579
return
1580
}
···
1991
1992
patch := pullsToMerge.CombinedPatch()
1993
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
+
)
2000
if err != nil {
2001
+
log.Printf("failed to connect to knot server: %v", err)
2002
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
2003
return
2004
}
···
2015
log.Printf("failed to get primary email: %s", err)
2016
}
2017
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
2030
}
2031
2032
+
if email.Address != "" {
2033
+
mergeInput.AuthorEmail = &email.Address
2034
}
2035
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
+
}
2046
return
2047
}
2048
+29
-4
appview/repo/index.go
+29
-4
appview/repo/index.go
···
9
"sort"
10
"strings"
11
12
"tangled.sh/tangled.sh/core/appview/commitverify"
13
"tangled.sh/tangled.sh/core/appview/db"
14
"tangled.sh/tangled.sh/core/appview/oauth"
···
118
119
var forkInfo *types.ForkInfo
120
if user != nil && (repoInfo.Roles.IsOwner() || repoInfo.Roles.IsCollaborator()) {
121
-
forkInfo, err = getForkInfo(repoInfo, rp, f, user, signedClient)
122
if err != nil {
123
log.Printf("Failed to fetch fork information: %v", err)
124
return
···
231
}
232
233
func getForkInfo(
234
repoInfo repoinfo.RepoInfo,
235
rp *Repo,
236
f *reporesolver.ResolvedRepo,
···
270
return &forkInfo, nil
271
}
272
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)
276
return nil, err
277
}
278
279
hiddenRef := fmt.Sprintf("hidden/%s/%s", f.Ref, f.Ref)
···
9
"sort"
10
"strings"
11
12
+
"tangled.sh/tangled.sh/core/api/tangled"
13
"tangled.sh/tangled.sh/core/appview/commitverify"
14
"tangled.sh/tangled.sh/core/appview/db"
15
"tangled.sh/tangled.sh/core/appview/oauth"
···
119
120
var forkInfo *types.ForkInfo
121
if user != nil && (repoInfo.Roles.IsOwner() || repoInfo.Roles.IsCollaborator()) {
122
+
forkInfo, err = getForkInfo(r, repoInfo, rp, f, user, signedClient)
123
if err != nil {
124
log.Printf("Failed to fetch fork information: %v", err)
125
return
···
232
}
233
234
func getForkInfo(
235
+
r *http.Request,
236
repoInfo repoinfo.RepoInfo,
237
rp *Repo,
238
f *reporesolver.ResolvedRepo,
···
272
return &forkInfo, nil
273
}
274
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)
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")
302
}
303
304
hiddenRef := fmt.Sprintf("hidden/%s/%s", f.Ref, f.Ref)
+105
-66
appview/repo/repo.go
+105
-66
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(
···
915
}
916
log.Println("removed repo record ", f.RepoAt.String())
917
918
-
secret, err := db.GetRegistrationKey(rp.db, f.Knot)
919
if err != nil {
920
-
log.Printf("no key found for domain %s: %s\n", f.Knot, err)
921
return
922
}
923
924
-
ksClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev)
925
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)
938
} else {
939
log.Println("removed repo from knot ", f.Knot)
940
}
···
1010
return
1011
}
1012
1013
-
secret, err := db.GetRegistrationKey(rp.db, f.Knot)
1014
if err != nil {
1015
-
log.Printf("no key found for domain %s: %s\n", f.Knot, err)
1016
return
1017
}
1018
1019
-
ksClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev)
1020
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.")
1033
return
1034
}
1035
···
1323
1324
switch r.Method {
1325
case http.MethodPost:
1326
-
secret, err := db.GetRegistrationKey(rp.db, f.Knot)
1327
if err != nil {
1328
-
rp.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", f.Knot))
1329
return
1330
}
1331
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.")
1335
return
1336
}
1337
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)
1348
if err != nil {
1349
-
rp.pages.Notice(w, "repo", "Failed to sync repository fork.")
1350
return
1351
}
1352
···
1409
// repo with this name already exists, append random string
1410
forkName = fmt.Sprintf("%s-%s", forkName, randomString(3))
1411
}
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
-
}
1417
1418
-
client, err := knotclient.NewSignedClient(knot, secret, rp.config.Core.Dev)
1419
if err != nil {
1420
-
rp.pages.Notice(w, "repo", "Failed to reach knot server.")
1421
return
1422
}
1423
···
1453
}
1454
}()
1455
1456
-
resp, err := client.ForkRepo(user.Did, forkSourceUrl, forkName)
1457
if err != nil {
1458
-
rp.pages.Notice(w, "repo", "Failed to create repository on knot server.")
1459
-
return
1460
-
}
1461
1462
-
switch resp.StatusCode {
1463
-
case http.StatusConflict:
1464
-
rp.pages.Notice(w, "repo", "A repository with that name already exists.")
1465
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
}
1471
1472
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
+
xrpcerr "tangled.sh/tangled.sh/core/xrpc/errors"
39
+
"tangled.sh/tangled.sh/core/xrpc/serviceauth"
40
41
securejoin "github.com/cyphar/filepath-securejoin"
42
"github.com/go-chi/chi/v5"
43
"github.com/go-git/go-git/v5/plumbing"
44
45
"github.com/bluesky-social/indigo/atproto/syntax"
46
)
47
48
type Repo struct {
···
56
enforcer *rbac.Enforcer
57
notifier notify.Notifier
58
logger *slog.Logger
59
+
serviceAuth *serviceauth.ServiceAuth
60
}
61
62
func New(
···
918
}
919
log.Println("removed repo record ", f.RepoAt.String())
920
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
+
)
927
if err != nil {
928
+
log.Println("failed to connect to knot server:", err)
929
return
930
}
931
932
+
err = tangled.RepoDelete(
933
+
r.Context(),
934
+
client,
935
+
&tangled.RepoDelete_Input{
936
+
Did: f.OwnerDid(),
937
+
Name: f.RepoName,
938
+
},
939
+
)
940
if err != nil {
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
948
} else {
949
log.Println("removed repo from knot ", f.Knot)
950
}
···
1020
return
1021
}
1022
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
+
)
1029
if err != nil {
1030
+
log.Println("failed to connect to knot server:", err)
1031
+
rp.pages.Notice(w, "repo-settings", "Failed to connect to knot server.")
1032
return
1033
}
1034
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
+
)
1043
if err != nil {
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
+
}
1052
return
1053
}
1054
···
1342
1343
switch r.Method {
1344
case http.MethodPost:
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
+
)
1351
if err != nil {
1352
+
rp.pages.Notice(w, "repo", "Failed to connect to knot server.")
1353
return
1354
}
1355
1356
+
repoInfo := f.RepoInfo(user)
1357
+
if repoInfo.Source == nil {
1358
+
rp.pages.Notice(w, "repo", "This repository is not a fork.")
1359
return
1360
}
1361
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
+
)
1372
if err != nil {
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
+
}
1381
return
1382
}
1383
···
1440
// repo with this name already exists, append random string
1441
forkName = fmt.Sprintf("%s-%s", forkName, randomString(3))
1442
}
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
+
)
1449
1450
if err != nil {
1451
+
log.Printf("error creating client for knot server: %v", err)
1452
+
rp.pages.Notice(w, "repo", "Failed to connect to knot server.")
1453
return
1454
}
1455
···
1485
}
1486
}()
1487
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
+
1498
if err != nil {
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
+
}
1505
1506
+
log.Println(xe.Error())
1507
+
rp.pages.Notice(w, "repo", fmt.Sprintf("Failed to create repository on knot server: %s.", xe.Message))
1508
return
1509
}
1510
1511
xrpcClient, err := rp.oauth.AuthorizedClient(r)
+26
-19
appview/state/state.go
+26
-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 {
···
329
330
existingRepo, err := db.GetRepo(s.db, user.Did, repoName)
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))
333
return
334
}
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
-
}
341
342
-
client, err := knotclient.NewSignedClient(domain, secret, s.config.Core.Dev)
343
if err != nil {
344
s.pages.Notice(w, "repo", "Failed to connect to knot server.")
345
return
···
394
}
395
}()
396
397
-
resp, err := client.NewRepo(user.Did, repoName, defaultBranch)
398
if err != nil {
399
-
s.pages.Notice(w, "repo", "Failed to create repository on knot server.")
400
-
return
401
-
}
402
403
-
switch resp.StatusCode {
404
-
case http.StatusConflict:
405
-
s.pages.Notice(w, "repo", "A repository with that name already exists.")
406
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
}
412
413
repo.AtUri = atresp.Uri
···
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 {
···
329
330
existingRepo, err := db.GetRepo(s.db, user.Did, repoName)
331
if err == nil && existingRepo != nil {
332
+
s.pages.Notice(w, "repo", fmt.Sprintf("You already have a repository by this name on %s", existingRepo.Knot))
333
return
334
}
335
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
+
)
342
343
if err != nil {
344
s.pages.Notice(w, "repo", "Failed to connect to knot server.")
345
return
···
394
}
395
}()
396
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
+
407
if err != nil {
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
+
}
414
415
+
log.Println(xe.Error())
416
+
s.pages.Notice(w, "repo", fmt.Sprintf("Failed to create repository on knot server: %s.", xe.Message))
417
return
418
}
419
420
repo.AtUri = atresp.Uri