The merge request Merge action now runs through htmx for every mode (fast-forward, squash, merge) instead of a full-page POST and 303 reload.
The form posts asynchronously, drops double submits and shows a pending indicator; without JS it still posts normally.
htmx merges get OOB fragments (state badge + action area). Refusals, failures, expired sessions and rejected origins render a status in the merge box.
Other open tabs of the same MR receive the merged state through the live stream.
The checks-label observer watches the stable MR bar so it survives swaps.
Deferred: the fragment path still builds the full page view (diff, comments) before rendering only state/actions; a dedicated state view builder is a follow-up.
Checks: go test ./..., go vet, node jstest suite (198 pass). Not manually tested in a browser.
@@ -50,9 +50,7 @@ Limits: the 100 most recent commits of the merge request, 16 KiB of each text, 1
50
50
51
51
The signed-in owner has an Inbox at `/-/inbox`, reached from the **Inbox** button at the top left of the home page, which shows the number of open items. It lists the open merge requests and the open issues of every repository, most recently updated first. The counters at the top (`N merge requests · M issues`) always count everything; `?repo=<name>` restricts the two lists to one repository, and the repository links under the counters set it. Repositories with issues off contribute no issues.
52
52
53
-
The **Running** section, after **Awaiting moderation**, lists queued and in-progress CI runs newest first, with links to each run, its repository, ref, and start time. The `N running` counter counts every repository; the repository filter also applies to this section. **Shift+I** (`I`) opens the inbox from any page for the signed-in owner, unless single-key shortcuts are off; lowercase `i` still opens the issues tab.
54
-
55
-
The page updates live: run status changes, merge request and issue events of any repository refresh the counters and the lists. Anyone who is not the signed-in owner, including a token, gets the same 404 as for an unknown page, and the same answer for the `owner` event stream it follows.
53
+
The page updates live: merge request and issue events of any repository refresh the counters and the lists. Anyone who is not the signed-in owner, including a token, gets the same 404 as for an unknown page, and the same answer for the `owner` event stream it follows.
56
54
57
55
## Public form and moderation
58
56
@@ -50,9 +50,7 @@ Limits: the 100 most recent commits of the merge request, 16 KiB of each text, 1
50
50
51
The signed-in owner has an Inbox at `/-/inbox`, reached from the **Inbox** button at the top left of the home page, which shows the number of open items. It lists the open merge requests and the open issues of every repository, most recently updated first. The counters at the top (`N merge requests · M issues`) always count everything; `?repo=<name>` restricts the two lists to one repository, and the repository links under the counters set it. Repositories with issues off contribute no issues.
51
The signed-in owner has an Inbox at `/-/inbox`, reached from the **Inbox** button at the top left of the home page, which shows the number of open items. It lists the open merge requests and the open issues of every repository, most recently updated first. The counters at the top (`N merge requests · M issues`) always count everything; `?repo=<name>` restricts the two lists to one repository, and the repository links under the counters set it. Repositories with issues off contribute no issues.
52
52
53
-
The **Running** section, after **Awaiting moderation**, lists queued and in-progress CI runs newest first, with links to each run, its repository, ref, and start time. The `N running` counter counts every repository; the repository filter also applies to this section. **Shift+I** (`I`) opens the inbox from any page for the signed-in owner, unless single-key shortcuts are off; lowercase `i` still opens the issues tab.
53
+
The page updates live: merge request and issue events of any repository refresh the counters and the lists. Anyone who is not the signed-in owner, including a token, gets the same 404 as for an unknown page, and the same answer for the `owner` event stream it follows.
54
-
55
-
The page updates live: run status changes, merge request and issue events of any repository refresh the counters and the lists. Anyone who is not the signed-in owner, including a token, gets the same 404 as for an unknown page, and the same answer for the `owner` event stream it follows.
56
54
57
## Public form and moderation
55
## Public form and moderation
58
56
Mdocs/releases.md+5-44
@@ -57,60 +57,21 @@ the S3 endpoint. Stored-token publishers need `release:write` and, for private
57
57
repository reads, `repo:read`. The owner component is `ERMITE_OWNER` (`owner` by
58
58
default).
59
59
60
-
GoReleaser does not read `GITHUB_API_URL` or `GITHUB_SERVER_URL` by itself, so
61
-
template `github_urls` from them (replace the fallback host and repository):
60
+
GoReleaser configuration (replace the host and repository):
62
61
63
62
```yaml
64
63
version: 2
65
-
# In CI the runner sets GITHUB_API_URL and GITHUB_SERVER_URL to the address the
66
-
# job can reach; the public URLs are the fallback for a local run.
67
64
github_urls:
68
-
api: '{{ or (index .Env "GITHUB_API_URL") "https://git.example.org/-/github/api" }}/'
69
-
upload: '{{ or (index .Env "GITHUB_API_URL") "https://git.example.org/-/github/api" }}/uploads/'
70
-
download: '{{ or (index .Env "GITHUB_SERVER_URL") "https://git.example.org" }}/'
s.write(ctx, w, r, http.StatusInternalServerError, MRActionStatus("the merge could not be completed. reload to check its state. reference: "+id, strings.TrimSuffix(r.URL.Path, "/merge")))
s.write(ctx, w, r, http.StatusInternalServerError, MRActionStatus("the merge could not be completed. reload to check its state. reference: "+id, strings.TrimSuffix(r.URL.Path, "/merge")))
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div><dt><kbd>g h</kbd></dt><dd>home</dd></div><div><dt><kbd>w</kbd></dt><dd>wide mode: use the whole width of the screen, or not (remembered)</dd></div><div><dt><kbd>y</kbd></dt><dd>copy a permalink pinned to the commit</dd></div><div><dt><kbd>d</kbd> <kbd>u</kbd> <kbd>x</kbd></dt><dd>diff: split / unified / collapse or expand all</dd></div><div><dt><kbd>e</kbd> <kbd>E</kbd></dt><dd>diff: the whole file in view / every file, with the lines the hunks hide</dd></div><div><dt><kbd>n</kbd></dt><dd>merge request: next note in the diff</dd></div>")
54
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " branch or tag</dd></div><div><dt><kbd>s</kbd> <kbd>t</kbd> <kbd>c</kbd> <kbd>r</kbd> <kbd>m</kbd> <kbd>i</kbd></dt><dd>tabs: summary, files, commits, branches & tags, merge requests, issues</dd></div><div><dt><kbd>g h</kbd></dt><dd>home</dd></div><div><dt><kbd>w</kbd></dt><dd>wide mode: use the whole width of the screen, or not (remembered)</dd></div><div><dt><kbd>y</kbd></dt><dd>copy a permalink pinned to the commit</dd></div><div><dt><kbd>d</kbd> <kbd>u</kbd> <kbd>x</kbd></dt><dd>diff: split / unified / collapse or expand all</dd></div><div><dt><kbd>e</kbd> <kbd>E</kbd></dt><dd>diff: the whole file in view / every file, with the lines the hunks hide</dd></div><div><dt><kbd>n</kbd></dt><dd>merge request: next note in the diff</dd></div>")
65
55
if templ_7745c5c3_Err != nil {
66
56
return templ_7745c5c3_Err
67
57
}
68
58
if mr {
69
-
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<div><dt><kbd>g f</kbd></dt><dd>merge request: the list of files (j k move, enter opens, esc back)</dd></div><div><dt><kbd>M</kbd></dt><dd>merge request: the merge menu; there 1–3 pick the mode, D deletes the branch, enter merges</dd></div><div><dt><kbd>R</kbd></dt><dd>merge request: mark the head read</dd></div>")
59
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<div><dt><kbd>g f</kbd></dt><dd>merge request: the list of files (j k move, enter opens, esc back)</dd></div><div><dt><kbd>M</kbd></dt><dd>merge request: the merge menu; there 1–3 pick the mode, D deletes the branch, enter merges</dd></div><div><dt><kbd>R</kbd></dt><dd>merge request: mark the head read</dd></div>")
70
60
if templ_7745c5c3_Err != nil {
71
61
return templ_7745c5c3_Err
72
62
}
73
63
}
74
-
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<div><dt><kbd>esc</kbd></dt><dd>close a dialog, leave a field</dd></div></dl></dialog>")
64
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div><dt><kbd>esc</kbd></dt><dd>close a dialog, leave a field</dd></div></dl></dialog>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " branch or tag</dd></div><div><dt><kbd>s</kbd> <kbd>t</kbd> <kbd>c</kbd> <kbd>r</kbd> <kbd>m</kbd> <kbd>i</kbd></dt><dd>tabs: summary, files, commits, branches & tags, merge requests, issues</dd></div><div><dt><kbd>g h</kbd></dt><dd>home</dd></div><div><dt><kbd>w</kbd></dt><dd>wide mode: use the whole width of the screen, or not (remembered)</dd></div><div><dt><kbd>y</kbd></dt><dd>copy a permalink pinned to the commit</dd></div><div><dt><kbd>d</kbd> <kbd>u</kbd> <kbd>x</kbd></dt><dd>diff: split / unified / collapse or expand all</dd></div><div><dt><kbd>e</kbd> <kbd>E</kbd></dt><dd>diff: the whole file in view / every file, with the lines the hunks hide</dd></div><div><dt><kbd>n</kbd></dt><dd>merge request: next note in the diff</dd></div>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div><dt><kbd>g h</kbd></dt><dd>home</dd></div><div><dt><kbd>w</kbd></dt><dd>wide mode: use the whole width of the screen, or not (remembered)</dd></div><div><dt><kbd>y</kbd></dt><dd>copy a permalink pinned to the commit</dd></div><div><dt><kbd>d</kbd> <kbd>u</kbd> <kbd>x</kbd></dt><dd>diff: split / unified / collapse or expand all</dd></div><div><dt><kbd>e</kbd> <kbd>E</kbd></dt><dd>diff: the whole file in view / every file, with the lines the hunks hide</dd></div><div><dt><kbd>n</kbd></dt><dd>merge request: next note in the diff</dd></div>")
65
if templ_7745c5c3_Err != nil {
55
if templ_7745c5c3_Err != nil {
66
return templ_7745c5c3_Err
56
return templ_7745c5c3_Err
67
}
57
}
68
if mr {
58
if mr {
69
-
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<div><dt><kbd>g f</kbd></dt><dd>merge request: the list of files (j k move, enter opens, esc back)</dd></div><div><dt><kbd>M</kbd></dt><dd>merge request: the merge menu; there 1–3 pick the mode, D deletes the branch, enter merges</dd></div><div><dt><kbd>R</kbd></dt><dd>merge request: mark the head read</dd></div>")
59
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<div><dt><kbd>g f</kbd></dt><dd>merge request: the list of files (j k move, enter opens, esc back)</dd></div><div><dt><kbd>M</kbd></dt><dd>merge request: the merge menu; there 1–3 pick the mode, D deletes the branch, enter merges</dd></div><div><dt><kbd>R</kbd></dt><dd>merge request: mark the head read</dd></div>")
70
if templ_7745c5c3_Err != nil {
60
if templ_7745c5c3_Err != nil {
71
return templ_7745c5c3_Err
61
return templ_7745c5c3_Err
72
}
62
}
73
}
63
}
74
-
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<div><dt><kbd>esc</kbd></dt><dd>close a dialog, leave a field</dd></div></dl></dialog>")
64
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div><dt><kbd>esc</kbd></dt><dd>close a dialog, leave a field</dd></div></dl></dialog>")