···
···
15
-
"go.opentelemetry.io/otel/attribute"
"tangled.sh/tangled.sh/core/api/tangled"
"tangled.sh/tangled.sh/core/appview"
"tangled.sh/tangled.sh/core/appview/auth"
"tangled.sh/tangled.sh/core/appview/db"
"tangled.sh/tangled.sh/core/appview/pages"
"tangled.sh/tangled.sh/core/patchutil"
22
-
"tangled.sh/tangled.sh/core/telemetry"
"tangled.sh/tangled.sh/core/types"
comatproto "github.com/bluesky-social/indigo/api/atproto"
···
func (s *State) PullActions(w http.ResponseWriter, r *http.Request) {
33
-
ctx, span := s.t.TraceStart(r.Context(), "PullActions")
user := s.auth.GetUser(r)
39
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
33
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
45
-
pull, ok := ctx.Value("pull").(*db.Pull)
39
+
pull, ok := r.Context().Value("pull").(*db.Pull)
log.Println("failed to get pull")
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
···
63
-
_, mergeSpan := s.t.TraceStart(ctx, "mergeCheck")
64
-
mergeCheckResponse := s.mergeCheck(ctx, f, pull)
57
+
mergeCheckResponse := s.mergeCheck(f, pull)
resubmitResult := pages.Unknown
if user.Did == pull.OwnerDid {
69
-
_, resubmitSpan := s.t.TraceStart(ctx, "resubmitCheck")
70
-
resubmitResult = s.resubmitCheck(ctx, f, pull)
60
+
resubmitResult = s.resubmitCheck(f, pull)
74
-
_, renderSpan := s.t.TraceStart(ctx, "renderPullActions")
s.pages.PullActionsFragment(w, pages.PullActionsParams{
77
-
RepoInfo: f.RepoInfo(ctx, s, user),
65
+
RepoInfo: f.RepoInfo(s, user),
RoundNumber: roundNumber,
MergeCheck: mergeCheckResponse,
ResubmitCheck: resubmitResult,
func (s *State) RepoSinglePull(w http.ResponseWriter, r *http.Request) {
89
-
ctx, span := s.t.TraceStart(r.Context(), "RepoSinglePull")
user := s.auth.GetUser(r)
93
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
77
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
96
-
span.RecordError(err)
100
-
pull, ok := ctx.Value("pull").(*db.Pull)
83
+
pull, ok := r.Context().Value("pull").(*db.Pull)
102
-
err := errors.New("failed to get pull from context")
104
-
span.RecordError(err)
85
+
log.Println("failed to get pull")
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
109
-
attrs := telemetry.MapAttrs[string](map[string]string{
110
-
"pull.id": fmt.Sprintf("%d", pull.PullId),
111
-
"pull.owner": pull.OwnerDid,
114
-
span.SetAttributes(attrs...)
for _, submission := range pull.Submissions {
totalIdents += len(submission.Comments)
···
133
-
resolvedIds := s.resolver.ResolveIdents(ctx, identsToResolve)
107
+
resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve)
didHandleMap := make(map[string]string)
for _, identity := range resolvedIds {
if !identity.Handle.IsInvalidHandle() {
···
didHandleMap[identity.DID.String()] = identity.DID.String()
142
-
span.SetAttributes(attribute.Int("identities.resolved", len(resolvedIds)))
144
-
mergeCheckResponse := s.mergeCheck(ctx, f, pull)
117
+
mergeCheckResponse := s.mergeCheck(f, pull)
resubmitResult := pages.Unknown
if user != nil && user.Did == pull.OwnerDid {
148
-
resubmitResult = s.resubmitCheck(ctx, f, pull)
120
+
resubmitResult = s.resubmitCheck(f, pull)
s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{
153
-
RepoInfo: f.RepoInfo(ctx, s, user),
125
+
RepoInfo: f.RepoInfo(s, user),
DidHandleMap: didHandleMap,
MergeCheck: mergeCheckResponse,
···
161
-
func (s *State) mergeCheck(ctx context.Context, f *FullyResolvedRepo, pull *db.Pull) types.MergeCheckResponse {
133
+
func (s *State) mergeCheck(f *FullyResolvedRepo, pull *db.Pull) types.MergeCheckResponse {
if pull.State == db.PullMerged {
return types.MergeCheckResponse{}
···
return mergeCheckResponse
221
-
func (s *State) resubmitCheck(ctx context.Context, f *FullyResolvedRepo, pull *db.Pull) pages.ResubmitResult {
222
-
ctx, span := s.t.TraceStart(ctx, "resubmitCheck")
225
-
span.SetAttributes(attribute.Int("pull.id", pull.PullId))
193
+
func (s *State) resubmitCheck(f *FullyResolvedRepo, pull *db.Pull) pages.ResubmitResult {
if pull.State == db.PullMerged || pull.PullSource == nil {
228
-
span.SetAttributes(attribute.String("result", "Unknown"))
···
if pull.PullSource.RepoAt != nil {
236
-
span.SetAttributes(attribute.Bool("isForkBased", true))
237
-
sourceRepo, err := db.GetRepoByAtUri(ctx, s.db, pull.PullSource.RepoAt.String())
202
+
sourceRepo, err := db.GetRepoByAtUri(s.db, pull.PullSource.RepoAt.String())
log.Println("failed to get source repo", err)
240
-
span.RecordError(err)
241
-
span.SetAttributes(attribute.String("error", "failed_to_get_source_repo"))
242
-
span.SetAttributes(attribute.String("result", "Unknown"))
···
repoName = sourceRepo.Name
// pulls within the same repo
251
-
span.SetAttributes(attribute.Bool("isBranchBased", true))
257
-
span.SetAttributes(
258
-
attribute.String("knot", knot),
259
-
attribute.String("ownerDid", ownerDid),
260
-
attribute.String("repoName", repoName),
261
-
attribute.String("sourceBranch", pull.PullSource.Branch),
us, err := NewUnsignedClient(knot, s.config.Dev)
log.Printf("failed to setup client for %s; ignoring: %v", knot, err)
267
-
span.RecordError(err)
268
-
span.SetAttributes(attribute.String("error", "failed_to_setup_client"))
269
-
span.SetAttributes(attribute.String("result", "Unknown"))
resp, err := us.Branch(ownerDid, repoName, pull.PullSource.Branch)
log.Println("failed to reach knotserver", err)
276
-
span.RecordError(err)
277
-
span.SetAttributes(attribute.String("error", "failed_to_reach_knotserver"))
278
-
span.SetAttributes(attribute.String("result", "Unknown"))
body, err := io.ReadAll(resp.Body)
log.Printf("error reading response body: %v", err)
285
-
span.RecordError(err)
286
-
span.SetAttributes(attribute.String("error", "failed_to_read_response"))
287
-
span.SetAttributes(attribute.String("result", "Unknown"))
···
var result types.RepoBranchResponse
if err := json.Unmarshal(body, &result); err != nil {
log.Println("failed to parse response:", err)
295
-
span.RecordError(err)
296
-
span.SetAttributes(attribute.String("error", "failed_to_parse_response"))
297
-
span.SetAttributes(attribute.String("result", "Unknown"))
latestSubmission := pull.Submissions[pull.LastRoundNumber()]
303
-
span.SetAttributes(
304
-
attribute.String("latestSubmission.SourceRev", latestSubmission.SourceRev),
305
-
attribute.String("branch.Hash", result.Branch.Hash),
if latestSubmission.SourceRev != result.Branch.Hash {
fmt.Println(latestSubmission.SourceRev, result.Branch.Hash)
310
-
span.SetAttributes(attribute.String("result", "ShouldResubmit"))
return pages.ShouldResubmit
314
-
span.SetAttributes(attribute.String("result", "ShouldNotResubmit"))
return pages.ShouldNotResubmit
func (s *State) RepoPullPatch(w http.ResponseWriter, r *http.Request) {
319
-
ctx, span := s.t.TraceStart(r.Context(), "RepoPullPatch")
322
-
user := s.auth.GetUser(r.WithContext(ctx))
323
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
253
+
user := s.auth.GetUser(r)
254
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
326
-
span.RecordError(err)
330
-
pull, ok := ctx.Value("pull").(*db.Pull)
260
+
pull, ok := r.Context().Value("pull").(*db.Pull)
332
-
err := errors.New("failed to get pull from context")
334
-
span.RecordError(err)
262
+
log.Println("failed to get pull")
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
···
if err != nil || roundIdInt >= len(pull.Submissions) {
http.Error(w, "bad round id", http.StatusBadRequest)
log.Println("failed to parse round id", err)
344
-
span.RecordError(err)
345
-
span.SetAttributes(attribute.String("error", "bad_round_id"))
349
-
span.SetAttributes(
350
-
attribute.Int("pull.id", pull.PullId),
351
-
attribute.Int("round", roundIdInt),
352
-
attribute.String("pull.owner", pull.OwnerDid),
identsToResolve := []string{pull.OwnerDid}
356
-
resolvedIds := s.resolver.ResolveIdents(ctx, identsToResolve)
276
+
resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve)
didHandleMap := make(map[string]string)
for _, identity := range resolvedIds {
if !identity.Handle.IsInvalidHandle() {
···
didHandleMap[identity.DID.String()] = identity.DID.String()
365
-
span.SetAttributes(attribute.Int("identities.resolved", len(resolvedIds)))
diff := pull.Submissions[roundIdInt].AsNiceDiff(pull.TargetBranch)
s.pages.RepoPullPatchPage(w, pages.RepoPullPatchParams{
DidHandleMap: didHandleMap,
372
-
RepoInfo: f.RepoInfo(ctx, s, user),
291
+
RepoInfo: f.RepoInfo(s, user),
Submission: pull.Submissions[roundIdInt],
func (s *State) RepoPullInterdiff(w http.ResponseWriter, r *http.Request) {
381
-
ctx, span := s.t.TraceStart(r.Context(), "RepoPullInterdiff")
user := s.auth.GetUser(r)
386
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
303
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
392
-
pull, ok := ctx.Value("pull").(*db.Pull)
309
+
pull, ok := r.Context().Value("pull").(*db.Pull)
log.Println("failed to get pull")
s.pages.Notice(w, "pull-error", "Failed to get pull.")
399
-
_, roundSpan := s.t.TraceStart(ctx, "parseRound")
roundId := chi.URLParam(r, "round")
roundIdInt, err := strconv.Atoi(roundId)
if err != nil || roundIdInt >= len(pull.Submissions) {
http.Error(w, "bad round id", http.StatusBadRequest)
log.Println("failed to parse round id", err)
http.Error(w, "bad round id", http.StatusBadRequest)
log.Println("cannot interdiff initial submission")
417
-
_, identSpan := s.t.TraceStart(ctx, "resolveIdentities")
identsToResolve := []string{pull.OwnerDid}
419
-
resolvedIds := s.resolver.ResolveIdents(ctx, identsToResolve)
331
+
resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve)
didHandleMap := make(map[string]string)
for _, identity := range resolvedIds {
if !identity.Handle.IsInvalidHandle() {
···
didHandleMap[identity.DID.String()] = identity.DID.String()
430
-
_, diffSpan := s.t.TraceStart(ctx, "calculateInterdiff")
currentPatch, err := pull.Submissions[roundIdInt].AsDiff(pull.TargetBranch)
log.Println("failed to interdiff; current patch malformed")
s.pages.Notice(w, fmt.Sprintf("interdiff-error-%d", roundIdInt), "Failed to calculate interdiff; current patch is invalid.")
···
log.Println("failed to interdiff; previous patch malformed")
s.pages.Notice(w, fmt.Sprintf("interdiff-error-%d", roundIdInt), "Failed to calculate interdiff; previous patch is invalid.")
interdiff := patchutil.Interdiff(previousPatch, currentPatch)
450
-
_, renderSpan := s.t.TraceStart(ctx, "renderInterdiffPage")
s.pages.RepoPullInterdiffPage(w, pages.RepoPullInterdiffParams{
452
-
LoggedInUser: s.auth.GetUser(r.WithContext(ctx)),
453
-
RepoInfo: f.RepoInfo(ctx, s, user),
358
+
LoggedInUser: s.auth.GetUser(r),
359
+
RepoInfo: f.RepoInfo(s, user),
DidHandleMap: didHandleMap,
func (s *State) RepoPullPatchRaw(w http.ResponseWriter, r *http.Request) {
464
-
ctx, span := s.t.TraceStart(r.Context(), "RepoPullPatchRaw")
467
-
pull, ok := ctx.Value("pull").(*db.Pull)
369
+
pull, ok := r.Context().Value("pull").(*db.Pull)
log.Println("failed to get pull")
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
474
-
_, roundSpan := s.t.TraceStart(ctx, "parseRound")
roundId := chi.URLParam(r, "round")
roundIdInt, err := strconv.Atoi(roundId)
if err != nil || roundIdInt >= len(pull.Submissions) {
http.Error(w, "bad round id", http.StatusBadRequest)
log.Println("failed to parse round id", err)
485
-
_, identSpan := s.t.TraceStart(ctx, "resolveIdentities")
identsToResolve := []string{pull.OwnerDid}
487
-
resolvedIds := s.resolver.ResolveIdents(ctx, identsToResolve)
385
+
resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve)
didHandleMap := make(map[string]string)
for _, identity := range resolvedIds {
if !identity.Handle.IsInvalidHandle() {
···
didHandleMap[identity.DID.String()] = identity.DID.String()
498
-
_, writeSpan := s.t.TraceStart(ctx, "writePatch")
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte(pull.Submissions[roundIdInt].Patch))
func (s *State) RepoPulls(w http.ResponseWriter, r *http.Request) {
505
-
ctx, span := s.t.TraceStart(r.Context(), "RepoPulls")
user := s.auth.GetUser(r)
511
-
_, stateSpan := s.t.TraceStart(ctx, "determinePullState")
switch params.Get("state") {
···
521
-
_, repoSpan := s.t.TraceStart(ctx, "resolveRepo")
522
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
411
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
530
-
_, pullsSpan := s.t.TraceStart(ctx, "getPulls")
531
-
pulls, err := db.GetPulls(ctx, s.db, f.RepoAt, state)
417
+
pulls, err := db.GetPulls(s.db, f.RepoAt, state)
log.Println("failed to get pulls", err)
s.pages.Notice(w, "pulls", "Failed to load pulls. Try again later.")
540
-
_, sourceRepoSpan := s.t.TraceStart(ctx, "resolvePullSources")
for _, p := range pulls {
var pullSourceRepo *db.Repo
if p.PullSource.RepoAt != nil {
545
-
pullSourceRepo, err = db.GetRepoByAtUri(ctx, s.db, p.PullSource.RepoAt.String())
428
+
pullSourceRepo, err = db.GetRepoByAtUri(s.db, p.PullSource.RepoAt.String())
log.Printf("failed to get repo by at uri: %v", err)
···
555
-
sourceRepoSpan.End()
557
-
_, identSpan := s.t.TraceStart(ctx, "resolveIdentities")
identsToResolve := make([]string, len(pulls))
for i, pull := range pulls {
identsToResolve[i] = pull.OwnerDid
562
-
resolvedIds := s.resolver.ResolveIdents(ctx, identsToResolve)
443
+
resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve)
didHandleMap := make(map[string]string)
for _, identity := range resolvedIds {
if !identity.Handle.IsInvalidHandle() {
···
didHandleMap[identity.DID.String()] = identity.DID.String()
573
-
_, renderSpan := s.t.TraceStart(ctx, "renderPullsPage")
s.pages.RepoPulls(w, pages.RepoPullsParams{
575
-
LoggedInUser: s.auth.GetUser(r.WithContext(ctx)),
576
-
RepoInfo: f.RepoInfo(ctx, s, user),
454
+
LoggedInUser: s.auth.GetUser(r),
455
+
RepoInfo: f.RepoInfo(s, user),
DidHandleMap: didHandleMap,
func (s *State) PullComment(w http.ResponseWriter, r *http.Request) {
586
-
ctx, span := s.t.TraceStart(r.Context(), "PullComment")
589
-
user := s.auth.GetUser(r.WithContext(ctx))
590
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
464
+
user := s.auth.GetUser(r)
465
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
596
-
pull, ok := ctx.Value("pull").(*db.Pull)
471
+
pull, ok := r.Context().Value("pull").(*db.Pull)
log.Println("failed to get pull")
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
603
-
_, roundSpan := s.t.TraceStart(ctx, "parseRoundNumber")
roundNumberStr := chi.URLParam(r, "round")
roundNumber, err := strconv.Atoi(roundNumberStr)
if err != nil || roundNumber >= len(pull.Submissions) {
http.Error(w, "bad round id", http.StatusBadRequest)
log.Println("failed to parse round id", err)
616
-
_, renderSpan := s.t.TraceStart(ctx, "renderCommentFragment")
s.pages.PullNewCommentFragment(w, pages.PullNewCommentParams{
619
-
RepoInfo: f.RepoInfo(ctx, s, user),
490
+
RepoInfo: f.RepoInfo(s, user),
RoundNumber: roundNumber,
626
-
postCtx, postSpan := s.t.TraceStart(ctx, "CreateComment")
627
-
defer postSpan.End()
629
-
_, validateSpan := s.t.TraceStart(postCtx, "validateComment")
body := r.FormValue("body")
s.pages.Notice(w, "pull", "Comment body is required")
639
-
_, txSpan := s.t.TraceStart(postCtx, "startTransaction")
640
-
tx, err := s.db.BeginTx(postCtx, nil)
503
+
tx, err := s.db.BeginTx(r.Context(), nil)
log.Println("failed to start transaction", err)
s.pages.Notice(w, "pull-comment", "Failed to create comment.")
createdAt := time.Now().Format(time.RFC3339)
653
-
_, pullAtSpan := s.t.TraceStart(postCtx, "getPullAt")
654
-
pullAt, err := db.GetPullAt(postCtx, s.db, f.RepoAt, pull.PullId)
514
+
pullAt, err := db.GetPullAt(s.db, f.RepoAt, pull.PullId)
log.Println("failed to get pull at", err)
s.pages.Notice(w, "pull-comment", "Failed to create comment.")
663
-
_, atProtoSpan := s.t.TraceStart(postCtx, "createAtProtoRecord")
atUri := f.RepoAt.String()
665
-
client, _ := s.auth.AuthorizedClient(r.WithContext(postCtx))
666
-
atResp, err := comatproto.RepoPutRecord(postCtx, client, &comatproto.RepoPutRecord_Input{
522
+
client, _ := s.auth.AuthorizedClient(r)
523
+
atResp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoPullCommentNSID,
···
log.Println("failed to create pull comment", err)
s.pages.Notice(w, "pull-comment", "Failed to create comment.")
// Create the pull comment in the database with the commentAt field
689
-
_, dbSpan := s.t.TraceStart(postCtx, "createDbComment")
690
-
commentId, err := db.NewPullComment(postCtx, tx, &db.PullComment{
544
+
commentId, err := db.NewPullComment(tx, &db.PullComment{
RepoAt: f.RepoAt.String(),
···
log.Println("failed to create pull comment", err)
s.pages.Notice(w, "pull-comment", "Failed to create comment.")
558
+
// Commit the transaction
if err = tx.Commit(); err != nil {
log.Println("failed to commit transaction", err)
s.pages.Notice(w, "pull-comment", "Failed to create comment.")
···
func (s *State) NewPull(w http.ResponseWriter, r *http.Request) {
718
-
ctx, span := s.t.TraceStart(r.Context(), "NewPull")
721
-
user := s.auth.GetUser(r.WithContext(ctx))
722
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
571
+
user := s.auth.GetUser(r)
572
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
725
-
span.RecordError(err)
731
-
span.SetAttributes(attribute.String("method", "GET"))
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
log.Printf("failed to create unsigned client for %s", f.Knot)
736
-
span.RecordError(err)
···
resp, err := us.Branches(f.OwnerDid(), f.RepoName)
log.Println("failed to reach knotserver", err)
744
-
span.RecordError(err)
body, err := io.ReadAll(resp.Body)
log.Printf("Error reading response body: %v", err)
751
-
span.RecordError(err)
···
err = json.Unmarshal(body, &result)
log.Println("failed to parse response:", err)
759
-
span.RecordError(err)
s.pages.RepoNewPull(w, pages.RepoNewPullParams{
765
-
RepoInfo: f.RepoInfo(ctx, s, user),
608
+
RepoInfo: f.RepoInfo(s, user),
Branches: result.Branches,
769
-
span.SetAttributes(attribute.String("method", "POST"))
title := r.FormValue("title")
body := r.FormValue("body")
targetBranch := r.FormValue("targetBranch")
fromFork := r.FormValue("fork")
sourceBranch := r.FormValue("sourceBranch")
patch := r.FormValue("patch")
778
-
span.SetAttributes(
779
-
attribute.String("targetBranch", targetBranch),
780
-
attribute.String("sourceBranch", sourceBranch),
781
-
attribute.Bool("hasFork", fromFork != ""),
782
-
attribute.Bool("hasPatch", patch != ""),
s.pages.Notice(w, "pull", "Target branch is required.")
787
-
span.SetAttributes(attribute.String("error", "missing_target_branch"))
// Determine PR type based on input parameters
792
-
isPushAllowed := f.RepoInfo(ctx, s, user).Roles.IsPushAllowed()
625
+
isPushAllowed := f.RepoInfo(s, user).Roles.IsPushAllowed()
isBranchBased := isPushAllowed && sourceBranch != "" && fromFork == ""
isForkBased := fromFork != "" && sourceBranch != ""
isPatchBased := patch != "" && !isBranchBased && !isForkBased
797
-
span.SetAttributes(
798
-
attribute.Bool("isPushAllowed", isPushAllowed),
799
-
attribute.Bool("isBranchBased", isBranchBased),
800
-
attribute.Bool("isForkBased", isForkBased),
801
-
attribute.Bool("isPatchBased", isPatchBased),
if isPatchBased && !patchutil.IsFormatPatch(patch) {
s.pages.Notice(w, "pull", "Title is required for git-diff patches.")
807
-
span.SetAttributes(attribute.String("error", "missing_title_for_git_diff"))
···
// Validate we have at least one valid PR creation method
if !isBranchBased && !isPatchBased && !isForkBased {
s.pages.Notice(w, "pull", "Neither source branch nor patch supplied.")
815
-
span.SetAttributes(attribute.String("error", "no_valid_pr_method"))
// Can't mix branch-based and patch-based approaches
if isBranchBased && patch != "" {
s.pages.Notice(w, "pull", "Cannot select both patch and source branch.")
822
-
span.SetAttributes(attribute.String("error", "mixed_pr_methods"))
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
log.Printf("failed to create unsigned client to %s: %v", f.Knot, err)
829
-
span.RecordError(err)
s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.")
···
caps, err := us.Capabilities()
log.Println("error fetching knot caps", f.Knot, err)
837
-
span.RecordError(err)
s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.")
842
-
span.SetAttributes(
843
-
attribute.Bool("caps.pullRequests.formatPatch", caps.PullRequests.FormatPatch),
844
-
attribute.Bool("caps.pullRequests.branchSubmissions", caps.PullRequests.BranchSubmissions),
845
-
attribute.Bool("caps.pullRequests.forkSubmissions", caps.PullRequests.ForkSubmissions),
846
-
attribute.Bool("caps.pullRequests.patchSubmissions", caps.PullRequests.PatchSubmissions),
if !caps.PullRequests.FormatPatch {
s.pages.Notice(w, "pull", "This knot doesn't support format-patch. Unfortunately, there is no fallback for now.")
851
-
span.SetAttributes(attribute.String("error", "formatpatch_not_supported"))
···
if !caps.PullRequests.BranchSubmissions {
s.pages.Notice(w, "pull", "This knot doesn't support branch-based pull requests. Try another way?")
859
-
span.SetAttributes(attribute.String("error", "branch_submissions_not_supported"))
862
-
s.handleBranchBasedPull(w, r.WithContext(ctx), f, user, title, body, targetBranch, sourceBranch)
674
+
s.handleBranchBasedPull(w, r, f, user, title, body, targetBranch, sourceBranch)
if !caps.PullRequests.ForkSubmissions {
s.pages.Notice(w, "pull", "This knot doesn't support fork-based pull requests. Try another way?")
866
-
span.SetAttributes(attribute.String("error", "fork_submissions_not_supported"))
869
-
s.handleForkBasedPull(w, r.WithContext(ctx), f, user, fromFork, title, body, targetBranch, sourceBranch)
680
+
s.handleForkBasedPull(w, r, f, user, fromFork, title, body, targetBranch, sourceBranch)
if !caps.PullRequests.PatchSubmissions {
s.pages.Notice(w, "pull", "This knot doesn't support patch-based pull requests. Send your patch over email.")
873
-
span.SetAttributes(attribute.String("error", "patch_submissions_not_supported"))
876
-
s.handlePatchBasedPull(w, r.WithContext(ctx), f, user, title, body, targetBranch, patch)
686
+
s.handlePatchBasedPull(w, r, f, user, title, body, targetBranch, patch)
func (s *State) handleBranchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, title, body, targetBranch, sourceBranch string) {
883
-
ctx, span := s.t.TraceStart(r.Context(), "handleBranchBasedPull")
886
-
span.SetAttributes(
887
-
attribute.String("targetBranch", targetBranch),
888
-
attribute.String("sourceBranch", sourceBranch),
pullSource := &db.PullSource{
···
ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev)
log.Printf("failed to create signed client for %s: %s", f.Knot, err)
902
-
span.RecordError(err)
903
-
span.SetAttributes(attribute.String("error", "client_creation_failed"))
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···
comparison, err := ksClient.Compare(f.OwnerDid(), f.RepoName, targetBranch, sourceBranch)
log.Println("failed to compare", err)
911
-
span.RecordError(err)
912
-
span.SetAttributes(attribute.String("error", "comparison_failed"))
s.pages.Notice(w, "pull", err.Error())
···
sourceRev := comparison.Rev2
patch := comparison.Patch
920
-
span.SetAttributes(attribute.String("sourceRev", sourceRev))
if !patchutil.IsPatchValid(patch) {
923
-
span.SetAttributes(attribute.String("error", "invalid_patch_format"))
s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.")
928
-
s.createPullRequest(w, r.WithContext(ctx), f, user, title, body, targetBranch, patch, sourceRev, pullSource, recordPullSource)
723
+
s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, sourceRev, pullSource, recordPullSource)
func (s *State) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, title, body, targetBranch, patch string) {
932
-
ctx, span := s.t.TraceStart(r.Context(), "handlePatchBasedPull")
935
-
span.SetAttributes(attribute.String("targetBranch", targetBranch))
if !patchutil.IsPatchValid(patch) {
938
-
span.SetAttributes(attribute.String("error", "invalid_patch_format"))
s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.")
943
-
s.createPullRequest(w, r.WithContext(ctx), f, user, title, body, targetBranch, patch, "", nil, nil)
732
+
s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, "", nil, nil)
func (s *State) handleForkBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, forkRepo string, title, body, targetBranch, sourceBranch string) {
947
-
ctx, span := s.t.TraceStart(r.Context(), "handleForkBasedPull")
950
-
span.SetAttributes(
951
-
attribute.String("forkRepo", forkRepo),
952
-
attribute.String("targetBranch", targetBranch),
953
-
attribute.String("sourceBranch", sourceBranch),
956
-
fork, err := db.GetForkByDid(ctx, s.db, user.Did, forkRepo)
736
+
fork, err := db.GetForkByDid(s.db, user.Did, forkRepo)
if errors.Is(err, sql.ErrNoRows) {
958
-
span.SetAttributes(attribute.String("error", "fork_not_found"))
s.pages.Notice(w, "pull", "No such fork.")
log.Println("failed to fetch fork:", err)
963
-
span.RecordError(err)
964
-
span.SetAttributes(attribute.String("error", "fork_fetch_failed"))
s.pages.Notice(w, "pull", "Failed to fetch fork.")
···
secret, err := db.GetRegistrationKey(s.db, fork.Knot)
log.Println("failed to fetch registration key:", err)
972
-
span.RecordError(err)
973
-
span.SetAttributes(attribute.String("error", "registration_key_fetch_failed"))
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···
sc, err := NewSignedClient(fork.Knot, secret, s.config.Dev)
log.Println("failed to create signed client:", err)
981
-
span.RecordError(err)
982
-
span.SetAttributes(attribute.String("error", "signed_client_creation_failed"))
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···
us, err := NewUnsignedClient(fork.Knot, s.config.Dev)
log.Println("failed to create unsigned client:", err)
990
-
span.RecordError(err)
991
-
span.SetAttributes(attribute.String("error", "unsigned_client_creation_failed"))
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···
resp, err := sc.NewHiddenRef(user.Did, fork.Name, sourceBranch, targetBranch)
log.Println("failed to create hidden ref:", err, resp.StatusCode)
999
-
span.RecordError(err)
1000
-
span.SetAttributes(attribute.String("error", "hidden_ref_creation_failed"))
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
1007
-
span.SetAttributes(attribute.String("error", "not_found_status"))
1009
-
span.SetAttributes(attribute.String("error", "bad_request_status"))
s.pages.Notice(w, "pull", "Branch based pull requests are not supported on this knot.")
hiddenRef := fmt.Sprintf("hidden/%s/%s", sourceBranch, targetBranch)
1015
-
span.SetAttributes(attribute.String("hiddenRef", hiddenRef))
// We're now comparing the sourceBranch (on the fork) against the hiddenRef which is tracking
// the targetBranch on the target repository. This code is a bit confusing, but here's an example:
// hiddenRef: hidden/feature-1/main (on repo-fork)
···
comparison, err := us.Compare(user.Did, fork.Name, hiddenRef, sourceBranch)
log.Println("failed to compare across branches", err)
1025
-
span.RecordError(err)
1026
-
span.SetAttributes(attribute.String("error", "branch_comparison_failed"))
s.pages.Notice(w, "pull", err.Error())
sourceRev := comparison.Rev2
patch := comparison.Patch
1033
-
span.SetAttributes(attribute.String("sourceRev", sourceRev))
if !patchutil.IsPatchValid(patch) {
1036
-
span.SetAttributes(attribute.String("error", "invalid_patch_format"))
s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.")
···
forkAtUri, err := syntax.ParseATURI(fork.AtUri)
log.Println("failed to parse fork AT URI", err)
1044
-
span.RecordError(err)
1045
-
span.SetAttributes(attribute.String("error", "fork_aturi_parse_failed"))
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
1050
-
s.createPullRequest(w, r.WithContext(ctx), f, user, title, body, targetBranch, patch, sourceRev, &db.PullSource{
809
+
s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, sourceRev, &db.PullSource{
}, &tangled.RepoPull_Source{Branch: sourceBranch, Repo: &fork.AtUri})
···
pullSource *db.PullSource,
recordPullSource *tangled.RepoPull_Source,
1067
-
ctx, span := s.t.TraceStart(r.Context(), "createPullRequest")
1070
-
span.SetAttributes(
1071
-
attribute.String("targetBranch", targetBranch),
1072
-
attribute.String("sourceRev", sourceRev),
1073
-
attribute.Bool("hasPullSource", pullSource != nil),
1076
-
tx, err := s.db.BeginTx(ctx, nil)
826
+
tx, err := s.db.BeginTx(r.Context(), nil)
log.Println("failed to start tx")
1079
-
span.RecordError(err)
1080
-
span.SetAttributes(attribute.String("error", "transaction_start_failed"))
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···
formatPatches, err := patchutil.ExtractPatches(patch)
1091
-
span.RecordError(err)
1092
-
span.SetAttributes(attribute.String("error", "extract_patches_failed"))
s.pages.Notice(w, "pull", fmt.Sprintf("Failed to extract patches: %v", err))
if len(formatPatches) == 0 {
1097
-
span.SetAttributes(attribute.String("error", "no_patches_found"))
s.pages.Notice(w, "pull", "No patches found in the supplied format-patch.")
title = formatPatches[0].Title
body = formatPatches[0].Body
1104
-
span.SetAttributes(
1105
-
attribute.Bool("title_extracted", true),
1106
-
attribute.Bool("body_extracted", formatPatches[0].Body != ""),
···
1115
-
err = db.NewPull(ctx, tx, &db.Pull{
856
+
err = db.NewPull(tx, &db.Pull{
TargetBranch: targetBranch,
···
log.Println("failed to create pull request", err)
1129
-
span.RecordError(err)
1130
-
span.SetAttributes(attribute.String("error", "db_create_pull_failed"))
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
1135
-
client, _ := s.auth.AuthorizedClient(r.WithContext(ctx))
873
+
client, _ := s.auth.AuthorizedClient(r)
pullId, err := db.NextPullId(s.db, f.RepoAt)
log.Println("failed to get pull id", err)
1139
-
span.RecordError(err)
1140
-
span.SetAttributes(attribute.String("error", "get_pull_id_failed"))
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
1144
-
span.SetAttributes(attribute.Int("pullId", pullId))
1146
-
_, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{
881
+
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoPullNSID,
···
log.Println("failed to create pull request", err)
1164
-
span.RecordError(err)
1165
-
span.SetAttributes(attribute.String("error", "atproto_create_record_failed"))
1166
-
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
1170
-
if err = tx.Commit(); err != nil {
1171
-
log.Println("failed to commit transaction", err)
1172
-
span.RecordError(err)
1173
-
span.SetAttributes(attribute.String("error", "transaction_commit_failed"))
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···
func (s *State) ValidatePatch(w http.ResponseWriter, r *http.Request) {
1182
-
ctx, span := s.t.TraceStart(r.Context(), "ValidatePatch")
1185
-
_, err := s.fullyResolvedRepo(r.WithContext(ctx))
907
+
_, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
1188
-
span.RecordError(err)
1189
-
span.SetAttributes(attribute.String("error", "resolve_repo_failed"))
patch := r.FormValue("patch")
1194
-
span.SetAttributes(attribute.Bool("hasPatch", patch != ""))
1197
-
span.SetAttributes(attribute.String("error", "empty_patch"))
s.pages.Notice(w, "patch-error", "Patch is required.")
1202
-
if !patchutil.IsPatchValid(patch) {
1203
-
span.SetAttributes(attribute.String("error", "invalid_patch_format"))
919
+
if patch == "" || !patchutil.IsPatchValid(patch) {
s.pages.Notice(w, "patch-error", "Invalid patch format. Please provide a valid git diff or format-patch.")
1208
-
isFormatPatch := patchutil.IsFormatPatch(patch)
1209
-
span.SetAttributes(attribute.Bool("isFormatPatch", isFormatPatch))
1211
-
if isFormatPatch {
924
+
if patchutil.IsFormatPatch(patch) {
s.pages.Notice(w, "patch-preview", "git-format-patch detected. Title and description are optional; if left out, they will be extracted from the first commit.")
s.pages.Notice(w, "patch-preview", "Regular git-diff detected. Please provide a title and description.")
···
func (s *State) PatchUploadFragment(w http.ResponseWriter, r *http.Request) {
1219
-
ctx, span := s.t.TraceStart(r.Context(), "PatchUploadFragment")
1222
-
user := s.auth.GetUser(r.WithContext(ctx))
1223
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
932
+
user := s.auth.GetUser(r)
933
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
1226
-
span.RecordError(err)
1227
-
span.SetAttributes(attribute.String("error", "resolve_repo_failed"))
s.pages.PullPatchUploadFragment(w, pages.PullPatchUploadParams{
1232
-
RepoInfo: f.RepoInfo(ctx, s, user),
940
+
RepoInfo: f.RepoInfo(s, user),
func (s *State) CompareBranchesFragment(w http.ResponseWriter, r *http.Request) {
1237
-
ctx, span := s.t.TraceStart(r.Context(), "CompareBranchesFragment")
1240
-
user := s.auth.GetUser(r.WithContext(ctx))
1241
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
945
+
user := s.auth.GetUser(r)
946
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
1244
-
span.RecordError(err)
1245
-
span.SetAttributes(attribute.String("error", "resolve_repo_failed"))
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
log.Printf("failed to create unsigned client for %s", f.Knot)
1252
-
span.RecordError(err)
1253
-
span.SetAttributes(attribute.String("error", "client_creation_failed"))
···
resp, err := us.Branches(f.OwnerDid(), f.RepoName)
log.Println("failed to reach knotserver", err)
1261
-
span.RecordError(err)
1262
-
span.SetAttributes(attribute.String("error", "knotserver_connection_failed"))
body, err := io.ReadAll(resp.Body)
log.Printf("Error reading response body: %v", err)
1269
-
span.RecordError(err)
1270
-
span.SetAttributes(attribute.String("error", "response_read_failed"))
1273
-
defer resp.Body.Close()
var result types.RepoBranchesResponse
err = json.Unmarshal(body, &result)
log.Println("failed to parse response:", err)
1279
-
span.RecordError(err)
1280
-
span.SetAttributes(attribute.String("error", "response_parse_failed"))
1283
-
span.SetAttributes(attribute.Int("branches.count", len(result.Branches)))
s.pages.PullCompareBranchesFragment(w, pages.PullCompareBranchesParams{
1286
-
RepoInfo: f.RepoInfo(ctx, s, user),
979
+
RepoInfo: f.RepoInfo(s, user),
Branches: result.Branches,
func (s *State) CompareForksFragment(w http.ResponseWriter, r *http.Request) {
1292
-
ctx, span := s.t.TraceStart(r.Context(), "CompareForksFragment")
1295
-
user := s.auth.GetUser(r.WithContext(ctx))
1296
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
985
+
user := s.auth.GetUser(r)
986
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
1299
-
span.RecordError(err)
1303
-
forks, err := db.GetForksByDid(ctx, s.db, user.Did)
992
+
forks, err := db.GetForksByDid(s.db, user.Did)
log.Println("failed to get forks", err)
1306
-
span.RecordError(err)
s.pages.PullCompareForkFragment(w, pages.PullCompareForkParams{
1311
-
RepoInfo: f.RepoInfo(ctx, s, user),
999
+
RepoInfo: f.RepoInfo(s, user),
func (s *State) CompareForksBranchesFragment(w http.ResponseWriter, r *http.Request) {
1317
-
ctx, span := s.t.TraceStart(r.Context(), "CompareForksBranchesFragment")
1005
+
user := s.auth.GetUser(r)
1320
-
user := s.auth.GetUser(r.WithContext(ctx))
1322
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
1007
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
1325
-
span.RecordError(err)
forkVal := r.URL.Query().Get("fork")
1330
-
span.SetAttributes(attribute.String("fork", forkVal))
1333
-
repo, err := db.GetRepo(ctx, s.db, user.Did, forkVal)
1016
+
repo, err := db.GetRepo(s.db, user.Did, forkVal)
log.Println("failed to get repo", user.Did, forkVal)
1336
-
span.RecordError(err)
sourceBranchesClient, err := NewUnsignedClient(repo.Knot, s.config.Dev)
log.Printf("failed to create unsigned client for %s", repo.Knot)
1343
-
span.RecordError(err)
···
sourceResp, err := sourceBranchesClient.Branches(user.Did, repo.Name)
log.Println("failed to reach knotserver for source branches", err)
1351
-
span.RecordError(err)
sourceBody, err := io.ReadAll(sourceResp.Body)
log.Println("failed to read source response body", err)
1358
-
span.RecordError(err)
defer sourceResp.Body.Close()
···
err = json.Unmarshal(sourceBody, &sourceResult)
log.Println("failed to parse source branches response:", err)
1367
-
span.RecordError(err)
targetBranchesClient, err := NewUnsignedClient(f.Knot, s.config.Dev)
log.Printf("failed to create unsigned client for target knot %s", f.Knot)
1374
-
span.RecordError(err)
···
targetResp, err := targetBranchesClient.Branches(f.OwnerDid(), f.RepoName)
log.Println("failed to reach knotserver for target branches", err)
1382
-
span.RecordError(err)
targetBody, err := io.ReadAll(targetResp.Body)
log.Println("failed to read target response body", err)
1389
-
span.RecordError(err)
defer targetResp.Body.Close()
···
err = json.Unmarshal(targetBody, &targetResult)
log.Println("failed to parse target branches response:", err)
1398
-
span.RecordError(err)
s.pages.PullCompareForkBranchesFragment(w, pages.PullCompareForkBranchesParams{
1403
-
RepoInfo: f.RepoInfo(ctx, s, user),
1077
+
RepoInfo: f.RepoInfo(s, user),
SourceBranches: sourceResult.Branches,
TargetBranches: targetResult.Branches,
func (s *State) ResubmitPull(w http.ResponseWriter, r *http.Request) {
1410
-
ctx, span := s.t.TraceStart(r.Context(), "ResubmitPull")
1413
-
user := s.auth.GetUser(r.WithContext(ctx))
1414
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
1084
+
user := s.auth.GetUser(r)
1085
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
1417
-
span.RecordError(err)
1421
-
pull, ok := ctx.Value("pull").(*db.Pull)
1091
+
pull, ok := r.Context().Value("pull").(*db.Pull)
log.Println("failed to get pull")
1424
-
span.RecordError(errors.New("failed to get pull from context"))
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
1429
-
span.SetAttributes(
1430
-
attribute.Int("pull.id", pull.PullId),
1431
-
attribute.String("pull.owner", pull.OwnerDid),
1432
-
attribute.String("method", r.Method),
s.pages.PullResubmitFragment(w, pages.PullResubmitParams{
1438
-
RepoInfo: f.RepoInfo(ctx, s, user),
1101
+
RepoInfo: f.RepoInfo(s, user),
1444
-
span.SetAttributes(attribute.String("pull.type", "patch_based"))
1445
-
s.resubmitPatch(w, r.WithContext(ctx))
1107
+
s.resubmitPatch(w, r)
} else if pull.IsBranchBased() {
1448
-
span.SetAttributes(attribute.String("pull.type", "branch_based"))
1449
-
s.resubmitBranch(w, r.WithContext(ctx))
1110
+
s.resubmitBranch(w, r)
} else if pull.IsForkBased() {
1452
-
span.SetAttributes(attribute.String("pull.type", "fork_based"))
1453
-
s.resubmitFork(w, r.WithContext(ctx))
1113
+
s.resubmitFork(w, r)
1456
-
span.SetAttributes(attribute.String("pull.type", "unknown"))
func (s *State) resubmitPatch(w http.ResponseWriter, r *http.Request) {
1461
-
ctx, span := s.t.TraceStart(r.Context(), "resubmitPatch")
1464
-
user := s.auth.GetUser(r.WithContext(ctx))
1120
+
user := s.auth.GetUser(r)
1466
-
pull, ok := ctx.Value("pull").(*db.Pull)
1122
+
pull, ok := r.Context().Value("pull").(*db.Pull)
log.Println("failed to get pull")
1469
-
span.RecordError(errors.New("failed to get pull from context"))
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
1474
-
span.SetAttributes(
1475
-
attribute.Int("pull.id", pull.PullId),
1476
-
attribute.String("pull.owner", pull.OwnerDid),
1479
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
1129
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
1482
-
span.RecordError(err)
if user.Did != pull.OwnerDid {
log.Println("unauthorized user")
1488
-
span.SetAttributes(attribute.String("error", "unauthorized_user"))
w.WriteHeader(http.StatusUnauthorized)
patch := r.FormValue("patch")
1494
-
span.SetAttributes(attribute.Bool("has_patch", patch != ""))
if err = validateResubmittedPatch(pull, patch); err != nil {
1497
-
span.SetAttributes(attribute.String("error", "invalid_patch"))
s.pages.Notice(w, "resubmit-error", err.Error())
1502
-
tx, err := s.db.BeginTx(ctx, nil)
1148
+
tx, err := s.db.BeginTx(r.Context(), nil)
log.Println("failed to start tx")
1505
-
span.RecordError(err)
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···
err = db.ResubmitPull(tx, pull, patch, "")
log.Println("failed to resubmit pull request", err)
1514
-
span.RecordError(err)
s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull request. Try again later.")
1518
-
client, _ := s.auth.AuthorizedClient(r.WithContext(ctx))
1162
+
client, _ := s.auth.AuthorizedClient(r)
1520
-
ex, err := comatproto.RepoGetRecord(ctx, client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1164
+
ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1523
-
span.RecordError(err)
1524
-
span.SetAttributes(attribute.String("error", "record_not_found"))
s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
1529
-
_, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{
1171
+
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoPullNSID,
···
log.Println("failed to update record", err)
1546
-
span.RecordError(err)
s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.")
if err = tx.Commit(); err != nil {
log.Println("failed to commit transaction", err)
1553
-
span.RecordError(err)
s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull.")
···
func (s *State) resubmitBranch(w http.ResponseWriter, r *http.Request) {
1563
-
ctx, span := s.t.TraceStart(r.Context(), "resubmitBranch")
1203
+
user := s.auth.GetUser(r)
1566
-
user := s.auth.GetUser(r.WithContext(ctx))
1568
-
pull, ok := ctx.Value("pull").(*db.Pull)
1205
+
pull, ok := r.Context().Value("pull").(*db.Pull)
log.Println("failed to get pull")
1571
-
span.RecordError(errors.New("failed to get pull from context"))
1572
-
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
1208
+
s.pages.Notice(w, "resubmit-error", "Failed to edit patch. Try again later.")
1576
-
span.SetAttributes(
1577
-
attribute.Int("pull.id", pull.PullId),
1578
-
attribute.String("pull.owner", pull.OwnerDid),
1579
-
attribute.String("pull.source_branch", pull.PullSource.Branch),
1580
-
attribute.String("pull.target_branch", pull.TargetBranch),
1583
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
1212
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
1586
-
span.RecordError(err)
if user.Did != pull.OwnerDid {
log.Println("unauthorized user")
1592
-
span.SetAttributes(attribute.String("error", "unauthorized_user"))
w.WriteHeader(http.StatusUnauthorized)
1597
-
if !f.RepoInfo(ctx, s, user).Roles.IsPushAllowed() {
1224
+
if !f.RepoInfo(s, user).Roles.IsPushAllowed() {
log.Println("unauthorized user")
1599
-
span.SetAttributes(attribute.String("error", "push_not_allowed"))
w.WriteHeader(http.StatusUnauthorized)
···
ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev)
log.Printf("failed to create client for %s: %s", f.Knot, err)
1607
-
span.RecordError(err)
1608
-
span.SetAttributes(attribute.String("error", "client_creation_failed"))
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···
comparison, err := ksClient.Compare(f.OwnerDid(), f.RepoName, pull.TargetBranch, pull.PullSource.Branch)
log.Printf("compare request failed: %s", err)
1616
-
span.RecordError(err)
1617
-
span.SetAttributes(attribute.String("error", "compare_failed"))
s.pages.Notice(w, "resubmit-error", err.Error())
sourceRev := comparison.Rev2
patch := comparison.Patch
1624
-
span.SetAttributes(attribute.String("source_rev", sourceRev))
if err = validateResubmittedPatch(pull, patch); err != nil {
1627
-
span.SetAttributes(attribute.String("error", "invalid_patch"))
s.pages.Notice(w, "resubmit-error", err.Error())
if sourceRev == pull.Submissions[pull.LastRoundNumber()].SourceRev {
1633
-
span.SetAttributes(attribute.String("error", "no_changes"))
s.pages.Notice(w, "resubmit-error", "This branch has not changed since the last submission.")
1638
-
tx, err := s.db.BeginTx(ctx, nil)
1257
+
tx, err := s.db.BeginTx(r.Context(), nil)
log.Println("failed to start tx")
1641
-
span.RecordError(err)
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···
err = db.ResubmitPull(tx, pull, patch, sourceRev)
log.Println("failed to create pull request", err)
1650
-
span.RecordError(err)
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1654
-
client, _ := s.auth.AuthorizedClient(r.WithContext(ctx))
1271
+
client, _ := s.auth.AuthorizedClient(r)
1656
-
ex, err := comatproto.RepoGetRecord(ctx, client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1273
+
ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1659
-
span.RecordError(err)
1660
-
span.SetAttributes(attribute.String("error", "record_not_found"))
s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
···
recordPullSource := &tangled.RepoPull_Source{
Branch: pull.PullSource.Branch,
1668
-
_, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{
1283
+
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoPullNSID,
···
log.Println("failed to update record", err)
1686
-
span.RecordError(err)
s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.")
if err = tx.Commit(); err != nil {
log.Println("failed to commit transaction", err)
1693
-
span.RecordError(err)
s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull.")
···
func (s *State) resubmitFork(w http.ResponseWriter, r *http.Request) {
1703
-
ctx, span := s.t.TraceStart(r.Context(), "resubmitFork")
1706
-
user := s.auth.GetUser(r.WithContext(ctx))
1316
+
user := s.auth.GetUser(r)
1708
-
pull, ok := ctx.Value("pull").(*db.Pull)
1318
+
pull, ok := r.Context().Value("pull").(*db.Pull)
log.Println("failed to get pull")
1711
-
span.RecordError(errors.New("failed to get pull from context"))
1712
-
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
1321
+
s.pages.Notice(w, "resubmit-error", "Failed to edit patch. Try again later.")
1716
-
span.SetAttributes(
1717
-
attribute.Int("pull.id", pull.PullId),
1718
-
attribute.String("pull.owner", pull.OwnerDid),
1719
-
attribute.String("pull.source_branch", pull.PullSource.Branch),
1720
-
attribute.String("pull.target_branch", pull.TargetBranch),
1723
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
1325
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to get repo and knot", err)
1726
-
span.RecordError(err)
if user.Did != pull.OwnerDid {
log.Println("unauthorized user")
1732
-
span.SetAttributes(attribute.String("error", "unauthorized_user"))
w.WriteHeader(http.StatusUnauthorized)
1737
-
forkRepo, err := db.GetRepoByAtUri(ctx, s.db, pull.PullSource.RepoAt.String())
1337
+
forkRepo, err := db.GetRepoByAtUri(s.db, pull.PullSource.RepoAt.String())
log.Println("failed to get source repo", err)
1740
-
span.RecordError(err)
1741
-
span.SetAttributes(attribute.String("error", "source_repo_not_found"))
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1746
-
span.SetAttributes(
1747
-
attribute.String("fork.knot", forkRepo.Knot),
1748
-
attribute.String("fork.did", forkRepo.Did),
1749
-
attribute.String("fork.name", forkRepo.Name),
// extract patch by performing compare
ksClient, err := NewUnsignedClient(forkRepo.Knot, s.config.Dev)
log.Printf("failed to create client for %s: %s", forkRepo.Knot, err)
1756
-
span.RecordError(err)
1757
-
span.SetAttributes(attribute.String("error", "client_creation_failed"))
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···
secret, err := db.GetRegistrationKey(s.db, forkRepo.Knot)
log.Printf("failed to get registration key for %s: %s", forkRepo.Knot, err)
1765
-
span.RecordError(err)
1766
-
span.SetAttributes(attribute.String("error", "reg_key_not_found"))
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···
signedClient, err := NewSignedClient(forkRepo.Knot, secret, s.config.Dev)
log.Printf("failed to create signed client for %s: %s", forkRepo.Knot, err)
1775
-
span.RecordError(err)
1776
-
span.SetAttributes(attribute.String("error", "signed_client_creation_failed"))
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···
resp, err := signedClient.NewHiddenRef(forkRepo.Did, forkRepo.Name, pull.PullSource.Branch, pull.TargetBranch)
if err != nil || resp.StatusCode != http.StatusNoContent {
log.Printf("failed to update tracking branch: %s", err)
1784
-
span.RecordError(err)
1785
-
span.SetAttributes(attribute.String("error", "hidden_ref_update_failed"))
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
hiddenRef := fmt.Sprintf("hidden/%s/%s", pull.PullSource.Branch, pull.TargetBranch)
1791
-
span.SetAttributes(attribute.String("hidden_ref", hiddenRef))
comparison, err := ksClient.Compare(forkRepo.Did, forkRepo.Name, hiddenRef, pull.PullSource.Branch)
log.Printf("failed to compare branches: %s", err)
1796
-
span.RecordError(err)
1797
-
span.SetAttributes(attribute.String("error", "compare_failed"))
s.pages.Notice(w, "resubmit-error", err.Error())
sourceRev := comparison.Rev2
patch := comparison.Patch
1804
-
span.SetAttributes(attribute.String("source_rev", sourceRev))
if err = validateResubmittedPatch(pull, patch); err != nil {
1807
-
span.SetAttributes(attribute.String("error", "invalid_patch"))
s.pages.Notice(w, "resubmit-error", err.Error())
if sourceRev == pull.Submissions[pull.LastRoundNumber()].SourceRev {
1813
-
span.SetAttributes(attribute.String("error", "no_changes"))
s.pages.Notice(w, "resubmit-error", "This branch has not changed since the last submission.")
1818
-
tx, err := s.db.BeginTx(ctx, nil)
1395
+
tx, err := s.db.BeginTx(r.Context(), nil)
log.Println("failed to start tx")
1821
-
span.RecordError(err)
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···
err = db.ResubmitPull(tx, pull, patch, sourceRev)
log.Println("failed to create pull request", err)
1830
-
span.RecordError(err)
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1834
-
client, _ := s.auth.AuthorizedClient(r.WithContext(ctx))
1409
+
client, _ := s.auth.AuthorizedClient(r)
1836
-
ex, err := comatproto.RepoGetRecord(ctx, client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1411
+
ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1839
-
span.RecordError(err)
1840
-
span.SetAttributes(attribute.String("error", "record_not_found"))
s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
···
Branch: pull.PullSource.Branch,
1850
-
_, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{
1423
+
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoPullNSID,
···
log.Println("failed to update record", err)
1868
-
span.RecordError(err)
s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.")
if err = tx.Commit(); err != nil {
log.Println("failed to commit transaction", err)
1875
-
span.RecordError(err)
s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull.")
···
func (s *State) MergePull(w http.ResponseWriter, r *http.Request) {
1902
-
ctx, span := s.t.TraceStart(r.Context(), "MergePull")
1905
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
1473
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to resolve repo:", err)
1908
-
span.RecordError(err)
1909
-
span.SetAttributes(attribute.String("error", "resolve_repo_failed"))
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1914
-
pull, ok := ctx.Value("pull").(*db.Pull)
1480
+
pull, ok := r.Context().Value("pull").(*db.Pull)
log.Println("failed to get pull")
1917
-
span.SetAttributes(attribute.String("error", "pull_not_in_context"))
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
1922
-
span.SetAttributes(
1923
-
attribute.Int("pull.id", pull.PullId),
1924
-
attribute.String("pull.owner", pull.OwnerDid),
1925
-
attribute.String("target_branch", pull.TargetBranch),
secret, err := db.GetRegistrationKey(s.db, f.Knot)
log.Printf("no registration key found for domain %s: %s\n", f.Knot, err)
1931
-
span.RecordError(err)
1932
-
span.SetAttributes(attribute.String("error", "reg_key_not_found"))
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1937
-
ident, err := s.resolver.ResolveIdent(ctx, pull.OwnerDid)
1494
+
ident, err := s.resolver.ResolveIdent(r.Context(), pull.OwnerDid)
log.Printf("resolving identity: %s", err)
1940
-
span.RecordError(err)
1941
-
span.SetAttributes(attribute.String("error", "resolve_identity_failed"))
w.WriteHeader(http.StatusNotFound)
···
email, err := db.GetPrimaryEmail(s.db, pull.OwnerDid)
log.Printf("failed to get primary email: %s", err)
1949
-
span.RecordError(err)
1950
-
span.SetAttributes(attribute.String("error", "get_email_failed"))
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
log.Printf("failed to create signed client for %s: %s", f.Knot, err)
1956
-
span.RecordError(err)
1957
-
span.SetAttributes(attribute.String("error", "client_creation_failed"))
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
···
resp, err := ksClient.Merge([]byte(pull.LatestPatch()), f.OwnerDid(), f.RepoName, pull.TargetBranch, pull.Title, pull.Body, ident.Handle.String(), email.Address)
log.Printf("failed to merge pull request: %s", err)
1966
-
span.RecordError(err)
1967
-
span.SetAttributes(attribute.String("error", "merge_failed"))
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1972
-
span.SetAttributes(attribute.Int("response.status", resp.StatusCode))
if resp.StatusCode == http.StatusOK {
err := db.MergePull(s.db, f.RepoAt, pull.PullId)
log.Printf("failed to update pull request status in database: %s", err)
1978
-
span.RecordError(err)
1979
-
span.SetAttributes(attribute.String("error", "db_update_failed"))
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
s.pages.HxLocation(w, fmt.Sprintf("/@%s/%s/pulls/%d", f.OwnerHandle(), f.RepoName, pull.PullId))
log.Printf("knotserver returned non-OK status code for merge: %d", resp.StatusCode)
1986
-
span.SetAttributes(attribute.String("error", "non_ok_response"))
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
func (s *State) ClosePull(w http.ResponseWriter, r *http.Request) {
1992
-
ctx, span := s.t.TraceStart(r.Context(), "ClosePull")
1995
-
user := s.auth.GetUser(r.WithContext(ctx))
1536
+
user := s.auth.GetUser(r)
1997
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
1538
+
f, err := s.fullyResolvedRepo(r)
log.Println("malformed middleware")
2000
-
span.RecordError(err)
2001
-
span.SetAttributes(attribute.String("error", "resolve_repo_failed"))
2005
-
pull, ok := ctx.Value("pull").(*db.Pull)
1544
+
pull, ok := r.Context().Value("pull").(*db.Pull)
log.Println("failed to get pull")
2008
-
span.SetAttributes(attribute.String("error", "pull_not_in_context"))
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
2013
-
span.SetAttributes(
2014
-
attribute.Int("pull.id", pull.PullId),
2015
-
attribute.String("pull.owner", pull.OwnerDid),
2016
-
attribute.String("user.did", user.Did),
// auth filter: only owner or collaborators can close
roles := RolesInRepo(s, user, f)
isCollaborator := roles.IsCollaborator()
isPullAuthor := user.Did == pull.OwnerDid
isCloseAllowed := isCollaborator || isPullAuthor
2025
-
span.SetAttributes(
2026
-
attribute.Bool("is_collaborator", isCollaborator),
2027
-
attribute.Bool("is_pull_author", isPullAuthor),
2028
-
attribute.Bool("is_close_allowed", isCloseAllowed),
log.Println("failed to close pull")
2033
-
span.SetAttributes(attribute.String("error", "unauthorized"))
s.pages.Notice(w, "pull-close", "You are unauthorized to close this pull.")
2039
-
tx, err := s.db.BeginTx(ctx, nil)
1563
+
tx, err := s.db.BeginTx(r.Context(), nil)
log.Println("failed to start transaction", err)
2042
-
span.RecordError(err)
2043
-
span.SetAttributes(attribute.String("error", "transaction_start_failed"))
s.pages.Notice(w, "pull-close", "Failed to close pull.")
···
err = db.ClosePull(tx, f.RepoAt, pull.PullId)
log.Println("failed to close pull", err)
2052
-
span.RecordError(err)
2053
-
span.SetAttributes(attribute.String("error", "db_close_failed"))
s.pages.Notice(w, "pull-close", "Failed to close pull.")
···
// Commit the transaction
if err = tx.Commit(); err != nil {
log.Println("failed to commit transaction", err)
2061
-
span.RecordError(err)
2062
-
span.SetAttributes(attribute.String("error", "transaction_commit_failed"))
s.pages.Notice(w, "pull-close", "Failed to close pull.")
···
func (s *State) ReopenPull(w http.ResponseWriter, r *http.Request) {
2072
-
ctx, span := s.t.TraceStart(r.Context(), "ReopenPull")
2075
-
user := s.auth.GetUser(r.WithContext(ctx))
1590
+
user := s.auth.GetUser(r)
2077
-
f, err := s.fullyResolvedRepo(r.WithContext(ctx))
1592
+
f, err := s.fullyResolvedRepo(r)
log.Println("failed to resolve repo", err)
2080
-
span.RecordError(err)
2081
-
span.SetAttributes(attribute.String("error", "resolve_repo_failed"))
s.pages.Notice(w, "pull-reopen", "Failed to reopen pull.")
2086
-
pull, ok := ctx.Value("pull").(*db.Pull)
1599
+
pull, ok := r.Context().Value("pull").(*db.Pull)
log.Println("failed to get pull")
2089
-
span.SetAttributes(attribute.String("error", "pull_not_in_context"))
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
2094
-
span.SetAttributes(
2095
-
attribute.Int("pull.id", pull.PullId),
2096
-
attribute.String("pull.owner", pull.OwnerDid),
2097
-
attribute.String("user.did", user.Did),
2100
-
// auth filter: only owner or collaborators can reopen
1606
+
// auth filter: only owner or collaborators can close
roles := RolesInRepo(s, user, f)
isCollaborator := roles.IsCollaborator()
isPullAuthor := user.Did == pull.OwnerDid
2104
-
isReopenAllowed := isCollaborator || isPullAuthor
2106
-
span.SetAttributes(
2107
-
attribute.Bool("is_collaborator", isCollaborator),
2108
-
attribute.Bool("is_pull_author", isPullAuthor),
2109
-
attribute.Bool("is_reopen_allowed", isReopenAllowed),
2112
-
if !isReopenAllowed {
2113
-
log.Println("failed to reopen pull")
2114
-
span.SetAttributes(attribute.String("error", "unauthorized"))
2115
-
s.pages.Notice(w, "pull-close", "You are unauthorized to reopen this pull.")
1610
+
isCloseAllowed := isCollaborator || isPullAuthor
1611
+
if !isCloseAllowed {
1612
+
log.Println("failed to close pull")
1613
+
s.pages.Notice(w, "pull-close", "You are unauthorized to close this pull.")
2120
-
tx, err := s.db.BeginTx(ctx, nil)
1618
+
tx, err := s.db.BeginTx(r.Context(), nil)
log.Println("failed to start transaction", err)
2123
-
span.RecordError(err)
2124
-
span.SetAttributes(attribute.String("error", "transaction_start_failed"))
s.pages.Notice(w, "pull-reopen", "Failed to reopen pull.")
···
err = db.ReopenPull(tx, f.RepoAt, pull.PullId)
log.Println("failed to reopen pull", err)
2133
-
span.RecordError(err)
2134
-
span.SetAttributes(attribute.String("error", "db_reopen_failed"))
s.pages.Notice(w, "pull-reopen", "Failed to reopen pull.")
···
// Commit the transaction
if err = tx.Commit(); err != nil {
log.Println("failed to commit transaction", err)
2142
-
span.RecordError(err)
2143
-
span.SetAttributes(attribute.String("error", "transaction_commit_failed"))
s.pages.Notice(w, "pull-reopen", "Failed to reopen pull.")