detached 9795e63

feat(ports): add auto-merge service methods, CIActivity and AutoMergeTrigger ports

commit
9795e63610e2e4ddb7781331513fa284f4d7efcd
author
brice · · 2026-10-20 15:44 UTC
parent
4bb6db7
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
9 files · +427 -0
M internal/adapters/rpc/mergerequest.go +11 -0
@@ -4,6 +4,7 @@ package rpc
44
55 import (
66 "context"
7+ "errors"
78 "fmt"
89 "strconv"
910
@@ -19,6 +20,16 @@ type mergeRequestService struct {
1920 mrs ports.MergeRequestService
2021 }
2122
23+// EnableAutoMerge is not wired yet.
24+func (s *mergeRequestService) EnableAutoMerge(context.Context, *connect.Request[pb.EnableAutoMergeRequest]) (*connect.Response[pb.EnableAutoMergeResponse], error) {
25+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("auto-merge is not implemented yet"))
26+}
27+
28+// CancelAutoMerge is not wired yet.
29+func (s *mergeRequestService) CancelAutoMerge(context.Context, *connect.Request[pb.CancelAutoMergeRequest]) (*connect.Response[pb.CancelAutoMergeResponse], error) {
30+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("auto-merge is not implemented yet"))
31+}
32+
2233 func (s *mergeRequestService) EditComment(ctx context.Context, req *connect.Request[pb.EditCommentRequest]) (*connect.Response[pb.EditCommentResponse], error) {
2334 name, err := domain.ParseRepoName(req.Msg.GetRepo())
2435 if err != nil {
@@ -4,6 +4,7 @@ package rpc
4 4
5 import (5 import (
6 "context"6 "context"
7+ "errors"
7 "fmt"8 "fmt"
8 "strconv"9 "strconv"
9 10
@@ -19,6 +20,16 @@ type mergeRequestService struct {
19 mrs ports.MergeRequestService20 mrs ports.MergeRequestService
20 }21 }
21 22
23+// EnableAutoMerge is not wired yet.
24+func (s *mergeRequestService) EnableAutoMerge(context.Context, *connect.Request[pb.EnableAutoMergeRequest]) (*connect.Response[pb.EnableAutoMergeResponse], error) {
25+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("auto-merge is not implemented yet"))
26+}
27+
28+// CancelAutoMerge is not wired yet.
29+func (s *mergeRequestService) CancelAutoMerge(context.Context, *connect.Request[pb.CancelAutoMergeRequest]) (*connect.Response[pb.CancelAutoMergeResponse], error) {
30+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("auto-merge is not implemented yet"))
31+}
32+
22 func (s *mergeRequestService) EditComment(ctx context.Context, req *connect.Request[pb.EditCommentRequest]) (*connect.Response[pb.EditCommentResponse], error) {33 func (s *mergeRequestService) EditComment(ctx context.Context, req *connect.Request[pb.EditCommentRequest]) (*connect.Response[pb.EditCommentResponse], error) {
23 name, err := domain.ParseRepoName(req.Msg.GetRepo())34 name, err := domain.ParseRepoName(req.Msg.GetRepo())
24 if err != nil {35 if err != nil {
M internal/ports/ci.go +8 -0
@@ -896,3 +896,11 @@ type JobSettings struct {
896896 type CIJobSettings interface {
897897 Resolve(ctx context.Context, req JobSettingsRequest) (JobSettings, error)
898898 }
899+
900+// CIActivity tells whether CI still has queued work that may create runs for a
901+// head. *usecase.CI implements it.
902+type CIActivity interface {
903+ // Settled reports that no push trigger of the repository and no pull event
904+ // of the merge request is queued or being planned.
905+ Settled(ctx context.Context, repo domain.RepoName, number int64, source string, head domain.ObjectID) bool
906+}
@@ -896,3 +896,11 @@ type JobSettings struct {
896 type CIJobSettings interface {896 type CIJobSettings interface {
897 Resolve(ctx context.Context, req JobSettingsRequest) (JobSettings, error)897 Resolve(ctx context.Context, req JobSettingsRequest) (JobSettings, error)
898 }898 }
899+
900+// CIActivity tells whether CI still has queued work that may create runs for a
901+// head. *usecase.CI implements it.
902+type CIActivity interface {
903+ // Settled reports that no push trigger of the repository and no pull event
904+ // of the merge request is queued or being planned.
905+ Settled(ctx context.Context, repo domain.RepoName, number int64, source string, head domain.ObjectID) bool
906+}
M internal/ports/dto.go +8 -0
@@ -51,6 +51,14 @@ type UpdateRepoParams struct {
5151 FailingChecksBlock *bool
5252 // Issues replaces the issues mode.
5353 Issues *domain.IssuesMode
54+ // AllowAutoMerge replaces the setting of that name.
55+ AllowAutoMerge *bool
56+}
57+
58+// EnableAutoMergeParams are the settings of EnableAutoMerge.
59+type EnableAutoMergeParams struct {
60+ // Mode is the merge mode to use; empty means fast-forward.
61+ Mode domain.MergeMode
5462 }
5563
5664 // TokenPage is a page of stored tokens, newest first.
@@ -51,6 +51,14 @@ type UpdateRepoParams struct {
51 FailingChecksBlock *bool51 FailingChecksBlock *bool
52 // Issues replaces the issues mode.52 // Issues replaces the issues mode.
53 Issues *domain.IssuesMode53 Issues *domain.IssuesMode
54+ // AllowAutoMerge replaces the setting of that name.
55+ AllowAutoMerge *bool
56+}
57+
58+// EnableAutoMergeParams are the settings of EnableAutoMerge.
59+type EnableAutoMergeParams struct {
60+ // Mode is the merge mode to use; empty means fast-forward.
61+ Mode domain.MergeMode
54 }62 }
55 63
56 // TokenPage is a page of stored tokens, newest first.64 // TokenPage is a page of stored tokens, newest first.
A internal/ports/mocks/AutoMergeTrigger.go +94 -0
@@ -0,0 +1,94 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package mocks
6+
7+import (
8+ "context"
9+
10+ "bnema.dev/ermite/internal/domain"
11+ mock "github.com/stretchr/testify/mock"
12+)
13+
14+// NewAutoMergeTrigger creates a new instance of AutoMergeTrigger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
15+// The first argument is typically a *testing.T value.
16+func NewAutoMergeTrigger(t interface {
17+ mock.TestingT
18+ Cleanup(func())
19+}) *AutoMergeTrigger {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
24+ mock := &AutoMergeTrigger{}
25+ mock.Mock.Test(t)
26+
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
33+
34+ return mock
35+}
36+
37+// AutoMergeTrigger is an autogenerated mock type for the AutoMergeTrigger type
38+type AutoMergeTrigger struct {
39+ mock.Mock
40+}
41+
42+type AutoMergeTrigger_Expecter struct {
43+ mock *mock.Mock
44+}
45+
46+func (_m *AutoMergeTrigger) EXPECT() *AutoMergeTrigger_Expecter {
47+ return &AutoMergeTrigger_Expecter{mock: &_m.Mock}
48+}
49+
50+// OnRepoChanged provides a mock function for the type AutoMergeTrigger
51+func (_mock *AutoMergeTrigger) OnRepoChanged(ctx context.Context, repo domain.RepoName) {
52+ _mock.Called(ctx, repo)
53+ return
54+}
55+
56+// AutoMergeTrigger_OnRepoChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OnRepoChanged'
57+type AutoMergeTrigger_OnRepoChanged_Call struct {
58+ *mock.Call
59+}
60+
61+// OnRepoChanged is a helper method to define mock.On call
62+// - ctx context.Context
63+// - repo domain.RepoName
64+func (_e *AutoMergeTrigger_Expecter) OnRepoChanged(ctx any, repo any) *AutoMergeTrigger_OnRepoChanged_Call {
65+ return &AutoMergeTrigger_OnRepoChanged_Call{Call: _e.mock.On("OnRepoChanged", ctx, repo)}
66+}
67+
68+func (_c *AutoMergeTrigger_OnRepoChanged_Call) Run(run func(ctx context.Context, repo domain.RepoName)) *AutoMergeTrigger_OnRepoChanged_Call {
69+ _c.Call.Run(func(args mock.Arguments) {
70+ var arg0 context.Context
71+ if args[0] != nil {
72+ arg0 = args[0].(context.Context)
73+ }
74+ var arg1 domain.RepoName
75+ if args[1] != nil {
76+ arg1 = args[1].(domain.RepoName)
77+ }
78+ run(
79+ arg0,
80+ arg1,
81+ )
82+ })
83+ return _c
84+}
85+
86+func (_c *AutoMergeTrigger_OnRepoChanged_Call) Return() *AutoMergeTrigger_OnRepoChanged_Call {
87+ _c.Call.Return()
88+ return _c
89+}
90+
91+func (_c *AutoMergeTrigger_OnRepoChanged_Call) RunAndReturn(run func(ctx context.Context, repo domain.RepoName)) *AutoMergeTrigger_OnRepoChanged_Call {
92+ _c.Run(run)
93+ return _c
94+}
@@ -0,0 +1,94 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package mocks
6+
7+import (
8+ "context"
9+
10+ "bnema.dev/ermite/internal/domain"
11+ mock "github.com/stretchr/testify/mock"
12+)
13+
14+// NewAutoMergeTrigger creates a new instance of AutoMergeTrigger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
15+// The first argument is typically a *testing.T value.
16+func NewAutoMergeTrigger(t interface {
17+ mock.TestingT
18+ Cleanup(func())
19+}) *AutoMergeTrigger {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
24+ mock := &AutoMergeTrigger{}
25+ mock.Mock.Test(t)
26+
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
33+
34+ return mock
35+}
36+
37+// AutoMergeTrigger is an autogenerated mock type for the AutoMergeTrigger type
38+type AutoMergeTrigger struct {
39+ mock.Mock
40+}
41+
42+type AutoMergeTrigger_Expecter struct {
43+ mock *mock.Mock
44+}
45+
46+func (_m *AutoMergeTrigger) EXPECT() *AutoMergeTrigger_Expecter {
47+ return &AutoMergeTrigger_Expecter{mock: &_m.Mock}
48+}
49+
50+// OnRepoChanged provides a mock function for the type AutoMergeTrigger
51+func (_mock *AutoMergeTrigger) OnRepoChanged(ctx context.Context, repo domain.RepoName) {
52+ _mock.Called(ctx, repo)
53+ return
54+}
55+
56+// AutoMergeTrigger_OnRepoChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OnRepoChanged'
57+type AutoMergeTrigger_OnRepoChanged_Call struct {
58+ *mock.Call
59+}
60+
61+// OnRepoChanged is a helper method to define mock.On call
62+// - ctx context.Context
63+// - repo domain.RepoName
64+func (_e *AutoMergeTrigger_Expecter) OnRepoChanged(ctx any, repo any) *AutoMergeTrigger_OnRepoChanged_Call {
65+ return &AutoMergeTrigger_OnRepoChanged_Call{Call: _e.mock.On("OnRepoChanged", ctx, repo)}
66+}
67+
68+func (_c *AutoMergeTrigger_OnRepoChanged_Call) Run(run func(ctx context.Context, repo domain.RepoName)) *AutoMergeTrigger_OnRepoChanged_Call {
69+ _c.Call.Run(func(args mock.Arguments) {
70+ var arg0 context.Context
71+ if args[0] != nil {
72+ arg0 = args[0].(context.Context)
73+ }
74+ var arg1 domain.RepoName
75+ if args[1] != nil {
76+ arg1 = args[1].(domain.RepoName)
77+ }
78+ run(
79+ arg0,
80+ arg1,
81+ )
82+ })
83+ return _c
84+}
85+
86+func (_c *AutoMergeTrigger_OnRepoChanged_Call) Return() *AutoMergeTrigger_OnRepoChanged_Call {
87+ _c.Call.Return()
88+ return _c
89+}
90+
91+func (_c *AutoMergeTrigger_OnRepoChanged_Call) RunAndReturn(run func(ctx context.Context, repo domain.RepoName)) *AutoMergeTrigger_OnRepoChanged_Call {
92+ _c.Run(run)
93+ return _c
94+}
A internal/ports/mocks/CIActivity.go +123 -0
@@ -0,0 +1,123 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package mocks
6+
7+import (
8+ "context"
9+
10+ "bnema.dev/ermite/internal/domain"
11+ mock "github.com/stretchr/testify/mock"
12+)
13+
14+// NewCIActivity creates a new instance of CIActivity. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
15+// The first argument is typically a *testing.T value.
16+func NewCIActivity(t interface {
17+ mock.TestingT
18+ Cleanup(func())
19+}) *CIActivity {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
24+ mock := &CIActivity{}
25+ mock.Mock.Test(t)
26+
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
33+
34+ return mock
35+}
36+
37+// CIActivity is an autogenerated mock type for the CIActivity type
38+type CIActivity struct {
39+ mock.Mock
40+}
41+
42+type CIActivity_Expecter struct {
43+ mock *mock.Mock
44+}
45+
46+func (_m *CIActivity) EXPECT() *CIActivity_Expecter {
47+ return &CIActivity_Expecter{mock: &_m.Mock}
48+}
49+
50+// Settled provides a mock function for the type CIActivity
51+func (_mock *CIActivity) Settled(ctx context.Context, repo domain.RepoName, number int64, source string, head domain.ObjectID) bool {
52+ ret := _mock.Called(ctx, repo, number, source, head)
53+
54+ if len(ret) == 0 {
55+ panic("no return value specified for Settled")
56+ }
57+
58+ var r0 bool
59+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RepoName, int64, string, domain.ObjectID) bool); ok {
60+ r0 = returnFunc(ctx, repo, number, source, head)
61+ } else {
62+ r0 = ret.Get(0).(bool)
63+ }
64+ return r0
65+}
66+
67+// CIActivity_Settled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Settled'
68+type CIActivity_Settled_Call struct {
69+ *mock.Call
70+}
71+
72+// Settled is a helper method to define mock.On call
73+// - ctx context.Context
74+// - repo domain.RepoName
75+// - number int64
76+// - source string
77+// - head domain.ObjectID
78+func (_e *CIActivity_Expecter) Settled(ctx any, repo any, number any, source any, head any) *CIActivity_Settled_Call {
79+ return &CIActivity_Settled_Call{Call: _e.mock.On("Settled", ctx, repo, number, source, head)}
80+}
81+
82+func (_c *CIActivity_Settled_Call) Run(run func(ctx context.Context, repo domain.RepoName, number int64, source string, head domain.ObjectID)) *CIActivity_Settled_Call {
83+ _c.Call.Run(func(args mock.Arguments) {
84+ var arg0 context.Context
85+ if args[0] != nil {
86+ arg0 = args[0].(context.Context)
87+ }
88+ var arg1 domain.RepoName
89+ if args[1] != nil {
90+ arg1 = args[1].(domain.RepoName)
91+ }
92+ var arg2 int64
93+ if args[2] != nil {
94+ arg2 = args[2].(int64)
95+ }
96+ var arg3 string
97+ if args[3] != nil {
98+ arg3 = args[3].(string)
99+ }
100+ var arg4 domain.ObjectID
101+ if args[4] != nil {
102+ arg4 = args[4].(domain.ObjectID)
103+ }
104+ run(
105+ arg0,
106+ arg1,
107+ arg2,
108+ arg3,
109+ arg4,
110+ )
111+ })
112+ return _c
113+}
114+
115+func (_c *CIActivity_Settled_Call) Return(b bool) *CIActivity_Settled_Call {
116+ _c.Call.Return(b)
117+ return _c
118+}
119+
120+func (_c *CIActivity_Settled_Call) RunAndReturn(run func(ctx context.Context, repo domain.RepoName, number int64, source string, head domain.ObjectID) bool) *CIActivity_Settled_Call {
121+ _c.Call.Return(run)
122+ return _c
123+}
@@ -0,0 +1,123 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package mocks
6+
7+import (
8+ "context"
9+
10+ "bnema.dev/ermite/internal/domain"
11+ mock "github.com/stretchr/testify/mock"
12+)
13+
14+// NewCIActivity creates a new instance of CIActivity. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
15+// The first argument is typically a *testing.T value.
16+func NewCIActivity(t interface {
17+ mock.TestingT
18+ Cleanup(func())
19+}) *CIActivity {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
24+ mock := &CIActivity{}
25+ mock.Mock.Test(t)
26+
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
33+
34+ return mock
35+}
36+
37+// CIActivity is an autogenerated mock type for the CIActivity type
38+type CIActivity struct {
39+ mock.Mock
40+}
41+
42+type CIActivity_Expecter struct {
43+ mock *mock.Mock
44+}
45+
46+func (_m *CIActivity) EXPECT() *CIActivity_Expecter {
47+ return &CIActivity_Expecter{mock: &_m.Mock}
48+}
49+
50+// Settled provides a mock function for the type CIActivity
51+func (_mock *CIActivity) Settled(ctx context.Context, repo domain.RepoName, number int64, source string, head domain.ObjectID) bool {
52+ ret := _mock.Called(ctx, repo, number, source, head)
53+
54+ if len(ret) == 0 {
55+ panic("no return value specified for Settled")
56+ }
57+
58+ var r0 bool
59+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RepoName, int64, string, domain.ObjectID) bool); ok {
60+ r0 = returnFunc(ctx, repo, number, source, head)
61+ } else {
62+ r0 = ret.Get(0).(bool)
63+ }
64+ return r0
65+}
66+
67+// CIActivity_Settled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Settled'
68+type CIActivity_Settled_Call struct {
69+ *mock.Call
70+}
71+
72+// Settled is a helper method to define mock.On call
73+// - ctx context.Context
74+// - repo domain.RepoName
75+// - number int64
76+// - source string
77+// - head domain.ObjectID
78+func (_e *CIActivity_Expecter) Settled(ctx any, repo any, number any, source any, head any) *CIActivity_Settled_Call {
79+ return &CIActivity_Settled_Call{Call: _e.mock.On("Settled", ctx, repo, number, source, head)}
80+}
81+
82+func (_c *CIActivity_Settled_Call) Run(run func(ctx context.Context, repo domain.RepoName, number int64, source string, head domain.ObjectID)) *CIActivity_Settled_Call {
83+ _c.Call.Run(func(args mock.Arguments) {
84+ var arg0 context.Context
85+ if args[0] != nil {
86+ arg0 = args[0].(context.Context)
87+ }
88+ var arg1 domain.RepoName
89+ if args[1] != nil {
90+ arg1 = args[1].(domain.RepoName)
91+ }
92+ var arg2 int64
93+ if args[2] != nil {
94+ arg2 = args[2].(int64)
95+ }
96+ var arg3 string
97+ if args[3] != nil {
98+ arg3 = args[3].(string)
99+ }
100+ var arg4 domain.ObjectID
101+ if args[4] != nil {
102+ arg4 = args[4].(domain.ObjectID)
103+ }
104+ run(
105+ arg0,
106+ arg1,
107+ arg2,
108+ arg3,
109+ arg4,
110+ )
111+ })
112+ return _c
113+}
114+
115+func (_c *CIActivity_Settled_Call) Return(b bool) *CIActivity_Settled_Call {
116+ _c.Call.Return(b)
117+ return _c
118+}
119+
120+func (_c *CIActivity_Settled_Call) RunAndReturn(run func(ctx context.Context, repo domain.RepoName, number int64, source string, head domain.ObjectID) bool) *CIActivity_Settled_Call {
121+ _c.Call.Return(run)
122+ return _c
123+}
M internal/ports/mocks/MergeRequestService.go +162 -0
@@ -132,6 +132,84 @@ func (_c *MergeRequestService_AddComment_Call) RunAndReturn(run func(ctx context
132132 return _c
133133 }
134134
135+// CancelAutoMerge provides a mock function for the type MergeRequestService
136+func (_mock *MergeRequestService) CancelAutoMerge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error) {
137+ ret := _mock.Called(ctx, p, name, number)
138+
139+ if len(ret) == 0 {
140+ panic("no return value specified for CancelAutoMerge")
141+ }
142+
143+ var r0 domain.MergeRequest
144+ var r1 error
145+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64) (domain.MergeRequest, error)); ok {
146+ return returnFunc(ctx, p, name, number)
147+ }
148+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64) domain.MergeRequest); ok {
149+ r0 = returnFunc(ctx, p, name, number)
150+ } else {
151+ r0 = ret.Get(0).(domain.MergeRequest)
152+ }
153+ if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, int64) error); ok {
154+ r1 = returnFunc(ctx, p, name, number)
155+ } else {
156+ r1 = ret.Error(1)
157+ }
158+ return r0, r1
159+}
160+
161+// MergeRequestService_CancelAutoMerge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CancelAutoMerge'
162+type MergeRequestService_CancelAutoMerge_Call struct {
163+ *mock.Call
164+}
165+
166+// CancelAutoMerge is a helper method to define mock.On call
167+// - ctx context.Context
168+// - p domain.Principal
169+// - name domain.RepoName
170+// - number int64
171+func (_e *MergeRequestService_Expecter) CancelAutoMerge(ctx any, p any, name any, number any) *MergeRequestService_CancelAutoMerge_Call {
172+ return &MergeRequestService_CancelAutoMerge_Call{Call: _e.mock.On("CancelAutoMerge", ctx, p, name, number)}
173+}
174+
175+func (_c *MergeRequestService_CancelAutoMerge_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64)) *MergeRequestService_CancelAutoMerge_Call {
176+ _c.Call.Run(func(args mock.Arguments) {
177+ var arg0 context.Context
178+ if args[0] != nil {
179+ arg0 = args[0].(context.Context)
180+ }
181+ var arg1 domain.Principal
182+ if args[1] != nil {
183+ arg1 = args[1].(domain.Principal)
184+ }
185+ var arg2 domain.RepoName
186+ if args[2] != nil {
187+ arg2 = args[2].(domain.RepoName)
188+ }
189+ var arg3 int64
190+ if args[3] != nil {
191+ arg3 = args[3].(int64)
192+ }
193+ run(
194+ arg0,
195+ arg1,
196+ arg2,
197+ arg3,
198+ )
199+ })
200+ return _c
201+}
202+
203+func (_c *MergeRequestService_CancelAutoMerge_Call) Return(mergeRequest domain.MergeRequest, err error) *MergeRequestService_CancelAutoMerge_Call {
204+ _c.Call.Return(mergeRequest, err)
205+ return _c
206+}
207+
208+func (_c *MergeRequestService_CancelAutoMerge_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error)) *MergeRequestService_CancelAutoMerge_Call {
209+ _c.Call.Return(run)
210+ return _c
211+}
212+
135213 // Close provides a mock function for the type MergeRequestService
136214 func (_mock *MergeRequestService) Close(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error) {
137215 ret := _mock.Called(ctx, p, name, number)
@@ -618,6 +696,90 @@ func (_c *MergeRequestService_EditComment_Call) RunAndReturn(run func(ctx contex
618696 return _c
619697 }
620698
699+// EnableAutoMerge provides a mock function for the type MergeRequestService
700+func (_mock *MergeRequestService) EnableAutoMerge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.EnableAutoMergeParams) (domain.MergeRequest, error) {
701+ ret := _mock.Called(ctx, p, name, number, params)
702+
703+ if len(ret) == 0 {
704+ panic("no return value specified for EnableAutoMerge")
705+ }
706+
707+ var r0 domain.MergeRequest
708+ var r1 error
709+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, ports.EnableAutoMergeParams) (domain.MergeRequest, error)); ok {
710+ return returnFunc(ctx, p, name, number, params)
711+ }
712+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, ports.EnableAutoMergeParams) domain.MergeRequest); ok {
713+ r0 = returnFunc(ctx, p, name, number, params)
714+ } else {
715+ r0 = ret.Get(0).(domain.MergeRequest)
716+ }
717+ if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, int64, ports.EnableAutoMergeParams) error); ok {
718+ r1 = returnFunc(ctx, p, name, number, params)
719+ } else {
720+ r1 = ret.Error(1)
721+ }
722+ return r0, r1
723+}
724+
725+// MergeRequestService_EnableAutoMerge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnableAutoMerge'
726+type MergeRequestService_EnableAutoMerge_Call struct {
727+ *mock.Call
728+}
729+
730+// EnableAutoMerge is a helper method to define mock.On call
731+// - ctx context.Context
732+// - p domain.Principal
733+// - name domain.RepoName
734+// - number int64
735+// - params ports.EnableAutoMergeParams
736+func (_e *MergeRequestService_Expecter) EnableAutoMerge(ctx any, p any, name any, number any, params any) *MergeRequestService_EnableAutoMerge_Call {
737+ return &MergeRequestService_EnableAutoMerge_Call{Call: _e.mock.On("EnableAutoMerge", ctx, p, name, number, params)}
738+}
739+
740+func (_c *MergeRequestService_EnableAutoMerge_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.EnableAutoMergeParams)) *MergeRequestService_EnableAutoMerge_Call {
741+ _c.Call.Run(func(args mock.Arguments) {
742+ var arg0 context.Context
743+ if args[0] != nil {
744+ arg0 = args[0].(context.Context)
745+ }
746+ var arg1 domain.Principal
747+ if args[1] != nil {
748+ arg1 = args[1].(domain.Principal)
749+ }
750+ var arg2 domain.RepoName
751+ if args[2] != nil {
752+ arg2 = args[2].(domain.RepoName)
753+ }
754+ var arg3 int64
755+ if args[3] != nil {
756+ arg3 = args[3].(int64)
757+ }
758+ var arg4 ports.EnableAutoMergeParams
759+ if args[4] != nil {
760+ arg4 = args[4].(ports.EnableAutoMergeParams)
761+ }
762+ run(
763+ arg0,
764+ arg1,
765+ arg2,
766+ arg3,
767+ arg4,
768+ )
769+ })
770+ return _c
771+}
772+
773+func (_c *MergeRequestService_EnableAutoMerge_Call) Return(mergeRequest domain.MergeRequest, err error) *MergeRequestService_EnableAutoMerge_Call {
774+ _c.Call.Return(mergeRequest, err)
775+ return _c
776+}
777+
778+func (_c *MergeRequestService_EnableAutoMerge_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.EnableAutoMergeParams) (domain.MergeRequest, error)) *MergeRequestService_EnableAutoMerge_Call {
779+ _c.Call.Return(run)
780+ return _c
781+}
782+
621783 // Get provides a mock function for the type MergeRequestService
622784 func (_mock *MergeRequestService) Get(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, opts ports.GetMergeRequestOptions) (ports.MergeRequestDetail, error) {
623785 ret := _mock.Called(ctx, p, name, number, opts)
@@ -132,6 +132,84 @@ func (_c *MergeRequestService_AddComment_Call) RunAndReturn(run func(ctx context
132 return _c132 return _c
133 }133 }
134 134
135+// CancelAutoMerge provides a mock function for the type MergeRequestService
136+func (_mock *MergeRequestService) CancelAutoMerge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error) {
137+ ret := _mock.Called(ctx, p, name, number)
138+
139+ if len(ret) == 0 {
140+ panic("no return value specified for CancelAutoMerge")
141+ }
142+
143+ var r0 domain.MergeRequest
144+ var r1 error
145+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64) (domain.MergeRequest, error)); ok {
146+ return returnFunc(ctx, p, name, number)
147+ }
148+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64) domain.MergeRequest); ok {
149+ r0 = returnFunc(ctx, p, name, number)
150+ } else {
151+ r0 = ret.Get(0).(domain.MergeRequest)
152+ }
153+ if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, int64) error); ok {
154+ r1 = returnFunc(ctx, p, name, number)
155+ } else {
156+ r1 = ret.Error(1)
157+ }
158+ return r0, r1
159+}
160+
161+// MergeRequestService_CancelAutoMerge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CancelAutoMerge'
162+type MergeRequestService_CancelAutoMerge_Call struct {
163+ *mock.Call
164+}
165+
166+// CancelAutoMerge is a helper method to define mock.On call
167+// - ctx context.Context
168+// - p domain.Principal
169+// - name domain.RepoName
170+// - number int64
171+func (_e *MergeRequestService_Expecter) CancelAutoMerge(ctx any, p any, name any, number any) *MergeRequestService_CancelAutoMerge_Call {
172+ return &MergeRequestService_CancelAutoMerge_Call{Call: _e.mock.On("CancelAutoMerge", ctx, p, name, number)}
173+}
174+
175+func (_c *MergeRequestService_CancelAutoMerge_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64)) *MergeRequestService_CancelAutoMerge_Call {
176+ _c.Call.Run(func(args mock.Arguments) {
177+ var arg0 context.Context
178+ if args[0] != nil {
179+ arg0 = args[0].(context.Context)
180+ }
181+ var arg1 domain.Principal
182+ if args[1] != nil {
183+ arg1 = args[1].(domain.Principal)
184+ }
185+ var arg2 domain.RepoName
186+ if args[2] != nil {
187+ arg2 = args[2].(domain.RepoName)
188+ }
189+ var arg3 int64
190+ if args[3] != nil {
191+ arg3 = args[3].(int64)
192+ }
193+ run(
194+ arg0,
195+ arg1,
196+ arg2,
197+ arg3,
198+ )
199+ })
200+ return _c
201+}
202+
203+func (_c *MergeRequestService_CancelAutoMerge_Call) Return(mergeRequest domain.MergeRequest, err error) *MergeRequestService_CancelAutoMerge_Call {
204+ _c.Call.Return(mergeRequest, err)
205+ return _c
206+}
207+
208+func (_c *MergeRequestService_CancelAutoMerge_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error)) *MergeRequestService_CancelAutoMerge_Call {
209+ _c.Call.Return(run)
210+ return _c
211+}
212+
135 // Close provides a mock function for the type MergeRequestService213 // Close provides a mock function for the type MergeRequestService
136 func (_mock *MergeRequestService) Close(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error) {214 func (_mock *MergeRequestService) Close(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error) {
137 ret := _mock.Called(ctx, p, name, number)215 ret := _mock.Called(ctx, p, name, number)
@@ -618,6 +696,90 @@ func (_c *MergeRequestService_EditComment_Call) RunAndReturn(run func(ctx contex
618 return _c696 return _c
619 }697 }
620 698
699+// EnableAutoMerge provides a mock function for the type MergeRequestService
700+func (_mock *MergeRequestService) EnableAutoMerge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.EnableAutoMergeParams) (domain.MergeRequest, error) {
701+ ret := _mock.Called(ctx, p, name, number, params)
702+
703+ if len(ret) == 0 {
704+ panic("no return value specified for EnableAutoMerge")
705+ }
706+
707+ var r0 domain.MergeRequest
708+ var r1 error
709+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, ports.EnableAutoMergeParams) (domain.MergeRequest, error)); ok {
710+ return returnFunc(ctx, p, name, number, params)
711+ }
712+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, ports.EnableAutoMergeParams) domain.MergeRequest); ok {
713+ r0 = returnFunc(ctx, p, name, number, params)
714+ } else {
715+ r0 = ret.Get(0).(domain.MergeRequest)
716+ }
717+ if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, int64, ports.EnableAutoMergeParams) error); ok {
718+ r1 = returnFunc(ctx, p, name, number, params)
719+ } else {
720+ r1 = ret.Error(1)
721+ }
722+ return r0, r1
723+}
724+
725+// MergeRequestService_EnableAutoMerge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnableAutoMerge'
726+type MergeRequestService_EnableAutoMerge_Call struct {
727+ *mock.Call
728+}
729+
730+// EnableAutoMerge is a helper method to define mock.On call
731+// - ctx context.Context
732+// - p domain.Principal
733+// - name domain.RepoName
734+// - number int64
735+// - params ports.EnableAutoMergeParams
736+func (_e *MergeRequestService_Expecter) EnableAutoMerge(ctx any, p any, name any, number any, params any) *MergeRequestService_EnableAutoMerge_Call {
737+ return &MergeRequestService_EnableAutoMerge_Call{Call: _e.mock.On("EnableAutoMerge", ctx, p, name, number, params)}
738+}
739+
740+func (_c *MergeRequestService_EnableAutoMerge_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.EnableAutoMergeParams)) *MergeRequestService_EnableAutoMerge_Call {
741+ _c.Call.Run(func(args mock.Arguments) {
742+ var arg0 context.Context
743+ if args[0] != nil {
744+ arg0 = args[0].(context.Context)
745+ }
746+ var arg1 domain.Principal
747+ if args[1] != nil {
748+ arg1 = args[1].(domain.Principal)
749+ }
750+ var arg2 domain.RepoName
751+ if args[2] != nil {
752+ arg2 = args[2].(domain.RepoName)
753+ }
754+ var arg3 int64
755+ if args[3] != nil {
756+ arg3 = args[3].(int64)
757+ }
758+ var arg4 ports.EnableAutoMergeParams
759+ if args[4] != nil {
760+ arg4 = args[4].(ports.EnableAutoMergeParams)
761+ }
762+ run(
763+ arg0,
764+ arg1,
765+ arg2,
766+ arg3,
767+ arg4,
768+ )
769+ })
770+ return _c
771+}
772+
773+func (_c *MergeRequestService_EnableAutoMerge_Call) Return(mergeRequest domain.MergeRequest, err error) *MergeRequestService_EnableAutoMerge_Call {
774+ _c.Call.Return(mergeRequest, err)
775+ return _c
776+}
777+
778+func (_c *MergeRequestService_EnableAutoMerge_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.EnableAutoMergeParams) (domain.MergeRequest, error)) *MergeRequestService_EnableAutoMerge_Call {
779+ _c.Call.Return(run)
780+ return _c
781+}
782+
621 // Get provides a mock function for the type MergeRequestService783 // Get provides a mock function for the type MergeRequestService
622 func (_mock *MergeRequestService) Get(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, opts ports.GetMergeRequestOptions) (ports.MergeRequestDetail, error) {784 func (_mock *MergeRequestService) Get(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, opts ports.GetMergeRequestOptions) (ports.MergeRequestDetail, error) {
623 ret := _mock.Called(ctx, p, name, number, opts)785 ret := _mock.Called(ctx, p, name, number, opts)
M internal/ports/ports.go +6 -0
@@ -437,6 +437,12 @@ type MergeGit interface {
437437 CountBehind(ctx context.Context, repo domain.RepoName, head, target domain.ObjectID, limit int) (n int, err error)
438438 }
439439
440+// AutoMergeTrigger asks the auto-merge evaluator to look at a repository
441+// again. It only marks the repository and returns.
442+type AutoMergeTrigger interface {
443+ OnRepoChanged(ctx context.Context, repo domain.RepoName)
444+}
445+
440446 // MergeabilityTrigger queues mergeability checks. It only queues the work and
441447 // returns.
442448 type MergeabilityTrigger interface {
@@ -437,6 +437,12 @@ type MergeGit interface {
437 CountBehind(ctx context.Context, repo domain.RepoName, head, target domain.ObjectID, limit int) (n int, err error)437 CountBehind(ctx context.Context, repo domain.RepoName, head, target domain.ObjectID, limit int) (n int, err error)
438 }438 }
439 439
440+// AutoMergeTrigger asks the auto-merge evaluator to look at a repository
441+// again. It only marks the repository and returns.
442+type AutoMergeTrigger interface {
443+ OnRepoChanged(ctx context.Context, repo domain.RepoName)
444+}
445+
440 // MergeabilityTrigger queues mergeability checks. It only queues the work and446 // MergeabilityTrigger queues mergeability checks. It only queues the work and
441 // returns.447 // returns.
442 type MergeabilityTrigger interface {448 type MergeabilityTrigger interface {
M internal/ports/services.go +5 -0
@@ -125,6 +125,11 @@ type MergeRequestService interface {
125125 Merge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params MergeParams) (MergeResult, error)
126126 // MarkReady takes a draft out of draft: its title loses its "WIP:" prefix.
127127 MarkReady(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error)
128+ // EnableAutoMerge sets an open merge request to merge itself once its
129+ // checks pass; enabling again replaces the mode and the head.
130+ EnableAutoMerge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params EnableAutoMergeParams) (domain.MergeRequest, error)
131+ // CancelAutoMerge turns auto-merge off on an open merge request.
132+ CancelAutoMerge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error)
128133 // CountOpen is the number of open merge requests of a repository the
129134 // principal can read. It reads no Git: the tab of every page shows it.
130135 CountOpen(ctx context.Context, p domain.Principal, name domain.RepoName) (int, error)
@@ -125,6 +125,11 @@ type MergeRequestService interface {
125 Merge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params MergeParams) (MergeResult, error)125 Merge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params MergeParams) (MergeResult, error)
126 // MarkReady takes a draft out of draft: its title loses its "WIP:" prefix.126 // MarkReady takes a draft out of draft: its title loses its "WIP:" prefix.
127 MarkReady(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error)127 MarkReady(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error)
128+ // EnableAutoMerge sets an open merge request to merge itself once its
129+ // checks pass; enabling again replaces the mode and the head.
130+ EnableAutoMerge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params EnableAutoMergeParams) (domain.MergeRequest, error)
131+ // CancelAutoMerge turns auto-merge off on an open merge request.
132+ CancelAutoMerge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error)
128 // CountOpen is the number of open merge requests of a repository the133 // CountOpen is the number of open merge requests of a repository the
129 // principal can read. It reads no Git: the tab of every page shows it.134 // principal can read. It reads no Git: the tab of every page shows it.
130 CountOpen(ctx context.Context, p domain.Principal, name domain.RepoName) (int, error)135 CountOpen(ctx context.Context, p domain.Principal, name domain.RepoName) (int, error)
M internal/usecase/mergerequests.go +10 -0
@@ -1520,3 +1520,13 @@ func (m *MergeRequests) PushSummary(ctx context.Context, p domain.Principal, rep
15201520 }
15211521 return ports.PushSummary{Count: len(commits), More: more}, nil
15221522 }
1523+
1524+// EnableAutoMerge is not implemented yet.
1525+func (m *MergeRequests) EnableAutoMerge(_ context.Context, _ domain.Principal, _ domain.RepoName, _ int64, _ ports.EnableAutoMergeParams) (domain.MergeRequest, error) {
1526+ return domain.MergeRequest{}, fmt.Errorf("%w: auto-merge is not implemented yet", domain.ErrPreconditionFailed)
1527+}
1528+
1529+// CancelAutoMerge is not implemented yet.
1530+func (m *MergeRequests) CancelAutoMerge(_ context.Context, _ domain.Principal, _ domain.RepoName, _ int64) (domain.MergeRequest, error) {
1531+ return domain.MergeRequest{}, fmt.Errorf("%w: auto-merge is not implemented yet", domain.ErrPreconditionFailed)
1532+}
@@ -1520,3 +1520,13 @@ func (m *MergeRequests) PushSummary(ctx context.Context, p domain.Principal, rep
1520 }1520 }
1521 return ports.PushSummary{Count: len(commits), More: more}, nil1521 return ports.PushSummary{Count: len(commits), More: more}, nil
1522 }1522 }
1523+
1524+// EnableAutoMerge is not implemented yet.
1525+func (m *MergeRequests) EnableAutoMerge(_ context.Context, _ domain.Principal, _ domain.RepoName, _ int64, _ ports.EnableAutoMergeParams) (domain.MergeRequest, error) {
1526+ return domain.MergeRequest{}, fmt.Errorf("%w: auto-merge is not implemented yet", domain.ErrPreconditionFailed)
1527+}
1528+
1529+// CancelAutoMerge is not implemented yet.
1530+func (m *MergeRequests) CancelAutoMerge(_ context.Context, _ domain.Principal, _ domain.RepoName, _ int64) (domain.MergeRequest, error) {
1531+ return domain.MergeRequest{}, fmt.Errorf("%w: auto-merge is not implemented yet", domain.ErrPreconditionFailed)
1532+}

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 45

↑↓ moveenter openesc close