···
49
+
// can be nil if this pull is not stacked
50
+
stack := r.Context().Value("stack").(db.Stack)
roundNumberStr := chi.URLParam(r, "round")
roundNumber, err := strconv.Atoi(roundNumberStr)
···
60
-
mergeCheckResponse := s.mergeCheck(f, pull)
63
+
mergeCheckResponse := s.mergeCheck(f, pull, stack)
resubmitResult := pages.Unknown
if user.Did == pull.OwnerDid {
resubmitResult = s.resubmitCheck(f, pull)
···
96
+
// can be nil if this pull is not stacked
97
+
stack := r.Context().Value("stack").(db.Stack)
for _, submission := range pull.Submissions {
totalIdents += len(submission.Comments)
···
120
-
mergeCheckResponse := s.mergeCheck(f, pull)
126
+
mergeCheckResponse := s.mergeCheck(f, pull, stack)
resubmitResult := pages.Unknown
if user != nil && user.Did == pull.OwnerDid {
resubmitResult = s.resubmitCheck(f, pull)
···
136
-
func (s *State) mergeCheck(f *FullyResolvedRepo, pull *db.Pull) types.MergeCheckResponse {
142
+
func (s *State) mergeCheck(f *FullyResolvedRepo, pull *db.Pull, stack db.Stack) types.MergeCheckResponse {
if pull.State == db.PullMerged {
return types.MergeCheckResponse{}
···
157
-
resp, err := ksClient.MergeCheck([]byte(pull.LatestPatch()), f.OwnerDid(), f.RepoName, pull.TargetBranch)
163
+
patch := pull.LatestPatch()
164
+
if pull.IsStacked() {
165
+
// combine patches of substack
166
+
subStack := stack.Below(pull)
168
+
// collect the portion of the stack that is mergeable
169
+
var mergeable db.Stack
170
+
for _, p := range subStack {
171
+
// stop at the first merged PR
172
+
if p.State == db.PullMerged {
176
+
// skip over closed PRs
178
+
// we will close PRs that are "removed" from a stack
179
+
if p.State != db.PullClosed {
180
+
mergeable = append(mergeable, p)
184
+
patch = mergeable.CombinedPatch()
187
+
resp, err := ksClient.MergeCheck([]byte(patch), f.OwnerDid(), f.RepoName, pull.TargetBranch)
log.Println("failed to check for mergeability:", err)
return types.MergeCheckResponse{
···
420
-
pulls, err := db.GetPulls(s.db, f.RepoAt, state)
450
+
pulls, err := db.GetPulls(
452
+
db.Filter("repo_at", f.RepoAt),
453
+
db.Filter("state", state),
log.Println("failed to get pulls", err)
s.pages.Notice(w, "pulls", "Failed to load pulls. Try again later.")
···
// TODO: can we just use a format-patch string here?
initialSubmission := db.PullSubmission{
1012
-
Patch: fp.Patch(),
err = db.NewPull(tx, &db.Pull{
···
TargetRepo: string(f.RepoAt),
TargetBranch: targetBranch,
1041
-
Patch: fp.Patch(),
Source: recordPullSource,
writes = append(writes, &comatproto.RepoApplyWrites_Input_Writes_Elem{
···
pull, ok := r.Context().Value("pull").(*db.Pull)
log.Println("failed to get pull")
1695
-
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
1729
+
s.pages.Notice(w, "pull-merge-error", "Failed to merge patch. Try again later.")
1733
+
var pullsToMerge db.Stack
1734
+
pullsToMerge = append(pullsToMerge, pull)
1735
+
if pull.IsStacked() {
1736
+
stack, ok := r.Context().Value("stack").(db.Stack)
1738
+
log.Println("failed to get stack")
1739
+
s.pages.Notice(w, "pull-merge-error", "Failed to merge patch. Try again later.")
1743
+
// combine patches of substack
1744
+
subStack := stack.Below(pull)
1746
+
// collect the portion of the stack that is mergeable
1747
+
for _, p := range subStack {
1748
+
// stop at the first merged PR
1749
+
if p.State == db.PullMerged {
1753
+
// skip over closed PRs
1755
+
// TODO: we need a "deleted" state for such PRs, but without losing discussions
1756
+
// we will close PRs that are "removed" from a stack
1757
+
if p.State == db.PullClosed {
1761
+
pullsToMerge = append(pullsToMerge, p)
1765
+
patch := pullsToMerge.CombinedPatch()
secret, err := db.GetRegistrationKey(s.db, f.Knot)
log.Printf("no registration key found for domain %s: %s\n", f.Knot, err)
···
// Merge the pull request
1726
-
resp, err := ksClient.Merge([]byte(pull.LatestPatch()), f.OwnerDid(), f.RepoName, pull.TargetBranch, pull.Title, pull.Body, ident.Handle.String(), email.Address)
1794
+
resp, err := ksClient.Merge([]byte(patch), f.OwnerDid(), f.RepoName, pull.TargetBranch, pull.Title, pull.Body, ident.Handle.String(), email.Address)
log.Printf("failed to merge pull request: %s", err)
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1733
-
if resp.StatusCode == http.StatusOK {
1734
-
err := db.MergePull(s.db, f.RepoAt, pull.PullId)
1801
+
if resp.StatusCode != http.StatusOK {
1802
+
log.Printf("knotserver returned non-OK status code for merge: %d", resp.StatusCode)
1803
+
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1807
+
tx, err := s.db.Begin()
1809
+
log.Printf("failed to start transcation", err)
1810
+
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1814
+
for _, p := range pullsToMerge {
1815
+
err := db.MergePull(tx, f.RepoAt, p.PullId)
log.Printf("failed to update pull request status in database: %s", err)
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1740
-
s.pages.HxLocation(w, fmt.Sprintf("/@%s/%s/pulls/%d", f.OwnerHandle(), f.RepoName, pull.PullId))
1742
-
log.Printf("knotserver returned non-OK status code for merge: %d", resp.StatusCode)
1825
+
// TODO: this is unsound, we should also revert the merge from the knotserver here
1826
+
log.Printf("failed to update pull request status in database: %s", err)
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1831
+
s.pages.HxLocation(w, fmt.Sprintf("/@%s/%s/pulls/%d", f.OwnerHandle(), f.RepoName, pull.PullId))
func (s *State) ClosePull(w http.ResponseWriter, r *http.Request) {
···
1782
-
// Close the pull in the database
1783
-
err = db.ClosePull(tx, f.RepoAt, pull.PullId)
1785
-
log.Println("failed to close pull", err)
1786
-
s.pages.Notice(w, "pull-close", "Failed to close pull.")
1869
+
var pullsToClose []*db.Pull
1870
+
pullsToClose = append(pullsToClose, pull)
1872
+
// if this PR is stacked, then we want to close all PRs below this one on the stack
1873
+
if pull.IsStacked() {
1874
+
stack := r.Context().Value("stack").(db.Stack)
1875
+
subStack := stack.StrictlyBelow(pull)
1876
+
pullsToClose = append(pullsToClose, subStack...)
1879
+
for _, p := range pullsToClose {
1880
+
// Close the pull in the database
1881
+
err = db.ClosePull(tx, f.RepoAt, p.PullId)
1883
+
log.Println("failed to close pull", err)
1884
+
s.pages.Notice(w, "pull-close", "Failed to close pull.")
// Commit the transaction
···
1837
-
// Reopen the pull in the database
1838
-
err = db.ReopenPull(tx, f.RepoAt, pull.PullId)
1840
-
log.Println("failed to reopen pull", err)
1841
-
s.pages.Notice(w, "pull-reopen", "Failed to reopen pull.")
1936
+
var pullsToReopen []*db.Pull
1937
+
pullsToReopen = append(pullsToReopen, pull)
1939
+
// if this PR is stacked, then we want to reopen all PRs below this one on the stack
1940
+
if pull.IsStacked() {
1941
+
stack := r.Context().Value("stack").(db.Stack)
1942
+
subStack := stack.StrictlyBelow(pull)
1943
+
pullsToReopen = append(pullsToReopen, subStack...)
1946
+
for _, p := range pullsToReopen {
1947
+
// Close the pull in the database
1948
+
err = db.ReopenPull(tx, f.RepoAt, p.PullId)
1950
+
log.Println("failed to close pull", err)
1951
+
s.pages.Notice(w, "pull-close", "Failed to close pull.")
// Commit the transaction