diff --git a/appview/db/db.go b/appview/db/db.go
index a501f141..f4295656 100644
--- a/appview/db/db.go
+++ b/appview/db/db.go
@@ -393,9 +393,6 @@ func Make(dbPath string) (*DB, error) {
db.Exec("pragma foreign_keys = off;")
runMigration(db, "recreate-pulls-column-for-stacking-support", func(tx *sql.Tx) error {
_, err := tx.Exec(`
- -- disable fk to not delete submissions table
- pragma foreign_keys = off;
-
create table pulls_new (
-- identifiers
id integer primary key autoincrement,
@@ -446,15 +443,11 @@ func Make(dbPath string) (*DB, error) {
drop table pulls;
alter table pulls_new rename to pulls;
-
- -- reenable fk
- pragma foreign_keys = on;
`)
return err
})
db.Exec("pragma foreign_keys = on;")
->>>>>>> Conflict 1 of 1 ends
return &DB{db}, nil
}
diff --git a/appview/db/pulls.go b/appview/db/pulls.go
index 71f8ce7e..85ec13c9 100644
--- a/appview/db/pulls.go
+++ b/appview/db/pulls.go
@@ -49,7 +49,7 @@ func (p PullState) IsMerged() bool {
func (p PullState) IsClosed() bool {
return p == PullClosed
}
-func (p PullState) IsDelete() bool {
+func (p PullState) IsDeleted() bool {
return p == PullDeleted
}
@@ -885,11 +885,12 @@ func NewPullComment(e Execer, comment *PullComment) (int64, error) {
func SetPullState(e Execer, repoAt syntax.ATURI, pullId int, pullState PullState) error {
_, err := e.Exec(
- `update pulls set state = ? where repo_at = ? and pull_id = ? and state <> ?`,
+ `update pulls set state = ? where repo_at = ? and pull_id = ? and (state <> ? or state <> ?)`,
pullState,
repoAt,
pullId,
PullDeleted, // only update state of non-deleted pulls
+ PullMerged, // only update state of non-merged pulls
)
return err
}
@@ -1032,6 +1033,19 @@ func GetStack(e Execer, stackId string) (Stack, error) {
return pulls, nil
}
+func GetAbandonedPulls(e Execer, stackId string) ([]*Pull, error) {
+ pulls, err := GetPulls(
+ e,
+ FilterEq("stack_id", stackId),
+ FilterEq("state", PullDeleted),
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ return pulls, nil
+}
+
// position of this pull in the stack
func (stack Stack) Position(pull *Pull) int {
return slices.IndexFunc(stack, func(p *Pull) bool {
@@ -1096,3 +1110,24 @@ func (stack Stack) CombinedPatch() string {
}
return combined.String()
}
+
+// filter out PRs that are "active"
+//
+// PRs that are still open are active
+func (stack Stack) Mergeable() Stack {
+ var mergeable Stack
+
+ for _, p := range stack {
+ // stop at the first merged PR
+ if p.State == PullMerged || p.State == PullClosed {
+ break
+ }
+
+ // skip over deleted PRs
+ if p.State != PullDeleted {
+ mergeable = append(mergeable, p)
+ }
+ }
+
+ return mergeable
+}
diff --git a/appview/pages/pages.go b/appview/pages/pages.go
index 863588a5..998fbc5e 100644
--- a/appview/pages/pages.go
+++ b/appview/pages/pages.go
@@ -738,14 +738,15 @@ func (r ResubmitResult) Unknown() bool {
}
type RepoSinglePullParams struct {
- LoggedInUser *oauth.User
- RepoInfo repoinfo.RepoInfo
- Active string
- DidHandleMap map[string]string
- Pull *db.Pull
- Stack db.Stack
- MergeCheck types.MergeCheckResponse
- ResubmitCheck ResubmitResult
+ LoggedInUser *oauth.User
+ RepoInfo repoinfo.RepoInfo
+ Active string
+ DidHandleMap map[string]string
+ Pull *db.Pull
+ Stack db.Stack
+ AbandonedPulls []*db.Pull
+ MergeCheck types.MergeCheckResponse
+ ResubmitCheck ResubmitResult
}
func (p *Pages) RepoSinglePull(w io.Writer, params RepoSinglePullParams) error {
@@ -837,6 +838,7 @@ type PullActionsParams struct {
RoundNumber int
MergeCheck types.MergeCheckResponse
ResubmitCheck ResubmitResult
+ Stack db.Stack
}
func (p *Pages) PullActionsFragment(w io.Writer, params PullActionsParams) error {
diff --git a/appview/pages/templates/repo/pulls/fragments/pullActions.html b/appview/pages/templates/repo/pulls/fragments/pullActions.html
index c4e4077c..e98b3d83 100644
--- a/appview/pages/templates/repo/pulls/fragments/pullActions.html
+++ b/appview/pages/templates/repo/pulls/fragments/pullActions.html
@@ -1,6 +1,17 @@
{{ define "repo/pulls/fragments/pullActions" }}
{{ $lastIdx := sub (len .Pull.Submissions) 1 }}
{{ $roundNumber := .RoundNumber }}
+ {{ $stack := .Stack }}
+
+ {{ $totalPulls := sub 0 1 }}
+ {{ $below := sub 0 1 }}
+ {{ $stackCount := "" }}
+ {{ if .Pull.IsStacked }}
+ {{ $totalPulls = len $stack }}
+ {{ $below = $stack.Below .Pull }}
+ {{ $mergeable := len $below.Mergeable }}
+ {{ $stackCount = printf "%d/%d" $mergeable $totalPulls }}
+ {{ end }}
{{ $isPushAllowed := .RepoInfo.Roles.IsPushAllowed }}
{{ $isMerged := .Pull.State.IsMerged }}
@@ -33,7 +44,7 @@
hx-confirm="Are you sure you want to merge pull #{{ .Pull.PullId }} into the `{{ .Pull.TargetBranch }}` branch?"
class="btn p-2 flex items-center gap-2 group" {{ $disabled }}>
{{ i "git-merge" "w-4 h-4" }}
- merge
+ merge{{if $stackCount}} {{$stackCount}}{{end}}
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
{{ end }}
diff --git a/appview/pages/templates/repo/pulls/fragments/pullHeader.html b/appview/pages/templates/repo/pulls/fragments/pullHeader.html
index 863dec16..a9f439a9 100644
--- a/appview/pages/templates/repo/pulls/fragments/pullHeader.html
+++ b/appview/pages/templates/repo/pulls/fragments/pullHeader.html
@@ -2,8 +2,8 @@
{{ block "pullState" .Pull }} {{ end }}
- #{{ .Pull.PullId }}
{{ .Pull.Title }}
+ #{{ .Pull.PullId }}
@@ -96,6 +96,9 @@
{{ else if .State.IsMerged }}
{{ $bgColor = "bg-purple-600 dark:bg-purple-700" }}
{{ $icon = "git-merge" }}
+ {{ else if .State.IsDeleted }}
+ {{ $bgColor = "bg-red-600 dark:bg-red-700" }}
+ {{ $icon = "git-pull-request-closed" }}
{{ end }}
diff --git a/appview/pages/templates/repo/pulls/fragments/pullStack.html b/appview/pages/templates/repo/pulls/fragments/pullStack.html
index 16750a07..41d5e492 100644
--- a/appview/pages/templates/repo/pulls/fragments/pullStack.html
+++ b/appview/pages/templates/repo/pulls/fragments/pullStack.html
@@ -1,27 +1,16 @@
{{ define "repo/pulls/fragments/pullStack" }}
-
+
STACK
+ {{ block "pullList" (list .Stack $) }} {{ end }}
+
+ {{ if gt (len .AbandonedPulls) 0 }}
+
ABANDONED PULLS
+ {{ block "pullList" (list .AbandonedPulls $) }} {{ end }}
+ {{ end }}
{{ end }}
{{ define "summarizedHeader" }}
-
+
{{ block "summarizedPullState" . }} {{ end }}
#{{ .PullId }}
@@ -35,12 +24,16 @@
{{ $commentCount := len $lastSubmission.Comments }}
+ {{ i "message-square" "w-3 h-3 md:hidden" }}
{{ $commentCount }}
- comment{{if ne $commentCount 1}}s{{end}}
+ comment{{if ne $commentCount 1}}s{{end}}
- round #{{ $latestRound }}
+
+ round
+ #{{ $latestRound }}
+
{{ end }}
@@ -55,9 +48,35 @@
{{ else if .State.IsMerged }}
{{ $fgColor = "text-purple-600 dark:text-purple-500" }}
{{ $icon = "git-merge" }}
+ {{ else if .State.IsDeleted }}
+ {{ $fgColor = "text-red-600 dark:text-red-500" }}
+ {{ $icon = "git-pull-request-closed" }}
{{ end }}
{{ $style := printf "w-4 h-4 %s" $fgColor }}
{{ i $icon $style }}
{{ end }}
+
+{{ define "pullList" }}
+ {{ $list := index . 0 }}
+ {{ $root := index . 1 }}
+
+{{ end }}
diff --git a/appview/pages/templates/repo/pulls/pull.html b/appview/pages/templates/repo/pulls/pull.html
index 5dcaac97..8c30dafb 100644
--- a/appview/pages/templates/repo/pulls/pull.html
+++ b/appview/pages/templates/repo/pulls/pull.html
@@ -15,7 +15,6 @@
{{ if .Pull.IsStacked }}
-
STACK
{{ template "repo/pulls/fragments/pullStack" . }}
{{ end }}
@@ -85,7 +84,7 @@
{{ end }}
-
+
{{ if .IsFormatPatch }}
{{ $patches := .AsFormatPatch }}
{{ $round := .RoundNumber }}
@@ -169,7 +168,7 @@
{{ end }}
{{ if $.LoggedInUser }}
- {{ template "repo/pulls/fragments/pullActions" (dict "LoggedInUser" $.LoggedInUser "Pull" $.Pull "RepoInfo" $.RepoInfo "RoundNumber" .RoundNumber "MergeCheck" $.MergeCheck "ResubmitCheck" $.ResubmitCheck) }}
+ {{ template "repo/pulls/fragments/pullActions" (dict "LoggedInUser" $.LoggedInUser "Pull" $.Pull "RepoInfo" $.RepoInfo "RoundNumber" .RoundNumber "MergeCheck" $.MergeCheck "ResubmitCheck" $.ResubmitCheck "Stack" $.Stack) }}
{{ else }}
+ {{ else if .Pull.State.IsDeleted }}
+
+
+ {{ i "git-pull-request-closed" "w-4 h-4" }}
+ This pull has been deleted (possibly by jj abandon or jj squash)
+
+
{{ else if and .MergeCheck .MergeCheck.Error }}
diff --git a/appview/state/middleware.go b/appview/state/middleware.go
index e0f409a8..e78cb0a3 100644
--- a/appview/state/middleware.go
+++ b/appview/state/middleware.go
@@ -178,8 +178,14 @@ func ResolvePull(s *State) middleware.Middleware {
log.Println("failed to get stack", err)
return
}
+ abandonedPulls, err := db.GetAbandonedPulls(s.db, pr.StackId)
+ if err != nil {
+ log.Println("failed to get abandoned pulls", err)
+ return
+ }
ctx = context.WithValue(ctx, "stack", stack)
+ ctx = context.WithValue(ctx, "abandonedPulls", abandonedPulls)
}
next.ServeHTTP(w, r.WithContext(ctx))
diff --git a/appview/state/pull.go b/appview/state/pull.go
index 3954206f..35c17c8c 100644
--- a/appview/state/pull.go
+++ b/appview/state/pull.go
@@ -75,6 +75,7 @@ func (s *State) PullActions(w http.ResponseWriter, r *http.Request) {
RoundNumber: roundNumber,
MergeCheck: mergeCheckResponse,
ResubmitCheck: resubmitResult,
+ Stack: stack,
})
return
}
@@ -97,6 +98,7 @@ func (s *State) RepoSinglePull(w http.ResponseWriter, r *http.Request) {
// can be nil if this pull is not stacked
stack, _ := r.Context().Value("stack").(db.Stack)
+ abandonedPulls, _ := r.Context().Value("abandonedPulls").([]*db.Pull)
totalIdents := 1
for _, submission := range pull.Submissions {
@@ -132,13 +134,14 @@ func (s *State) RepoSinglePull(w http.ResponseWriter, r *http.Request) {
}
s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{
- LoggedInUser: user,
- RepoInfo: f.RepoInfo(s, user),
- DidHandleMap: didHandleMap,
- Pull: pull,
- Stack: stack,
- MergeCheck: mergeCheckResponse,
- ResubmitCheck: resubmitResult,
+ LoggedInUser: user,
+ RepoInfo: f.RepoInfo(s, user),
+ DidHandleMap: didHandleMap,
+ Pull: pull,
+ Stack: stack,
+ AbandonedPulls: abandonedPulls,
+ MergeCheck: mergeCheckResponse,
+ ResubmitCheck: resubmitResult,
})
}
@@ -167,21 +170,9 @@ func (s *State) mergeCheck(f *FullyResolvedRepo, pull *db.Pull, stack db.Stack)
if pull.IsStacked() {
// combine patches of substack
subStack := stack.Below(pull)
-
// collect the portion of the stack that is mergeable
- var mergeable db.Stack
- for _, p := range subStack {
- // stop at the first merged PR
- if p.State == db.PullMerged || p.State == db.PullClosed {
- break
- }
-
- // skip over deleted PRs
- if p.State != db.PullDeleted {
- mergeable = append(mergeable, p)
- }
- }
-
+ mergeable := subStack.Mergeable()
+ // combine each patch
patch = mergeable.CombinedPatch()
}
@@ -225,7 +216,7 @@ func (s *State) mergeCheck(f *FullyResolvedRepo, pull *db.Pull, stack db.Stack)
}
func (s *State) resubmitCheck(f *FullyResolvedRepo, pull *db.Pull, stack db.Stack) pages.ResubmitResult {
- if pull.State == db.PullMerged || pull.PullSource == nil {
+ if pull.State == db.PullMerged || pull.State == db.PullDeleted || pull.PullSource == nil {
return pages.Unknown
}
@@ -903,6 +894,13 @@ func (s *State) createPullRequest(
return
}
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
+ return
+ }
+
tx, err := s.db.BeginTx(r.Context(), nil)
if err != nil {
log.Println("failed to start tx")
@@ -950,12 +948,6 @@ func (s *State) createPullRequest(
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
return
}
- client, err := s.oauth.AuthorizedClient(r)
- if err != nil {
- log.Println("failed to get authorized client", err)
- s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
- return
- }
pullId, err := db.NextPullId(tx, f.RepoAt)
if err != nil {
log.Println("failed to get pull id", err)
@@ -1820,21 +1812,10 @@ func (s *State) MergePull(w http.ResponseWriter, r *http.Request) {
// combine patches of substack
subStack := stack.Below(pull)
-
// collect the portion of the stack that is mergeable
- for _, p := range subStack {
- // stop at the first merged/closed PR
- if p.State == db.PullMerged || p.State == db.PullClosed {
- break
- }
-
- // skip over deleted PRs
- if p.State == db.PullDeleted {
- continue
- }
-
- pullsToMerge = append(pullsToMerge, p)
- }
+ mergeable := subStack.Mergeable()
+ // add to total patch
+ pullsToMerge = append(pullsToMerge, mergeable...)
}
patch := pullsToMerge.CombinedPatch()
@@ -2014,10 +1995,10 @@ func (s *State) ReopenPull(w http.ResponseWriter, r *http.Request) {
var pullsToReopen []*db.Pull
pullsToReopen = append(pullsToReopen, pull)
- // if this PR is stacked, then we want to reopen all PRs below this one on the stack
+ // if this PR is stacked, then we want to reopen all PRs above this one on the stack
if pull.IsStacked() {
stack := r.Context().Value("stack").(db.Stack)
- subStack := stack.StrictlyBelow(pull)
+ subStack := stack.StrictlyAbove(pull)
pullsToReopen = append(pullsToReopen, subStack...)
}
diff --git a/flake.nix b/flake.nix
index 8c32b023..fc66bfab 100644
--- a/flake.nix
+++ b/flake.nix
@@ -435,7 +435,7 @@
g = config.services.tangled-knotserver.gitUser;
in [
"d /var/lib/knotserver 0770 ${u} ${g} - -" # Create the directory first
- "f+ /var/lib/knotserver/secret 0660 ${u} ${g} - KNOT_SERVER_SECRET=679f15000084699abc6a20d3ef449efa3656583f38e456a08f0638250688ff2e"
+ "f+ /var/lib/knotserver/secret 0660 ${u} ${g} - KNOT_SERVER_SECRET=38a7c3237c2a585807e06a5bcfac92eb39442063f3da306b7acb15cfdc51d19d"
];
services.tangled-knotserver = {
enable = true;