detached 3130756

feat(api): add issue service, issues repo setting and issue:write scope

commit
31307565591ef7f7a6d4ec73137f80611c88bd55
author
brice · · 2026-10-19 05:15 UTC
committer
brice · · 2026-10-19 08:28 UTC
parent
11411cf
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
11 files · +2205 -115
M gen/ermite/ermiteconnect/event.connect.go +4 -2
@@ -48,7 +48,8 @@ type EventServiceClient interface {
4848 // The events are repo_created, repo_updated, repo_deleted, pushed, gap and,
4949 // for merge requests, merge_request_opened, merge_request_merged,
5050 // merge_request_closed, comment_added, comment_edited, comment_deleted and
51- // comment_resolved (a thread resolved or reopened). Each one is delivered on the
51+ // comment_resolved (a thread resolved or reopened); for issues, issue_opened,
52+ // issue_closed, issue_reopened and issue_commented. Each one is delivered on the
5253 // "repo:<name>" topic of its repository and on "home", subject to the
5354 // visibility of the repository.
5455 //
@@ -121,7 +122,8 @@ type EventServiceHandler interface {
121122 // The events are repo_created, repo_updated, repo_deleted, pushed, gap and,
122123 // for merge requests, merge_request_opened, merge_request_merged,
123124 // merge_request_closed, comment_added, comment_edited, comment_deleted and
124- // comment_resolved (a thread resolved or reopened). Each one is delivered on the
125+ // comment_resolved (a thread resolved or reopened); for issues, issue_opened,
126+ // issue_closed, issue_reopened and issue_commented. Each one is delivered on the
125127 // "repo:<name>" topic of its repository and on "home", subject to the
126128 // visibility of the repository.
127129 //
@@ -48,7 +48,8 @@ type EventServiceClient interface {
48 // The events are repo_created, repo_updated, repo_deleted, pushed, gap and,48 // The events are repo_created, repo_updated, repo_deleted, pushed, gap and,
49 // for merge requests, merge_request_opened, merge_request_merged,49 // for merge requests, merge_request_opened, merge_request_merged,
50 // merge_request_closed, comment_added, comment_edited, comment_deleted and50 // merge_request_closed, comment_added, comment_edited, comment_deleted and
51- // comment_resolved (a thread resolved or reopened). Each one is delivered on the51+ // comment_resolved (a thread resolved or reopened); for issues, issue_opened,
52+ // issue_closed, issue_reopened and issue_commented. Each one is delivered on the
52 // "repo:<name>" topic of its repository and on "home", subject to the53 // "repo:<name>" topic of its repository and on "home", subject to the
53 // visibility of the repository.54 // visibility of the repository.
54 //55 //
@@ -121,7 +122,8 @@ type EventServiceHandler interface {
121 // The events are repo_created, repo_updated, repo_deleted, pushed, gap and,122 // The events are repo_created, repo_updated, repo_deleted, pushed, gap and,
122 // for merge requests, merge_request_opened, merge_request_merged,123 // for merge requests, merge_request_opened, merge_request_merged,
123 // merge_request_closed, comment_added, comment_edited, comment_deleted and124 // merge_request_closed, comment_added, comment_edited, comment_deleted and
124- // comment_resolved (a thread resolved or reopened). Each one is delivered on the125+ // comment_resolved (a thread resolved or reopened); for issues, issue_opened,
126+ // issue_closed, issue_reopened and issue_commented. Each one is delivered on the
125 // "repo:<name>" topic of its repository and on "home", subject to the127 // "repo:<name>" topic of its repository and on "home", subject to the
126 // visibility of the repository.128 // visibility of the repository.
127 //129 //
A gen/ermite/ermiteconnect/issue.connect.go +265 -0
@@ -0,0 +1,265 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/issue.proto
6+
7+package ermiteconnect
8+
9+import (
10+ ermite "bnema.dev/ermite-api/gen/ermite"
11+ connect "connectrpc.com/connect"
12+ context "context"
13+ errors "errors"
14+ http "net/http"
15+ strings "strings"
16+)
17+
18+// This is a compile-time assertion to ensure that this generated file and the connect package are
19+// compatible. If you get a compiler error that this constant is not defined, this code was
20+// generated with a version of connect newer than the one compiled into your binary. You can fix the
21+// problem by either regenerating this code with an older version of connect or updating the connect
22+// version compiled into your binary.
23+const _ = connect.IsAtLeastVersion1_13_0
24+
25+const (
26+ // IssueServiceName is the fully-qualified name of the IssueService service.
27+ IssueServiceName = "ermite.IssueService"
28+)
29+
30+// These constants are the fully-qualified names of the RPCs defined in this package. They're
31+// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route.
32+//
33+// Note that these are different from the fully-qualified method names used by
34+// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to
35+// reflection-formatted method names, remove the leading slash and convert the remaining slash to a
36+// period.
37+const (
38+ // IssueServiceCreateIssueProcedure is the fully-qualified name of the IssueService's CreateIssue
39+ // RPC.
40+ IssueServiceCreateIssueProcedure = "/ermite.IssueService/CreateIssue"
41+ // IssueServiceListIssuesProcedure is the fully-qualified name of the IssueService's ListIssues RPC.
42+ IssueServiceListIssuesProcedure = "/ermite.IssueService/ListIssues"
43+ // IssueServiceGetIssueProcedure is the fully-qualified name of the IssueService's GetIssue RPC.
44+ IssueServiceGetIssueProcedure = "/ermite.IssueService/GetIssue"
45+ // IssueServiceAddIssueCommentProcedure is the fully-qualified name of the IssueService's
46+ // AddIssueComment RPC.
47+ IssueServiceAddIssueCommentProcedure = "/ermite.IssueService/AddIssueComment"
48+ // IssueServiceCloseIssueProcedure is the fully-qualified name of the IssueService's CloseIssue RPC.
49+ IssueServiceCloseIssueProcedure = "/ermite.IssueService/CloseIssue"
50+ // IssueServiceReopenIssueProcedure is the fully-qualified name of the IssueService's ReopenIssue
51+ // RPC.
52+ IssueServiceReopenIssueProcedure = "/ermite.IssueService/ReopenIssue"
53+)
54+
55+// IssueServiceClient is a client for the ermite.IssueService service.
56+type IssueServiceClient interface {
57+ // CreateIssue opens an issue. Needs the issue:write scope.
58+ CreateIssue(context.Context, *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error)
59+ // ListIssues lists issues, highest number first, optionally in one state.
60+ ListIssues(context.Context, *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error)
61+ // GetIssue returns an issue with its comments.
62+ GetIssue(context.Context, *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error)
63+ // AddIssueComment adds a comment. Needs the issue:write scope.
64+ AddIssueComment(context.Context, *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error)
65+ // CloseIssue closes an issue. Needs the issue:write scope.
66+ CloseIssue(context.Context, *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error)
67+ // ReopenIssue reopens an issue. Needs the issue:write scope.
68+ ReopenIssue(context.Context, *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error)
69+}
70+
71+// NewIssueServiceClient constructs a client for the ermite.IssueService service. By default, it
72+// uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends
73+// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or
74+// connect.WithGRPCWeb() options.
75+//
76+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
77+// http://api.acme.com or https://acme.com/grpc).
78+func NewIssueServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) IssueServiceClient {
79+ baseURL = strings.TrimRight(baseURL, "/")
80+ issueServiceMethods := ermite.File_ermite_issue_proto.Services().ByName("IssueService").Methods()
81+ return &issueServiceClient{
82+ createIssue: connect.NewClient[ermite.CreateIssueRequest, ermite.CreateIssueResponse](
83+ httpClient,
84+ baseURL+IssueServiceCreateIssueProcedure,
85+ connect.WithSchema(issueServiceMethods.ByName("CreateIssue")),
86+ connect.WithClientOptions(opts...),
87+ ),
88+ listIssues: connect.NewClient[ermite.ListIssuesRequest, ermite.ListIssuesResponse](
89+ httpClient,
90+ baseURL+IssueServiceListIssuesProcedure,
91+ connect.WithSchema(issueServiceMethods.ByName("ListIssues")),
92+ connect.WithClientOptions(opts...),
93+ ),
94+ getIssue: connect.NewClient[ermite.GetIssueRequest, ermite.GetIssueResponse](
95+ httpClient,
96+ baseURL+IssueServiceGetIssueProcedure,
97+ connect.WithSchema(issueServiceMethods.ByName("GetIssue")),
98+ connect.WithClientOptions(opts...),
99+ ),
100+ addIssueComment: connect.NewClient[ermite.AddIssueCommentRequest, ermite.AddIssueCommentResponse](
101+ httpClient,
102+ baseURL+IssueServiceAddIssueCommentProcedure,
103+ connect.WithSchema(issueServiceMethods.ByName("AddIssueComment")),
104+ connect.WithClientOptions(opts...),
105+ ),
106+ closeIssue: connect.NewClient[ermite.CloseIssueRequest, ermite.CloseIssueResponse](
107+ httpClient,
108+ baseURL+IssueServiceCloseIssueProcedure,
109+ connect.WithSchema(issueServiceMethods.ByName("CloseIssue")),
110+ connect.WithClientOptions(opts...),
111+ ),
112+ reopenIssue: connect.NewClient[ermite.ReopenIssueRequest, ermite.ReopenIssueResponse](
113+ httpClient,
114+ baseURL+IssueServiceReopenIssueProcedure,
115+ connect.WithSchema(issueServiceMethods.ByName("ReopenIssue")),
116+ connect.WithClientOptions(opts...),
117+ ),
118+ }
119+}
120+
121+// issueServiceClient implements IssueServiceClient.
122+type issueServiceClient struct {
123+ createIssue *connect.Client[ermite.CreateIssueRequest, ermite.CreateIssueResponse]
124+ listIssues *connect.Client[ermite.ListIssuesRequest, ermite.ListIssuesResponse]
125+ getIssue *connect.Client[ermite.GetIssueRequest, ermite.GetIssueResponse]
126+ addIssueComment *connect.Client[ermite.AddIssueCommentRequest, ermite.AddIssueCommentResponse]
127+ closeIssue *connect.Client[ermite.CloseIssueRequest, ermite.CloseIssueResponse]
128+ reopenIssue *connect.Client[ermite.ReopenIssueRequest, ermite.ReopenIssueResponse]
129+}
130+
131+// CreateIssue calls ermite.IssueService.CreateIssue.
132+func (c *issueServiceClient) CreateIssue(ctx context.Context, req *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error) {
133+ return c.createIssue.CallUnary(ctx, req)
134+}
135+
136+// ListIssues calls ermite.IssueService.ListIssues.
137+func (c *issueServiceClient) ListIssues(ctx context.Context, req *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error) {
138+ return c.listIssues.CallUnary(ctx, req)
139+}
140+
141+// GetIssue calls ermite.IssueService.GetIssue.
142+func (c *issueServiceClient) GetIssue(ctx context.Context, req *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error) {
143+ return c.getIssue.CallUnary(ctx, req)
144+}
145+
146+// AddIssueComment calls ermite.IssueService.AddIssueComment.
147+func (c *issueServiceClient) AddIssueComment(ctx context.Context, req *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error) {
148+ return c.addIssueComment.CallUnary(ctx, req)
149+}
150+
151+// CloseIssue calls ermite.IssueService.CloseIssue.
152+func (c *issueServiceClient) CloseIssue(ctx context.Context, req *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error) {
153+ return c.closeIssue.CallUnary(ctx, req)
154+}
155+
156+// ReopenIssue calls ermite.IssueService.ReopenIssue.
157+func (c *issueServiceClient) ReopenIssue(ctx context.Context, req *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error) {
158+ return c.reopenIssue.CallUnary(ctx, req)
159+}
160+
161+// IssueServiceHandler is an implementation of the ermite.IssueService service.
162+type IssueServiceHandler interface {
163+ // CreateIssue opens an issue. Needs the issue:write scope.
164+ CreateIssue(context.Context, *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error)
165+ // ListIssues lists issues, highest number first, optionally in one state.
166+ ListIssues(context.Context, *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error)
167+ // GetIssue returns an issue with its comments.
168+ GetIssue(context.Context, *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error)
169+ // AddIssueComment adds a comment. Needs the issue:write scope.
170+ AddIssueComment(context.Context, *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error)
171+ // CloseIssue closes an issue. Needs the issue:write scope.
172+ CloseIssue(context.Context, *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error)
173+ // ReopenIssue reopens an issue. Needs the issue:write scope.
174+ ReopenIssue(context.Context, *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error)
175+}
176+
177+// NewIssueServiceHandler builds an HTTP handler from the service implementation. It returns the
178+// path on which to mount the handler and the handler itself.
179+//
180+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
181+// and JSON codecs. They also support gzip compression.
182+func NewIssueServiceHandler(svc IssueServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
183+ issueServiceMethods := ermite.File_ermite_issue_proto.Services().ByName("IssueService").Methods()
184+ issueServiceCreateIssueHandler := connect.NewUnaryHandler(
185+ IssueServiceCreateIssueProcedure,
186+ svc.CreateIssue,
187+ connect.WithSchema(issueServiceMethods.ByName("CreateIssue")),
188+ connect.WithHandlerOptions(opts...),
189+ )
190+ issueServiceListIssuesHandler := connect.NewUnaryHandler(
191+ IssueServiceListIssuesProcedure,
192+ svc.ListIssues,
193+ connect.WithSchema(issueServiceMethods.ByName("ListIssues")),
194+ connect.WithHandlerOptions(opts...),
195+ )
196+ issueServiceGetIssueHandler := connect.NewUnaryHandler(
197+ IssueServiceGetIssueProcedure,
198+ svc.GetIssue,
199+ connect.WithSchema(issueServiceMethods.ByName("GetIssue")),
200+ connect.WithHandlerOptions(opts...),
201+ )
202+ issueServiceAddIssueCommentHandler := connect.NewUnaryHandler(
203+ IssueServiceAddIssueCommentProcedure,
204+ svc.AddIssueComment,
205+ connect.WithSchema(issueServiceMethods.ByName("AddIssueComment")),
206+ connect.WithHandlerOptions(opts...),
207+ )
208+ issueServiceCloseIssueHandler := connect.NewUnaryHandler(
209+ IssueServiceCloseIssueProcedure,
210+ svc.CloseIssue,
211+ connect.WithSchema(issueServiceMethods.ByName("CloseIssue")),
212+ connect.WithHandlerOptions(opts...),
213+ )
214+ issueServiceReopenIssueHandler := connect.NewUnaryHandler(
215+ IssueServiceReopenIssueProcedure,
216+ svc.ReopenIssue,
217+ connect.WithSchema(issueServiceMethods.ByName("ReopenIssue")),
218+ connect.WithHandlerOptions(opts...),
219+ )
220+ return "/ermite.IssueService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
221+ switch r.URL.Path {
222+ case IssueServiceCreateIssueProcedure:
223+ issueServiceCreateIssueHandler.ServeHTTP(w, r)
224+ case IssueServiceListIssuesProcedure:
225+ issueServiceListIssuesHandler.ServeHTTP(w, r)
226+ case IssueServiceGetIssueProcedure:
227+ issueServiceGetIssueHandler.ServeHTTP(w, r)
228+ case IssueServiceAddIssueCommentProcedure:
229+ issueServiceAddIssueCommentHandler.ServeHTTP(w, r)
230+ case IssueServiceCloseIssueProcedure:
231+ issueServiceCloseIssueHandler.ServeHTTP(w, r)
232+ case IssueServiceReopenIssueProcedure:
233+ issueServiceReopenIssueHandler.ServeHTTP(w, r)
234+ default:
235+ http.NotFound(w, r)
236+ }
237+ })
238+}
239+
240+// UnimplementedIssueServiceHandler returns CodeUnimplemented from all methods.
241+type UnimplementedIssueServiceHandler struct{}
242+
243+func (UnimplementedIssueServiceHandler) CreateIssue(context.Context, *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error) {
244+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.CreateIssue is not implemented"))
245+}
246+
247+func (UnimplementedIssueServiceHandler) ListIssues(context.Context, *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error) {
248+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.ListIssues is not implemented"))
249+}
250+
251+func (UnimplementedIssueServiceHandler) GetIssue(context.Context, *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error) {
252+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.GetIssue is not implemented"))
253+}
254+
255+func (UnimplementedIssueServiceHandler) AddIssueComment(context.Context, *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error) {
256+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.AddIssueComment is not implemented"))
257+}
258+
259+func (UnimplementedIssueServiceHandler) CloseIssue(context.Context, *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error) {
260+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.CloseIssue is not implemented"))
261+}
262+
263+func (UnimplementedIssueServiceHandler) ReopenIssue(context.Context, *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error) {
264+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.ReopenIssue is not implemented"))
265+}
@@ -0,0 +1,265 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/issue.proto
6+
7+package ermiteconnect
8+
9+import (
10+ ermite "bnema.dev/ermite-api/gen/ermite"
11+ connect "connectrpc.com/connect"
12+ context "context"
13+ errors "errors"
14+ http "net/http"
15+ strings "strings"
16+)
17+
18+// This is a compile-time assertion to ensure that this generated file and the connect package are
19+// compatible. If you get a compiler error that this constant is not defined, this code was
20+// generated with a version of connect newer than the one compiled into your binary. You can fix the
21+// problem by either regenerating this code with an older version of connect or updating the connect
22+// version compiled into your binary.
23+const _ = connect.IsAtLeastVersion1_13_0
24+
25+const (
26+ // IssueServiceName is the fully-qualified name of the IssueService service.
27+ IssueServiceName = "ermite.IssueService"
28+)
29+
30+// These constants are the fully-qualified names of the RPCs defined in this package. They're
31+// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route.
32+//
33+// Note that these are different from the fully-qualified method names used by
34+// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to
35+// reflection-formatted method names, remove the leading slash and convert the remaining slash to a
36+// period.
37+const (
38+ // IssueServiceCreateIssueProcedure is the fully-qualified name of the IssueService's CreateIssue
39+ // RPC.
40+ IssueServiceCreateIssueProcedure = "/ermite.IssueService/CreateIssue"
41+ // IssueServiceListIssuesProcedure is the fully-qualified name of the IssueService's ListIssues RPC.
42+ IssueServiceListIssuesProcedure = "/ermite.IssueService/ListIssues"
43+ // IssueServiceGetIssueProcedure is the fully-qualified name of the IssueService's GetIssue RPC.
44+ IssueServiceGetIssueProcedure = "/ermite.IssueService/GetIssue"
45+ // IssueServiceAddIssueCommentProcedure is the fully-qualified name of the IssueService's
46+ // AddIssueComment RPC.
47+ IssueServiceAddIssueCommentProcedure = "/ermite.IssueService/AddIssueComment"
48+ // IssueServiceCloseIssueProcedure is the fully-qualified name of the IssueService's CloseIssue RPC.
49+ IssueServiceCloseIssueProcedure = "/ermite.IssueService/CloseIssue"
50+ // IssueServiceReopenIssueProcedure is the fully-qualified name of the IssueService's ReopenIssue
51+ // RPC.
52+ IssueServiceReopenIssueProcedure = "/ermite.IssueService/ReopenIssue"
53+)
54+
55+// IssueServiceClient is a client for the ermite.IssueService service.
56+type IssueServiceClient interface {
57+ // CreateIssue opens an issue. Needs the issue:write scope.
58+ CreateIssue(context.Context, *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error)
59+ // ListIssues lists issues, highest number first, optionally in one state.
60+ ListIssues(context.Context, *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error)
61+ // GetIssue returns an issue with its comments.
62+ GetIssue(context.Context, *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error)
63+ // AddIssueComment adds a comment. Needs the issue:write scope.
64+ AddIssueComment(context.Context, *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error)
65+ // CloseIssue closes an issue. Needs the issue:write scope.
66+ CloseIssue(context.Context, *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error)
67+ // ReopenIssue reopens an issue. Needs the issue:write scope.
68+ ReopenIssue(context.Context, *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error)
69+}
70+
71+// NewIssueServiceClient constructs a client for the ermite.IssueService service. By default, it
72+// uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends
73+// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or
74+// connect.WithGRPCWeb() options.
75+//
76+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
77+// http://api.acme.com or https://acme.com/grpc).
78+func NewIssueServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) IssueServiceClient {
79+ baseURL = strings.TrimRight(baseURL, "/")
80+ issueServiceMethods := ermite.File_ermite_issue_proto.Services().ByName("IssueService").Methods()
81+ return &issueServiceClient{
82+ createIssue: connect.NewClient[ermite.CreateIssueRequest, ermite.CreateIssueResponse](
83+ httpClient,
84+ baseURL+IssueServiceCreateIssueProcedure,
85+ connect.WithSchema(issueServiceMethods.ByName("CreateIssue")),
86+ connect.WithClientOptions(opts...),
87+ ),
88+ listIssues: connect.NewClient[ermite.ListIssuesRequest, ermite.ListIssuesResponse](
89+ httpClient,
90+ baseURL+IssueServiceListIssuesProcedure,
91+ connect.WithSchema(issueServiceMethods.ByName("ListIssues")),
92+ connect.WithClientOptions(opts...),
93+ ),
94+ getIssue: connect.NewClient[ermite.GetIssueRequest, ermite.GetIssueResponse](
95+ httpClient,
96+ baseURL+IssueServiceGetIssueProcedure,
97+ connect.WithSchema(issueServiceMethods.ByName("GetIssue")),
98+ connect.WithClientOptions(opts...),
99+ ),
100+ addIssueComment: connect.NewClient[ermite.AddIssueCommentRequest, ermite.AddIssueCommentResponse](
101+ httpClient,
102+ baseURL+IssueServiceAddIssueCommentProcedure,
103+ connect.WithSchema(issueServiceMethods.ByName("AddIssueComment")),
104+ connect.WithClientOptions(opts...),
105+ ),
106+ closeIssue: connect.NewClient[ermite.CloseIssueRequest, ermite.CloseIssueResponse](
107+ httpClient,
108+ baseURL+IssueServiceCloseIssueProcedure,
109+ connect.WithSchema(issueServiceMethods.ByName("CloseIssue")),
110+ connect.WithClientOptions(opts...),
111+ ),
112+ reopenIssue: connect.NewClient[ermite.ReopenIssueRequest, ermite.ReopenIssueResponse](
113+ httpClient,
114+ baseURL+IssueServiceReopenIssueProcedure,
115+ connect.WithSchema(issueServiceMethods.ByName("ReopenIssue")),
116+ connect.WithClientOptions(opts...),
117+ ),
118+ }
119+}
120+
121+// issueServiceClient implements IssueServiceClient.
122+type issueServiceClient struct {
123+ createIssue *connect.Client[ermite.CreateIssueRequest, ermite.CreateIssueResponse]
124+ listIssues *connect.Client[ermite.ListIssuesRequest, ermite.ListIssuesResponse]
125+ getIssue *connect.Client[ermite.GetIssueRequest, ermite.GetIssueResponse]
126+ addIssueComment *connect.Client[ermite.AddIssueCommentRequest, ermite.AddIssueCommentResponse]
127+ closeIssue *connect.Client[ermite.CloseIssueRequest, ermite.CloseIssueResponse]
128+ reopenIssue *connect.Client[ermite.ReopenIssueRequest, ermite.ReopenIssueResponse]
129+}
130+
131+// CreateIssue calls ermite.IssueService.CreateIssue.
132+func (c *issueServiceClient) CreateIssue(ctx context.Context, req *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error) {
133+ return c.createIssue.CallUnary(ctx, req)
134+}
135+
136+// ListIssues calls ermite.IssueService.ListIssues.
137+func (c *issueServiceClient) ListIssues(ctx context.Context, req *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error) {
138+ return c.listIssues.CallUnary(ctx, req)
139+}
140+
141+// GetIssue calls ermite.IssueService.GetIssue.
142+func (c *issueServiceClient) GetIssue(ctx context.Context, req *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error) {
143+ return c.getIssue.CallUnary(ctx, req)
144+}
145+
146+// AddIssueComment calls ermite.IssueService.AddIssueComment.
147+func (c *issueServiceClient) AddIssueComment(ctx context.Context, req *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error) {
148+ return c.addIssueComment.CallUnary(ctx, req)
149+}
150+
151+// CloseIssue calls ermite.IssueService.CloseIssue.
152+func (c *issueServiceClient) CloseIssue(ctx context.Context, req *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error) {
153+ return c.closeIssue.CallUnary(ctx, req)
154+}
155+
156+// ReopenIssue calls ermite.IssueService.ReopenIssue.
157+func (c *issueServiceClient) ReopenIssue(ctx context.Context, req *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error) {
158+ return c.reopenIssue.CallUnary(ctx, req)
159+}
160+
161+// IssueServiceHandler is an implementation of the ermite.IssueService service.
162+type IssueServiceHandler interface {
163+ // CreateIssue opens an issue. Needs the issue:write scope.
164+ CreateIssue(context.Context, *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error)
165+ // ListIssues lists issues, highest number first, optionally in one state.
166+ ListIssues(context.Context, *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error)
167+ // GetIssue returns an issue with its comments.
168+ GetIssue(context.Context, *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error)
169+ // AddIssueComment adds a comment. Needs the issue:write scope.
170+ AddIssueComment(context.Context, *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error)
171+ // CloseIssue closes an issue. Needs the issue:write scope.
172+ CloseIssue(context.Context, *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error)
173+ // ReopenIssue reopens an issue. Needs the issue:write scope.
174+ ReopenIssue(context.Context, *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error)
175+}
176+
177+// NewIssueServiceHandler builds an HTTP handler from the service implementation. It returns the
178+// path on which to mount the handler and the handler itself.
179+//
180+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
181+// and JSON codecs. They also support gzip compression.
182+func NewIssueServiceHandler(svc IssueServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
183+ issueServiceMethods := ermite.File_ermite_issue_proto.Services().ByName("IssueService").Methods()
184+ issueServiceCreateIssueHandler := connect.NewUnaryHandler(
185+ IssueServiceCreateIssueProcedure,
186+ svc.CreateIssue,
187+ connect.WithSchema(issueServiceMethods.ByName("CreateIssue")),
188+ connect.WithHandlerOptions(opts...),
189+ )
190+ issueServiceListIssuesHandler := connect.NewUnaryHandler(
191+ IssueServiceListIssuesProcedure,
192+ svc.ListIssues,
193+ connect.WithSchema(issueServiceMethods.ByName("ListIssues")),
194+ connect.WithHandlerOptions(opts...),
195+ )
196+ issueServiceGetIssueHandler := connect.NewUnaryHandler(
197+ IssueServiceGetIssueProcedure,
198+ svc.GetIssue,
199+ connect.WithSchema(issueServiceMethods.ByName("GetIssue")),
200+ connect.WithHandlerOptions(opts...),
201+ )
202+ issueServiceAddIssueCommentHandler := connect.NewUnaryHandler(
203+ IssueServiceAddIssueCommentProcedure,
204+ svc.AddIssueComment,
205+ connect.WithSchema(issueServiceMethods.ByName("AddIssueComment")),
206+ connect.WithHandlerOptions(opts...),
207+ )
208+ issueServiceCloseIssueHandler := connect.NewUnaryHandler(
209+ IssueServiceCloseIssueProcedure,
210+ svc.CloseIssue,
211+ connect.WithSchema(issueServiceMethods.ByName("CloseIssue")),
212+ connect.WithHandlerOptions(opts...),
213+ )
214+ issueServiceReopenIssueHandler := connect.NewUnaryHandler(
215+ IssueServiceReopenIssueProcedure,
216+ svc.ReopenIssue,
217+ connect.WithSchema(issueServiceMethods.ByName("ReopenIssue")),
218+ connect.WithHandlerOptions(opts...),
219+ )
220+ return "/ermite.IssueService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
221+ switch r.URL.Path {
222+ case IssueServiceCreateIssueProcedure:
223+ issueServiceCreateIssueHandler.ServeHTTP(w, r)
224+ case IssueServiceListIssuesProcedure:
225+ issueServiceListIssuesHandler.ServeHTTP(w, r)
226+ case IssueServiceGetIssueProcedure:
227+ issueServiceGetIssueHandler.ServeHTTP(w, r)
228+ case IssueServiceAddIssueCommentProcedure:
229+ issueServiceAddIssueCommentHandler.ServeHTTP(w, r)
230+ case IssueServiceCloseIssueProcedure:
231+ issueServiceCloseIssueHandler.ServeHTTP(w, r)
232+ case IssueServiceReopenIssueProcedure:
233+ issueServiceReopenIssueHandler.ServeHTTP(w, r)
234+ default:
235+ http.NotFound(w, r)
236+ }
237+ })
238+}
239+
240+// UnimplementedIssueServiceHandler returns CodeUnimplemented from all methods.
241+type UnimplementedIssueServiceHandler struct{}
242+
243+func (UnimplementedIssueServiceHandler) CreateIssue(context.Context, *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error) {
244+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.CreateIssue is not implemented"))
245+}
246+
247+func (UnimplementedIssueServiceHandler) ListIssues(context.Context, *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error) {
248+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.ListIssues is not implemented"))
249+}
250+
251+func (UnimplementedIssueServiceHandler) GetIssue(context.Context, *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error) {
252+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.GetIssue is not implemented"))
253+}
254+
255+func (UnimplementedIssueServiceHandler) AddIssueComment(context.Context, *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error) {
256+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.AddIssueComment is not implemented"))
257+}
258+
259+func (UnimplementedIssueServiceHandler) CloseIssue(context.Context, *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error) {
260+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.CloseIssue is not implemented"))
261+}
262+
263+func (UnimplementedIssueServiceHandler) ReopenIssue(context.Context, *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error) {
264+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.ReopenIssue is not implemented"))
265+}
M gen/ermite/event.pb.go +352 -48
@@ -157,6 +157,10 @@ type Event struct {
157157 // *Event_CommentEdited
158158 // *Event_CommentDeleted
159159 // *Event_CommentResolved
160+ // *Event_IssueOpened
161+ // *Event_IssueClosed
162+ // *Event_IssueReopened
163+ // *Event_IssueCommented
160164 Kind isEvent_Kind `protobuf_oneof:"kind"`
161165 unknownFields protoimpl.UnknownFields
162166 sizeCache protoimpl.SizeCache
@@ -339,6 +343,42 @@ func (x *Event) GetCommentResolved() *CommentResolved {
339343 return nil
340344 }
341345
346+func (x *Event) GetIssueOpened() *IssueOpened {
347+ if x != nil {
348+ if x, ok := x.Kind.(*Event_IssueOpened); ok {
349+ return x.IssueOpened
350+ }
351+ }
352+ return nil
353+}
354+
355+func (x *Event) GetIssueClosed() *IssueClosed {
356+ if x != nil {
357+ if x, ok := x.Kind.(*Event_IssueClosed); ok {
358+ return x.IssueClosed
359+ }
360+ }
361+ return nil
362+}
363+
364+func (x *Event) GetIssueReopened() *IssueReopened {
365+ if x != nil {
366+ if x, ok := x.Kind.(*Event_IssueReopened); ok {
367+ return x.IssueReopened
368+ }
369+ }
370+ return nil
371+}
372+
373+func (x *Event) GetIssueCommented() *IssueCommented {
374+ if x != nil {
375+ if x, ok := x.Kind.(*Event_IssueCommented); ok {
376+ return x.IssueCommented
377+ }
378+ }
379+ return nil
380+}
381+
342382 type isEvent_Kind interface {
343383 isEvent_Kind()
344384 }
@@ -413,6 +453,26 @@ type Event_CommentResolved struct {
413453 CommentResolved *CommentResolved `protobuf:"bytes,16,opt,name=comment_resolved,json=commentResolved,proto3,oneof"`
414454 }
415455
456+type Event_IssueOpened struct {
457+ // IssueOpened: an issue was opened.
458+ IssueOpened *IssueOpened `protobuf:"bytes,17,opt,name=issue_opened,json=issueOpened,proto3,oneof"`
459+}
460+
461+type Event_IssueClosed struct {
462+ // IssueClosed: an issue was closed.
463+ IssueClosed *IssueClosed `protobuf:"bytes,18,opt,name=issue_closed,json=issueClosed,proto3,oneof"`
464+}
465+
466+type Event_IssueReopened struct {
467+ // IssueReopened: an issue was reopened.
468+ IssueReopened *IssueReopened `protobuf:"bytes,19,opt,name=issue_reopened,json=issueReopened,proto3,oneof"`
469+}
470+
471+type Event_IssueCommented struct {
472+ // IssueCommented: a comment was added to an issue.
473+ IssueCommented *IssueCommented `protobuf:"bytes,20,opt,name=issue_commented,json=issueCommented,proto3,oneof"`
474+}
475+
416476 func (*Event_RepoCreated) isEvent_Kind() {}
417477
418478 func (*Event_RepoUpdated) isEvent_Kind() {}
@@ -441,6 +501,14 @@ func (*Event_CommentDeleted) isEvent_Kind() {}
441501
442502 func (*Event_CommentResolved) isEvent_Kind() {}
443503
504+func (*Event_IssueOpened) isEvent_Kind() {}
505+
506+func (*Event_IssueClosed) isEvent_Kind() {}
507+
508+func (*Event_IssueReopened) isEvent_Kind() {}
509+
510+func (*Event_IssueCommented) isEvent_Kind() {}
511+
444512 // RepoCreated reports a new repository.
445513 type RepoCreated struct {
446514 state protoimpl.MessageState `protogen:"open.v1"`
@@ -1095,10 +1163,213 @@ func (x *CommentResolved) GetComment() *Comment {
10951163 return nil
10961164 }
10971165
1166+// IssueOpened reports a new issue.
1167+type IssueOpened struct {
1168+ state protoimpl.MessageState `protogen:"open.v1"`
1169+ // Issue is the new issue, including its repository and number.
1170+ Issue *Issue `protobuf:"bytes,1,opt,name=issue,proto3" json:"issue,omitempty"`
1171+ unknownFields protoimpl.UnknownFields
1172+ sizeCache protoimpl.SizeCache
1173+}
1174+
1175+func (x *IssueOpened) Reset() {
1176+ *x = IssueOpened{}
1177+ mi := &file_ermite_event_proto_msgTypes[15]
1178+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1179+ ms.StoreMessageInfo(mi)
1180+}
1181+
1182+func (x *IssueOpened) String() string {
1183+ return protoimpl.X.MessageStringOf(x)
1184+}
1185+
1186+func (*IssueOpened) ProtoMessage() {}
1187+
1188+func (x *IssueOpened) ProtoReflect() protoreflect.Message {
1189+ mi := &file_ermite_event_proto_msgTypes[15]
1190+ if x != nil {
1191+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1192+ if ms.LoadMessageInfo() == nil {
1193+ ms.StoreMessageInfo(mi)
1194+ }
1195+ return ms
1196+ }
1197+ return mi.MessageOf(x)
1198+}
1199+
1200+// Deprecated: Use IssueOpened.ProtoReflect.Descriptor instead.
1201+func (*IssueOpened) Descriptor() ([]byte, []int) {
1202+ return file_ermite_event_proto_rawDescGZIP(), []int{15}
1203+}
1204+
1205+func (x *IssueOpened) GetIssue() *Issue {
1206+ if x != nil {
1207+ return x.Issue
1208+ }
1209+ return nil
1210+}
1211+
1212+// IssueClosed reports a closed issue.
1213+type IssueClosed struct {
1214+ state protoimpl.MessageState `protogen:"open.v1"`
1215+ // Issue is the issue after closing, including its repository and number.
1216+ Issue *Issue `protobuf:"bytes,1,opt,name=issue,proto3" json:"issue,omitempty"`
1217+ unknownFields protoimpl.UnknownFields
1218+ sizeCache protoimpl.SizeCache
1219+}
1220+
1221+func (x *IssueClosed) Reset() {
1222+ *x = IssueClosed{}
1223+ mi := &file_ermite_event_proto_msgTypes[16]
1224+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1225+ ms.StoreMessageInfo(mi)
1226+}
1227+
1228+func (x *IssueClosed) String() string {
1229+ return protoimpl.X.MessageStringOf(x)
1230+}
1231+
1232+func (*IssueClosed) ProtoMessage() {}
1233+
1234+func (x *IssueClosed) ProtoReflect() protoreflect.Message {
1235+ mi := &file_ermite_event_proto_msgTypes[16]
1236+ if x != nil {
1237+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1238+ if ms.LoadMessageInfo() == nil {
1239+ ms.StoreMessageInfo(mi)
1240+ }
1241+ return ms
1242+ }
1243+ return mi.MessageOf(x)
1244+}
1245+
1246+// Deprecated: Use IssueClosed.ProtoReflect.Descriptor instead.
1247+func (*IssueClosed) Descriptor() ([]byte, []int) {
1248+ return file_ermite_event_proto_rawDescGZIP(), []int{16}
1249+}
1250+
1251+func (x *IssueClosed) GetIssue() *Issue {
1252+ if x != nil {
1253+ return x.Issue
1254+ }
1255+ return nil
1256+}
1257+
1258+// IssueReopened reports a reopened issue.
1259+type IssueReopened struct {
1260+ state protoimpl.MessageState `protogen:"open.v1"`
1261+ // Issue is the issue after reopening, including its repository and number.
1262+ Issue *Issue `protobuf:"bytes,1,opt,name=issue,proto3" json:"issue,omitempty"`
1263+ unknownFields protoimpl.UnknownFields
1264+ sizeCache protoimpl.SizeCache
1265+}
1266+
1267+func (x *IssueReopened) Reset() {
1268+ *x = IssueReopened{}
1269+ mi := &file_ermite_event_proto_msgTypes[17]
1270+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1271+ ms.StoreMessageInfo(mi)
1272+}
1273+
1274+func (x *IssueReopened) String() string {
1275+ return protoimpl.X.MessageStringOf(x)
1276+}
1277+
1278+func (*IssueReopened) ProtoMessage() {}
1279+
1280+func (x *IssueReopened) ProtoReflect() protoreflect.Message {
1281+ mi := &file_ermite_event_proto_msgTypes[17]
1282+ if x != nil {
1283+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1284+ if ms.LoadMessageInfo() == nil {
1285+ ms.StoreMessageInfo(mi)
1286+ }
1287+ return ms
1288+ }
1289+ return mi.MessageOf(x)
1290+}
1291+
1292+// Deprecated: Use IssueReopened.ProtoReflect.Descriptor instead.
1293+func (*IssueReopened) Descriptor() ([]byte, []int) {
1294+ return file_ermite_event_proto_rawDescGZIP(), []int{17}
1295+}
1296+
1297+func (x *IssueReopened) GetIssue() *Issue {
1298+ if x != nil {
1299+ return x.Issue
1300+ }
1301+ return nil
1302+}
1303+
1304+// IssueCommented reports a new comment on an issue.
1305+type IssueCommented struct {
1306+ state protoimpl.MessageState `protogen:"open.v1"`
1307+ // Repo is the name of the repository.
1308+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
1309+ // Number is the number of the issue.
1310+ Number int64 `protobuf:"varint,2,opt,name=number,proto3" json:"number,omitempty"`
1311+ // Comment is the new comment.
1312+ Comment *IssueComment `protobuf:"bytes,3,opt,name=comment,proto3" json:"comment,omitempty"`
1313+ unknownFields protoimpl.UnknownFields
1314+ sizeCache protoimpl.SizeCache
1315+}
1316+
1317+func (x *IssueCommented) Reset() {
1318+ *x = IssueCommented{}
1319+ mi := &file_ermite_event_proto_msgTypes[18]
1320+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1321+ ms.StoreMessageInfo(mi)
1322+}
1323+
1324+func (x *IssueCommented) String() string {
1325+ return protoimpl.X.MessageStringOf(x)
1326+}
1327+
1328+func (*IssueCommented) ProtoMessage() {}
1329+
1330+func (x *IssueCommented) ProtoReflect() protoreflect.Message {
1331+ mi := &file_ermite_event_proto_msgTypes[18]
1332+ if x != nil {
1333+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1334+ if ms.LoadMessageInfo() == nil {
1335+ ms.StoreMessageInfo(mi)
1336+ }
1337+ return ms
1338+ }
1339+ return mi.MessageOf(x)
1340+}
1341+
1342+// Deprecated: Use IssueCommented.ProtoReflect.Descriptor instead.
1343+func (*IssueCommented) Descriptor() ([]byte, []int) {
1344+ return file_ermite_event_proto_rawDescGZIP(), []int{18}
1345+}
1346+
1347+func (x *IssueCommented) GetRepo() string {
1348+ if x != nil {
1349+ return x.Repo
1350+ }
1351+ return ""
1352+}
1353+
1354+func (x *IssueCommented) GetNumber() int64 {
1355+ if x != nil {
1356+ return x.Number
1357+ }
1358+ return 0
1359+}
1360+
1361+func (x *IssueCommented) GetComment() *IssueComment {
1362+ if x != nil {
1363+ return x.Comment
1364+ }
1365+ return nil
1366+}
1367+
10981368 // Gap tells the client that events were lost: the requested resume point is
10991369 // older than the server's buffer. It has no fields. The client should reload
11001370 // the state it displays (repositories, refs, merge requests and their
1101-// comments, CI runs and their jobs) and carry on with the next events.
1371+// comments, issues and their comments, CI runs and their jobs) and carry on
1372+// with the next events.
11021373 type Gap struct {
11031374 state protoimpl.MessageState `protogen:"open.v1"`
11041375 unknownFields protoimpl.UnknownFields
@@ -1107,7 +1378,7 @@ type Gap struct {
11071378
11081379 func (x *Gap) Reset() {
11091380 *x = Gap{}
1110- mi := &file_ermite_event_proto_msgTypes[15]
1381+ mi := &file_ermite_event_proto_msgTypes[19]
11111382 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
11121383 ms.StoreMessageInfo(mi)
11131384 }
@@ -1119,7 +1390,7 @@ func (x *Gap) String() string {
11191390 func (*Gap) ProtoMessage() {}
11201391
11211392 func (x *Gap) ProtoReflect() protoreflect.Message {
1122- mi := &file_ermite_event_proto_msgTypes[15]
1393+ mi := &file_ermite_event_proto_msgTypes[19]
11231394 if x != nil {
11241395 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
11251396 if ms.LoadMessageInfo() == nil {
@@ -1132,7 +1403,7 @@ func (x *Gap) ProtoReflect() protoreflect.Message {
11321403
11331404 // Deprecated: Use Gap.ProtoReflect.Descriptor instead.
11341405 func (*Gap) Descriptor() ([]byte, []int) {
1135- return file_ermite_event_proto_rawDescGZIP(), []int{15}
1406+ return file_ermite_event_proto_rawDescGZIP(), []int{19}
11361407 }
11371408
11381409 // RunUpdated reports a CI run that was created or whose status, conclusion or
@@ -1147,7 +1418,7 @@ type RunUpdated struct {
11471418
11481419 func (x *RunUpdated) Reset() {
11491420 *x = RunUpdated{}
1150- mi := &file_ermite_event_proto_msgTypes[16]
1421+ mi := &file_ermite_event_proto_msgTypes[20]
11511422 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
11521423 ms.StoreMessageInfo(mi)
11531424 }
@@ -1159,7 +1430,7 @@ func (x *RunUpdated) String() string {
11591430 func (*RunUpdated) ProtoMessage() {}
11601431
11611432 func (x *RunUpdated) ProtoReflect() protoreflect.Message {
1162- mi := &file_ermite_event_proto_msgTypes[16]
1433+ mi := &file_ermite_event_proto_msgTypes[20]
11631434 if x != nil {
11641435 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
11651436 if ms.LoadMessageInfo() == nil {
@@ -1172,7 +1443,7 @@ func (x *RunUpdated) ProtoReflect() protoreflect.Message {
11721443
11731444 // Deprecated: Use RunUpdated.ProtoReflect.Descriptor instead.
11741445 func (*RunUpdated) Descriptor() ([]byte, []int) {
1175- return file_ermite_event_proto_rawDescGZIP(), []int{16}
1446+ return file_ermite_event_proto_rawDescGZIP(), []int{20}
11761447 }
11771448
11781449 func (x *RunUpdated) GetRun() *Run {
@@ -1194,7 +1465,7 @@ type JobUpdated struct {
11941465
11951466 func (x *JobUpdated) Reset() {
11961467 *x = JobUpdated{}
1197- mi := &file_ermite_event_proto_msgTypes[17]
1468+ mi := &file_ermite_event_proto_msgTypes[21]
11981469 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
11991470 ms.StoreMessageInfo(mi)
12001471 }
@@ -1206,7 +1477,7 @@ func (x *JobUpdated) String() string {
12061477 func (*JobUpdated) ProtoMessage() {}
12071478
12081479 func (x *JobUpdated) ProtoReflect() protoreflect.Message {
1209- mi := &file_ermite_event_proto_msgTypes[17]
1480+ mi := &file_ermite_event_proto_msgTypes[21]
12101481 if x != nil {
12111482 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
12121483 if ms.LoadMessageInfo() == nil {
@@ -1219,7 +1490,7 @@ func (x *JobUpdated) ProtoReflect() protoreflect.Message {
12191490
12201491 // Deprecated: Use JobUpdated.ProtoReflect.Descriptor instead.
12211492 func (*JobUpdated) Descriptor() ([]byte, []int) {
1222- return file_ermite_event_proto_rawDescGZIP(), []int{17}
1493+ return file_ermite_event_proto_rawDescGZIP(), []int{21}
12231494 }
12241495
12251496 func (x *JobUpdated) GetJob() *RunJob {
@@ -1233,12 +1504,12 @@ var File_ermite_event_proto protoreflect.FileDescriptor
12331504
12341505 const file_ermite_event_proto_rawDesc = "" +
12351506 "\n" +
1236- "\x12ermite/event.proto\x12\x06ermite\x1a\x1aermite/merge_request.proto\x1a\x11ermite/repo.proto\x1a\x10ermite/run.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"I\n" +
1507+ "\x12ermite/event.proto\x12\x06ermite\x1a\x12ermite/issue.proto\x1a\x1aermite/merge_request.proto\x1a\x11ermite/repo.proto\x1a\x10ermite/run.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"I\n" +
12371508 "\fWatchRequest\x12\x16\n" +
12381509 "\x06topics\x18\x01 \x03(\tR\x06topics\x12!\n" +
12391510 "\fresume_after\x18\x02 \x01(\tR\vresumeAfter\"4\n" +
12401511 "\rWatchResponse\x12#\n" +
1241- "\x05event\x18\x01 \x01(\v2\r.ermite.EventR\x05event\"\xac\a\n" +
1512+ "\x05event\x18\x01 \x01(\v2\r.ermite.EventR\x05event\"\xa3\t\n" +
12421513 "\x05Event\x12\x0e\n" +
12431514 "\x02id\x18\x01 \x01(\tR\x02id\x12.\n" +
12441515 "\x04time\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\x04time\x128\n" +
@@ -1258,7 +1529,11 @@ const file_ermite_event_proto_rawDesc = "" +
12581529 "jobUpdated\x12>\n" +
12591530 "\x0ecomment_edited\x18\x0e \x01(\v2\x15.ermite.CommentEditedH\x00R\rcommentEdited\x12A\n" +
12601531 "\x0fcomment_deleted\x18\x0f \x01(\v2\x16.ermite.CommentDeletedH\x00R\x0ecommentDeleted\x12D\n" +
1261- "\x10comment_resolved\x18\x10 \x01(\v2\x17.ermite.CommentResolvedH\x00R\x0fcommentResolvedB\x06\n" +
1532+ "\x10comment_resolved\x18\x10 \x01(\v2\x17.ermite.CommentResolvedH\x00R\x0fcommentResolved\x128\n" +
1533+ "\fissue_opened\x18\x11 \x01(\v2\x13.ermite.IssueOpenedH\x00R\vissueOpened\x128\n" +
1534+ "\fissue_closed\x18\x12 \x01(\v2\x13.ermite.IssueClosedH\x00R\vissueClosed\x12>\n" +
1535+ "\x0eissue_reopened\x18\x13 \x01(\v2\x15.ermite.IssueReopenedH\x00R\rissueReopened\x12A\n" +
1536+ "\x0fissue_commented\x18\x14 \x01(\v2\x16.ermite.IssueCommentedH\x00R\x0eissueCommentedB\x06\n" +
12621537 "\x04kind\"/\n" +
12631538 "\vRepoCreated\x12 \n" +
12641539 "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"/\n" +
@@ -1295,7 +1570,17 @@ const file_ermite_event_proto_rawDesc = "" +
12951570 "\x0fCommentResolved\x12\x12\n" +
12961571 "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x16\n" +
12971572 "\x06number\x18\x02 \x01(\x03R\x06number\x12)\n" +
1298- "\acomment\x18\x03 \x01(\v2\x0f.ermite.CommentR\acomment\"\x05\n" +
1573+ "\acomment\x18\x03 \x01(\v2\x0f.ermite.CommentR\acomment\"2\n" +
1574+ "\vIssueOpened\x12#\n" +
1575+ "\x05issue\x18\x01 \x01(\v2\r.ermite.IssueR\x05issue\"2\n" +
1576+ "\vIssueClosed\x12#\n" +
1577+ "\x05issue\x18\x01 \x01(\v2\r.ermite.IssueR\x05issue\"4\n" +
1578+ "\rIssueReopened\x12#\n" +
1579+ "\x05issue\x18\x01 \x01(\v2\r.ermite.IssueR\x05issue\"l\n" +
1580+ "\x0eIssueCommented\x12\x12\n" +
1581+ "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x16\n" +
1582+ "\x06number\x18\x02 \x01(\x03R\x06number\x12.\n" +
1583+ "\acomment\x18\x03 \x01(\v2\x14.ermite.IssueCommentR\acomment\"\x05\n" +
12991584 "\x03Gap\"+\n" +
13001585 "\n" +
13011586 "RunUpdated\x12\x1d\n" +
@@ -1321,7 +1606,7 @@ func file_ermite_event_proto_rawDescGZIP() []byte {
13211606 return file_ermite_event_proto_rawDescData
13221607 }
13231608
1324-var file_ermite_event_proto_msgTypes = make([]protoimpl.MessageInfo, 18)
1609+var file_ermite_event_proto_msgTypes = make([]protoimpl.MessageInfo, 22)
13251610 var file_ermite_event_proto_goTypes = []any{
13261611 (*WatchRequest)(nil), // 0: ermite.WatchRequest
13271612 (*WatchResponse)(nil), // 1: ermite.WatchResponse
@@ -1338,52 +1623,66 @@ var file_ermite_event_proto_goTypes = []any{
13381623 (*CommentEdited)(nil), // 12: ermite.CommentEdited
13391624 (*CommentDeleted)(nil), // 13: ermite.CommentDeleted
13401625 (*CommentResolved)(nil), // 14: ermite.CommentResolved
1341- (*Gap)(nil), // 15: ermite.Gap
1342- (*RunUpdated)(nil), // 16: ermite.RunUpdated
1343- (*JobUpdated)(nil), // 17: ermite.JobUpdated
1344- (*timestamppb.Timestamp)(nil), // 18: google.protobuf.Timestamp
1345- (*Repo)(nil), // 19: ermite.Repo
1346- (*MergeRequest)(nil), // 20: ermite.MergeRequest
1347- (*Comment)(nil), // 21: ermite.Comment
1348- (*Run)(nil), // 22: ermite.Run
1349- (*RunJob)(nil), // 23: ermite.RunJob
1626+ (*IssueOpened)(nil), // 15: ermite.IssueOpened
1627+ (*IssueClosed)(nil), // 16: ermite.IssueClosed
1628+ (*IssueReopened)(nil), // 17: ermite.IssueReopened
1629+ (*IssueCommented)(nil), // 18: ermite.IssueCommented
1630+ (*Gap)(nil), // 19: ermite.Gap
1631+ (*RunUpdated)(nil), // 20: ermite.RunUpdated
1632+ (*JobUpdated)(nil), // 21: ermite.JobUpdated
1633+ (*timestamppb.Timestamp)(nil), // 22: google.protobuf.Timestamp
1634+ (*Repo)(nil), // 23: ermite.Repo
1635+ (*MergeRequest)(nil), // 24: ermite.MergeRequest
1636+ (*Comment)(nil), // 25: ermite.Comment
1637+ (*Issue)(nil), // 26: ermite.Issue
1638+ (*IssueComment)(nil), // 27: ermite.IssueComment
1639+ (*Run)(nil), // 28: ermite.Run
1640+ (*RunJob)(nil), // 29: ermite.RunJob
13501641 }
13511642 var file_ermite_event_proto_depIdxs = []int32{
13521643 2, // 0: ermite.WatchResponse.event:type_name -> ermite.Event
1353- 18, // 1: ermite.Event.time:type_name -> google.protobuf.Timestamp
1644+ 22, // 1: ermite.Event.time:type_name -> google.protobuf.Timestamp
13541645 3, // 2: ermite.Event.repo_created:type_name -> ermite.RepoCreated
13551646 4, // 3: ermite.Event.repo_updated:type_name -> ermite.RepoUpdated
13561647 5, // 4: ermite.Event.repo_deleted:type_name -> ermite.RepoDeleted
13571648 6, // 5: ermite.Event.pushed:type_name -> ermite.Pushed
1358- 15, // 6: ermite.Event.gap:type_name -> ermite.Gap
1649+ 19, // 6: ermite.Event.gap:type_name -> ermite.Gap
13591650 8, // 7: ermite.Event.merge_request_opened:type_name -> ermite.MergeRequestOpened
13601651 9, // 8: ermite.Event.merge_request_merged:type_name -> ermite.MergeRequestMerged
13611652 10, // 9: ermite.Event.merge_request_closed:type_name -> ermite.MergeRequestClosed
13621653 11, // 10: ermite.Event.comment_added:type_name -> ermite.CommentAdded
1363- 16, // 11: ermite.Event.run_updated:type_name -> ermite.RunUpdated
1364- 17, // 12: ermite.Event.job_updated:type_name -> ermite.JobUpdated
1654+ 20, // 11: ermite.Event.run_updated:type_name -> ermite.RunUpdated
1655+ 21, // 12: ermite.Event.job_updated:type_name -> ermite.JobUpdated
13651656 12, // 13: ermite.Event.comment_edited:type_name -> ermite.CommentEdited
13661657 13, // 14: ermite.Event.comment_deleted:type_name -> ermite.CommentDeleted
13671658 14, // 15: ermite.Event.comment_resolved:type_name -> ermite.CommentResolved
1368- 19, // 16: ermite.RepoCreated.repo:type_name -> ermite.Repo
1369- 19, // 17: ermite.RepoUpdated.repo:type_name -> ermite.Repo
1370- 7, // 18: ermite.Pushed.ref_updates:type_name -> ermite.RefUpdate
1371- 20, // 19: ermite.MergeRequestOpened.merge_request:type_name -> ermite.MergeRequest
1372- 20, // 20: ermite.MergeRequestMerged.merge_request:type_name -> ermite.MergeRequest
1373- 20, // 21: ermite.MergeRequestClosed.merge_request:type_name -> ermite.MergeRequest
1374- 21, // 22: ermite.CommentAdded.comment:type_name -> ermite.Comment
1375- 21, // 23: ermite.CommentEdited.comment:type_name -> ermite.Comment
1376- 21, // 24: ermite.CommentDeleted.comment:type_name -> ermite.Comment
1377- 21, // 25: ermite.CommentResolved.comment:type_name -> ermite.Comment
1378- 22, // 26: ermite.RunUpdated.run:type_name -> ermite.Run
1379- 23, // 27: ermite.JobUpdated.job:type_name -> ermite.RunJob
1380- 0, // 28: ermite.EventService.Watch:input_type -> ermite.WatchRequest
1381- 1, // 29: ermite.EventService.Watch:output_type -> ermite.WatchResponse
1382- 29, // [29:30] is the sub-list for method output_type
1383- 28, // [28:29] is the sub-list for method input_type
1384- 28, // [28:28] is the sub-list for extension type_name
1385- 28, // [28:28] is the sub-list for extension extendee
1386- 0, // [0:28] is the sub-list for field type_name
1659+ 15, // 16: ermite.Event.issue_opened:type_name -> ermite.IssueOpened
1660+ 16, // 17: ermite.Event.issue_closed:type_name -> ermite.IssueClosed
1661+ 17, // 18: ermite.Event.issue_reopened:type_name -> ermite.IssueReopened
1662+ 18, // 19: ermite.Event.issue_commented:type_name -> ermite.IssueCommented
1663+ 23, // 20: ermite.RepoCreated.repo:type_name -> ermite.Repo
1664+ 23, // 21: ermite.RepoUpdated.repo:type_name -> ermite.Repo
1665+ 7, // 22: ermite.Pushed.ref_updates:type_name -> ermite.RefUpdate
1666+ 24, // 23: ermite.MergeRequestOpened.merge_request:type_name -> ermite.MergeRequest
1667+ 24, // 24: ermite.MergeRequestMerged.merge_request:type_name -> ermite.MergeRequest
1668+ 24, // 25: ermite.MergeRequestClosed.merge_request:type_name -> ermite.MergeRequest
1669+ 25, // 26: ermite.CommentAdded.comment:type_name -> ermite.Comment
1670+ 25, // 27: ermite.CommentEdited.comment:type_name -> ermite.Comment
1671+ 25, // 28: ermite.CommentDeleted.comment:type_name -> ermite.Comment
1672+ 25, // 29: ermite.CommentResolved.comment:type_name -> ermite.Comment
1673+ 26, // 30: ermite.IssueOpened.issue:type_name -> ermite.Issue
1674+ 26, // 31: ermite.IssueClosed.issue:type_name -> ermite.Issue
1675+ 26, // 32: ermite.IssueReopened.issue:type_name -> ermite.Issue
1676+ 27, // 33: ermite.IssueCommented.comment:type_name -> ermite.IssueComment
1677+ 28, // 34: ermite.RunUpdated.run:type_name -> ermite.Run
1678+ 29, // 35: ermite.JobUpdated.job:type_name -> ermite.RunJob
1679+ 0, // 36: ermite.EventService.Watch:input_type -> ermite.WatchRequest
1680+ 1, // 37: ermite.EventService.Watch:output_type -> ermite.WatchResponse
1681+ 37, // [37:38] is the sub-list for method output_type
1682+ 36, // [36:37] is the sub-list for method input_type
1683+ 36, // [36:36] is the sub-list for extension type_name
1684+ 36, // [36:36] is the sub-list for extension extendee
1685+ 0, // [0:36] is the sub-list for field type_name
13871686 }
13881687
13891688 func init() { file_ermite_event_proto_init() }
@@ -1391,6 +1690,7 @@ func file_ermite_event_proto_init() {
13911690 if File_ermite_event_proto != nil {
13921691 return
13931692 }
1693+ file_ermite_issue_proto_init()
13941694 file_ermite_merge_request_proto_init()
13951695 file_ermite_repo_proto_init()
13961696 file_ermite_run_proto_init()
@@ -1409,6 +1709,10 @@ func file_ermite_event_proto_init() {
14091709 (*Event_CommentEdited)(nil),
14101710 (*Event_CommentDeleted)(nil),
14111711 (*Event_CommentResolved)(nil),
1712+ (*Event_IssueOpened)(nil),
1713+ (*Event_IssueClosed)(nil),
1714+ (*Event_IssueReopened)(nil),
1715+ (*Event_IssueCommented)(nil),
14121716 }
14131717 type x struct{}
14141718 out := protoimpl.TypeBuilder{
@@ -1416,7 +1720,7 @@ func file_ermite_event_proto_init() {
14161720 GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
14171721 RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_event_proto_rawDesc), len(file_ermite_event_proto_rawDesc)),
14181722 NumEnums: 0,
1419- NumMessages: 18,
1723+ NumMessages: 22,
14201724 NumExtensions: 0,
14211725 NumServices: 1,
14221726 },
@@ -157,6 +157,10 @@ type Event struct {
157 // *Event_CommentEdited157 // *Event_CommentEdited
158 // *Event_CommentDeleted158 // *Event_CommentDeleted
159 // *Event_CommentResolved159 // *Event_CommentResolved
160+ // *Event_IssueOpened
161+ // *Event_IssueClosed
162+ // *Event_IssueReopened
163+ // *Event_IssueCommented
160 Kind isEvent_Kind `protobuf_oneof:"kind"`164 Kind isEvent_Kind `protobuf_oneof:"kind"`
161 unknownFields protoimpl.UnknownFields165 unknownFields protoimpl.UnknownFields
162 sizeCache protoimpl.SizeCache166 sizeCache protoimpl.SizeCache
@@ -339,6 +343,42 @@ func (x *Event) GetCommentResolved() *CommentResolved {
339 return nil343 return nil
340 }344 }
341 345
346+func (x *Event) GetIssueOpened() *IssueOpened {
347+ if x != nil {
348+ if x, ok := x.Kind.(*Event_IssueOpened); ok {
349+ return x.IssueOpened
350+ }
351+ }
352+ return nil
353+}
354+
355+func (x *Event) GetIssueClosed() *IssueClosed {
356+ if x != nil {
357+ if x, ok := x.Kind.(*Event_IssueClosed); ok {
358+ return x.IssueClosed
359+ }
360+ }
361+ return nil
362+}
363+
364+func (x *Event) GetIssueReopened() *IssueReopened {
365+ if x != nil {
366+ if x, ok := x.Kind.(*Event_IssueReopened); ok {
367+ return x.IssueReopened
368+ }
369+ }
370+ return nil
371+}
372+
373+func (x *Event) GetIssueCommented() *IssueCommented {
374+ if x != nil {
375+ if x, ok := x.Kind.(*Event_IssueCommented); ok {
376+ return x.IssueCommented
377+ }
378+ }
379+ return nil
380+}
381+
342 type isEvent_Kind interface {382 type isEvent_Kind interface {
343 isEvent_Kind()383 isEvent_Kind()
344 }384 }
@@ -413,6 +453,26 @@ type Event_CommentResolved struct {
413 CommentResolved *CommentResolved `protobuf:"bytes,16,opt,name=comment_resolved,json=commentResolved,proto3,oneof"`453 CommentResolved *CommentResolved `protobuf:"bytes,16,opt,name=comment_resolved,json=commentResolved,proto3,oneof"`
414 }454 }
415 455
456+type Event_IssueOpened struct {
457+ // IssueOpened: an issue was opened.
458+ IssueOpened *IssueOpened `protobuf:"bytes,17,opt,name=issue_opened,json=issueOpened,proto3,oneof"`
459+}
460+
461+type Event_IssueClosed struct {
462+ // IssueClosed: an issue was closed.
463+ IssueClosed *IssueClosed `protobuf:"bytes,18,opt,name=issue_closed,json=issueClosed,proto3,oneof"`
464+}
465+
466+type Event_IssueReopened struct {
467+ // IssueReopened: an issue was reopened.
468+ IssueReopened *IssueReopened `protobuf:"bytes,19,opt,name=issue_reopened,json=issueReopened,proto3,oneof"`
469+}
470+
471+type Event_IssueCommented struct {
472+ // IssueCommented: a comment was added to an issue.
473+ IssueCommented *IssueCommented `protobuf:"bytes,20,opt,name=issue_commented,json=issueCommented,proto3,oneof"`
474+}
475+
416 func (*Event_RepoCreated) isEvent_Kind() {}476 func (*Event_RepoCreated) isEvent_Kind() {}
417 477
418 func (*Event_RepoUpdated) isEvent_Kind() {}478 func (*Event_RepoUpdated) isEvent_Kind() {}
@@ -441,6 +501,14 @@ func (*Event_CommentDeleted) isEvent_Kind() {}
441 501
442 func (*Event_CommentResolved) isEvent_Kind() {}502 func (*Event_CommentResolved) isEvent_Kind() {}
443 503
504+func (*Event_IssueOpened) isEvent_Kind() {}
505+
506+func (*Event_IssueClosed) isEvent_Kind() {}
507+
508+func (*Event_IssueReopened) isEvent_Kind() {}
509+
510+func (*Event_IssueCommented) isEvent_Kind() {}
511+
444 // RepoCreated reports a new repository.512 // RepoCreated reports a new repository.
445 type RepoCreated struct {513 type RepoCreated struct {
446 state protoimpl.MessageState `protogen:"open.v1"`514 state protoimpl.MessageState `protogen:"open.v1"`
@@ -1095,10 +1163,213 @@ func (x *CommentResolved) GetComment() *Comment {
1095 return nil1163 return nil
1096 }1164 }
1097 1165
1166+// IssueOpened reports a new issue.
1167+type IssueOpened struct {
1168+ state protoimpl.MessageState `protogen:"open.v1"`
1169+ // Issue is the new issue, including its repository and number.
1170+ Issue *Issue `protobuf:"bytes,1,opt,name=issue,proto3" json:"issue,omitempty"`
1171+ unknownFields protoimpl.UnknownFields
1172+ sizeCache protoimpl.SizeCache
1173+}
1174+
1175+func (x *IssueOpened) Reset() {
1176+ *x = IssueOpened{}
1177+ mi := &file_ermite_event_proto_msgTypes[15]
1178+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1179+ ms.StoreMessageInfo(mi)
1180+}
1181+
1182+func (x *IssueOpened) String() string {
1183+ return protoimpl.X.MessageStringOf(x)
1184+}
1185+
1186+func (*IssueOpened) ProtoMessage() {}
1187+
1188+func (x *IssueOpened) ProtoReflect() protoreflect.Message {
1189+ mi := &file_ermite_event_proto_msgTypes[15]
1190+ if x != nil {
1191+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1192+ if ms.LoadMessageInfo() == nil {
1193+ ms.StoreMessageInfo(mi)
1194+ }
1195+ return ms
1196+ }
1197+ return mi.MessageOf(x)
1198+}
1199+
1200+// Deprecated: Use IssueOpened.ProtoReflect.Descriptor instead.
1201+func (*IssueOpened) Descriptor() ([]byte, []int) {
1202+ return file_ermite_event_proto_rawDescGZIP(), []int{15}
1203+}
1204+
1205+func (x *IssueOpened) GetIssue() *Issue {
1206+ if x != nil {
1207+ return x.Issue
1208+ }
1209+ return nil
1210+}
1211+
1212+// IssueClosed reports a closed issue.
1213+type IssueClosed struct {
1214+ state protoimpl.MessageState `protogen:"open.v1"`
1215+ // Issue is the issue after closing, including its repository and number.
1216+ Issue *Issue `protobuf:"bytes,1,opt,name=issue,proto3" json:"issue,omitempty"`
1217+ unknownFields protoimpl.UnknownFields
1218+ sizeCache protoimpl.SizeCache
1219+}
1220+
1221+func (x *IssueClosed) Reset() {
1222+ *x = IssueClosed{}
1223+ mi := &file_ermite_event_proto_msgTypes[16]
1224+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1225+ ms.StoreMessageInfo(mi)
1226+}
1227+
1228+func (x *IssueClosed) String() string {
1229+ return protoimpl.X.MessageStringOf(x)
1230+}
1231+
1232+func (*IssueClosed) ProtoMessage() {}
1233+
1234+func (x *IssueClosed) ProtoReflect() protoreflect.Message {
1235+ mi := &file_ermite_event_proto_msgTypes[16]
1236+ if x != nil {
1237+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1238+ if ms.LoadMessageInfo() == nil {
1239+ ms.StoreMessageInfo(mi)
1240+ }
1241+ return ms
1242+ }
1243+ return mi.MessageOf(x)
1244+}
1245+
1246+// Deprecated: Use IssueClosed.ProtoReflect.Descriptor instead.
1247+func (*IssueClosed) Descriptor() ([]byte, []int) {
1248+ return file_ermite_event_proto_rawDescGZIP(), []int{16}
1249+}
1250+
1251+func (x *IssueClosed) GetIssue() *Issue {
1252+ if x != nil {
1253+ return x.Issue
1254+ }
1255+ return nil
1256+}
1257+
1258+// IssueReopened reports a reopened issue.
1259+type IssueReopened struct {
1260+ state protoimpl.MessageState `protogen:"open.v1"`
1261+ // Issue is the issue after reopening, including its repository and number.
1262+ Issue *Issue `protobuf:"bytes,1,opt,name=issue,proto3" json:"issue,omitempty"`
1263+ unknownFields protoimpl.UnknownFields
1264+ sizeCache protoimpl.SizeCache
1265+}
1266+
1267+func (x *IssueReopened) Reset() {
1268+ *x = IssueReopened{}
1269+ mi := &file_ermite_event_proto_msgTypes[17]
1270+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1271+ ms.StoreMessageInfo(mi)
1272+}
1273+
1274+func (x *IssueReopened) String() string {
1275+ return protoimpl.X.MessageStringOf(x)
1276+}
1277+
1278+func (*IssueReopened) ProtoMessage() {}
1279+
1280+func (x *IssueReopened) ProtoReflect() protoreflect.Message {
1281+ mi := &file_ermite_event_proto_msgTypes[17]
1282+ if x != nil {
1283+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1284+ if ms.LoadMessageInfo() == nil {
1285+ ms.StoreMessageInfo(mi)
1286+ }
1287+ return ms
1288+ }
1289+ return mi.MessageOf(x)
1290+}
1291+
1292+// Deprecated: Use IssueReopened.ProtoReflect.Descriptor instead.
1293+func (*IssueReopened) Descriptor() ([]byte, []int) {
1294+ return file_ermite_event_proto_rawDescGZIP(), []int{17}
1295+}
1296+
1297+func (x *IssueReopened) GetIssue() *Issue {
1298+ if x != nil {
1299+ return x.Issue
1300+ }
1301+ return nil
1302+}
1303+
1304+// IssueCommented reports a new comment on an issue.
1305+type IssueCommented struct {
1306+ state protoimpl.MessageState `protogen:"open.v1"`
1307+ // Repo is the name of the repository.
1308+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
1309+ // Number is the number of the issue.
1310+ Number int64 `protobuf:"varint,2,opt,name=number,proto3" json:"number,omitempty"`
1311+ // Comment is the new comment.
1312+ Comment *IssueComment `protobuf:"bytes,3,opt,name=comment,proto3" json:"comment,omitempty"`
1313+ unknownFields protoimpl.UnknownFields
1314+ sizeCache protoimpl.SizeCache
1315+}
1316+
1317+func (x *IssueCommented) Reset() {
1318+ *x = IssueCommented{}
1319+ mi := &file_ermite_event_proto_msgTypes[18]
1320+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1321+ ms.StoreMessageInfo(mi)
1322+}
1323+
1324+func (x *IssueCommented) String() string {
1325+ return protoimpl.X.MessageStringOf(x)
1326+}
1327+
1328+func (*IssueCommented) ProtoMessage() {}
1329+
1330+func (x *IssueCommented) ProtoReflect() protoreflect.Message {
1331+ mi := &file_ermite_event_proto_msgTypes[18]
1332+ if x != nil {
1333+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1334+ if ms.LoadMessageInfo() == nil {
1335+ ms.StoreMessageInfo(mi)
1336+ }
1337+ return ms
1338+ }
1339+ return mi.MessageOf(x)
1340+}
1341+
1342+// Deprecated: Use IssueCommented.ProtoReflect.Descriptor instead.
1343+func (*IssueCommented) Descriptor() ([]byte, []int) {
1344+ return file_ermite_event_proto_rawDescGZIP(), []int{18}
1345+}
1346+
1347+func (x *IssueCommented) GetRepo() string {
1348+ if x != nil {
1349+ return x.Repo
1350+ }
1351+ return ""
1352+}
1353+
1354+func (x *IssueCommented) GetNumber() int64 {
1355+ if x != nil {
1356+ return x.Number
1357+ }
1358+ return 0
1359+}
1360+
1361+func (x *IssueCommented) GetComment() *IssueComment {
1362+ if x != nil {
1363+ return x.Comment
1364+ }
1365+ return nil
1366+}
1367+
1098 // Gap tells the client that events were lost: the requested resume point is1368 // Gap tells the client that events were lost: the requested resume point is
1099 // older than the server's buffer. It has no fields. The client should reload1369 // older than the server's buffer. It has no fields. The client should reload
1100 // the state it displays (repositories, refs, merge requests and their1370 // the state it displays (repositories, refs, merge requests and their
1101-// comments, CI runs and their jobs) and carry on with the next events.1371+// comments, issues and their comments, CI runs and their jobs) and carry on
1372+// with the next events.
1102 type Gap struct {1373 type Gap struct {
1103 state protoimpl.MessageState `protogen:"open.v1"`1374 state protoimpl.MessageState `protogen:"open.v1"`
1104 unknownFields protoimpl.UnknownFields1375 unknownFields protoimpl.UnknownFields
@@ -1107,7 +1378,7 @@ type Gap struct {
1107 1378
1108 func (x *Gap) Reset() {1379 func (x *Gap) Reset() {
1109 *x = Gap{}1380 *x = Gap{}
1110- mi := &file_ermite_event_proto_msgTypes[15]1381+ mi := &file_ermite_event_proto_msgTypes[19]
1111 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))1382 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1112 ms.StoreMessageInfo(mi)1383 ms.StoreMessageInfo(mi)
1113 }1384 }
@@ -1119,7 +1390,7 @@ func (x *Gap) String() string {
1119 func (*Gap) ProtoMessage() {}1390 func (*Gap) ProtoMessage() {}
1120 1391
1121 func (x *Gap) ProtoReflect() protoreflect.Message {1392 func (x *Gap) ProtoReflect() protoreflect.Message {
1122- mi := &file_ermite_event_proto_msgTypes[15]1393+ mi := &file_ermite_event_proto_msgTypes[19]
1123 if x != nil {1394 if x != nil {
1124 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))1395 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1125 if ms.LoadMessageInfo() == nil {1396 if ms.LoadMessageInfo() == nil {
@@ -1132,7 +1403,7 @@ func (x *Gap) ProtoReflect() protoreflect.Message {
1132 1403
1133 // Deprecated: Use Gap.ProtoReflect.Descriptor instead.1404 // Deprecated: Use Gap.ProtoReflect.Descriptor instead.
1134 func (*Gap) Descriptor() ([]byte, []int) {1405 func (*Gap) Descriptor() ([]byte, []int) {
1135- return file_ermite_event_proto_rawDescGZIP(), []int{15}1406+ return file_ermite_event_proto_rawDescGZIP(), []int{19}
1136 }1407 }
1137 1408
1138 // RunUpdated reports a CI run that was created or whose status, conclusion or1409 // RunUpdated reports a CI run that was created or whose status, conclusion or
@@ -1147,7 +1418,7 @@ type RunUpdated struct {
1147 1418
1148 func (x *RunUpdated) Reset() {1419 func (x *RunUpdated) Reset() {
1149 *x = RunUpdated{}1420 *x = RunUpdated{}
1150- mi := &file_ermite_event_proto_msgTypes[16]1421+ mi := &file_ermite_event_proto_msgTypes[20]
1151 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))1422 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1152 ms.StoreMessageInfo(mi)1423 ms.StoreMessageInfo(mi)
1153 }1424 }
@@ -1159,7 +1430,7 @@ func (x *RunUpdated) String() string {
1159 func (*RunUpdated) ProtoMessage() {}1430 func (*RunUpdated) ProtoMessage() {}
1160 1431
1161 func (x *RunUpdated) ProtoReflect() protoreflect.Message {1432 func (x *RunUpdated) ProtoReflect() protoreflect.Message {
1162- mi := &file_ermite_event_proto_msgTypes[16]1433+ mi := &file_ermite_event_proto_msgTypes[20]
1163 if x != nil {1434 if x != nil {
1164 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))1435 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1165 if ms.LoadMessageInfo() == nil {1436 if ms.LoadMessageInfo() == nil {
@@ -1172,7 +1443,7 @@ func (x *RunUpdated) ProtoReflect() protoreflect.Message {
1172 1443
1173 // Deprecated: Use RunUpdated.ProtoReflect.Descriptor instead.1444 // Deprecated: Use RunUpdated.ProtoReflect.Descriptor instead.
1174 func (*RunUpdated) Descriptor() ([]byte, []int) {1445 func (*RunUpdated) Descriptor() ([]byte, []int) {
1175- return file_ermite_event_proto_rawDescGZIP(), []int{16}1446+ return file_ermite_event_proto_rawDescGZIP(), []int{20}
1176 }1447 }
1177 1448
1178 func (x *RunUpdated) GetRun() *Run {1449 func (x *RunUpdated) GetRun() *Run {
@@ -1194,7 +1465,7 @@ type JobUpdated struct {
1194 1465
1195 func (x *JobUpdated) Reset() {1466 func (x *JobUpdated) Reset() {
1196 *x = JobUpdated{}1467 *x = JobUpdated{}
1197- mi := &file_ermite_event_proto_msgTypes[17]1468+ mi := &file_ermite_event_proto_msgTypes[21]
1198 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))1469 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1199 ms.StoreMessageInfo(mi)1470 ms.StoreMessageInfo(mi)
1200 }1471 }
@@ -1206,7 +1477,7 @@ func (x *JobUpdated) String() string {
1206 func (*JobUpdated) ProtoMessage() {}1477 func (*JobUpdated) ProtoMessage() {}
1207 1478
1208 func (x *JobUpdated) ProtoReflect() protoreflect.Message {1479 func (x *JobUpdated) ProtoReflect() protoreflect.Message {
1209- mi := &file_ermite_event_proto_msgTypes[17]1480+ mi := &file_ermite_event_proto_msgTypes[21]
1210 if x != nil {1481 if x != nil {
1211 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))1482 ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1212 if ms.LoadMessageInfo() == nil {1483 if ms.LoadMessageInfo() == nil {
@@ -1219,7 +1490,7 @@ func (x *JobUpdated) ProtoReflect() protoreflect.Message {
1219 1490
1220 // Deprecated: Use JobUpdated.ProtoReflect.Descriptor instead.1491 // Deprecated: Use JobUpdated.ProtoReflect.Descriptor instead.
1221 func (*JobUpdated) Descriptor() ([]byte, []int) {1492 func (*JobUpdated) Descriptor() ([]byte, []int) {
1222- return file_ermite_event_proto_rawDescGZIP(), []int{17}1493+ return file_ermite_event_proto_rawDescGZIP(), []int{21}
1223 }1494 }
1224 1495
1225 func (x *JobUpdated) GetJob() *RunJob {1496 func (x *JobUpdated) GetJob() *RunJob {
@@ -1233,12 +1504,12 @@ var File_ermite_event_proto protoreflect.FileDescriptor
1233 1504
1234 const file_ermite_event_proto_rawDesc = "" +1505 const file_ermite_event_proto_rawDesc = "" +
1235 "\n" +1506 "\n" +
1236- "\x12ermite/event.proto\x12\x06ermite\x1a\x1aermite/merge_request.proto\x1a\x11ermite/repo.proto\x1a\x10ermite/run.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"I\n" +1507+ "\x12ermite/event.proto\x12\x06ermite\x1a\x12ermite/issue.proto\x1a\x1aermite/merge_request.proto\x1a\x11ermite/repo.proto\x1a\x10ermite/run.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"I\n" +
1237 "\fWatchRequest\x12\x16\n" +1508 "\fWatchRequest\x12\x16\n" +
1238 "\x06topics\x18\x01 \x03(\tR\x06topics\x12!\n" +1509 "\x06topics\x18\x01 \x03(\tR\x06topics\x12!\n" +
1239 "\fresume_after\x18\x02 \x01(\tR\vresumeAfter\"4\n" +1510 "\fresume_after\x18\x02 \x01(\tR\vresumeAfter\"4\n" +
1240 "\rWatchResponse\x12#\n" +1511 "\rWatchResponse\x12#\n" +
1241- "\x05event\x18\x01 \x01(\v2\r.ermite.EventR\x05event\"\xac\a\n" +1512+ "\x05event\x18\x01 \x01(\v2\r.ermite.EventR\x05event\"\xa3\t\n" +
1242 "\x05Event\x12\x0e\n" +1513 "\x05Event\x12\x0e\n" +
1243 "\x02id\x18\x01 \x01(\tR\x02id\x12.\n" +1514 "\x02id\x18\x01 \x01(\tR\x02id\x12.\n" +
1244 "\x04time\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\x04time\x128\n" +1515 "\x04time\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\x04time\x128\n" +
@@ -1258,7 +1529,11 @@ const file_ermite_event_proto_rawDesc = "" +
1258 "jobUpdated\x12>\n" +1529 "jobUpdated\x12>\n" +
1259 "\x0ecomment_edited\x18\x0e \x01(\v2\x15.ermite.CommentEditedH\x00R\rcommentEdited\x12A\n" +1530 "\x0ecomment_edited\x18\x0e \x01(\v2\x15.ermite.CommentEditedH\x00R\rcommentEdited\x12A\n" +
1260 "\x0fcomment_deleted\x18\x0f \x01(\v2\x16.ermite.CommentDeletedH\x00R\x0ecommentDeleted\x12D\n" +1531 "\x0fcomment_deleted\x18\x0f \x01(\v2\x16.ermite.CommentDeletedH\x00R\x0ecommentDeleted\x12D\n" +
1261- "\x10comment_resolved\x18\x10 \x01(\v2\x17.ermite.CommentResolvedH\x00R\x0fcommentResolvedB\x06\n" +1532+ "\x10comment_resolved\x18\x10 \x01(\v2\x17.ermite.CommentResolvedH\x00R\x0fcommentResolved\x128\n" +
1533+ "\fissue_opened\x18\x11 \x01(\v2\x13.ermite.IssueOpenedH\x00R\vissueOpened\x128\n" +
1534+ "\fissue_closed\x18\x12 \x01(\v2\x13.ermite.IssueClosedH\x00R\vissueClosed\x12>\n" +
1535+ "\x0eissue_reopened\x18\x13 \x01(\v2\x15.ermite.IssueReopenedH\x00R\rissueReopened\x12A\n" +
1536+ "\x0fissue_commented\x18\x14 \x01(\v2\x16.ermite.IssueCommentedH\x00R\x0eissueCommentedB\x06\n" +
1262 "\x04kind\"/\n" +1537 "\x04kind\"/\n" +
1263 "\vRepoCreated\x12 \n" +1538 "\vRepoCreated\x12 \n" +
1264 "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"/\n" +1539 "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"/\n" +
@@ -1295,7 +1570,17 @@ const file_ermite_event_proto_rawDesc = "" +
1295 "\x0fCommentResolved\x12\x12\n" +1570 "\x0fCommentResolved\x12\x12\n" +
1296 "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x16\n" +1571 "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x16\n" +
1297 "\x06number\x18\x02 \x01(\x03R\x06number\x12)\n" +1572 "\x06number\x18\x02 \x01(\x03R\x06number\x12)\n" +
1298- "\acomment\x18\x03 \x01(\v2\x0f.ermite.CommentR\acomment\"\x05\n" +1573+ "\acomment\x18\x03 \x01(\v2\x0f.ermite.CommentR\acomment\"2\n" +
1574+ "\vIssueOpened\x12#\n" +
1575+ "\x05issue\x18\x01 \x01(\v2\r.ermite.IssueR\x05issue\"2\n" +
1576+ "\vIssueClosed\x12#\n" +
1577+ "\x05issue\x18\x01 \x01(\v2\r.ermite.IssueR\x05issue\"4\n" +
1578+ "\rIssueReopened\x12#\n" +
1579+ "\x05issue\x18\x01 \x01(\v2\r.ermite.IssueR\x05issue\"l\n" +
1580+ "\x0eIssueCommented\x12\x12\n" +
1581+ "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x16\n" +
1582+ "\x06number\x18\x02 \x01(\x03R\x06number\x12.\n" +
1583+ "\acomment\x18\x03 \x01(\v2\x14.ermite.IssueCommentR\acomment\"\x05\n" +
1299 "\x03Gap\"+\n" +1584 "\x03Gap\"+\n" +
1300 "\n" +1585 "\n" +
1301 "RunUpdated\x12\x1d\n" +1586 "RunUpdated\x12\x1d\n" +
@@ -1321,7 +1606,7 @@ func file_ermite_event_proto_rawDescGZIP() []byte {
1321 return file_ermite_event_proto_rawDescData1606 return file_ermite_event_proto_rawDescData
1322 }1607 }
1323 1608
1324-var file_ermite_event_proto_msgTypes = make([]protoimpl.MessageInfo, 18)1609+var file_ermite_event_proto_msgTypes = make([]protoimpl.MessageInfo, 22)
1325 var file_ermite_event_proto_goTypes = []any{1610 var file_ermite_event_proto_goTypes = []any{
1326 (*WatchRequest)(nil), // 0: ermite.WatchRequest1611 (*WatchRequest)(nil), // 0: ermite.WatchRequest
1327 (*WatchResponse)(nil), // 1: ermite.WatchResponse1612 (*WatchResponse)(nil), // 1: ermite.WatchResponse
@@ -1338,52 +1623,66 @@ var file_ermite_event_proto_goTypes = []any{
1338 (*CommentEdited)(nil), // 12: ermite.CommentEdited1623 (*CommentEdited)(nil), // 12: ermite.CommentEdited
1339 (*CommentDeleted)(nil), // 13: ermite.CommentDeleted1624 (*CommentDeleted)(nil), // 13: ermite.CommentDeleted
1340 (*CommentResolved)(nil), // 14: ermite.CommentResolved1625 (*CommentResolved)(nil), // 14: ermite.CommentResolved
1341- (*Gap)(nil), // 15: ermite.Gap1626+ (*IssueOpened)(nil), // 15: ermite.IssueOpened
1342- (*RunUpdated)(nil), // 16: ermite.RunUpdated1627+ (*IssueClosed)(nil), // 16: ermite.IssueClosed
1343- (*JobUpdated)(nil), // 17: ermite.JobUpdated1628+ (*IssueReopened)(nil), // 17: ermite.IssueReopened
1344- (*timestamppb.Timestamp)(nil), // 18: google.protobuf.Timestamp1629+ (*IssueCommented)(nil), // 18: ermite.IssueCommented
1345- (*Repo)(nil), // 19: ermite.Repo1630+ (*Gap)(nil), // 19: ermite.Gap
1346- (*MergeRequest)(nil), // 20: ermite.MergeRequest1631+ (*RunUpdated)(nil), // 20: ermite.RunUpdated
1347- (*Comment)(nil), // 21: ermite.Comment1632+ (*JobUpdated)(nil), // 21: ermite.JobUpdated
1348- (*Run)(nil), // 22: ermite.Run1633+ (*timestamppb.Timestamp)(nil), // 22: google.protobuf.Timestamp
1349- (*RunJob)(nil), // 23: ermite.RunJob1634+ (*Repo)(nil), // 23: ermite.Repo
1635+ (*MergeRequest)(nil), // 24: ermite.MergeRequest
1636+ (*Comment)(nil), // 25: ermite.Comment
1637+ (*Issue)(nil), // 26: ermite.Issue
1638+ (*IssueComment)(nil), // 27: ermite.IssueComment
1639+ (*Run)(nil), // 28: ermite.Run
1640+ (*RunJob)(nil), // 29: ermite.RunJob
1350 }1641 }
1351 var file_ermite_event_proto_depIdxs = []int32{1642 var file_ermite_event_proto_depIdxs = []int32{
1352 2, // 0: ermite.WatchResponse.event:type_name -> ermite.Event1643 2, // 0: ermite.WatchResponse.event:type_name -> ermite.Event
1353- 18, // 1: ermite.Event.time:type_name -> google.protobuf.Timestamp1644+ 22, // 1: ermite.Event.time:type_name -> google.protobuf.Timestamp
1354 3, // 2: ermite.Event.repo_created:type_name -> ermite.RepoCreated1645 3, // 2: ermite.Event.repo_created:type_name -> ermite.RepoCreated
1355 4, // 3: ermite.Event.repo_updated:type_name -> ermite.RepoUpdated1646 4, // 3: ermite.Event.repo_updated:type_name -> ermite.RepoUpdated
1356 5, // 4: ermite.Event.repo_deleted:type_name -> ermite.RepoDeleted1647 5, // 4: ermite.Event.repo_deleted:type_name -> ermite.RepoDeleted
1357 6, // 5: ermite.Event.pushed:type_name -> ermite.Pushed1648 6, // 5: ermite.Event.pushed:type_name -> ermite.Pushed
1358- 15, // 6: ermite.Event.gap:type_name -> ermite.Gap1649+ 19, // 6: ermite.Event.gap:type_name -> ermite.Gap
1359 8, // 7: ermite.Event.merge_request_opened:type_name -> ermite.MergeRequestOpened1650 8, // 7: ermite.Event.merge_request_opened:type_name -> ermite.MergeRequestOpened
1360 9, // 8: ermite.Event.merge_request_merged:type_name -> ermite.MergeRequestMerged1651 9, // 8: ermite.Event.merge_request_merged:type_name -> ermite.MergeRequestMerged
1361 10, // 9: ermite.Event.merge_request_closed:type_name -> ermite.MergeRequestClosed1652 10, // 9: ermite.Event.merge_request_closed:type_name -> ermite.MergeRequestClosed
1362 11, // 10: ermite.Event.comment_added:type_name -> ermite.CommentAdded1653 11, // 10: ermite.Event.comment_added:type_name -> ermite.CommentAdded
1363- 16, // 11: ermite.Event.run_updated:type_name -> ermite.RunUpdated1654+ 20, // 11: ermite.Event.run_updated:type_name -> ermite.RunUpdated
1364- 17, // 12: ermite.Event.job_updated:type_name -> ermite.JobUpdated1655+ 21, // 12: ermite.Event.job_updated:type_name -> ermite.JobUpdated
1365 12, // 13: ermite.Event.comment_edited:type_name -> ermite.CommentEdited1656 12, // 13: ermite.Event.comment_edited:type_name -> ermite.CommentEdited
1366 13, // 14: ermite.Event.comment_deleted:type_name -> ermite.CommentDeleted1657 13, // 14: ermite.Event.comment_deleted:type_name -> ermite.CommentDeleted
1367 14, // 15: ermite.Event.comment_resolved:type_name -> ermite.CommentResolved1658 14, // 15: ermite.Event.comment_resolved:type_name -> ermite.CommentResolved
1368- 19, // 16: ermite.RepoCreated.repo:type_name -> ermite.Repo1659+ 15, // 16: ermite.Event.issue_opened:type_name -> ermite.IssueOpened
1369- 19, // 17: ermite.RepoUpdated.repo:type_name -> ermite.Repo1660+ 16, // 17: ermite.Event.issue_closed:type_name -> ermite.IssueClosed
1370- 7, // 18: ermite.Pushed.ref_updates:type_name -> ermite.RefUpdate1661+ 17, // 18: ermite.Event.issue_reopened:type_name -> ermite.IssueReopened
1371- 20, // 19: ermite.MergeRequestOpened.merge_request:type_name -> ermite.MergeRequest1662+ 18, // 19: ermite.Event.issue_commented:type_name -> ermite.IssueCommented
1372- 20, // 20: ermite.MergeRequestMerged.merge_request:type_name -> ermite.MergeRequest1663+ 23, // 20: ermite.RepoCreated.repo:type_name -> ermite.Repo
1373- 20, // 21: ermite.MergeRequestClosed.merge_request:type_name -> ermite.MergeRequest1664+ 23, // 21: ermite.RepoUpdated.repo:type_name -> ermite.Repo
1374- 21, // 22: ermite.CommentAdded.comment:type_name -> ermite.Comment1665+ 7, // 22: ermite.Pushed.ref_updates:type_name -> ermite.RefUpdate
1375- 21, // 23: ermite.CommentEdited.comment:type_name -> ermite.Comment1666+ 24, // 23: ermite.MergeRequestOpened.merge_request:type_name -> ermite.MergeRequest
1376- 21, // 24: ermite.CommentDeleted.comment:type_name -> ermite.Comment1667+ 24, // 24: ermite.MergeRequestMerged.merge_request:type_name -> ermite.MergeRequest
1377- 21, // 25: ermite.CommentResolved.comment:type_name -> ermite.Comment1668+ 24, // 25: ermite.MergeRequestClosed.merge_request:type_name -> ermite.MergeRequest
1378- 22, // 26: ermite.RunUpdated.run:type_name -> ermite.Run1669+ 25, // 26: ermite.CommentAdded.comment:type_name -> ermite.Comment
1379- 23, // 27: ermite.JobUpdated.job:type_name -> ermite.RunJob1670+ 25, // 27: ermite.CommentEdited.comment:type_name -> ermite.Comment
1380- 0, // 28: ermite.EventService.Watch:input_type -> ermite.WatchRequest1671+ 25, // 28: ermite.CommentDeleted.comment:type_name -> ermite.Comment
1381- 1, // 29: ermite.EventService.Watch:output_type -> ermite.WatchResponse1672+ 25, // 29: ermite.CommentResolved.comment:type_name -> ermite.Comment
1382- 29, // [29:30] is the sub-list for method output_type1673+ 26, // 30: ermite.IssueOpened.issue:type_name -> ermite.Issue
1383- 28, // [28:29] is the sub-list for method input_type1674+ 26, // 31: ermite.IssueClosed.issue:type_name -> ermite.Issue
1384- 28, // [28:28] is the sub-list for extension type_name1675+ 26, // 32: ermite.IssueReopened.issue:type_name -> ermite.Issue
1385- 28, // [28:28] is the sub-list for extension extendee1676+ 27, // 33: ermite.IssueCommented.comment:type_name -> ermite.IssueComment
1386- 0, // [0:28] is the sub-list for field type_name1677+ 28, // 34: ermite.RunUpdated.run:type_name -> ermite.Run
1678+ 29, // 35: ermite.JobUpdated.job:type_name -> ermite.RunJob
1679+ 0, // 36: ermite.EventService.Watch:input_type -> ermite.WatchRequest
1680+ 1, // 37: ermite.EventService.Watch:output_type -> ermite.WatchResponse
1681+ 37, // [37:38] is the sub-list for method output_type
1682+ 36, // [36:37] is the sub-list for method input_type
1683+ 36, // [36:36] is the sub-list for extension type_name
1684+ 36, // [36:36] is the sub-list for extension extendee
1685+ 0, // [0:36] is the sub-list for field type_name
1387 }1686 }
1388 1687
1389 func init() { file_ermite_event_proto_init() }1688 func init() { file_ermite_event_proto_init() }
@@ -1391,6 +1690,7 @@ func file_ermite_event_proto_init() {
1391 if File_ermite_event_proto != nil {1690 if File_ermite_event_proto != nil {
1392 return1691 return
1393 }1692 }
1693+ file_ermite_issue_proto_init()
1394 file_ermite_merge_request_proto_init()1694 file_ermite_merge_request_proto_init()
1395 file_ermite_repo_proto_init()1695 file_ermite_repo_proto_init()
1396 file_ermite_run_proto_init()1696 file_ermite_run_proto_init()
@@ -1409,6 +1709,10 @@ func file_ermite_event_proto_init() {
1409 (*Event_CommentEdited)(nil),1709 (*Event_CommentEdited)(nil),
1410 (*Event_CommentDeleted)(nil),1710 (*Event_CommentDeleted)(nil),
1411 (*Event_CommentResolved)(nil),1711 (*Event_CommentResolved)(nil),
1712+ (*Event_IssueOpened)(nil),
1713+ (*Event_IssueClosed)(nil),
1714+ (*Event_IssueReopened)(nil),
1715+ (*Event_IssueCommented)(nil),
1412 }1716 }
1413 type x struct{}1717 type x struct{}
1414 out := protoimpl.TypeBuilder{1718 out := protoimpl.TypeBuilder{
@@ -1416,7 +1720,7 @@ func file_ermite_event_proto_init() {
1416 GoPackagePath: reflect.TypeOf(x{}).PkgPath(),1720 GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
1417 RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_event_proto_rawDesc), len(file_ermite_event_proto_rawDesc)),1721 RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_event_proto_rawDesc), len(file_ermite_event_proto_rawDesc)),
1418 NumEnums: 0,1722 NumEnums: 0,
1419- NumMessages: 18,1723+ NumMessages: 22,
1420 NumExtensions: 0,1724 NumExtensions: 0,
1421 NumServices: 1,1725 NumServices: 1,
1422 },1726 },
A gen/ermite/issue.pb.go +1108 -0 generated file: collapsed
M gen/ermite/repo.pb.go +146 -57 generated file: collapsed
M gen/ermite/token.pb.go +8 -2 generated file: collapsed
A issue_test.go +85 -0
@@ -0,0 +1,85 @@
1+// SPDX-License-Identifier: MIT
2+
3+package api_test
4+
5+import (
6+ "testing"
7+
8+ "bnema.dev/ermite-api/gen/ermite"
9+ "bnema.dev/ermite-api/gen/ermite/ermiteconnect"
10+ "google.golang.org/protobuf/proto"
11+ "google.golang.org/protobuf/reflect/protoreflect"
12+)
13+
14+func TestIssueProcedures(t *testing.T) {
15+ tests := map[string]string{
16+ ermiteconnect.IssueServiceCreateIssueProcedure: "CreateIssue",
17+ ermiteconnect.IssueServiceListIssuesProcedure: "ListIssues",
18+ ermiteconnect.IssueServiceGetIssueProcedure: "GetIssue",
19+ ermiteconnect.IssueServiceAddIssueCommentProcedure: "AddIssueComment",
20+ ermiteconnect.IssueServiceCloseIssueProcedure: "CloseIssue",
21+ ermiteconnect.IssueServiceReopenIssueProcedure: "ReopenIssue",
22+ }
23+ for got, name := range tests {
24+ if want := "/ermite.IssueService/" + name; got != want {
25+ t.Errorf("procedure = %q, want %q", got, want)
26+ }
27+ }
28+}
29+
30+func TestIssueContract(t *testing.T) {
31+ for _, tt := range []struct {
32+ msg proto.Message
33+ fields map[string]int
34+ }{
35+ {&ermite.Issue{}, map[string]int{"repo": 1, "number": 2, "title": 3, "body": 4, "state": 5, "author": 6, "created_at": 7, "updated_at": 8, "comment_count": 9}},
36+ {&ermite.IssueComment{}, map[string]int{"id": 1, "author": 2, "text": 3, "created_at": 4}},
37+ {&ermite.RepoSettings{}, map[string]int{"issues": 3}},
38+ {&ermite.UpdateRepoRequest{}, map[string]int{"issues": 8}},
39+ {&ermite.Event{}, map[string]int{"issue_opened": 17, "issue_closed": 18, "issue_reopened": 19, "issue_commented": 20}},
40+ } {
41+ md := tt.msg.ProtoReflect().Descriptor()
42+ for name, num := range tt.fields {
43+ if fd := md.Fields().ByName(protoreflect.Name(name)); fd == nil || int(fd.Number()) != num {
44+ t.Errorf("%s.%s = %v, want %d", md.Name(), name, fd, num)
45+ }
46+ }
47+ }
48+ if ermite.Scope_SCOPE_ISSUE_WRITE != 11 {
49+ t.Fatal("issue:write scope number changed")
50+ }
51+ for name, want := range map[string]int32{"ISSUE_STATE_UNSPECIFIED": 0, "ISSUE_STATE_OPEN": 1, "ISSUE_STATE_CLOSED": 2, "ISSUE_STATE_PENDING": 3} {
52+ if got := ermite.IssueState_value[name]; got != want {
53+ t.Errorf("%s = %d, want %d", name, got, want)
54+ }
55+ }
56+ for name, want := range map[string]int32{"ISSUES_MODE_UNSPECIFIED": 0, "ISSUES_MODE_OFF": 1, "ISSUES_MODE_OWNER": 2, "ISSUES_MODE_PUBLIC": 3} {
57+ if got := ermite.IssuesMode_value[name]; got != want {
58+ t.Errorf("%s = %d, want %d", name, got, want)
59+ }
60+ }
61+ mode := ermite.IssuesMode_ISSUES_MODE_OFF
62+ for _, in := range []proto.Message{
63+ &ermite.UpdateRepoRequest{Repo: "r", Issues: &mode},
64+ &ermite.Event{Kind: &ermite.Event_IssueOpened{IssueOpened: &ermite.IssueOpened{Issue: &ermite.Issue{Repo: "r", Number: 1}}}},
65+ &ermite.Event{Kind: &ermite.Event_IssueClosed{IssueClosed: &ermite.IssueClosed{Issue: &ermite.Issue{Repo: "r", Number: 1}}}},
66+ &ermite.Event{Kind: &ermite.Event_IssueReopened{IssueReopened: &ermite.IssueReopened{Issue: &ermite.Issue{Repo: "r", Number: 1}}}},
67+ &ermite.Event{Kind: &ermite.Event_IssueCommented{IssueCommented: &ermite.IssueCommented{Repo: "r", Number: 1, Comment: &ermite.IssueComment{Id: "c", Text: "hi"}}}},
68+ } {
69+ b, err := proto.Marshal(in)
70+ if err != nil {
71+ t.Fatal(err)
72+ }
73+ out := in.ProtoReflect().New().Interface()
74+ if err := proto.Unmarshal(b, out); err != nil {
75+ t.Fatal(err)
76+ }
77+ if !proto.Equal(in, out) {
78+ t.Errorf("%T: round trip mismatch", in)
79+ }
80+ }
81+ fd := (&ermite.UpdateRepoRequest{}).ProtoReflect().Descriptor().Fields().ByName("issues")
82+ if !fd.HasOptionalKeyword() {
83+ t.Fatal("UpdateRepoRequest.issues must be optional")
84+ }
85+}
@@ -0,0 +1,85 @@
1+// SPDX-License-Identifier: MIT
2+
3+package api_test
4+
5+import (
6+ "testing"
7+
8+ "bnema.dev/ermite-api/gen/ermite"
9+ "bnema.dev/ermite-api/gen/ermite/ermiteconnect"
10+ "google.golang.org/protobuf/proto"
11+ "google.golang.org/protobuf/reflect/protoreflect"
12+)
13+
14+func TestIssueProcedures(t *testing.T) {
15+ tests := map[string]string{
16+ ermiteconnect.IssueServiceCreateIssueProcedure: "CreateIssue",
17+ ermiteconnect.IssueServiceListIssuesProcedure: "ListIssues",
18+ ermiteconnect.IssueServiceGetIssueProcedure: "GetIssue",
19+ ermiteconnect.IssueServiceAddIssueCommentProcedure: "AddIssueComment",
20+ ermiteconnect.IssueServiceCloseIssueProcedure: "CloseIssue",
21+ ermiteconnect.IssueServiceReopenIssueProcedure: "ReopenIssue",
22+ }
23+ for got, name := range tests {
24+ if want := "/ermite.IssueService/" + name; got != want {
25+ t.Errorf("procedure = %q, want %q", got, want)
26+ }
27+ }
28+}
29+
30+func TestIssueContract(t *testing.T) {
31+ for _, tt := range []struct {
32+ msg proto.Message
33+ fields map[string]int
34+ }{
35+ {&ermite.Issue{}, map[string]int{"repo": 1, "number": 2, "title": 3, "body": 4, "state": 5, "author": 6, "created_at": 7, "updated_at": 8, "comment_count": 9}},
36+ {&ermite.IssueComment{}, map[string]int{"id": 1, "author": 2, "text": 3, "created_at": 4}},
37+ {&ermite.RepoSettings{}, map[string]int{"issues": 3}},
38+ {&ermite.UpdateRepoRequest{}, map[string]int{"issues": 8}},
39+ {&ermite.Event{}, map[string]int{"issue_opened": 17, "issue_closed": 18, "issue_reopened": 19, "issue_commented": 20}},
40+ } {
41+ md := tt.msg.ProtoReflect().Descriptor()
42+ for name, num := range tt.fields {
43+ if fd := md.Fields().ByName(protoreflect.Name(name)); fd == nil || int(fd.Number()) != num {
44+ t.Errorf("%s.%s = %v, want %d", md.Name(), name, fd, num)
45+ }
46+ }
47+ }
48+ if ermite.Scope_SCOPE_ISSUE_WRITE != 11 {
49+ t.Fatal("issue:write scope number changed")
50+ }
51+ for name, want := range map[string]int32{"ISSUE_STATE_UNSPECIFIED": 0, "ISSUE_STATE_OPEN": 1, "ISSUE_STATE_CLOSED": 2, "ISSUE_STATE_PENDING": 3} {
52+ if got := ermite.IssueState_value[name]; got != want {
53+ t.Errorf("%s = %d, want %d", name, got, want)
54+ }
55+ }
56+ for name, want := range map[string]int32{"ISSUES_MODE_UNSPECIFIED": 0, "ISSUES_MODE_OFF": 1, "ISSUES_MODE_OWNER": 2, "ISSUES_MODE_PUBLIC": 3} {
57+ if got := ermite.IssuesMode_value[name]; got != want {
58+ t.Errorf("%s = %d, want %d", name, got, want)
59+ }
60+ }
61+ mode := ermite.IssuesMode_ISSUES_MODE_OFF
62+ for _, in := range []proto.Message{
63+ &ermite.UpdateRepoRequest{Repo: "r", Issues: &mode},
64+ &ermite.Event{Kind: &ermite.Event_IssueOpened{IssueOpened: &ermite.IssueOpened{Issue: &ermite.Issue{Repo: "r", Number: 1}}}},
65+ &ermite.Event{Kind: &ermite.Event_IssueClosed{IssueClosed: &ermite.IssueClosed{Issue: &ermite.Issue{Repo: "r", Number: 1}}}},
66+ &ermite.Event{Kind: &ermite.Event_IssueReopened{IssueReopened: &ermite.IssueReopened{Issue: &ermite.Issue{Repo: "r", Number: 1}}}},
67+ &ermite.Event{Kind: &ermite.Event_IssueCommented{IssueCommented: &ermite.IssueCommented{Repo: "r", Number: 1, Comment: &ermite.IssueComment{Id: "c", Text: "hi"}}}},
68+ } {
69+ b, err := proto.Marshal(in)
70+ if err != nil {
71+ t.Fatal(err)
72+ }
73+ out := in.ProtoReflect().New().Interface()
74+ if err := proto.Unmarshal(b, out); err != nil {
75+ t.Fatal(err)
76+ }
77+ if !proto.Equal(in, out) {
78+ t.Errorf("%T: round trip mismatch", in)
79+ }
80+ }
81+ fd := (&ermite.UpdateRepoRequest{}).ProtoReflect().Descriptor().Fields().ByName("issues")
82+ if !fd.HasOptionalKeyword() {
83+ t.Fatal("UpdateRepoRequest.issues must be optional")
84+ }
85+}
M proto/ermite/event.proto +41 -2
@@ -4,6 +4,7 @@ syntax = "proto3";
44
55 package ermite;
66
7+import "ermite/issue.proto";
78 import "ermite/merge_request.proto";
89 import "ermite/repo.proto";
910 import "ermite/run.proto";
@@ -18,7 +19,8 @@ service EventService {
1819 // The events are repo_created, repo_updated, repo_deleted, pushed, gap and,
1920 // for merge requests, merge_request_opened, merge_request_merged,
2021 // merge_request_closed, comment_added, comment_edited, comment_deleted and
21- // comment_resolved (a thread resolved or reopened). Each one is delivered on the
22+ // comment_resolved (a thread resolved or reopened); for issues, issue_opened,
23+ // issue_closed, issue_reopened and issue_commented. Each one is delivered on the
2224 // "repo:<name>" topic of its repository and on "home", subject to the
2325 // visibility of the repository.
2426 //
@@ -109,6 +111,14 @@ message Event {
109111 CommentDeleted comment_deleted = 15;
110112 // CommentResolved: a merge request comment was resolved or unresolved.
111113 CommentResolved comment_resolved = 16;
114+ // IssueOpened: an issue was opened.
115+ IssueOpened issue_opened = 17;
116+ // IssueClosed: an issue was closed.
117+ IssueClosed issue_closed = 18;
118+ // IssueReopened: an issue was reopened.
119+ IssueReopened issue_reopened = 19;
120+ // IssueCommented: a comment was added to an issue.
121+ IssueCommented issue_commented = 20;
112122 }
113123 }
114124
@@ -209,10 +219,39 @@ message CommentResolved {
209219 Comment comment = 3;
210220 }
211221
222+// IssueOpened reports a new issue.
223+message IssueOpened {
224+ // Issue is the new issue, including its repository and number.
225+ Issue issue = 1;
226+}
227+
228+// IssueClosed reports a closed issue.
229+message IssueClosed {
230+ // Issue is the issue after closing, including its repository and number.
231+ Issue issue = 1;
232+}
233+
234+// IssueReopened reports a reopened issue.
235+message IssueReopened {
236+ // Issue is the issue after reopening, including its repository and number.
237+ Issue issue = 1;
238+}
239+
240+// IssueCommented reports a new comment on an issue.
241+message IssueCommented {
242+ // Repo is the name of the repository.
243+ string repo = 1;
244+ // Number is the number of the issue.
245+ int64 number = 2;
246+ // Comment is the new comment.
247+ IssueComment comment = 3;
248+}
249+
212250 // Gap tells the client that events were lost: the requested resume point is
213251 // older than the server's buffer. It has no fields. The client should reload
214252 // the state it displays (repositories, refs, merge requests and their
215-// comments, CI runs and their jobs) and carry on with the next events.
253+// comments, issues and their comments, CI runs and their jobs) and carry on
254+// with the next events.
216255 message Gap {}
217256
218257 // RunUpdated reports a CI run that was created or whose status, conclusion or
@@ -4,6 +4,7 @@ syntax = "proto3";
4 4
5 package ermite;5 package ermite;
6 6
7+import "ermite/issue.proto";
7 import "ermite/merge_request.proto";8 import "ermite/merge_request.proto";
8 import "ermite/repo.proto";9 import "ermite/repo.proto";
9 import "ermite/run.proto";10 import "ermite/run.proto";
@@ -18,7 +19,8 @@ service EventService {
18 // The events are repo_created, repo_updated, repo_deleted, pushed, gap and,19 // The events are repo_created, repo_updated, repo_deleted, pushed, gap and,
19 // for merge requests, merge_request_opened, merge_request_merged,20 // for merge requests, merge_request_opened, merge_request_merged,
20 // merge_request_closed, comment_added, comment_edited, comment_deleted and21 // merge_request_closed, comment_added, comment_edited, comment_deleted and
21- // comment_resolved (a thread resolved or reopened). Each one is delivered on the22+ // comment_resolved (a thread resolved or reopened); for issues, issue_opened,
23+ // issue_closed, issue_reopened and issue_commented. Each one is delivered on the
22 // "repo:<name>" topic of its repository and on "home", subject to the24 // "repo:<name>" topic of its repository and on "home", subject to the
23 // visibility of the repository.25 // visibility of the repository.
24 //26 //
@@ -109,6 +111,14 @@ message Event {
109 CommentDeleted comment_deleted = 15;111 CommentDeleted comment_deleted = 15;
110 // CommentResolved: a merge request comment was resolved or unresolved.112 // CommentResolved: a merge request comment was resolved or unresolved.
111 CommentResolved comment_resolved = 16;113 CommentResolved comment_resolved = 16;
114+ // IssueOpened: an issue was opened.
115+ IssueOpened issue_opened = 17;
116+ // IssueClosed: an issue was closed.
117+ IssueClosed issue_closed = 18;
118+ // IssueReopened: an issue was reopened.
119+ IssueReopened issue_reopened = 19;
120+ // IssueCommented: a comment was added to an issue.
121+ IssueCommented issue_commented = 20;
112 }122 }
113 }123 }
114 124
@@ -209,10 +219,39 @@ message CommentResolved {
209 Comment comment = 3;219 Comment comment = 3;
210 }220 }
211 221
222+// IssueOpened reports a new issue.
223+message IssueOpened {
224+ // Issue is the new issue, including its repository and number.
225+ Issue issue = 1;
226+}
227+
228+// IssueClosed reports a closed issue.
229+message IssueClosed {
230+ // Issue is the issue after closing, including its repository and number.
231+ Issue issue = 1;
232+}
233+
234+// IssueReopened reports a reopened issue.
235+message IssueReopened {
236+ // Issue is the issue after reopening, including its repository and number.
237+ Issue issue = 1;
238+}
239+
240+// IssueCommented reports a new comment on an issue.
241+message IssueCommented {
242+ // Repo is the name of the repository.
243+ string repo = 1;
244+ // Number is the number of the issue.
245+ int64 number = 2;
246+ // Comment is the new comment.
247+ IssueComment comment = 3;
248+}
249+
212 // Gap tells the client that events were lost: the requested resume point is250 // Gap tells the client that events were lost: the requested resume point is
213 // older than the server's buffer. It has no fields. The client should reload251 // older than the server's buffer. It has no fields. The client should reload
214 // the state it displays (repositories, refs, merge requests and their252 // the state it displays (repositories, refs, merge requests and their
215-// comments, CI runs and their jobs) and carry on with the next events.253+// comments, issues and their comments, CI runs and their jobs) and carry on
254+// with the next events.
216 message Gap {}255 message Gap {}
217 256
218 // RunUpdated reports a CI run that was created or whose status, conclusion or257 // RunUpdated reports a CI run that was created or whose status, conclusion or
A proto/ermite/issue.proto +172 -0
@@ -0,0 +1,172 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "google/protobuf/timestamp.proto";
8+
9+// IssueState is where an issue is in its life.
10+enum IssueState {
11+ // Not set. In ListIssuesRequest.state it means every state. Never returned
12+ // by the server.
13+ ISSUE_STATE_UNSPECIFIED = 0;
14+ // The issue is open.
15+ ISSUE_STATE_OPEN = 1;
16+ // The issue is closed.
17+ ISSUE_STATE_CLOSED = 2;
18+ // Reserved for later use: awaiting moderation, owner-only.
19+ ISSUE_STATE_PENDING = 3;
20+}
21+
22+// Issue is a discussion in a repository.
23+message Issue {
24+ // Repo is the name of the repository.
25+ string repo = 1;
26+ // Number identifies the issue within its repository.
27+ int64 number = 2;
28+ // Title is the one-line title.
29+ string title = 3;
30+ // Body is the content of the issue. It may be empty.
31+ string body = 4;
32+ // State is where the issue is in its life.
33+ IssueState state = 5;
34+ // Author names who created the issue: the label of the token that was used,
35+ // "root" for the root token, or "owner" for a web session. It is
36+ // informational: labels are not unique and the token may be gone.
37+ string author = 6;
38+ // CreatedAt is when the issue was created.
39+ google.protobuf.Timestamp created_at = 7;
40+ // UpdatedAt is when the issue last changed.
41+ google.protobuf.Timestamp updated_at = 8;
42+ // CommentCount is the number of comments on the issue.
43+ int32 comment_count = 9;
44+}
45+
46+// IssueComment is a note on an issue.
47+message IssueComment {
48+ // Id identifies the comment within its issue. Opaque.
49+ string id = 1;
50+ // Author names who wrote the comment, like Issue.author.
51+ string author = 2;
52+ // Text is the content of the comment.
53+ string text = 3;
54+ // CreatedAt is when the comment was written.
55+ google.protobuf.Timestamp created_at = 4;
56+}
57+
58+// IssueService manages issues and their comments.
59+service IssueService {
60+ // CreateIssue opens an issue. Needs the issue:write scope.
61+ rpc CreateIssue(CreateIssueRequest) returns (CreateIssueResponse);
62+ // ListIssues lists issues, highest number first, optionally in one state.
63+ rpc ListIssues(ListIssuesRequest) returns (ListIssuesResponse);
64+ // GetIssue returns an issue with its comments.
65+ rpc GetIssue(GetIssueRequest) returns (GetIssueResponse);
66+ // AddIssueComment adds a comment. Needs the issue:write scope.
67+ rpc AddIssueComment(AddIssueCommentRequest) returns (AddIssueCommentResponse);
68+ // CloseIssue closes an issue. Needs the issue:write scope.
69+ rpc CloseIssue(CloseIssueRequest) returns (CloseIssueResponse);
70+ // ReopenIssue reopens an issue. Needs the issue:write scope.
71+ rpc ReopenIssue(ReopenIssueRequest) returns (ReopenIssueResponse);
72+}
73+
74+// CreateIssueRequest describes the issue to open.
75+message CreateIssueRequest {
76+ // Repo is the repository name.
77+ string repo = 1;
78+ // Title is the one-line title. Required.
79+ string title = 2;
80+ // Body is the optional content.
81+ string body = 3;
82+}
83+
84+// CreateIssueResponse holds the new issue.
85+message CreateIssueResponse {
86+ // Issue is the created issue.
87+ Issue issue = 1;
88+}
89+
90+// ListIssuesRequest selects a page of issues.
91+message ListIssuesRequest {
92+ // Repo is the repository name.
93+ string repo = 1;
94+ // State restricts the result to one state. ISSUE_STATE_UNSPECIFIED means
95+ // every state.
96+ IssueState state = 2;
97+ // PageSize is the maximum number of issues to return. 0 means the server
98+ // default; values above the server maximum are lowered to it.
99+ int32 page_size = 3;
100+ // PageToken is the next_page_token of a previous response, to continue the
101+ // same listing. Empty for the first page. Other fields must be unchanged.
102+ string page_token = 4;
103+}
104+
105+// ListIssuesResponse is one page of issues.
106+message ListIssuesResponse {
107+ // Issues are the issues of this page, highest number first.
108+ repeated Issue issues = 1;
109+ // NextPageToken is passed as page_token to get the next page. Empty when
110+ // there is no next page.
111+ string next_page_token = 2;
112+}
113+
114+// GetIssueRequest selects an issue.
115+message GetIssueRequest {
116+ // Repo is the repository name.
117+ string repo = 1;
118+ // Number is the issue number.
119+ int64 number = 2;
120+}
121+
122+// GetIssueResponse holds an issue with its comments.
123+message GetIssueResponse {
124+ // Issue is the issue.
125+ Issue issue = 1;
126+ // Comments are every comment of the issue, oldest first.
127+ repeated IssueComment comments = 2;
128+}
129+
130+// AddIssueCommentRequest describes the comment to add.
131+message AddIssueCommentRequest {
132+ // Repo is the repository name.
133+ string repo = 1;
134+ // Number is the issue number.
135+ int64 number = 2;
136+ // Text is the content. Required.
137+ string text = 3;
138+}
139+
140+// AddIssueCommentResponse holds the new comment.
141+message AddIssueCommentResponse {
142+ // Comment is the created comment.
143+ IssueComment comment = 1;
144+}
145+
146+// CloseIssueRequest names the issue to close.
147+message CloseIssueRequest {
148+ // Repo is the repository name.
149+ string repo = 1;
150+ // Number is the issue number.
151+ int64 number = 2;
152+}
153+
154+// CloseIssueResponse holds the issue after closing.
155+message CloseIssueResponse {
156+ // Issue is the closed issue.
157+ Issue issue = 1;
158+}
159+
160+// ReopenIssueRequest names the issue to reopen.
161+message ReopenIssueRequest {
162+ // Repo is the repository name.
163+ string repo = 1;
164+ // Number is the issue number.
165+ int64 number = 2;
166+}
167+
168+// ReopenIssueResponse holds the issue after reopening.
169+message ReopenIssueResponse {
170+ // Issue is the reopened issue.
171+ Issue issue = 1;
172+}
@@ -0,0 +1,172 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "google/protobuf/timestamp.proto";
8+
9+// IssueState is where an issue is in its life.
10+enum IssueState {
11+ // Not set. In ListIssuesRequest.state it means every state. Never returned
12+ // by the server.
13+ ISSUE_STATE_UNSPECIFIED = 0;
14+ // The issue is open.
15+ ISSUE_STATE_OPEN = 1;
16+ // The issue is closed.
17+ ISSUE_STATE_CLOSED = 2;
18+ // Reserved for later use: awaiting moderation, owner-only.
19+ ISSUE_STATE_PENDING = 3;
20+}
21+
22+// Issue is a discussion in a repository.
23+message Issue {
24+ // Repo is the name of the repository.
25+ string repo = 1;
26+ // Number identifies the issue within its repository.
27+ int64 number = 2;
28+ // Title is the one-line title.
29+ string title = 3;
30+ // Body is the content of the issue. It may be empty.
31+ string body = 4;
32+ // State is where the issue is in its life.
33+ IssueState state = 5;
34+ // Author names who created the issue: the label of the token that was used,
35+ // "root" for the root token, or "owner" for a web session. It is
36+ // informational: labels are not unique and the token may be gone.
37+ string author = 6;
38+ // CreatedAt is when the issue was created.
39+ google.protobuf.Timestamp created_at = 7;
40+ // UpdatedAt is when the issue last changed.
41+ google.protobuf.Timestamp updated_at = 8;
42+ // CommentCount is the number of comments on the issue.
43+ int32 comment_count = 9;
44+}
45+
46+// IssueComment is a note on an issue.
47+message IssueComment {
48+ // Id identifies the comment within its issue. Opaque.
49+ string id = 1;
50+ // Author names who wrote the comment, like Issue.author.
51+ string author = 2;
52+ // Text is the content of the comment.
53+ string text = 3;
54+ // CreatedAt is when the comment was written.
55+ google.protobuf.Timestamp created_at = 4;
56+}
57+
58+// IssueService manages issues and their comments.
59+service IssueService {
60+ // CreateIssue opens an issue. Needs the issue:write scope.
61+ rpc CreateIssue(CreateIssueRequest) returns (CreateIssueResponse);
62+ // ListIssues lists issues, highest number first, optionally in one state.
63+ rpc ListIssues(ListIssuesRequest) returns (ListIssuesResponse);
64+ // GetIssue returns an issue with its comments.
65+ rpc GetIssue(GetIssueRequest) returns (GetIssueResponse);
66+ // AddIssueComment adds a comment. Needs the issue:write scope.
67+ rpc AddIssueComment(AddIssueCommentRequest) returns (AddIssueCommentResponse);
68+ // CloseIssue closes an issue. Needs the issue:write scope.
69+ rpc CloseIssue(CloseIssueRequest) returns (CloseIssueResponse);
70+ // ReopenIssue reopens an issue. Needs the issue:write scope.
71+ rpc ReopenIssue(ReopenIssueRequest) returns (ReopenIssueResponse);
72+}
73+
74+// CreateIssueRequest describes the issue to open.
75+message CreateIssueRequest {
76+ // Repo is the repository name.
77+ string repo = 1;
78+ // Title is the one-line title. Required.
79+ string title = 2;
80+ // Body is the optional content.
81+ string body = 3;
82+}
83+
84+// CreateIssueResponse holds the new issue.
85+message CreateIssueResponse {
86+ // Issue is the created issue.
87+ Issue issue = 1;
88+}
89+
90+// ListIssuesRequest selects a page of issues.
91+message ListIssuesRequest {
92+ // Repo is the repository name.
93+ string repo = 1;
94+ // State restricts the result to one state. ISSUE_STATE_UNSPECIFIED means
95+ // every state.
96+ IssueState state = 2;
97+ // PageSize is the maximum number of issues to return. 0 means the server
98+ // default; values above the server maximum are lowered to it.
99+ int32 page_size = 3;
100+ // PageToken is the next_page_token of a previous response, to continue the
101+ // same listing. Empty for the first page. Other fields must be unchanged.
102+ string page_token = 4;
103+}
104+
105+// ListIssuesResponse is one page of issues.
106+message ListIssuesResponse {
107+ // Issues are the issues of this page, highest number first.
108+ repeated Issue issues = 1;
109+ // NextPageToken is passed as page_token to get the next page. Empty when
110+ // there is no next page.
111+ string next_page_token = 2;
112+}
113+
114+// GetIssueRequest selects an issue.
115+message GetIssueRequest {
116+ // Repo is the repository name.
117+ string repo = 1;
118+ // Number is the issue number.
119+ int64 number = 2;
120+}
121+
122+// GetIssueResponse holds an issue with its comments.
123+message GetIssueResponse {
124+ // Issue is the issue.
125+ Issue issue = 1;
126+ // Comments are every comment of the issue, oldest first.
127+ repeated IssueComment comments = 2;
128+}
129+
130+// AddIssueCommentRequest describes the comment to add.
131+message AddIssueCommentRequest {
132+ // Repo is the repository name.
133+ string repo = 1;
134+ // Number is the issue number.
135+ int64 number = 2;
136+ // Text is the content. Required.
137+ string text = 3;
138+}
139+
140+// AddIssueCommentResponse holds the new comment.
141+message AddIssueCommentResponse {
142+ // Comment is the created comment.
143+ IssueComment comment = 1;
144+}
145+
146+// CloseIssueRequest names the issue to close.
147+message CloseIssueRequest {
148+ // Repo is the repository name.
149+ string repo = 1;
150+ // Number is the issue number.
151+ int64 number = 2;
152+}
153+
154+// CloseIssueResponse holds the issue after closing.
155+message CloseIssueResponse {
156+ // Issue is the closed issue.
157+ Issue issue = 1;
158+}
159+
160+// ReopenIssueRequest names the issue to reopen.
161+message ReopenIssueRequest {
162+ // Repo is the repository name.
163+ string repo = 1;
164+ // Number is the issue number.
165+ int64 number = 2;
166+}
167+
168+// ReopenIssueResponse holds the issue after reopening.
169+message ReopenIssueResponse {
170+ // Issue is the reopened issue.
171+ Issue issue = 1;
172+}
M proto/ermite/repo.proto +21 -4
@@ -20,8 +20,20 @@ enum Visibility {
2020 VISIBILITY_PRIVATE = 2;
2121 }
2222
23+// IssuesMode says who may write issues in a repository.
24+enum IssuesMode {
25+ // Not set.
26+ ISSUES_MODE_UNSPECIFIED = 0;
27+ // Issues are disabled.
28+ ISSUES_MODE_OFF = 1;
29+ // Only the owner may write issues.
30+ ISSUES_MODE_OWNER = 2;
31+ // Issues are open to public participation.
32+ ISSUES_MODE_PUBLIC = 3;
33+}
34+
2335 // RepoSettings are the settings of a repository that govern its merge
24-// requests.
36+// requests and issues.
2537 message RepoSettings {
2638 // AllowedMergeModes are the modes with which a merge request of the
2739 // repository may be merged. It is never empty in a response and has no
@@ -33,6 +45,8 @@ message RepoSettings {
3345 // explicitly, so a later change of the server default never alters an
3446 // existing repository.
3547 bool failing_checks_block = 2;
48+ // Issues is the issue participation mode of the repository.
49+ IssuesMode issues = 3;
3650 }
3751
3852 // Repo is the metadata of a repository. Git-owned state (refs, trees, history)
@@ -53,7 +67,7 @@ message Repo {
5367 google.protobuf.Timestamp created_at = 5;
5468 // PushedAt is the time of the last push. It is unset until the first push.
5569 google.protobuf.Timestamp pushed_at = 6;
56- // Settings are the merge settings of the repository. Always set in a
70+ // Settings are the settings of the repository. Always set in a
5771 // response, with the defaults for a repository that never changed them.
5872 RepoSettings settings = 7;
5973 // Topics classify the repository, as on GitHub: at most 20, each 1-50
@@ -153,8 +167,9 @@ message UpdateRepoRequest {
153167 string default_branch = 4;
154168 // UpdateMask lists the fields to change: "description", "visibility",
155169 // "default_branch", "topics", "settings.allowed_merge_modes" and/or
156- // "settings.failing_checks_block". "settings" stands for both settings
157- // paths. It must not be empty. Other paths are invalid_argument.
170+ // "settings.failing_checks_block". "settings" stands for both merge settings
171+ // paths. The optional issues field changes the issue mode separately.
172+ // It must not be empty. Other paths are invalid_argument.
158173 google.protobuf.FieldMask update_mask = 5;
159174 // Settings holds the new merge settings. Only the fields named in
160175 // update_mask are used. allowed_merge_modes must then not be empty nor
@@ -165,6 +180,8 @@ message UpdateRepoRequest {
165180 // Topics replace the topics of the repository (see Repo.topics). Used only
166181 // if update_mask contains "topics"; an empty list then clears them.
167182 repeated string topics = 7;
183+ // Issues is the new issue participation mode. When absent it is unchanged.
184+ optional IssuesMode issues = 8;
168185 }
169186
170187 // UpdateRepoResponse holds the repository after the update.
@@ -20,8 +20,20 @@ enum Visibility {
20 VISIBILITY_PRIVATE = 2;20 VISIBILITY_PRIVATE = 2;
21 }21 }
22 22
23+// IssuesMode says who may write issues in a repository.
24+enum IssuesMode {
25+ // Not set.
26+ ISSUES_MODE_UNSPECIFIED = 0;
27+ // Issues are disabled.
28+ ISSUES_MODE_OFF = 1;
29+ // Only the owner may write issues.
30+ ISSUES_MODE_OWNER = 2;
31+ // Issues are open to public participation.
32+ ISSUES_MODE_PUBLIC = 3;
33+}
34+
23 // RepoSettings are the settings of a repository that govern its merge35 // RepoSettings are the settings of a repository that govern its merge
24-// requests.36+// requests and issues.
25 message RepoSettings {37 message RepoSettings {
26 // AllowedMergeModes are the modes with which a merge request of the38 // AllowedMergeModes are the modes with which a merge request of the
27 // repository may be merged. It is never empty in a response and has no39 // repository may be merged. It is never empty in a response and has no
@@ -33,6 +45,8 @@ message RepoSettings {
33 // explicitly, so a later change of the server default never alters an45 // explicitly, so a later change of the server default never alters an
34 // existing repository.46 // existing repository.
35 bool failing_checks_block = 2;47 bool failing_checks_block = 2;
48+ // Issues is the issue participation mode of the repository.
49+ IssuesMode issues = 3;
36 }50 }
37 51
38 // Repo is the metadata of a repository. Git-owned state (refs, trees, history)52 // Repo is the metadata of a repository. Git-owned state (refs, trees, history)
@@ -53,7 +67,7 @@ message Repo {
53 google.protobuf.Timestamp created_at = 5;67 google.protobuf.Timestamp created_at = 5;
54 // PushedAt is the time of the last push. It is unset until the first push.68 // PushedAt is the time of the last push. It is unset until the first push.
55 google.protobuf.Timestamp pushed_at = 6;69 google.protobuf.Timestamp pushed_at = 6;
56- // Settings are the merge settings of the repository. Always set in a70+ // Settings are the settings of the repository. Always set in a
57 // response, with the defaults for a repository that never changed them.71 // response, with the defaults for a repository that never changed them.
58 RepoSettings settings = 7;72 RepoSettings settings = 7;
59 // Topics classify the repository, as on GitHub: at most 20, each 1-5073 // Topics classify the repository, as on GitHub: at most 20, each 1-50
@@ -153,8 +167,9 @@ message UpdateRepoRequest {
153 string default_branch = 4;167 string default_branch = 4;
154 // UpdateMask lists the fields to change: "description", "visibility",168 // UpdateMask lists the fields to change: "description", "visibility",
155 // "default_branch", "topics", "settings.allowed_merge_modes" and/or169 // "default_branch", "topics", "settings.allowed_merge_modes" and/or
156- // "settings.failing_checks_block". "settings" stands for both settings170+ // "settings.failing_checks_block". "settings" stands for both merge settings
157- // paths. It must not be empty. Other paths are invalid_argument.171+ // paths. The optional issues field changes the issue mode separately.
172+ // It must not be empty. Other paths are invalid_argument.
158 google.protobuf.FieldMask update_mask = 5;173 google.protobuf.FieldMask update_mask = 5;
159 // Settings holds the new merge settings. Only the fields named in174 // Settings holds the new merge settings. Only the fields named in
160 // update_mask are used. allowed_merge_modes must then not be empty nor175 // update_mask are used. allowed_merge_modes must then not be empty nor
@@ -165,6 +180,8 @@ message UpdateRepoRequest {
165 // Topics replace the topics of the repository (see Repo.topics). Used only180 // Topics replace the topics of the repository (see Repo.topics). Used only
166 // if update_mask contains "topics"; an empty list then clears them.181 // if update_mask contains "topics"; an empty list then clears them.
167 repeated string topics = 7;182 repeated string topics = 7;
183+ // Issues is the new issue participation mode. When absent it is unchanged.
184+ optional IssuesMode issues = 8;
168 }185 }
169 186
170 // UpdateRepoResponse holds the repository after the update.187 // UpdateRepoResponse holds the repository after the update.
M proto/ermite/token.proto +3 -0
@@ -42,6 +42,9 @@ enum Scope {
4242 // SCOPE_MR_REVIEW allows setting a verdict (approve, changes requested) on
4343 // merge request notes. Wire name: mr:review.
4444 SCOPE_MR_REVIEW = 10;
45+ // SCOPE_ISSUE_WRITE allows creating, commenting on, closing and reopening
46+ // issues. Wire name: issue:write.
47+ SCOPE_ISSUE_WRITE = 11;
4548 }
4649
4750 // Token describes a stored token. It never contains the secret nor its hash.
@@ -42,6 +42,9 @@ enum Scope {
42 // SCOPE_MR_REVIEW allows setting a verdict (approve, changes requested) on42 // SCOPE_MR_REVIEW allows setting a verdict (approve, changes requested) on
43 // merge request notes. Wire name: mr:review.43 // merge request notes. Wire name: mr:review.
44 SCOPE_MR_REVIEW = 10;44 SCOPE_MR_REVIEW = 10;
45+ // SCOPE_ISSUE_WRITE allows creating, commenting on, closing and reopening
46+ // issues. Wire name: issue:write.
47+ SCOPE_ISSUE_WRITE = 11;
45 }48 }
46 49
47 // Token describes a stored token. It never contains the secret nor its hash.50 // Token describes a stored token. It never contains the secret nor its hash.

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