This repository has no description
1package pulls
2
3import (
4 "fmt"
5 "net/http"
6 "time"
7
8 "github.com/bluesky-social/indigo/atproto/syntax"
9 "tangled.org/core/api/tangled"
10 "tangled.org/core/appview/db"
11 "tangled.org/core/appview/models"
12 "tangled.org/core/appview/oauth"
13 "tangled.org/core/appview/reporesolver"
14 "tangled.org/core/orm"
15)
16
17func (s *Pulls) MergePull(w http.ResponseWriter, r *http.Request) {
18 l := s.logger.With("handler", "MergePull")
19
20 user := s.oauth.GetMultiAccountUser(r)
21 if user == nil {
22 l.Error("nil user")
23 s.pages.Notice(w, "pull-action-error", "You must be logged in to merge this pull.")
24 return
25 }
26 l = l.With("user", user.Did)
27
28 f, err := s.repoResolver.Resolve(r)
29 if err != nil {
30 l.Error("failed to resolve repo", "err", err)
31 s.pages.Notice(w, "pull-action-error", "Failed to merge pull request. Try again later.")
32 return
33 }
34 l = l.With("repo", f.RepoDid)
35
36 pull, ok := r.Context().Value("pull").(*models.Pull)
37 if !ok {
38 l.Error("failed to get pull")
39 s.pages.Notice(w, "pull-action-error", "Failed to merge patch. Try again later.")
40 return
41 }
42 l = l.With("pull_id", pull.PullId, "target_branch", pull.TargetBranch)
43
44 // merge target branch
45 {
46 client, err := s.oauth.ServiceClient(
47 r,
48 oauth.WithService(f.Knot),
49 oauth.WithLxm(tangled.GitMergeCommitNSID),
50 oauth.WithDev(s.config.Core.Dev),
51 oauth.WithTimeout(time.Second*20), // merge is quite slow on large repos, like witchsky
52 )
53 if err != nil {
54 l.Error("failed to connect to knot server", "err", err, "knot", f.Knot)
55 s.pages.Notice(w, "pull-action-error", "Failed to merge pull request. Try again later.")
56 return
57 }
58
59 var mergeCommit *tangled.GitMergeCommit_Input_MergeCommit
60 // TODO: pass custom merge commit body
61
62 err = tangled.GitMergeCommit(r.Context(), client, &tangled.GitMergeCommit_Input{
63 Target: &tangled.GitMergeCommit_Input_Target{
64 Repo: pull.RepoDid.String(),
65 Branch: pull.TargetBranch,
66 },
67 Source: &tangled.GitMergeCommit_Input_Source{
68 Repo: pull.SourceRepo.String(),
69 Commit: pull.LatestVersion().Head,
70 },
71 MergeCommit: mergeCommit,
72 Style: "rebase",
73 })
74 if err != nil {
75 s.logger.Error("failed to merge", "err", err)
76 s.pages.Notice(w, "pull-action-error", err.Error())
77 return
78 }
79 }
80
81 if err := s.writePullStatusRecord(r, user.Did, pull.AtUri(), models.StateMerged); err != nil {
82 l.Error("failed to write issue state record", "err", err)
83 s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.")
84 return
85 }
86
87 tx, err := s.db.Begin()
88 if err != nil {
89 l.Error("failed to start transaction", "err", err)
90 s.pages.Notice(w, "pull-action-error", "Failed to merge pull request. Try again later.")
91 return
92 }
93 defer tx.Rollback()
94
95 err = db.MergePulls(
96 tx,
97 orm.FilterEq("at_uri", pull.AtUri()),
98 )
99 if err != nil {
100 l.Error("failed to update pull request status in database", "err", err)
101 s.pages.Notice(w, "pull-action-error", "Failed to merge pull request. Try again later.")
102 return
103 }
104
105 err = tx.Commit()
106 if err != nil {
107 // TODO: this is unsound, we should also revert the merge from the knotserver here
108 l.Error("failed to commit merge transaction", "err", err)
109 s.pages.Notice(w, "pull-action-error", "Failed to merge pull request. Try again later.")
110 return
111 }
112
113 s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), pull)
114
115 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f)
116 s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
117}