detached f9976e7

feat(proto): require the head the caller saw to enable auto-merge

commit
f9976e7ef950a413ab4cb985f1b850caf1c8c8cf
author
brice · · 2026-10-20 16:18 UTC
committer
brice · · 2026-10-20 16:24 UTC
parent
35fc113
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
checks
4/4
refs
tag: v0.14.0
3 files · +36 -12
M gen/ermite/ermiteconnect/merge_request.connect.go +10 -6
@@ -149,11 +149,13 @@ type MergeRequestServiceClient interface {
149149 // RepoSettings.failing_checks_block says. Needs the mr:merge scope and, for a
150150 // token limited to branches, write access to the target branch
151151 // (permission_denied otherwise). The server records the caller, the mode and
152- // the current head; it merges as the caller, after resolving the caller
152+ // the head the caller saw; it merges as the caller, after resolving the caller
153153 // again, and cancels the auto-merge if the caller can no longer merge, if the
154154 // mode is no longer allowed, if the source branch moves or if the setting is
155- // turned off. Fails with invalid_argument if the mode is not a merge mode,
156- // and with failed_precondition if the merge request is not open, is a draft,
155+ // turned off. Fails with invalid_argument if the mode is not a merge mode or
156+ // if head_id is empty or not a commit id, and with failed_precondition if the
157+ // merge request is not open, if the source branch no longer points to head_id
158+ // ("branch moved, read again"), is a draft,
157159 // RepoSettings.allow_auto_merge is off, the mode is not allowed by
158160 // RepoSettings, or the server has no CI. Enabling again replaces the mode.
159161 // Publishes MergeRequestAutoMergeEnabled. Needs the
@@ -409,11 +411,13 @@ type MergeRequestServiceHandler interface {
409411 // RepoSettings.failing_checks_block says. Needs the mr:merge scope and, for a
410412 // token limited to branches, write access to the target branch
411413 // (permission_denied otherwise). The server records the caller, the mode and
412- // the current head; it merges as the caller, after resolving the caller
414+ // the head the caller saw; it merges as the caller, after resolving the caller
413415 // again, and cancels the auto-merge if the caller can no longer merge, if the
414416 // mode is no longer allowed, if the source branch moves or if the setting is
415- // turned off. Fails with invalid_argument if the mode is not a merge mode,
416- // and with failed_precondition if the merge request is not open, is a draft,
417+ // turned off. Fails with invalid_argument if the mode is not a merge mode or
418+ // if head_id is empty or not a commit id, and with failed_precondition if the
419+ // merge request is not open, if the source branch no longer points to head_id
420+ // ("branch moved, read again"), is a draft,
417421 // RepoSettings.allow_auto_merge is off, the mode is not allowed by
418422 // RepoSettings, or the server has no CI. Enabling again replaces the mode.
419423 // Publishes MergeRequestAutoMergeEnabled. Needs the
@@ -149,11 +149,13 @@ type MergeRequestServiceClient interface {
149 // RepoSettings.failing_checks_block says. Needs the mr:merge scope and, for a149 // RepoSettings.failing_checks_block says. Needs the mr:merge scope and, for a
150 // token limited to branches, write access to the target branch150 // token limited to branches, write access to the target branch
151 // (permission_denied otherwise). The server records the caller, the mode and151 // (permission_denied otherwise). The server records the caller, the mode and
152- // the current head; it merges as the caller, after resolving the caller152+ // the head the caller saw; it merges as the caller, after resolving the caller
153 // again, and cancels the auto-merge if the caller can no longer merge, if the153 // again, and cancels the auto-merge if the caller can no longer merge, if the
154 // mode is no longer allowed, if the source branch moves or if the setting is154 // mode is no longer allowed, if the source branch moves or if the setting is
155- // turned off. Fails with invalid_argument if the mode is not a merge mode,155+ // turned off. Fails with invalid_argument if the mode is not a merge mode or
156- // and with failed_precondition if the merge request is not open, is a draft,156+ // if head_id is empty or not a commit id, and with failed_precondition if the
157+ // merge request is not open, if the source branch no longer points to head_id
158+ // ("branch moved, read again"), is a draft,
157 // RepoSettings.allow_auto_merge is off, the mode is not allowed by159 // RepoSettings.allow_auto_merge is off, the mode is not allowed by
158 // RepoSettings, or the server has no CI. Enabling again replaces the mode.160 // RepoSettings, or the server has no CI. Enabling again replaces the mode.
159 // Publishes MergeRequestAutoMergeEnabled. Needs the161 // Publishes MergeRequestAutoMergeEnabled. Needs the
@@ -409,11 +411,13 @@ type MergeRequestServiceHandler interface {
409 // RepoSettings.failing_checks_block says. Needs the mr:merge scope and, for a411 // RepoSettings.failing_checks_block says. Needs the mr:merge scope and, for a
410 // token limited to branches, write access to the target branch412 // token limited to branches, write access to the target branch
411 // (permission_denied otherwise). The server records the caller, the mode and413 // (permission_denied otherwise). The server records the caller, the mode and
412- // the current head; it merges as the caller, after resolving the caller414+ // the head the caller saw; it merges as the caller, after resolving the caller
413 // again, and cancels the auto-merge if the caller can no longer merge, if the415 // again, and cancels the auto-merge if the caller can no longer merge, if the
414 // mode is no longer allowed, if the source branch moves or if the setting is416 // mode is no longer allowed, if the source branch moves or if the setting is
415- // turned off. Fails with invalid_argument if the mode is not a merge mode,417+ // turned off. Fails with invalid_argument if the mode is not a merge mode or
416- // and with failed_precondition if the merge request is not open, is a draft,418+ // if head_id is empty or not a commit id, and with failed_precondition if the
419+ // merge request is not open, if the source branch no longer points to head_id
420+ // ("branch moved, read again"), is a draft,
417 // RepoSettings.allow_auto_merge is off, the mode is not allowed by421 // RepoSettings.allow_auto_merge is off, the mode is not allowed by
418 // RepoSettings, or the server has no CI. Enabling again replaces the mode.422 // RepoSettings, or the server has no CI. Enabling again replaces the mode.
419 // Publishes MergeRequestAutoMergeEnabled. Needs the423 // Publishes MergeRequestAutoMergeEnabled. Needs the
M gen/ermite/merge_request.pb.go +16 -3
@@ -2176,7 +2176,12 @@ type EnableAutoMergeRequest struct {
21762176 Number int64 `protobuf:"varint,2,opt,name=number,proto3" json:"number,omitempty"`
21772177 // Mode is how to merge. MERGE_MODE_UNSPECIFIED means fast-forward. The mode
21782178 // must be in RepoSettings.allowed_merge_modes of the repository.
2179- Mode MergeMode `protobuf:"varint,3,opt,name=mode,proto3,enum=ermite.MergeMode" json:"mode,omitempty"`
2179+ Mode MergeMode `protobuf:"varint,3,opt,name=mode,proto3,enum=ermite.MergeMode" json:"mode,omitempty"`
2180+ // HeadId is the full id of the commit the caller reviewed, that is the
2181+ // MergeRequest.head_id it was shown. Required. The auto-merge is enabled
2182+ // only if the source branch still points to it; failed_precondition (branch
2183+ // moved) otherwise.
2184+ HeadId string `protobuf:"bytes,4,opt,name=head_id,json=headId,proto3" json:"head_id,omitempty"`
21802185 unknownFields protoimpl.UnknownFields
21812186 sizeCache protoimpl.SizeCache
21822187 }
@@ -2232,6 +2237,13 @@ func (x *EnableAutoMergeRequest) GetMode() MergeMode {
22322237 return MergeMode_MERGE_MODE_UNSPECIFIED
22332238 }
22342239
2240+func (x *EnableAutoMergeRequest) GetHeadId() string {
2241+ if x != nil {
2242+ return x.HeadId
2243+ }
2244+ return ""
2245+}
2246+
22352247 // EnableAutoMergeResponse holds the merge request with auto-merge enabled.
22362248 type EnableAutoMergeResponse struct {
22372249 state protoimpl.MessageState `protogen:"open.v1"`
@@ -2638,11 +2650,12 @@ const file_ermite_merge_request_proto_rawDesc = "" +
26382650 "\x14delete_source_branch\x18\x05 \x01(\bR\x12deleteSourceBranch\"\x8a\x01\n" +
26392651 "\x19MergeMergeRequestResponse\x129\n" +
26402652 "\rmerge_request\x18\x01 \x01(\v2\x14.ermite.MergeRequestR\fmergeRequest\x122\n" +
2641- "\x15source_branch_deleted\x18\x02 \x01(\bR\x13sourceBranchDeleted\"k\n" +
2653+ "\x15source_branch_deleted\x18\x02 \x01(\bR\x13sourceBranchDeleted\"\x84\x01\n" +
26422654 "\x16EnableAutoMergeRequest\x12\x12\n" +
26432655 "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x16\n" +
26442656 "\x06number\x18\x02 \x01(\x03R\x06number\x12%\n" +
2645- "\x04mode\x18\x03 \x01(\x0e2\x11.ermite.MergeModeR\x04mode\"T\n" +
2657+ "\x04mode\x18\x03 \x01(\x0e2\x11.ermite.MergeModeR\x04mode\x12\x17\n" +
2658+ "\ahead_id\x18\x04 \x01(\tR\x06headId\"T\n" +
26462659 "\x17EnableAutoMergeResponse\x129\n" +
26472660 "\rmerge_request\x18\x01 \x01(\v2\x14.ermite.MergeRequestR\fmergeRequest\"D\n" +
26482661 "\x16CancelAutoMergeRequest\x12\x12\n" +
@@ -2176,7 +2176,12 @@ type EnableAutoMergeRequest struct {
2176 Number int64 `protobuf:"varint,2,opt,name=number,proto3" json:"number,omitempty"`2176 Number int64 `protobuf:"varint,2,opt,name=number,proto3" json:"number,omitempty"`
2177 // Mode is how to merge. MERGE_MODE_UNSPECIFIED means fast-forward. The mode2177 // Mode is how to merge. MERGE_MODE_UNSPECIFIED means fast-forward. The mode
2178 // must be in RepoSettings.allowed_merge_modes of the repository.2178 // must be in RepoSettings.allowed_merge_modes of the repository.
2179- Mode MergeMode `protobuf:"varint,3,opt,name=mode,proto3,enum=ermite.MergeMode" json:"mode,omitempty"`2179+ Mode MergeMode `protobuf:"varint,3,opt,name=mode,proto3,enum=ermite.MergeMode" json:"mode,omitempty"`
2180+ // HeadId is the full id of the commit the caller reviewed, that is the
2181+ // MergeRequest.head_id it was shown. Required. The auto-merge is enabled
2182+ // only if the source branch still points to it; failed_precondition (branch
2183+ // moved) otherwise.
2184+ HeadId string `protobuf:"bytes,4,opt,name=head_id,json=headId,proto3" json:"head_id,omitempty"`
2180 unknownFields protoimpl.UnknownFields2185 unknownFields protoimpl.UnknownFields
2181 sizeCache protoimpl.SizeCache2186 sizeCache protoimpl.SizeCache
2182 }2187 }
@@ -2232,6 +2237,13 @@ func (x *EnableAutoMergeRequest) GetMode() MergeMode {
2232 return MergeMode_MERGE_MODE_UNSPECIFIED2237 return MergeMode_MERGE_MODE_UNSPECIFIED
2233 }2238 }
2234 2239
2240+func (x *EnableAutoMergeRequest) GetHeadId() string {
2241+ if x != nil {
2242+ return x.HeadId
2243+ }
2244+ return ""
2245+}
2246+
2235 // EnableAutoMergeResponse holds the merge request with auto-merge enabled.2247 // EnableAutoMergeResponse holds the merge request with auto-merge enabled.
2236 type EnableAutoMergeResponse struct {2248 type EnableAutoMergeResponse struct {
2237 state protoimpl.MessageState `protogen:"open.v1"`2249 state protoimpl.MessageState `protogen:"open.v1"`
@@ -2638,11 +2650,12 @@ const file_ermite_merge_request_proto_rawDesc = "" +
2638 "\x14delete_source_branch\x18\x05 \x01(\bR\x12deleteSourceBranch\"\x8a\x01\n" +2650 "\x14delete_source_branch\x18\x05 \x01(\bR\x12deleteSourceBranch\"\x8a\x01\n" +
2639 "\x19MergeMergeRequestResponse\x129\n" +2651 "\x19MergeMergeRequestResponse\x129\n" +
2640 "\rmerge_request\x18\x01 \x01(\v2\x14.ermite.MergeRequestR\fmergeRequest\x122\n" +2652 "\rmerge_request\x18\x01 \x01(\v2\x14.ermite.MergeRequestR\fmergeRequest\x122\n" +
2641- "\x15source_branch_deleted\x18\x02 \x01(\bR\x13sourceBranchDeleted\"k\n" +2653+ "\x15source_branch_deleted\x18\x02 \x01(\bR\x13sourceBranchDeleted\"\x84\x01\n" +
2642 "\x16EnableAutoMergeRequest\x12\x12\n" +2654 "\x16EnableAutoMergeRequest\x12\x12\n" +
2643 "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x16\n" +2655 "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x16\n" +
2644 "\x06number\x18\x02 \x01(\x03R\x06number\x12%\n" +2656 "\x06number\x18\x02 \x01(\x03R\x06number\x12%\n" +
2645- "\x04mode\x18\x03 \x01(\x0e2\x11.ermite.MergeModeR\x04mode\"T\n" +2657+ "\x04mode\x18\x03 \x01(\x0e2\x11.ermite.MergeModeR\x04mode\x12\x17\n" +
2658+ "\ahead_id\x18\x04 \x01(\tR\x06headId\"T\n" +
2646 "\x17EnableAutoMergeResponse\x129\n" +2659 "\x17EnableAutoMergeResponse\x129\n" +
2647 "\rmerge_request\x18\x01 \x01(\v2\x14.ermite.MergeRequestR\fmergeRequest\"D\n" +2660 "\rmerge_request\x18\x01 \x01(\v2\x14.ermite.MergeRequestR\fmergeRequest\"D\n" +
2648 "\x16CancelAutoMergeRequest\x12\x12\n" +2661 "\x16CancelAutoMergeRequest\x12\x12\n" +
M proto/ermite/merge_request.proto +10 -3
@@ -322,11 +322,13 @@ service MergeRequestService {
322322 // RepoSettings.failing_checks_block says. Needs the mr:merge scope and, for a
323323 // token limited to branches, write access to the target branch
324324 // (permission_denied otherwise). The server records the caller, the mode and
325- // the current head; it merges as the caller, after resolving the caller
325+ // the head the caller saw; it merges as the caller, after resolving the caller
326326 // again, and cancels the auto-merge if the caller can no longer merge, if the
327327 // mode is no longer allowed, if the source branch moves or if the setting is
328- // turned off. Fails with invalid_argument if the mode is not a merge mode,
329- // and with failed_precondition if the merge request is not open, is a draft,
328+ // turned off. Fails with invalid_argument if the mode is not a merge mode or
329+ // if head_id is empty or not a commit id, and with failed_precondition if the
330+ // merge request is not open, if the source branch no longer points to head_id
331+ // ("branch moved, read again"), is a draft,
330332 // RepoSettings.allow_auto_merge is off, the mode is not allowed by
331333 // RepoSettings, or the server has no CI. Enabling again replaces the mode.
332334 // Publishes MergeRequestAutoMergeEnabled. Needs the
@@ -591,6 +593,11 @@ message EnableAutoMergeRequest {
591593 // Mode is how to merge. MERGE_MODE_UNSPECIFIED means fast-forward. The mode
592594 // must be in RepoSettings.allowed_merge_modes of the repository.
593595 MergeMode mode = 3;
596+ // HeadId is the full id of the commit the caller reviewed, that is the
597+ // MergeRequest.head_id it was shown. Required. The auto-merge is enabled
598+ // only if the source branch still points to it; failed_precondition (branch
599+ // moved) otherwise.
600+ string head_id = 4;
594601 }
595602
596603 // EnableAutoMergeResponse holds the merge request with auto-merge enabled.
@@ -322,11 +322,13 @@ service MergeRequestService {
322 // RepoSettings.failing_checks_block says. Needs the mr:merge scope and, for a322 // RepoSettings.failing_checks_block says. Needs the mr:merge scope and, for a
323 // token limited to branches, write access to the target branch323 // token limited to branches, write access to the target branch
324 // (permission_denied otherwise). The server records the caller, the mode and324 // (permission_denied otherwise). The server records the caller, the mode and
325- // the current head; it merges as the caller, after resolving the caller325+ // the head the caller saw; it merges as the caller, after resolving the caller
326 // again, and cancels the auto-merge if the caller can no longer merge, if the326 // again, and cancels the auto-merge if the caller can no longer merge, if the
327 // mode is no longer allowed, if the source branch moves or if the setting is327 // mode is no longer allowed, if the source branch moves or if the setting is
328- // turned off. Fails with invalid_argument if the mode is not a merge mode,328+ // turned off. Fails with invalid_argument if the mode is not a merge mode or
329- // and with failed_precondition if the merge request is not open, is a draft,329+ // if head_id is empty or not a commit id, and with failed_precondition if the
330+ // merge request is not open, if the source branch no longer points to head_id
331+ // ("branch moved, read again"), is a draft,
330 // RepoSettings.allow_auto_merge is off, the mode is not allowed by332 // RepoSettings.allow_auto_merge is off, the mode is not allowed by
331 // RepoSettings, or the server has no CI. Enabling again replaces the mode.333 // RepoSettings, or the server has no CI. Enabling again replaces the mode.
332 // Publishes MergeRequestAutoMergeEnabled. Needs the334 // Publishes MergeRequestAutoMergeEnabled. Needs the
@@ -591,6 +593,11 @@ message EnableAutoMergeRequest {
591 // Mode is how to merge. MERGE_MODE_UNSPECIFIED means fast-forward. The mode593 // Mode is how to merge. MERGE_MODE_UNSPECIFIED means fast-forward. The mode
592 // must be in RepoSettings.allowed_merge_modes of the repository.594 // must be in RepoSettings.allowed_merge_modes of the repository.
593 MergeMode mode = 3;595 MergeMode mode = 3;
596+ // HeadId is the full id of the commit the caller reviewed, that is the
597+ // MergeRequest.head_id it was shown. Required. The auto-merge is enabled
598+ // only if the source branch still points to it; failed_precondition (branch
599+ // moved) otherwise.
600+ string head_id = 4;
594 }601 }
595 602
596 // EnableAutoMergeResponse holds the merge request with auto-merge enabled.603 // EnableAutoMergeResponse holds the merge request with auto-merge enabled.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 18

↑↓ moveenter openesc close