Signed-off-by: Seongmin Lee git@boltless.me
+47
-49
appview/pulls/pulls.go
+47
-49
appview/pulls/pulls.go
···
115
return
116
}
117
118
-
mergeCheckResponse := s.mergeCheck(r, f, pull, stack)
119
-
branchDeleteStatus := s.branchDeleteStatus(r, f, pull)
120
resubmitResult := pages.Unknown
121
if user.Did == pull.OwnerDid {
122
-
resubmitResult = s.resubmitCheck(r, f, pull, stack)
123
}
124
125
s.pages.PullActionsFragment(w, pages.PullActionsParams{
···
155
stack, _ := r.Context().Value("stack").(models.Stack)
156
abandonedPulls, _ := r.Context().Value("abandonedPulls").([]*models.Pull)
157
158
-
mergeCheckResponse := s.mergeCheck(r, f, pull, stack)
159
-
branchDeleteStatus := s.branchDeleteStatus(r, f, pull)
160
resubmitResult := pages.Unknown
161
if user != nil && user.Did == pull.OwnerDid {
162
-
resubmitResult = s.resubmitCheck(r, f, pull, stack)
163
}
164
165
m := make(map[string]models.Pipeline)
···
237
})
238
}
239
240
-
func (s *Pulls) mergeCheck(r *http.Request, f *reporesolver.ResolvedRepo, pull *models.Pull, stack models.Stack) types.MergeCheckResponse {
241
if pull.State == models.PullMerged {
242
return types.MergeCheckResponse{}
243
}
···
304
return result
305
}
306
307
-
func (s *Pulls) branchDeleteStatus(r *http.Request, f *reporesolver.ResolvedRepo, pull *models.Pull) *models.BranchDeleteStatus {
308
if pull.State != models.PullMerged {
309
return nil
310
}
···
315
}
316
317
var branch string
318
-
var repo *models.Repo
319
// check if the branch exists
320
// NOTE: appview could cache branches/tags etc. for every repo by listening for gitRefUpdates
321
if pull.IsBranchBased() {
322
branch = pull.PullSource.Branch
323
-
repo = &f.Repo
324
} else if pull.IsForkBased() {
325
branch = pull.PullSource.Branch
326
repo = pull.PullSource.Repo
···
359
}
360
}
361
362
-
func (s *Pulls) resubmitCheck(r *http.Request, f *reporesolver.ResolvedRepo, pull *models.Pull, stack models.Stack) pages.ResubmitResult {
363
if pull.State == models.PullMerged || pull.State == models.PullDeleted || pull.PullSource == nil {
364
return pages.Unknown
365
}
···
379
repoName = sourceRepo.Name
380
} else {
381
// pulls within the same repo
382
-
knot = f.Knot
383
-
ownerDid = f.Did
384
-
repoName = f.Name
385
}
386
387
scheme := "http"
···
393
Host: host,
394
}
395
396
-
repo := fmt.Sprintf("%s/%s", ownerDid, repoName)
397
-
branchResp, err := tangled.RepoBranch(r.Context(), xrpcc, pull.PullSource.Branch, repo)
398
if err != nil {
399
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
400
log.Println("failed to call XRPC repo.branches", xrpcerr)
···
951
s.pages.Notice(w, "pull", "This knot doesn't support branch-based pull requests. Try another way?")
952
return
953
}
954
-
s.handleBranchBasedPull(w, r, f, user, title, body, targetBranch, sourceBranch, isStacked)
955
} else if isForkBased {
956
if !caps.PullRequests.ForkSubmissions {
957
s.pages.Notice(w, "pull", "This knot doesn't support fork-based pull requests. Try another way?")
958
return
959
}
960
-
s.handleForkBasedPull(w, r, f, user, fromFork, title, body, targetBranch, sourceBranch, isStacked)
961
} else if isPatchBased {
962
if !caps.PullRequests.PatchSubmissions {
963
s.pages.Notice(w, "pull", "This knot doesn't support patch-based pull requests. Send your patch over email.")
964
return
965
}
966
-
s.handlePatchBasedPull(w, r, f, user, title, body, targetBranch, patch, isStacked)
967
}
968
return
969
}
···
972
func (s *Pulls) handleBranchBasedPull(
973
w http.ResponseWriter,
974
r *http.Request,
975
-
f *reporesolver.ResolvedRepo,
976
user *oauth.User,
977
title,
978
body,
···
984
if !s.config.Core.Dev {
985
scheme = "https"
986
}
987
-
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
988
xrpcc := &indigoxrpc.Client{
989
Host: host,
990
}
991
992
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
993
-
xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, targetBranch, sourceBranch)
994
if err != nil {
995
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
996
log.Println("failed to call XRPC repo.compare", xrpcerr)
···
1027
Sha: comparison.Rev2,
1028
}
1029
1030
-
s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, combined, sourceRev, pullSource, recordPullSource, isStacked)
1031
}
1032
1033
-
func (s *Pulls) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, f *reporesolver.ResolvedRepo, user *oauth.User, title, body, targetBranch, patch string, isStacked bool) {
1034
if err := s.validator.ValidatePatch(&patch); err != nil {
1035
s.logger.Error("patch validation failed", "err", err)
1036
s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.")
1037
return
1038
}
1039
1040
-
s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, "", "", nil, nil, isStacked)
1041
}
1042
1043
-
func (s *Pulls) handleForkBasedPull(w http.ResponseWriter, r *http.Request, f *reporesolver.ResolvedRepo, user *oauth.User, forkRepo string, title, body, targetBranch, sourceBranch string, isStacked bool) {
1044
repoString := strings.SplitN(forkRepo, "/", 2)
1045
forkOwnerDid := repoString[0]
1046
repoName := repoString[1]
···
1142
Sha: sourceRev,
1143
}
1144
1145
-
s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, combined, sourceRev, pullSource, recordPullSource, isStacked)
1146
}
1147
1148
func (s *Pulls) createPullRequest(
1149
w http.ResponseWriter,
1150
r *http.Request,
1151
-
f *reporesolver.ResolvedRepo,
1152
user *oauth.User,
1153
title, body, targetBranch string,
1154
patch string,
···
1163
s.createStackedPullRequest(
1164
w,
1165
r,
1166
-
f,
1167
user,
1168
targetBranch,
1169
patch,
···
1220
Body: body,
1221
TargetBranch: targetBranch,
1222
OwnerDid: user.Did,
1223
-
RepoAt: f.RepoAt(),
1224
Rkey: rkey,
1225
Submissions: []*models.PullSubmission{
1226
&initialSubmission,
···
1233
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
1234
return
1235
}
1236
-
pullId, err := db.NextPullId(tx, f.RepoAt())
1237
if err != nil {
1238
log.Println("failed to get pull id", err)
1239
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···
1248
Val: &tangled.RepoPull{
1249
Title: title,
1250
Target: &tangled.RepoPull_Target{
1251
-
Repo: string(f.RepoAt()),
1252
Branch: targetBranch,
1253
},
1254
Patch: patch,
···
1271
1272
s.notifier.NewPull(r.Context(), pull)
1273
1274
-
ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo)
1275
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pullId))
1276
}
1277
1278
func (s *Pulls) createStackedPullRequest(
1279
w http.ResponseWriter,
1280
r *http.Request,
1281
-
f *reporesolver.ResolvedRepo,
1282
user *oauth.User,
1283
targetBranch string,
1284
patch string,
···
1310
1311
// build a stack out of this patch
1312
stackId := uuid.New()
1313
-
stack, err := newStack(f, user, targetBranch, patch, pullSource, stackId.String())
1314
if err != nil {
1315
log.Println("failed to create stack", err)
1316
s.pages.Notice(w, "pull", fmt.Sprintf("Failed to create stack: %v", err))
···
1373
return
1374
}
1375
1376
-
ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo)
1377
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls", ownerSlashRepo))
1378
}
1379
···
1645
1646
patch := r.FormValue("patch")
1647
1648
-
s.resubmitPullHelper(w, r, f, user, pull, patch, "", "")
1649
}
1650
1651
func (s *Pulls) resubmitBranch(w http.ResponseWriter, r *http.Request) {
···
1710
patch := comparison.FormatPatchRaw
1711
combined := comparison.CombinedPatchRaw
1712
1713
-
s.resubmitPullHelper(w, r, f, user, pull, patch, combined, sourceRev)
1714
}
1715
1716
func (s *Pulls) resubmitFork(w http.ResponseWriter, r *http.Request) {
···
1807
patch := comparison.FormatPatchRaw
1808
combined := comparison.CombinedPatchRaw
1809
1810
-
s.resubmitPullHelper(w, r, f, user, pull, patch, combined, sourceRev)
1811
}
1812
1813
func (s *Pulls) resubmitPullHelper(
1814
w http.ResponseWriter,
1815
r *http.Request,
1816
-
f *reporesolver.ResolvedRepo,
1817
user *oauth.User,
1818
pull *models.Pull,
1819
patch string,
···
1822
) {
1823
if pull.IsStacked() {
1824
log.Println("resubmitting stacked PR")
1825
-
s.resubmitStackedPullHelper(w, r, f, user, pull, patch, pull.StackId)
1826
return
1827
}
1828
···
1902
Val: &tangled.RepoPull{
1903
Title: pull.Title,
1904
Target: &tangled.RepoPull_Target{
1905
-
Repo: string(f.RepoAt()),
1906
Branch: pull.TargetBranch,
1907
},
1908
Patch: patch, // new patch
···
1923
return
1924
}
1925
1926
-
ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo)
1927
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
1928
}
1929
1930
func (s *Pulls) resubmitStackedPullHelper(
1931
w http.ResponseWriter,
1932
r *http.Request,
1933
-
f *reporesolver.ResolvedRepo,
1934
user *oauth.User,
1935
pull *models.Pull,
1936
patch string,
···
1939
targetBranch := pull.TargetBranch
1940
1941
origStack, _ := r.Context().Value("stack").(models.Stack)
1942
-
newStack, err := newStack(f, user, targetBranch, patch, pull.PullSource, stackId)
1943
if err != nil {
1944
log.Println("failed to create resubmitted stack", err)
1945
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
···
2117
return
2118
}
2119
2120
-
ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo)
2121
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
2122
}
2123
···
2387
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
2388
}
2389
2390
-
func newStack(f *reporesolver.ResolvedRepo, user *oauth.User, targetBranch, patch string, pullSource *models.PullSource, stackId string) (models.Stack, error) {
2391
formatPatches, err := patchutil.ExtractPatches(patch)
2392
if err != nil {
2393
return nil, fmt.Errorf("Failed to extract patches: %v", err)
···
2422
Body: body,
2423
TargetBranch: targetBranch,
2424
OwnerDid: user.Did,
2425
-
RepoAt: f.RepoAt(),
2426
Rkey: rkey,
2427
Submissions: []*models.PullSubmission{
2428
&initialSubmission,
···
115
return
116
}
117
118
+
mergeCheckResponse := s.mergeCheck(r, &f.Repo, pull, stack)
119
+
branchDeleteStatus := s.branchDeleteStatus(r, &f.Repo, pull)
120
resubmitResult := pages.Unknown
121
if user.Did == pull.OwnerDid {
122
+
resubmitResult = s.resubmitCheck(r, &f.Repo, pull, stack)
123
}
124
125
s.pages.PullActionsFragment(w, pages.PullActionsParams{
···
155
stack, _ := r.Context().Value("stack").(models.Stack)
156
abandonedPulls, _ := r.Context().Value("abandonedPulls").([]*models.Pull)
157
158
+
mergeCheckResponse := s.mergeCheck(r, &f.Repo, pull, stack)
159
+
branchDeleteStatus := s.branchDeleteStatus(r, &f.Repo, pull)
160
resubmitResult := pages.Unknown
161
if user != nil && user.Did == pull.OwnerDid {
162
+
resubmitResult = s.resubmitCheck(r, &f.Repo, pull, stack)
163
}
164
165
m := make(map[string]models.Pipeline)
···
237
})
238
}
239
240
+
func (s *Pulls) mergeCheck(r *http.Request, f *models.Repo, pull *models.Pull, stack models.Stack) types.MergeCheckResponse {
241
if pull.State == models.PullMerged {
242
return types.MergeCheckResponse{}
243
}
···
304
return result
305
}
306
307
+
func (s *Pulls) branchDeleteStatus(r *http.Request, repo *models.Repo, pull *models.Pull) *models.BranchDeleteStatus {
308
if pull.State != models.PullMerged {
309
return nil
310
}
···
315
}
316
317
var branch string
318
// check if the branch exists
319
// NOTE: appview could cache branches/tags etc. for every repo by listening for gitRefUpdates
320
if pull.IsBranchBased() {
321
branch = pull.PullSource.Branch
322
} else if pull.IsForkBased() {
323
branch = pull.PullSource.Branch
324
repo = pull.PullSource.Repo
···
357
}
358
}
359
360
+
func (s *Pulls) resubmitCheck(r *http.Request, repo *models.Repo, pull *models.Pull, stack models.Stack) pages.ResubmitResult {
361
if pull.State == models.PullMerged || pull.State == models.PullDeleted || pull.PullSource == nil {
362
return pages.Unknown
363
}
···
377
repoName = sourceRepo.Name
378
} else {
379
// pulls within the same repo
380
+
knot = repo.Knot
381
+
ownerDid = repo.Did
382
+
repoName = repo.Name
383
}
384
385
scheme := "http"
···
391
Host: host,
392
}
393
394
+
didSlashName := fmt.Sprintf("%s/%s", ownerDid, repoName)
395
+
branchResp, err := tangled.RepoBranch(r.Context(), xrpcc, pull.PullSource.Branch, didSlashName)
396
if err != nil {
397
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
398
log.Println("failed to call XRPC repo.branches", xrpcerr)
···
949
s.pages.Notice(w, "pull", "This knot doesn't support branch-based pull requests. Try another way?")
950
return
951
}
952
+
s.handleBranchBasedPull(w, r, &f.Repo, user, title, body, targetBranch, sourceBranch, isStacked)
953
} else if isForkBased {
954
if !caps.PullRequests.ForkSubmissions {
955
s.pages.Notice(w, "pull", "This knot doesn't support fork-based pull requests. Try another way?")
956
return
957
}
958
+
s.handleForkBasedPull(w, r, &f.Repo, user, fromFork, title, body, targetBranch, sourceBranch, isStacked)
959
} else if isPatchBased {
960
if !caps.PullRequests.PatchSubmissions {
961
s.pages.Notice(w, "pull", "This knot doesn't support patch-based pull requests. Send your patch over email.")
962
return
963
}
964
+
s.handlePatchBasedPull(w, r, &f.Repo, user, title, body, targetBranch, patch, isStacked)
965
}
966
return
967
}
···
970
func (s *Pulls) handleBranchBasedPull(
971
w http.ResponseWriter,
972
r *http.Request,
973
+
repo *models.Repo,
974
user *oauth.User,
975
title,
976
body,
···
982
if !s.config.Core.Dev {
983
scheme = "https"
984
}
985
+
host := fmt.Sprintf("%s://%s", scheme, repo.Knot)
986
xrpcc := &indigoxrpc.Client{
987
Host: host,
988
}
989
990
+
didSlashRepo := fmt.Sprintf("%s/%s", repo.Did, repo.Name)
991
+
xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, didSlashRepo, targetBranch, sourceBranch)
992
if err != nil {
993
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
994
log.Println("failed to call XRPC repo.compare", xrpcerr)
···
1025
Sha: comparison.Rev2,
1026
}
1027
1028
+
s.createPullRequest(w, r, repo, user, title, body, targetBranch, patch, combined, sourceRev, pullSource, recordPullSource, isStacked)
1029
}
1030
1031
+
func (s *Pulls) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, repo *models.Repo, user *oauth.User, title, body, targetBranch, patch string, isStacked bool) {
1032
if err := s.validator.ValidatePatch(&patch); err != nil {
1033
s.logger.Error("patch validation failed", "err", err)
1034
s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.")
1035
return
1036
}
1037
1038
+
s.createPullRequest(w, r, repo, user, title, body, targetBranch, patch, "", "", nil, nil, isStacked)
1039
}
1040
1041
+
func (s *Pulls) handleForkBasedPull(w http.ResponseWriter, r *http.Request, repo *models.Repo, user *oauth.User, forkRepo string, title, body, targetBranch, sourceBranch string, isStacked bool) {
1042
repoString := strings.SplitN(forkRepo, "/", 2)
1043
forkOwnerDid := repoString[0]
1044
repoName := repoString[1]
···
1140
Sha: sourceRev,
1141
}
1142
1143
+
s.createPullRequest(w, r, repo, user, title, body, targetBranch, patch, combined, sourceRev, pullSource, recordPullSource, isStacked)
1144
}
1145
1146
func (s *Pulls) createPullRequest(
1147
w http.ResponseWriter,
1148
r *http.Request,
1149
+
repo *models.Repo,
1150
user *oauth.User,
1151
title, body, targetBranch string,
1152
patch string,
···
1161
s.createStackedPullRequest(
1162
w,
1163
r,
1164
+
repo,
1165
user,
1166
targetBranch,
1167
patch,
···
1218
Body: body,
1219
TargetBranch: targetBranch,
1220
OwnerDid: user.Did,
1221
+
RepoAt: repo.RepoAt(),
1222
Rkey: rkey,
1223
Submissions: []*models.PullSubmission{
1224
&initialSubmission,
···
1231
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
1232
return
1233
}
1234
+
pullId, err := db.NextPullId(tx, repo.RepoAt())
1235
if err != nil {
1236
log.Println("failed to get pull id", err)
1237
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···
1246
Val: &tangled.RepoPull{
1247
Title: title,
1248
Target: &tangled.RepoPull_Target{
1249
+
Repo: string(repo.RepoAt()),
1250
Branch: targetBranch,
1251
},
1252
Patch: patch,
···
1269
1270
s.notifier.NewPull(r.Context(), pull)
1271
1272
+
ownerSlashRepo := reporesolver.GetBaseRepoPath(r, repo)
1273
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pullId))
1274
}
1275
1276
func (s *Pulls) createStackedPullRequest(
1277
w http.ResponseWriter,
1278
r *http.Request,
1279
+
repo *models.Repo,
1280
user *oauth.User,
1281
targetBranch string,
1282
patch string,
···
1308
1309
// build a stack out of this patch
1310
stackId := uuid.New()
1311
+
stack, err := newStack(repo, user, targetBranch, patch, pullSource, stackId.String())
1312
if err != nil {
1313
log.Println("failed to create stack", err)
1314
s.pages.Notice(w, "pull", fmt.Sprintf("Failed to create stack: %v", err))
···
1371
return
1372
}
1373
1374
+
ownerSlashRepo := reporesolver.GetBaseRepoPath(r, repo)
1375
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls", ownerSlashRepo))
1376
}
1377
···
1643
1644
patch := r.FormValue("patch")
1645
1646
+
s.resubmitPullHelper(w, r, &f.Repo, user, pull, patch, "", "")
1647
}
1648
1649
func (s *Pulls) resubmitBranch(w http.ResponseWriter, r *http.Request) {
···
1708
patch := comparison.FormatPatchRaw
1709
combined := comparison.CombinedPatchRaw
1710
1711
+
s.resubmitPullHelper(w, r, &f.Repo, user, pull, patch, combined, sourceRev)
1712
}
1713
1714
func (s *Pulls) resubmitFork(w http.ResponseWriter, r *http.Request) {
···
1805
patch := comparison.FormatPatchRaw
1806
combined := comparison.CombinedPatchRaw
1807
1808
+
s.resubmitPullHelper(w, r, &f.Repo, user, pull, patch, combined, sourceRev)
1809
}
1810
1811
func (s *Pulls) resubmitPullHelper(
1812
w http.ResponseWriter,
1813
r *http.Request,
1814
+
repo *models.Repo,
1815
user *oauth.User,
1816
pull *models.Pull,
1817
patch string,
···
1820
) {
1821
if pull.IsStacked() {
1822
log.Println("resubmitting stacked PR")
1823
+
s.resubmitStackedPullHelper(w, r, repo, user, pull, patch, pull.StackId)
1824
return
1825
}
1826
···
1900
Val: &tangled.RepoPull{
1901
Title: pull.Title,
1902
Target: &tangled.RepoPull_Target{
1903
+
Repo: string(repo.RepoAt()),
1904
Branch: pull.TargetBranch,
1905
},
1906
Patch: patch, // new patch
···
1921
return
1922
}
1923
1924
+
ownerSlashRepo := reporesolver.GetBaseRepoPath(r, repo)
1925
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
1926
}
1927
1928
func (s *Pulls) resubmitStackedPullHelper(
1929
w http.ResponseWriter,
1930
r *http.Request,
1931
+
repo *models.Repo,
1932
user *oauth.User,
1933
pull *models.Pull,
1934
patch string,
···
1937
targetBranch := pull.TargetBranch
1938
1939
origStack, _ := r.Context().Value("stack").(models.Stack)
1940
+
newStack, err := newStack(repo, user, targetBranch, patch, pull.PullSource, stackId)
1941
if err != nil {
1942
log.Println("failed to create resubmitted stack", err)
1943
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
···
2115
return
2116
}
2117
2118
+
ownerSlashRepo := reporesolver.GetBaseRepoPath(r, repo)
2119
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
2120
}
2121
···
2385
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
2386
}
2387
2388
+
func newStack(repo *models.Repo, user *oauth.User, targetBranch, patch string, pullSource *models.PullSource, stackId string) (models.Stack, error) {
2389
formatPatches, err := patchutil.ExtractPatches(patch)
2390
if err != nil {
2391
return nil, fmt.Errorf("Failed to extract patches: %v", err)
···
2420
Body: body,
2421
TargetBranch: targetBranch,
2422
OwnerDid: user.Did,
2423
+
RepoAt: repo.RepoAt(),
2424
Rkey: rkey,
2425
Submissions: []*models.PullSubmission{
2426
&initialSubmission,
+3
-4
appview/repo/artifact.go
+3
-4
appview/repo/artifact.go
···
14
"tangled.org/core/appview/db"
15
"tangled.org/core/appview/models"
16
"tangled.org/core/appview/pages"
17
-
"tangled.org/core/appview/reporesolver"
18
"tangled.org/core/appview/xrpcclient"
19
"tangled.org/core/tid"
20
"tangled.org/core/types"
···
39
return
40
}
41
42
-
tag, err := rp.resolveTag(r.Context(), f, tagParam)
43
if err != nil {
44
log.Println("failed to resolve tag", err)
45
rp.pages.Notice(w, "upload", "failed to upload artifact, error in tag resolution")
···
147
tagParam := chi.URLParam(r, "tag")
148
filename := chi.URLParam(r, "file")
149
150
-
tag, err := rp.resolveTag(r.Context(), f, tagParam)
151
if err != nil {
152
log.Println("failed to resolve tag", err)
153
rp.pages.Notice(w, "upload", "failed to upload artifact, error in tag resolution")
···
290
w.Write([]byte{})
291
}
292
293
-
func (rp *Repo) resolveTag(ctx context.Context, f *reporesolver.ResolvedRepo, tagParam string) (*types.TagReference, error) {
294
tagParam, err := url.QueryUnescape(tagParam)
295
if err != nil {
296
return nil, err
···
14
"tangled.org/core/appview/db"
15
"tangled.org/core/appview/models"
16
"tangled.org/core/appview/pages"
17
"tangled.org/core/appview/xrpcclient"
18
"tangled.org/core/tid"
19
"tangled.org/core/types"
···
38
return
39
}
40
41
+
tag, err := rp.resolveTag(r.Context(), &f.Repo, tagParam)
42
if err != nil {
43
log.Println("failed to resolve tag", err)
44
rp.pages.Notice(w, "upload", "failed to upload artifact, error in tag resolution")
···
146
tagParam := chi.URLParam(r, "tag")
147
filename := chi.URLParam(r, "file")
148
149
+
tag, err := rp.resolveTag(r.Context(), &f.Repo, tagParam)
150
if err != nil {
151
log.Println("failed to resolve tag", err)
152
rp.pages.Notice(w, "upload", "failed to upload artifact, error in tag resolution")
···
289
w.Write([]byte{})
290
}
291
292
+
func (rp *Repo) resolveTag(ctx context.Context, f *models.Repo, tagParam string) (*types.TagReference, error) {
293
tagParam, err := url.QueryUnescape(tagParam)
294
if err != nil {
295
return nil, err
+6
-6
appview/repo/blob.go
+6
-6
appview/repo/blob.go
···
74
}
75
76
// Create the blob view
77
-
blobView := NewBlobView(resp, rp.config, f, ref, filePath, r.URL.Query())
78
79
user := rp.oauth.GetUser(r)
80
···
178
}
179
180
// NewBlobView creates a BlobView from the XRPC response
181
-
func NewBlobView(resp *tangled.RepoBlob_Output, config *config.Config, f *reporesolver.ResolvedRepo, ref, filePath string, queryParams url.Values) models.BlobView {
182
view := models.BlobView{
183
Contents: "",
184
Lines: 0,
···
200
201
// Determine if binary
202
if resp.IsBinary != nil && *resp.IsBinary {
203
-
view.ContentSrc = generateBlobURL(config, f, ref, filePath)
204
ext := strings.ToLower(filepath.Ext(resp.Path))
205
206
switch ext {
···
252
return view
253
}
254
255
-
func generateBlobURL(config *config.Config, f *reporesolver.ResolvedRepo, ref, filePath string) string {
256
scheme := "http"
257
if !config.Core.Dev {
258
scheme = "https"
259
}
260
261
-
repoName := fmt.Sprintf("%s/%s", f.Did, f.Name)
262
baseURL := &url.URL{
263
Scheme: scheme,
264
-
Host: f.Knot,
265
Path: "/xrpc/sh.tangled.repo.blob",
266
}
267
query := baseURL.Query()
···
74
}
75
76
// Create the blob view
77
+
blobView := NewBlobView(resp, rp.config, &f.Repo, ref, filePath, r.URL.Query())
78
79
user := rp.oauth.GetUser(r)
80
···
178
}
179
180
// NewBlobView creates a BlobView from the XRPC response
181
+
func NewBlobView(resp *tangled.RepoBlob_Output, config *config.Config, repo *models.Repo, ref, filePath string, queryParams url.Values) models.BlobView {
182
view := models.BlobView{
183
Contents: "",
184
Lines: 0,
···
200
201
// Determine if binary
202
if resp.IsBinary != nil && *resp.IsBinary {
203
+
view.ContentSrc = generateBlobURL(config, repo, ref, filePath)
204
ext := strings.ToLower(filepath.Ext(resp.Path))
205
206
switch ext {
···
252
return view
253
}
254
255
+
func generateBlobURL(config *config.Config, repo *models.Repo, ref, filePath string) string {
256
scheme := "http"
257
if !config.Core.Dev {
258
scheme = "https"
259
}
260
261
+
repoName := fmt.Sprintf("%s/%s", repo.Did, repo.Name)
262
baseURL := &url.URL{
263
Scheme: scheme,
264
+
Host: repo.Knot,
265
Path: "/xrpc/sh.tangled.repo.blob",
266
}
267
query := baseURL.Query()
+14
-14
appview/repo/index.go
+14
-14
appview/repo/index.go
···
54
user := rp.oauth.GetUser(r)
55
56
// Build index response from multiple XRPC calls
57
-
result, err := rp.buildIndexResponse(r.Context(), xrpcc, f, ref)
58
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
59
if errors.Is(xrpcerr, xrpcclient.ErrXrpcUnsupported) {
60
l.Error("failed to call XRPC repo.index", "err", err)
···
129
}
130
131
// TODO: a bit dirty
132
-
languageInfo, err := rp.getLanguageInfo(r.Context(), l, f, xrpcc, result.Ref, ref == "")
133
if err != nil {
134
l.Warn("failed to compute language percentages", "err", err)
135
// non-fatal
···
164
func (rp *Repo) getLanguageInfo(
165
ctx context.Context,
166
l *slog.Logger,
167
-
f *reporesolver.ResolvedRepo,
168
xrpcc *indigoxrpc.Client,
169
currentRef string,
170
isDefaultRef bool,
···
172
// first attempt to fetch from db
173
langs, err := db.GetRepoLanguages(
174
rp.db,
175
-
db.FilterEq("repo_at", f.RepoAt()),
176
db.FilterEq("ref", currentRef),
177
)
178
179
if err != nil || langs == nil {
180
// non-fatal, fetch langs from ks via XRPC
181
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
182
-
ls, err := tangled.RepoLanguages(ctx, xrpcc, currentRef, repo)
183
if err != nil {
184
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
185
l.Error("failed to call XRPC repo.languages", "err", xrpcerr)
···
194
195
for _, lang := range ls.Languages {
196
langs = append(langs, models.RepoLanguage{
197
-
RepoAt: f.RepoAt(),
198
Ref: currentRef,
199
IsDefaultRef: isDefaultRef,
200
Language: lang.Name,
···
209
defer tx.Rollback()
210
211
// update appview's cache
212
-
err = db.UpdateRepoLanguages(tx, f.RepoAt(), currentRef, langs)
213
if err != nil {
214
// non-fatal
215
l.Error("failed to cache lang results", "err", err)
···
254
}
255
256
// buildIndexResponse creates a RepoIndexResponse by combining multiple xrpc calls in parallel
257
-
func (rp *Repo) buildIndexResponse(ctx context.Context, xrpcc *indigoxrpc.Client, f *reporesolver.ResolvedRepo, ref string) (*types.RepoIndexResponse, error) {
258
-
repo := fmt.Sprintf("%s/%s", f.Did, f.Name)
259
260
// first get branches to determine the ref if not specified
261
-
branchesBytes, err := tangled.RepoBranches(ctx, xrpcc, "", 0, repo)
262
if err != nil {
263
return nil, fmt.Errorf("failed to call repoBranches: %w", err)
264
}
···
302
wg.Add(1)
303
go func() {
304
defer wg.Done()
305
-
tagsBytes, err := tangled.RepoTags(ctx, xrpcc, "", 0, repo)
306
if err != nil {
307
errs = errors.Join(errs, fmt.Errorf("failed to call repoTags: %w", err))
308
return
···
317
wg.Add(1)
318
go func() {
319
defer wg.Done()
320
-
resp, err := tangled.RepoTree(ctx, xrpcc, "", ref, repo)
321
if err != nil {
322
errs = errors.Join(errs, fmt.Errorf("failed to call repoTree: %w", err))
323
return
···
329
wg.Add(1)
330
go func() {
331
defer wg.Done()
332
-
logBytes, err := tangled.RepoLog(ctx, xrpcc, "", 50, "", ref, repo)
333
if err != nil {
334
errs = errors.Join(errs, fmt.Errorf("failed to call repoLog: %w", err))
335
return
···
54
user := rp.oauth.GetUser(r)
55
56
// Build index response from multiple XRPC calls
57
+
result, err := rp.buildIndexResponse(r.Context(), xrpcc, &f.Repo, ref)
58
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
59
if errors.Is(xrpcerr, xrpcclient.ErrXrpcUnsupported) {
60
l.Error("failed to call XRPC repo.index", "err", err)
···
129
}
130
131
// TODO: a bit dirty
132
+
languageInfo, err := rp.getLanguageInfo(r.Context(), l, &f.Repo, xrpcc, result.Ref, ref == "")
133
if err != nil {
134
l.Warn("failed to compute language percentages", "err", err)
135
// non-fatal
···
164
func (rp *Repo) getLanguageInfo(
165
ctx context.Context,
166
l *slog.Logger,
167
+
repo *models.Repo,
168
xrpcc *indigoxrpc.Client,
169
currentRef string,
170
isDefaultRef bool,
···
172
// first attempt to fetch from db
173
langs, err := db.GetRepoLanguages(
174
rp.db,
175
+
db.FilterEq("repo_at", repo.RepoAt()),
176
db.FilterEq("ref", currentRef),
177
)
178
179
if err != nil || langs == nil {
180
// non-fatal, fetch langs from ks via XRPC
181
+
didSlashRepo := fmt.Sprintf("%s/%s", repo.Did, repo.Name)
182
+
ls, err := tangled.RepoLanguages(ctx, xrpcc, currentRef, didSlashRepo)
183
if err != nil {
184
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
185
l.Error("failed to call XRPC repo.languages", "err", xrpcerr)
···
194
195
for _, lang := range ls.Languages {
196
langs = append(langs, models.RepoLanguage{
197
+
RepoAt: repo.RepoAt(),
198
Ref: currentRef,
199
IsDefaultRef: isDefaultRef,
200
Language: lang.Name,
···
209
defer tx.Rollback()
210
211
// update appview's cache
212
+
err = db.UpdateRepoLanguages(tx, repo.RepoAt(), currentRef, langs)
213
if err != nil {
214
// non-fatal
215
l.Error("failed to cache lang results", "err", err)
···
254
}
255
256
// buildIndexResponse creates a RepoIndexResponse by combining multiple xrpc calls in parallel
257
+
func (rp *Repo) buildIndexResponse(ctx context.Context, xrpcc *indigoxrpc.Client, repo *models.Repo, ref string) (*types.RepoIndexResponse, error) {
258
+
didSlashRepo := fmt.Sprintf("%s/%s", repo.Did, repo.Name)
259
260
// first get branches to determine the ref if not specified
261
+
branchesBytes, err := tangled.RepoBranches(ctx, xrpcc, "", 0, didSlashRepo)
262
if err != nil {
263
return nil, fmt.Errorf("failed to call repoBranches: %w", err)
264
}
···
302
wg.Add(1)
303
go func() {
304
defer wg.Done()
305
+
tagsBytes, err := tangled.RepoTags(ctx, xrpcc, "", 0, didSlashRepo)
306
if err != nil {
307
errs = errors.Join(errs, fmt.Errorf("failed to call repoTags: %w", err))
308
return
···
317
wg.Add(1)
318
go func() {
319
defer wg.Done()
320
+
resp, err := tangled.RepoTree(ctx, xrpcc, "", ref, didSlashRepo)
321
if err != nil {
322
errs = errors.Join(errs, fmt.Errorf("failed to call repoTree: %w", err))
323
return
···
329
wg.Add(1)
330
go func() {
331
defer wg.Done()
332
+
logBytes, err := tangled.RepoLog(ctx, xrpcc, "", 50, "", ref, didSlashRepo)
333
if err != nil {
334
errs = errors.Join(errs, fmt.Errorf("failed to call repoLog: %w", err))
335
return