Signed-off-by: Lewis lewis@tangled.org
+290
-163
Diff
round #8
+3
-2
appview/issues/issues.go
+3
-2
appview/issues/issues.go
···
306
306
return
307
307
}
308
308
309
-
roles := repoinfo.RolesInRepo{Roles: rp.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())}
309
+
roles := repoinfo.RolesInRepo{Roles: rp.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.RepoIdentifier())}
310
310
isRepoOwner := roles.IsOwner()
311
311
isCollaborator := roles.IsCollaborator()
312
312
isIssueOwner := user.Active.Did == issue.Did
···
354
354
return
355
355
}
356
356
357
-
roles := repoinfo.RolesInRepo{Roles: rp.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())}
357
+
roles := repoinfo.RolesInRepo{Roles: rp.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.RepoIdentifier())}
358
358
isRepoOwner := roles.IsOwner()
359
359
isCollaborator := roles.IsCollaborator()
360
360
isIssueOwner := user.Active.Did == issue.Did
···
1011
1011
1012
1012
issue := &models.Issue{
1013
1013
RepoAt: f.RepoAt(),
1014
+
RepoDid: f.RepoDid,
1014
1015
Rkey: tid.TID(),
1015
1016
Title: r.FormValue("title"),
1016
1017
Body: body,
+5
-2
appview/pages/funcmap.go
+5
-2
appview/pages/funcmap.go
···
78
78
return identity.Handle.String()
79
79
},
80
80
"ownerSlashRepo": func(repo *models.Repo) string {
81
+
if repo.RepoDid != "" {
82
+
return repo.RepoDid
83
+
}
81
84
ownerId, err := p.resolver.ResolveIdent(context.Background(), repo.Did)
82
85
if err != nil {
83
-
return repo.DidSlashRepo()
86
+
return repo.RepoIdentifier()
84
87
}
85
88
handle := ownerId.Handle
86
89
if handle != "" && !handle.IsInvalidHandle() {
87
90
return string(handle) + "/" + repo.Name
88
91
}
89
-
return repo.DidSlashRepo()
92
+
return repo.RepoIdentifier()
90
93
},
91
94
"truncateAt30": func(s string) string {
92
95
if len(s) <= 30 {
+1
appview/pages/repoinfo/repoinfo.go
+1
appview/pages/repoinfo/repoinfo.go
+21
appview/pages/templates/repo/fork.html
+21
appview/pages/templates/repo/fork.html
···
37
37
<p class="text-sm text-gray-500 dark:text-gray-400">A knot hosts repository data. <a href="/settings/knots" class="underline">Learn how to register your own knot.</a></p>
38
38
</fieldset>
39
39
40
+
<fieldset class="space-y-3">
41
+
<details>
42
+
<summary class="dark:text-white cursor-pointer select-none">Bring your own DID</summary>
43
+
<div class="mt-2">
44
+
<input
45
+
type="text"
46
+
id="repo_did"
47
+
name="repo_did"
48
+
class="w-full p-2 border rounded bg-gray-100 dark:bg-gray-700 dark:text-white dark:border-gray-600"
49
+
placeholder="did:web:example.com"
50
+
/>
51
+
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">
52
+
Provide a <code>did:web</code> you control to use as this fork's identity.
53
+
You must serve a DID doc on your domain with a <code>tangled_knot</code> service
54
+
endpoint pointing to the selected knot. If left empty, a <code>did:plc</code> will be
55
+
automatically created for you!
56
+
</p>
57
+
</div>
58
+
</details>
59
+
</fieldset>
60
+
40
61
<div class="space-y-2">
41
62
<button type="submit" class="btn-create flex items-center gap-2">
42
63
{{ i "git-fork" "w-4 h-4" }}
+26
appview/pages/templates/repo/new.html
+26
appview/pages/templates/repo/new.html
···
70
70
<div class="space-y-2">
71
71
{{ template "defaultBranch" . }}
72
72
{{ template "knot" . }}
73
+
{{ template "repoDid" . }}
73
74
</div>
74
75
</div>
75
76
</div>
···
171
172
</div>
172
173
{{ end }}
173
174
175
+
{{ define "repoDid" }}
176
+
<div>
177
+
<details>
178
+
<summary class="text-sm font-bold uppercase dark:text-white mb-1 cursor-pointer select-none">
179
+
Bring your own DID
180
+
</summary>
181
+
<div class="mt-2">
182
+
<input
183
+
type="text"
184
+
id="repo_did"
185
+
name="repo_did"
186
+
class="w-full dark:bg-gray-700 dark:text-white dark:border-gray-600 border border-gray-300 rounded px-3 py-2"
187
+
placeholder="did:web:example.com"
188
+
/>
189
+
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">
190
+
Provide a <code>did:web</code> you control to use as this repo's identity.
191
+
You must serve a DID doc on your domain with a <code>tangled_knot</code> service
192
+
endpoint pointing to the selected knot. If left empty, a <code>did:plc</code> will be
193
+
automatically created for you!
194
+
</p>
195
+
</div>
196
+
</details>
197
+
</div>
198
+
{{ end }}
199
+
174
200
{{ define "numberCircle" }}
175
201
<div class="w-6 h-6 bg-gray-200 dark:bg-gray-600 rounded-full flex items-center justify-center text-sm font-medium mt-1">
176
202
{{.}}
+44
-45
appview/pulls/pulls.go
+44
-45
appview/pulls/pulls.go
···
406
406
}
407
407
408
408
// user can only delete branch if they are a collaborator in the repo that the branch belongs to
409
-
perms := s.enforcer.GetPermissionsInRepo(user.Active.Did, repo.Knot, repo.DidSlashRepo())
409
+
perms := s.enforcer.GetPermissionsInRepo(user.Active.Did, repo.Knot, repo.RepoIdentifier())
410
410
if !slices.Contains(perms, "repo:push") {
411
411
return nil
412
412
}
···
420
420
Host: host,
421
421
}
422
422
423
-
resp, err := tangled.RepoBranch(r.Context(), xrpcc, branch, fmt.Sprintf("%s/%s", repo.Did, repo.Name))
423
+
resp, err := tangled.RepoBranch(r.Context(), xrpcc, branch, repo.RepoIdentifier())
424
424
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
425
425
return nil
426
426
}
···
436
436
return pages.Unknown
437
437
}
438
438
439
-
var knot, ownerDid, repoName string
440
-
439
+
var sourceRepo *models.Repo
441
440
if pull.PullSource.RepoAt != nil {
442
-
// fork-based pulls
443
-
sourceRepo, err := db.GetRepoByAtUri(s.db, pull.PullSource.RepoAt.String())
441
+
var err error
442
+
sourceRepo, err = db.GetRepoByAtUri(s.db, pull.PullSource.RepoAt.String())
444
443
if err != nil {
445
444
log.Println("failed to get source repo", err)
446
445
return pages.Unknown
447
446
}
448
-
449
-
knot = sourceRepo.Knot
450
-
ownerDid = sourceRepo.Did
451
-
repoName = sourceRepo.Name
452
447
} else {
453
-
// pulls within the same repo
454
-
knot = repo.Knot
455
-
ownerDid = repo.Did
456
-
repoName = repo.Name
448
+
sourceRepo = repo
457
449
}
458
450
459
451
scheme := "http"
460
452
if !s.config.Core.Dev {
461
453
scheme = "https"
462
454
}
463
-
host := fmt.Sprintf("%s://%s", scheme, knot)
455
+
host := fmt.Sprintf("%s://%s", scheme, sourceRepo.Knot)
464
456
xrpcc := &indigoxrpc.Client{
465
457
Host: host,
466
458
}
467
459
468
-
didSlashName := fmt.Sprintf("%s/%s", ownerDid, repoName)
469
-
branchResp, err := tangled.RepoBranch(r.Context(), xrpcc, pull.PullSource.Branch, didSlashName)
460
+
branchResp, err := tangled.RepoBranch(r.Context(), xrpcc, pull.PullSource.Branch, sourceRepo.RepoIdentifier())
470
461
if err != nil {
471
462
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
472
463
log.Println("failed to call XRPC repo.branches", xrpcerr)
···
863
854
comment := &models.PullComment{
864
855
OwnerDid: user.Active.Did,
865
856
RepoAt: f.RepoAt().String(),
857
+
RepoDid: f.RepoDid,
866
858
PullId: pull.PullId,
867
859
Body: body,
868
860
CommentAt: atResp.Uri,
···
913
905
Host: host,
914
906
}
915
907
916
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
917
-
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
908
+
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, f.RepoIdentifier())
918
909
if err != nil {
919
910
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
920
911
log.Println("failed to call XRPC repo.branches", xrpcerr)
···
963
954
}
964
955
965
956
// Determine PR type based on input parameters
966
-
roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())}
957
+
roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.RepoIdentifier())}
967
958
isPushAllowed := roles.IsPushAllowed()
968
959
isBranchBased := isPushAllowed && sourceBranch != "" && fromFork == ""
969
960
isForkBased := fromFork != "" && sourceBranch != ""
···
1079
1070
Host: host,
1080
1071
}
1081
1072
1082
-
didSlashRepo := fmt.Sprintf("%s/%s", repo.Did, repo.Name)
1083
-
xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, didSlashRepo, targetBranch, sourceBranch)
1073
+
xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo.RepoIdentifier(), targetBranch, sourceBranch)
1084
1074
if err != nil {
1085
1075
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1086
1076
log.Println("failed to call XRPC repo.compare", xrpcerr)
···
1189
1179
Host: forkHost,
1190
1180
}
1191
1181
1192
-
forkRepoId := fmt.Sprintf("%s/%s", fork.Did, fork.Name)
1193
-
forkXrpcBytes, err := tangled.RepoCompare(r.Context(), forkXrpcc, forkRepoId, hiddenRef, sourceBranch)
1182
+
forkXrpcBytes, err := tangled.RepoCompare(r.Context(), forkXrpcc, fork.RepoIdentifier(), hiddenRef, sourceBranch)
1194
1183
if err != nil {
1195
1184
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1196
1185
log.Println("failed to call XRPC repo.compare for fork", xrpcerr)
···
1223
1212
forkAtUriStr := forkAtUri.String()
1224
1213
1225
1214
pullSource := &models.PullSource{
1226
-
Branch: sourceBranch,
1227
-
RepoAt: &forkAtUri,
1215
+
Branch: sourceBranch,
1216
+
RepoAt: &forkAtUri,
1217
+
RepoDid: fork.RepoDid,
1228
1218
}
1229
1219
recordPullSource := &tangled.RepoPull_Source{
1230
1220
Branch: sourceBranch,
1231
-
Repo: &forkAtUriStr,
1232
1221
Sha: sourceRev,
1233
1222
}
1223
+
if fork.RepoDid != "" {
1224
+
recordPullSource.RepoDid = &fork.RepoDid
1225
+
} else {
1226
+
recordPullSource.Repo = &forkAtUriStr
1227
+
}
1234
1228
1235
1229
s.createPullRequest(w, r, repo, user, title, body, targetBranch, patch, combined, sourceRev, pullSource, recordPullSource, isStacked)
1236
1230
}
···
1313
1307
TargetBranch: targetBranch,
1314
1308
OwnerDid: user.Active.Did,
1315
1309
RepoAt: repo.RepoAt(),
1310
+
RepoDid: repo.RepoDid,
1316
1311
Rkey: rkey,
1317
1312
Mentions: mentions,
1318
1313
References: references,
···
1347
1342
Rkey: rkey,
1348
1343
Record: &lexutil.LexiconTypeDecoder{
1349
1344
Val: &tangled.RepoPull{
1350
-
Title: title,
1351
-
Target: &tangled.RepoPull_Target{
1352
-
Repo: string(repo.RepoAt()),
1353
-
Branch: targetBranch,
1354
-
},
1345
+
Title: title,
1346
+
Target: repoPullTarget(repo, targetBranch),
1355
1347
PatchBlob: blob.Blob,
1356
1348
Source: recordPullSource,
1357
1349
CreatedAt: time.Now().Format(time.RFC3339),
···
1544
1536
Host: host,
1545
1537
}
1546
1538
1547
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
1548
-
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
1539
+
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, f.RepoIdentifier())
1549
1540
if err != nil {
1550
1541
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1551
1542
log.Println("failed to call XRPC repo.branches", xrpcerr)
···
1631
1622
Host: sourceHost,
1632
1623
}
1633
1624
1634
-
sourceRepo := fmt.Sprintf("%s/%s", forkOwnerDid, repo.Name)
1635
-
sourceXrpcBytes, err := tangled.RepoBranches(r.Context(), sourceXrpcc, "", 0, sourceRepo)
1625
+
sourceXrpcBytes, err := tangled.RepoBranches(r.Context(), sourceXrpcc, "", 0, repo.RepoIdentifier())
1636
1626
if err != nil {
1637
1627
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1638
1628
log.Println("failed to call XRPC repo.branches for source", xrpcerr)
···
1660
1650
Host: targetHost,
1661
1651
}
1662
1652
1663
-
targetRepo := fmt.Sprintf("%s/%s", f.Did, f.Name)
1664
-
targetXrpcBytes, err := tangled.RepoBranches(r.Context(), targetXrpcc, "", 0, targetRepo)
1653
+
targetXrpcBytes, err := tangled.RepoBranches(r.Context(), targetXrpcc, "", 0, f.RepoIdentifier())
1665
1654
if err != nil {
1666
1655
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1667
1656
log.Println("failed to call XRPC repo.branches for target", xrpcerr)
···
1771
1760
return
1772
1761
}
1773
1762
1774
-
roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())}
1763
+
roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.RepoIdentifier())}
1775
1764
if !roles.IsPushAllowed() {
1776
1765
log.Println("unauthorized user")
1777
1766
w.WriteHeader(http.StatusUnauthorized)
···
1787
1776
Host: host,
1788
1777
}
1789
1778
1790
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
1791
-
xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, pull.TargetBranch, pull.PullSource.Branch)
1779
+
xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, f.RepoIdentifier(), pull.TargetBranch, pull.PullSource.Branch)
1792
1780
if err != nil {
1793
1781
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1794
1782
log.Println("failed to call XRPC repo.compare", xrpcerr)
···
1881
1869
forkScheme = "https"
1882
1870
}
1883
1871
forkHost := fmt.Sprintf("%s://%s", forkScheme, forkRepo.Knot)
1884
-
forkRepoId := fmt.Sprintf("%s/%s", forkRepo.Did, forkRepo.Name)
1885
-
forkXrpcBytes, err := tangled.RepoCompare(r.Context(), &indigoxrpc.Client{Host: forkHost}, forkRepoId, hiddenRef, pull.PullSource.Branch)
1872
+
forkXrpcBytes, err := tangled.RepoCompare(r.Context(), &indigoxrpc.Client{Host: forkHost}, forkRepo.RepoIdentifier(), hiddenRef, pull.PullSource.Branch)
1886
1873
if err != nil {
1887
1874
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1888
1875
log.Println("failed to call XRPC repo.compare for fork", xrpcerr)
···
2360
2347
}
2361
2348
2362
2349
// auth filter: only owner or collaborators can close
2363
-
roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())}
2350
+
roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.RepoIdentifier())}
2364
2351
isOwner := roles.IsOwner()
2365
2352
isCollaborator := roles.IsCollaborator()
2366
2353
isPullAuthor := user.Active.Did == pull.OwnerDid
···
2434
2421
}
2435
2422
2436
2423
// auth filter: only owner or collaborators can close
2437
-
roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())}
2424
+
roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.RepoIdentifier())}
2438
2425
isOwner := roles.IsOwner()
2439
2426
isCollaborator := roles.IsCollaborator()
2440
2427
isPullAuthor := user.Active.Did == pull.OwnerDid
···
2528
2515
TargetBranch: targetBranch,
2529
2516
OwnerDid: user.Active.Did,
2530
2517
RepoAt: repo.RepoAt(),
2518
+
RepoDid: repo.RepoDid,
2531
2519
Rkey: rkey,
2532
2520
Mentions: mentions,
2533
2521
References: references,
···
2559
2547
}
2560
2548
2561
2549
func ptrPullState(s models.PullState) *models.PullState { return &s }
2550
+
2551
+
func repoPullTarget(repo *models.Repo, branch string) *tangled.RepoPull_Target {
2552
+
target := &tangled.RepoPull_Target{Branch: branch}
2553
+
if repo.RepoDid != "" {
2554
+
target.RepoDid = &repo.RepoDid
2555
+
} else {
2556
+
s := string(repo.RepoAt())
2557
+
target.Repo = &s
2558
+
}
2559
+
return target
2560
+
}
+2
-2
appview/repo/archive.go
+2
-2
appview/repo/archive.go
···
25
25
scheme = "https"
26
26
}
27
27
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
28
-
didSlashRepo := f.DidSlashRepo()
28
+
didSlashRepo := f.RepoIdentifier()
29
29
30
30
// build the xrpc url
31
31
u, err := url.Parse(host)
···
70
70
if link := resp.Header.Get("Link"); link != "" {
71
71
if resolvedRef, err := extractImmutableLink(link); err == nil {
72
72
newLink := fmt.Sprintf("<%s/%s/archive/%s.tar.gz>; rel=\"immutable\"",
73
-
rp.config.Core.BaseUrl(), f.DidSlashRepo(), resolvedRef)
73
+
rp.config.Core.BaseUrl(), f.RepoIdentifier(), resolvedRef)
74
74
w.Header().Set("Link", newLink)
75
75
}
76
76
}
+19
-9
appview/repo/artifact.go
+19
-9
appview/repo/artifact.go
···
80
80
Repo: user.Active.Did,
81
81
Rkey: rkey,
82
82
Record: &lexutil.LexiconTypeDecoder{
83
-
Val: &tangled.RepoArtifact{
84
-
Artifact: uploadBlobResp.Blob,
85
-
CreatedAt: createdAt.Format(time.RFC3339),
86
-
Name: header.Filename,
87
-
Repo: f.RepoAt().String(),
88
-
Tag: tag.Tag.Hash[:],
89
-
},
83
+
Val: repoArtifactRecord(f, uploadBlobResp.Blob, createdAt, header.Filename, tag.Tag.Hash[:]),
90
84
},
91
85
})
92
86
if err != nil {
···
109
103
Did: user.Active.Did,
110
104
Rkey: rkey,
111
105
RepoAt: f.RepoAt(),
106
+
RepoDid: f.RepoDid,
112
107
Tag: tag.Tag.Hash,
113
108
CreatedAt: createdAt,
114
109
BlobCid: cid.Cid(uploadBlobResp.Blob.Ref),
···
322
317
Host: host,
323
318
}
324
319
325
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
326
-
xrpcBytes, err := tangled.RepoTags(ctx, xrpcc, "", 0, repo)
320
+
xrpcBytes, err := tangled.RepoTags(ctx, xrpcc, "", 0, f.RepoIdentifier())
327
321
if err != nil {
328
322
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
329
323
l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
···
358
352
359
353
return tag, nil
360
354
}
355
+
356
+
func repoArtifactRecord(f *models.Repo, blob *lexutil.LexBlob, createdAt time.Time, name string, tag []byte) *tangled.RepoArtifact {
357
+
rec := &tangled.RepoArtifact{
358
+
Artifact: blob,
359
+
CreatedAt: createdAt.Format(time.RFC3339),
360
+
Name: name,
361
+
Tag: tag,
362
+
}
363
+
if f.RepoDid != "" {
364
+
rec.RepoDid = &f.RepoDid
365
+
} else {
366
+
s := f.RepoAt().String()
367
+
rec.Repo = &s
368
+
}
369
+
return rec
370
+
}
+3
-4
appview/repo/blob.go
+3
-4
appview/repo/blob.go
···
58
58
xrpcc := &indigoxrpc.Client{
59
59
Host: host,
60
60
}
61
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
62
-
resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, repo)
61
+
resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, f.RepoIdentifier())
63
62
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
64
63
l.Error("failed to call XRPC repo.blob", "err", xrpcerr)
65
64
rp.pages.Error503(w)
···
139
138
if !rp.config.Core.Dev {
140
139
scheme = "https"
141
140
}
142
-
repo := f.DidSlashRepo()
141
+
repo := f.RepoIdentifier()
143
142
baseURL := &url.URL{
144
143
Scheme: scheme,
145
144
Host: f.Knot,
···
290
289
scheme = "https"
291
290
}
292
291
293
-
repoName := fmt.Sprintf("%s/%s", repo.Did, repo.Name)
292
+
repoName := repo.RepoIdentifier()
294
293
baseURL := &url.URL{
295
294
Scheme: scheme,
296
295
Host: repo.Knot,
+1
-2
appview/repo/branches.go
+1
-2
appview/repo/branches.go
···
29
29
xrpcc := &indigoxrpc.Client{
30
30
Host: host,
31
31
}
32
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
33
-
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
32
+
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, f.RepoIdentifier())
34
33
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
35
34
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
36
35
rp.pages.Error503(w)
+7
-7
appview/repo/compare.go
+7
-7
appview/repo/compare.go
···
36
36
Host: host,
37
37
}
38
38
39
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
40
-
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
39
+
repoId := f.RepoIdentifier()
40
+
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repoId)
41
41
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
42
42
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
43
43
rp.pages.Error503(w)
···
74
74
head = queryHead
75
75
}
76
76
77
-
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
77
+
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repoId)
78
78
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
79
79
l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
80
80
rp.pages.Error503(w)
···
149
149
Host: host,
150
150
}
151
151
152
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
152
+
repoId := f.RepoIdentifier()
153
153
154
-
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
154
+
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repoId)
155
155
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
156
156
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
157
157
rp.pages.Error503(w)
···
165
165
return
166
166
}
167
167
168
-
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
168
+
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repoId)
169
169
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
170
170
l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
171
171
rp.pages.Error503(w)
···
179
179
return
180
180
}
181
181
182
-
compareBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, base, head)
182
+
compareBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repoId, base, head)
183
183
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
184
184
l.Error("failed to call XRPC repo.compare", "err", xrpcerr)
185
185
rp.pages.Error503(w)
+7
-8
appview/repo/index.go
+7
-8
appview/repo/index.go
···
182
182
183
183
if err != nil || langs == nil {
184
184
// non-fatal, fetch langs from ks via XRPC
185
-
didSlashRepo := fmt.Sprintf("%s/%s", repo.Did, repo.Name)
186
-
ls, err := tangled.RepoLanguages(ctx, xrpcc, currentRef, didSlashRepo)
185
+
ls, err := tangled.RepoLanguages(ctx, xrpcc, currentRef, repo.RepoIdentifier())
187
186
if err != nil {
188
187
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
189
188
l.Error("failed to call XRPC repo.languages", "err", xrpcerr)
···
199
198
for _, lang := range ls.Languages {
200
199
langs = append(langs, models.RepoLanguage{
201
200
RepoAt: repo.RepoAt(),
201
+
RepoDid: repo.RepoDid,
202
202
Ref: currentRef,
203
203
IsDefaultRef: isDefaultRef,
204
204
Language: lang.Name,
···
259
259
260
260
// buildIndexResponse creates a RepoIndexResponse by combining multiple xrpc calls in parallel
261
261
func (rp *Repo) buildIndexResponse(ctx context.Context, xrpcc *indigoxrpc.Client, repo *models.Repo, ref string) (*types.RepoIndexResponse, error) {
262
-
didSlashRepo := fmt.Sprintf("%s/%s", repo.Did, repo.Name)
262
+
repoId := repo.RepoIdentifier()
263
263
264
-
// first get branches to determine the ref if not specified
265
-
branchesBytes, err := tangled.RepoBranches(ctx, xrpcc, "", 0, didSlashRepo)
264
+
branchesBytes, err := tangled.RepoBranches(ctx, xrpcc, "", 0, repoId)
266
265
if err != nil {
267
266
return nil, fmt.Errorf("failed to call repoBranches: %w", err)
268
267
}
···
304
303
305
304
// tags
306
305
wg.Go(func() {
307
-
tagsBytes, err := tangled.RepoTags(ctx, xrpcc, "", 0, didSlashRepo)
306
+
tagsBytes, err := tangled.RepoTags(ctx, xrpcc, "", 0, repoId)
308
307
if err != nil {
309
308
errs = errors.Join(errs, fmt.Errorf("failed to call repoTags: %w", err))
310
309
return
···
317
316
318
317
// tree/files
319
318
wg.Go(func() {
320
-
resp, err := tangled.RepoTree(ctx, xrpcc, "", ref, didSlashRepo)
319
+
resp, err := tangled.RepoTree(ctx, xrpcc, "", ref, repoId)
321
320
if err != nil {
322
321
errs = errors.Join(errs, fmt.Errorf("failed to call repoTree: %w", err))
323
322
return
···
327
326
328
327
// commits
329
328
wg.Go(func() {
330
-
logBytes, err := tangled.RepoLog(ctx, xrpcc, "", 50, "", ref, didSlashRepo)
329
+
logBytes, err := tangled.RepoLog(ctx, xrpcc, "", 50, "", ref, repoId)
331
330
if err != nil {
332
331
errs = errors.Join(errs, fmt.Errorf("failed to call repoLog: %w", err))
333
332
return
+5
-6
appview/repo/log.go
+5
-6
appview/repo/log.go
···
57
57
cursor = strconv.Itoa(offset)
58
58
}
59
59
60
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
61
-
xrpcBytes, err := tangled.RepoLog(r.Context(), xrpcc, cursor, limit, "", ref, repo)
60
+
xrpcBytes, err := tangled.RepoLog(r.Context(), xrpcc, cursor, limit, "", ref, f.RepoIdentifier())
62
61
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
63
62
l.Error("failed to call XRPC repo.log", "err", xrpcerr)
64
63
rp.pages.Error503(w)
···
72
71
return
73
72
}
74
73
75
-
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
74
+
repoId := f.RepoIdentifier()
75
+
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repoId)
76
76
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
77
77
l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
78
78
rp.pages.Error503(w)
···
93
93
}
94
94
}
95
95
96
-
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
96
+
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repoId)
97
97
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
98
98
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
99
99
rp.pages.Error503(w)
···
172
172
Host: host,
173
173
}
174
174
175
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
176
-
xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, repo)
175
+
xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, f.RepoIdentifier())
177
176
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
178
177
l.Error("failed to call XRPC repo.diff", "err", xrpcerr)
179
178
rp.pages.Error503(w)
+128
-55
appview/repo/repo.go
+128
-55
appview/repo/repo.go
···
35
35
atpclient "github.com/bluesky-social/indigo/atproto/client"
36
36
"github.com/bluesky-social/indigo/atproto/syntax"
37
37
lexutil "github.com/bluesky-social/indigo/lex/util"
38
-
securejoin "github.com/cyphar/filepath-securejoin"
38
+
39
39
"github.com/go-chi/chi/v5"
40
40
)
41
41
···
315
315
return
316
316
}
317
317
318
-
err = db.SubscribeLabel(tx, &models.RepoLabel{
318
+
if err = db.SubscribeLabel(tx, &models.RepoLabel{
319
319
RepoAt: f.RepoAt(),
320
320
LabelAt: label.AtUri(),
321
-
})
321
+
RepoDid: f.RepoDid,
322
+
}); err != nil {
323
+
fail("Failed to subscribe to label.", err)
324
+
return
325
+
}
322
326
323
327
err = tx.Commit()
324
328
if err != nil {
···
510
514
err = db.SubscribeLabel(tx, &models.RepoLabel{
511
515
RepoAt: f.RepoAt(),
512
516
LabelAt: syntax.ATURI(l),
517
+
RepoDid: f.RepoDid,
513
518
})
514
519
if err != nil {
515
520
fail("Failed to subscribe to label.", err)
···
752
757
Repo: currentUser.Active.Did,
753
758
Rkey: rkey,
754
759
Record: &lexutil.LexiconTypeDecoder{
755
-
Val: &tangled.RepoCollaborator{
756
-
Subject: collaboratorIdent.DID.String(),
757
-
Repo: string(f.RepoAt()),
758
-
CreatedAt: createdAt.Format(time.RFC3339),
759
-
}},
760
+
Val: repoCollaboratorRecord(f, collaboratorIdent.DID.String(), createdAt),
761
+
},
760
762
})
761
763
// invalid record
762
764
if err != nil {
···
791
793
}
792
794
defer rollback()
793
795
794
-
err = rp.enforcer.AddCollaborator(collaboratorIdent.DID.String(), f.Knot, f.DidSlashRepo())
796
+
err = rp.enforcer.AddCollaborator(collaboratorIdent.DID.String(), f.Knot, f.RepoIdentifier())
795
797
if err != nil {
796
798
fail("Failed to add collaborator permissions.", err)
797
799
return
···
802
804
Rkey: rkey,
803
805
SubjectDid: collaboratorIdent.DID,
804
806
RepoAt: f.RepoAt(),
807
+
RepoDid: f.RepoDid,
805
808
Created: createdAt,
806
809
})
807
810
if err != nil {
···
897
900
}()
898
901
899
902
// remove collaborator RBAC
900
-
repoCollaborators, err := rp.enforcer.E.GetImplicitUsersForResourceByDomain(f.DidSlashRepo(), f.Knot)
903
+
repoCollaborators, err := rp.enforcer.E.GetImplicitUsersForResourceByDomain(f.RepoIdentifier(), f.Knot)
901
904
if err != nil {
902
905
rp.pages.Notice(w, noticeId, "Failed to remove collaborators")
903
906
return
904
907
}
905
908
for _, c := range repoCollaborators {
906
909
did := c[0]
907
-
rp.enforcer.RemoveCollaborator(did, f.Knot, f.DidSlashRepo())
910
+
rp.enforcer.RemoveCollaborator(did, f.Knot, f.RepoIdentifier())
908
911
}
909
912
l.Info("removed collaborators")
910
913
911
914
// remove repo RBAC
912
-
err = rp.enforcer.RemoveRepo(f.Did, f.Knot, f.DidSlashRepo())
915
+
err = rp.enforcer.RemoveRepo(f.Did, f.Knot, f.RepoIdentifier())
913
916
if err != nil {
914
917
rp.pages.Notice(w, noticeId, "Failed to update RBAC rules")
915
918
return
···
1064
1067
uri = "http"
1065
1068
}
1066
1069
1067
-
forkSourceUrl := fmt.Sprintf("%s://%s/%s/%s", uri, f.Knot, f.Did, f.Name)
1070
+
forkSourceUrl := fmt.Sprintf("%s://%s/%s", uri, f.Knot, f.RepoIdentifier())
1068
1071
l = l.With("cloneUrl", forkSourceUrl)
1069
1072
1070
-
sourceAt := f.RepoAt().String()
1071
-
1072
-
// create an atproto record for this fork
1073
1073
rkey := tid.TID()
1074
+
1075
+
// TODO: this could coordinate better with the knot to recieve a clone status
1076
+
client, err := rp.oauth.ServiceClient(
1077
+
r,
1078
+
oauth.WithService(targetKnot),
1079
+
oauth.WithLxm(tangled.RepoCreateNSID),
1080
+
oauth.WithDev(rp.config.Core.Dev),
1081
+
oauth.WithTimeout(time.Second*20),
1082
+
)
1083
+
if err != nil {
1084
+
l.Error("could not create service client", "err", err)
1085
+
rp.pages.Notice(w, "repo", "Failed to connect to knot server.")
1086
+
return
1087
+
}
1088
+
1089
+
forkInput := &tangled.RepoCreate_Input{
1090
+
Rkey: rkey,
1091
+
Name: forkName,
1092
+
Source: &forkSourceUrl,
1093
+
}
1094
+
if rd := strings.TrimSpace(r.FormValue("repo_did")); rd != "" {
1095
+
forkInput.RepoDid = &rd
1096
+
}
1097
+
1098
+
createResp, createErr := tangled.RepoCreate(
1099
+
r.Context(),
1100
+
client,
1101
+
forkInput,
1102
+
)
1103
+
if err := xrpcclient.HandleXrpcErr(createErr); err != nil {
1104
+
rp.pages.Notice(w, "repo", err.Error())
1105
+
return
1106
+
}
1107
+
1108
+
var repoDid string
1109
+
if createResp != nil && createResp.RepoDid != nil {
1110
+
repoDid = *createResp.RepoDid
1111
+
}
1112
+
if repoDid == "" {
1113
+
l.Error("knot returned empty repo DID for fork")
1114
+
rp.pages.Notice(w, "repo", "Knot failed to mint a repo DID. The knot may need to be upgraded.")
1115
+
return
1116
+
}
1117
+
1118
+
forkSource := f.RepoAt().String()
1119
+
if f.RepoDid != "" {
1120
+
forkSource = f.RepoDid
1121
+
}
1122
+
1074
1123
repo := &models.Repo{
1075
1124
Did: user.Active.Did,
1076
1125
Name: forkName,
1077
1126
Knot: targetKnot,
1078
1127
Rkey: rkey,
1079
-
Source: sourceAt,
1128
+
Source: forkSource,
1080
1129
Description: f.Description,
1081
1130
Created: time.Now(),
1082
1131
Labels: rp.config.Label.DefaultLabelDefs,
1132
+
RepoDid: repoDid,
1083
1133
}
1084
1134
record := repo.AsRecord()
1085
1135
1136
+
cleanupKnot := func() {
1137
+
go func() {
1138
+
delays := []time.Duration{0, 2 * time.Second, 5 * time.Second}
1139
+
for attempt, delay := range delays {
1140
+
time.Sleep(delay)
1141
+
deleteClient, dErr := rp.oauth.ServiceClient(
1142
+
r,
1143
+
oauth.WithService(targetKnot),
1144
+
oauth.WithLxm(tangled.RepoDeleteNSID),
1145
+
oauth.WithDev(rp.config.Core.Dev),
1146
+
)
1147
+
if dErr != nil {
1148
+
l.Error("failed to create delete client for knot cleanup", "attempt", attempt+1, "err", dErr)
1149
+
continue
1150
+
}
1151
+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1152
+
if dErr := tangled.RepoDelete(ctx, deleteClient, &tangled.RepoDelete_Input{
1153
+
Did: user.Active.Did,
1154
+
Name: forkName,
1155
+
Rkey: rkey,
1156
+
}); dErr != nil {
1157
+
cancel()
1158
+
l.Error("failed to clean up fork on knot after rollback", "attempt", attempt+1, "err", dErr)
1159
+
continue
1160
+
}
1161
+
cancel()
1162
+
l.Info("successfully cleaned up fork on knot after rollback", "attempt", attempt+1)
1163
+
return
1164
+
}
1165
+
l.Error("exhausted retries for knot cleanup, fork may be orphaned",
1166
+
"did", user.Active.Did, "fork", forkName, "knot", targetKnot)
1167
+
}()
1168
+
}
1169
+
1086
1170
atpClient, err := rp.oauth.AuthorizedClient(r)
1087
1171
if err != nil {
1088
1172
l.Error("failed to create xrpcclient", "err", err)
1173
+
cleanupKnot()
1089
1174
rp.pages.Notice(w, "repo", "Failed to fork repository.")
1090
1175
return
1091
1176
}
···
1100
1185
})
1101
1186
if err != nil {
1102
1187
l.Error("failed to write to PDS", "err", err)
1188
+
cleanupKnot()
1103
1189
rp.pages.Notice(w, "repo", "Failed to announce repository creation.")
1104
1190
return
1105
1191
}
···
1115
1201
return
1116
1202
}
1117
1203
1118
-
// The rollback function reverts a few things on failure:
1119
-
// - the pending txn
1120
-
// - the ACLs
1121
-
// - the atproto record created
1122
1204
rollback := func() {
1123
1205
err1 := tx.Rollback()
1124
1206
err2 := rp.enforcer.E.LoadPolicy()
1125
1207
err3 := rollbackRecord(context.Background(), aturi, atpClient)
1126
1208
1127
-
// ignore txn complete errors, this is okay
1128
1209
if errors.Is(err1, sql.ErrTxDone) {
1129
1210
err1 = nil
1130
1211
}
1131
1212
1132
1213
if errs := errors.Join(err1, err2, err3); errs != nil {
1133
1214
l.Error("failed to rollback changes", "errs", errs)
1134
-
return
1135
1215
}
1136
-
}
1137
-
defer rollback()
1138
-
1139
-
// TODO: this could coordinate better with the knot to recieve a clone status
1140
-
client, err := rp.oauth.ServiceClient(
1141
-
r,
1142
-
oauth.WithService(targetKnot),
1143
-
oauth.WithLxm(tangled.RepoCreateNSID),
1144
-
oauth.WithDev(rp.config.Core.Dev),
1145
-
oauth.WithTimeout(time.Second*20), // big repos take time to clone
1146
-
)
1147
-
if err != nil {
1148
-
l.Error("could not create service client", "err", err)
1149
-
rp.pages.Notice(w, "repo", "Failed to connect to knot server.")
1150
-
return
1151
-
}
1152
1216
1153
-
err = tangled.RepoCreate(
1154
-
r.Context(),
1155
-
client,
1156
-
&tangled.RepoCreate_Input{
1157
-
Rkey: rkey,
1158
-
Source: &forkSourceUrl,
1159
-
},
1160
-
)
1161
-
if err := xrpcclient.HandleXrpcErr(err); err != nil {
1162
-
rp.pages.Notice(w, "repo", err.Error())
1163
-
return
1217
+
if aturi != "" {
1218
+
cleanupKnot()
1219
+
}
1164
1220
}
1221
+
defer rollback()
1165
1222
1166
1223
err = db.AddRepo(tx, repo)
1167
1224
if err != nil {
···
1170
1227
return
1171
1228
}
1172
1229
1173
-
// acls
1174
-
p, _ := securejoin.SecureJoin(user.Active.Did, forkName)
1175
-
err = rp.enforcer.AddRepo(user.Active.Did, targetKnot, p)
1230
+
rbacPath := repo.RepoIdentifier()
1231
+
err = rp.enforcer.AddRepo(user.Active.Did, targetKnot, rbacPath)
1176
1232
if err != nil {
1177
1233
l.Error("failed to add ACLs", "err", err)
1178
1234
rp.pages.Notice(w, "repo", "Failed to set up repository permissions.")
···
1193
1249
return
1194
1250
}
1195
1251
1196
-
// reset the ATURI because the transaction completed successfully
1197
1252
aturi = ""
1198
1253
1199
1254
rp.notifier.NewRepo(r.Context(), repo)
1200
-
rp.pages.HxLocation(w, fmt.Sprintf("/%s/%s", user.Active.Did, forkName))
1255
+
if repoDid != "" {
1256
+
rp.pages.HxLocation(w, fmt.Sprintf("/%s", repoDid))
1257
+
} else {
1258
+
rp.pages.HxLocation(w, fmt.Sprintf("/%s/%s", user.Active.Did, forkName))
1259
+
}
1201
1260
}
1202
1261
}
1203
1262
···
1222
1281
})
1223
1282
return err
1224
1283
}
1284
+
1285
+
func repoCollaboratorRecord(f *models.Repo, subject string, createdAt time.Time) *tangled.RepoCollaborator {
1286
+
rec := &tangled.RepoCollaborator{
1287
+
Subject: subject,
1288
+
CreatedAt: createdAt.Format(time.RFC3339),
1289
+
}
1290
+
if f.RepoDid != "" {
1291
+
rec.RepoDid = &f.RepoDid
1292
+
} else {
1293
+
s := string(f.RepoAt())
1294
+
rec.Repo = &s
1295
+
}
1296
+
return rec
1297
+
}
+8
-9
appview/repo/settings.go
+8
-9
appview/repo/settings.go
···
293
293
// Skip entirely if there is no active domain claim — the site cannot be served anyway.
294
294
ownerClaim, _ := db.GetActiveDomainClaimForDid(rp.db, f.Did)
295
295
if ownerClaim == nil {
296
-
rp.logger.Info("skipping deploy: no active domain claim", "repo", f.DidSlashRepo())
296
+
rp.logger.Info("skipping deploy: no active domain claim", "repo", f.RepoIdentifier())
297
297
} else if rp.cfClient.Enabled() {
298
298
scheme := "http"
299
299
if !rp.config.Core.Dev {
···
313
313
314
314
deployErr := sites.Deploy(ctx, rp.cfClient, knotHost, f.Did, f.Name, branch, dir)
315
315
if deployErr != nil {
316
-
l.Error("sites: initial R2 sync failed", "repo", f.DidSlashRepo(), "err", deployErr)
316
+
l.Error("sites: initial R2 sync failed", "repo", f.RepoIdentifier(), "err", deployErr)
317
317
deploy.Status = models.SiteDeployStatusFailure
318
318
deploy.Error = deployErr.Error()
319
319
} else {
···
321
321
}
322
322
323
323
if err := db.AddSiteDeploy(rp.db, deploy); err != nil {
324
-
l.Error("sites: failed to record deploy", "repo", f.DidSlashRepo(), "err", err)
324
+
l.Error("sites: failed to record deploy", "repo", f.RepoIdentifier(), "err", err)
325
325
}
326
326
327
327
if deployErr == nil {
328
328
if err := sites.PutDomainMapping(ctx, rp.cfClient, ownerClaim.Domain, f.Did, f.Name, isIndex); err != nil {
329
329
l.Error("sites: KV write failed", "domain", ownerClaim.Domain, "err", err)
330
330
}
331
-
rp.logger.Info("site deployed to r2", "repo", f.DidSlashRepo(), "is_index", isIndex)
331
+
rp.logger.Info("site deployed to r2", "repo", f.RepoIdentifier(), "is_index", isIndex)
332
332
}
333
333
}()
334
334
} else {
335
-
rp.logger.Warn("cloudflare integration is disabled; site won't be deployed", "repo", f.DidSlashRepo())
335
+
rp.logger.Warn("cloudflare integration is disabled; site won't be deployed", "repo", f.RepoIdentifier())
336
336
}
337
337
338
338
rp.pages.HxRefresh(w)
···
367
367
go func() {
368
368
ctx := context.Background()
369
369
if err := sites.Delete(ctx, rp.cfClient, f.Did, f.Name); err != nil {
370
-
l.Error("sites: R2 delete failed", "repo", f.DidSlashRepo(), "err", err)
370
+
l.Error("sites: R2 delete failed", "repo", f.RepoIdentifier(), "err", err)
371
371
}
372
372
if ownerClaim != nil {
373
373
if err := sites.DeleteDomainMapping(ctx, rp.cfClient, ownerClaim.Domain, f.Name); err != nil {
···
395
395
Host: host,
396
396
}
397
397
398
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
399
-
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
398
+
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, f.RepoIdentifier())
400
399
var result types.RepoBranchesResponse
401
400
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
402
401
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
···
467
466
user := rp.oauth.GetMultiAccountUser(r)
468
467
469
468
collaborators, err := func(repo *models.Repo) ([]pages.Collaborator, error) {
470
-
repoCollaborators, err := rp.enforcer.E.GetImplicitUsersForResourceByDomain(repo.DidSlashRepo(), repo.Knot)
469
+
repoCollaborators, err := rp.enforcer.E.GetImplicitUsersForResourceByDomain(repo.RepoIdentifier(), repo.Knot)
471
470
if err != nil {
472
471
return nil, err
473
472
}
+1
-2
appview/repo/tree.go
+1
-2
appview/repo/tree.go
···
41
41
xrpcc := &indigoxrpc.Client{
42
42
Host: host,
43
43
}
44
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
45
-
xrpcResp, err := tangled.RepoTree(r.Context(), xrpcc, treePath, ref, repo)
44
+
xrpcResp, err := tangled.RepoTree(r.Context(), xrpcc, treePath, ref, f.RepoIdentifier())
46
45
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
47
46
l.Error("failed to call XRPC repo.tree", "err", xrpcerr)
48
47
rp.pages.Error503(w)
+6
-5
appview/repo/webhooks.go
+6
-5
appview/repo/webhooks.go
···
89
89
}
90
90
91
91
webhook := &models.Webhook{
92
-
RepoAt: f.RepoAt(),
93
-
Url: url,
94
-
Secret: secret,
95
-
Active: active,
96
-
Events: events,
92
+
RepoAt: f.RepoAt(),
93
+
RepoDid: f.RepoDid,
94
+
Url: url,
95
+
Secret: secret,
96
+
Active: active,
97
+
Events: events,
97
98
}
98
99
99
100
tx, err := rp.db.Begin()
History
9 rounds
2 comments
oyster.cafe
submitted
#8
1 commit
expand
collapse
appview: update repo, pulls, issues, and pages handlers for repo DID
Signed-off-by: Lewis <lewis@tangled.org>
expand 2 comments
I'll do some cutting then let you know! :p
This pull has been deleted (possibly by jj abandon or jj squash)
oyster.cafe
submitted
#7
1 commit
expand
collapse
appview: update repo, pulls, issues, and pages handlers for repo DID
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#6
1 commit
expand
collapse
appview: update repo, pulls, issues, and pages handlers for repo DID
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#5
1 commit
expand
collapse
appview: update repo, pulls, issues, and pages handlers for repo DID
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#4
1 commit
expand
collapse
appview: update repo, pulls, issues, and pages handlers for repo DID
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#3
1 commit
expand
collapse
appview: update repo, pulls, issues, and pages handlers for repo DID
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#2
1 commit
expand
collapse
appview: update repo, pulls, issues, and pages handlers for repo DID
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#1
1 commit
expand
collapse
appview: update repo, pulls, issues, and pages handlers for repo DID
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#0
1 commit
expand
collapse
appview: update repo, pulls, issues, and pages handlers for repo DID
Signed-off-by: Lewis <lewis@tangled.org>
Uh, in general I want to abandon like half of the stacks. I should've be more clear on this at first place.
Appview doesn't need to know about repo-did situation in most of the cases yet. If
repoDidis optional value, there is no reason to use it. Appview still has to support legacy at-uri based connection, so I'd suggest to not introduce extra behavior on referencing and only use repo-did when performing the repository migration. We don't need to touch any tables except therepositself.Appview will
sh.tangled.reporecords,repostable,No need to change other data.