detached a137f54

feat(api): add repository, git, token, event and server services

commit
a137f54f984aa8c562bf2bb9f3ca6bac0cc2c994
author
brice · · 2026-10-10 06:07 UTC
parent
037b5e9
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
20 files · +6623 -5
M README.md +17 -3
@@ -2,7 +2,7 @@
22
33 The public API contract of [ermite](https://git.bnema.dev/bnema/ermite), a single-user Git forge: protobuf definitions for its ConnectRPC services and the Go code generated from them.
44
5-Status: early development, no services defined yet.
5+Status: early development. The contract defines five services (below); the server that implements them is being built.
66
77 ```go
88 import "bnema.dev/ermite-api/gen/ermite"
@@ -10,10 +10,24 @@ import "bnema.dev/ermite-api/gen/ermite"
1010
1111 The contract has no version number. It only changes in backward-compatible ways (new fields, messages, RPCs and services), and CI rejects any breaking change.
1212
13+## Services
14+
15+Handlers are mounted under `/-/api/` by the server. Errors are Connect codes.
16+
17+| Service | RPCs |
18+|---|---|
19+| `RepoService` | `ListRepos`, `GetRepo`, `CreateRepo`, `UpdateRepo` (field mask), `DeleteRepo` |
20+| `GitService` | `ListRefs`, `GetTree`, `GetBlob` (streamed), `ListCommits`, `GetCommit` (structured diff), `ResolveRevision` |
21+| `TokenService` | `CreateToken` (secret shown once), `ListTokens`, `RevokeToken` |
22+| `EventService` | `Watch` (streamed, resumable) |
23+| `ServerService` | `GetVersion` (server version and feature list) |
24+
25+Tokens carry scopes only; presets such as `cli` or `agent` are a client concern.
26+
1327 ## Layout
1428
15-- `proto/ermite/`: `.proto` files of the `ermite` package, checked by `buf lint` and `buf breaking`.
16-- `gen/`: generated Go code, committed. Never edit it by hand.
29+- `proto/ermite/`: `.proto` files of the `ermite` package, one per service (`repo`, `git`, `token`, `event`, `server`) plus shared `types`. Checked by `buf lint` and `buf breaking`.
30+- `gen/ermite/`: generated Go messages. `gen/ermite/ermiteconnect/`: generated Connect clients and handlers. Committed, never edited by hand.
1731
1832 ## Generate
1933
@@ -2,7 +2,7 @@
2 2
3 The public API contract of [ermite](https://git.bnema.dev/bnema/ermite), a single-user Git forge: protobuf definitions for its ConnectRPC services and the Go code generated from them.3 The public API contract of [ermite](https://git.bnema.dev/bnema/ermite), a single-user Git forge: protobuf definitions for its ConnectRPC services and the Go code generated from them.
4 4
5-Status: early development, no services defined yet.5+Status: early development. The contract defines five services (below); the server that implements them is being built.
6 6
7 ```go7 ```go
8 import "bnema.dev/ermite-api/gen/ermite"8 import "bnema.dev/ermite-api/gen/ermite"
@@ -10,10 +10,24 @@ import "bnema.dev/ermite-api/gen/ermite"
10 10
11 The contract has no version number. It only changes in backward-compatible ways (new fields, messages, RPCs and services), and CI rejects any breaking change.11 The contract has no version number. It only changes in backward-compatible ways (new fields, messages, RPCs and services), and CI rejects any breaking change.
12 12
13+## Services
14+
15+Handlers are mounted under `/-/api/` by the server. Errors are Connect codes.
16+
17+| Service | RPCs |
18+|---|---|
19+| `RepoService` | `ListRepos`, `GetRepo`, `CreateRepo`, `UpdateRepo` (field mask), `DeleteRepo` |
20+| `GitService` | `ListRefs`, `GetTree`, `GetBlob` (streamed), `ListCommits`, `GetCommit` (structured diff), `ResolveRevision` |
21+| `TokenService` | `CreateToken` (secret shown once), `ListTokens`, `RevokeToken` |
22+| `EventService` | `Watch` (streamed, resumable) |
23+| `ServerService` | `GetVersion` (server version and feature list) |
24+
25+Tokens carry scopes only; presets such as `cli` or `agent` are a client concern.
26+
13 ## Layout27 ## Layout
14 28
15-- `proto/ermite/`: `.proto` files of the `ermite` package, checked by `buf lint` and `buf breaking`.29+- `proto/ermite/`: `.proto` files of the `ermite` package, one per service (`repo`, `git`, `token`, `event`, `server`) plus shared `types`. Checked by `buf lint` and `buf breaking`.
16-- `gen/`: generated Go code, committed. Never edit it by hand.30+- `gen/ermite/`: generated Go messages. `gen/ermite/ermiteconnect/`: generated Connect clients and handlers. Committed, never edited by hand.
17 31
18 ## Generate32 ## Generate
19 33
A gen/ermite/ermiteconnect/event.connect.go +128 -0
@@ -0,0 +1,128 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/event.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+ // EventServiceName is the fully-qualified name of the EventService service.
27+ EventServiceName = "ermite.EventService"
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+ // EventServiceWatchProcedure is the fully-qualified name of the EventService's Watch RPC.
39+ EventServiceWatchProcedure = "/ermite.EventService/Watch"
40+)
41+
42+// EventServiceClient is a client for the ermite.EventService service.
43+type EventServiceClient interface {
44+ // Watch streams events until the client cancels the call or the server shuts
45+ // down. Events are filtered by the caller's access: events of a private
46+ // repository are only sent to callers that may read it.
47+ //
48+ // The server keeps a bounded buffer of recent events. With resume_after set,
49+ // buffered events after that id are replayed first, then live events follow.
50+ // When resume_after is no longer buffered (or unknown), the stream begins
51+ // with a Gap event, then continues with the oldest buffered event: the client
52+ // must reload its state. Without resume_after, only new events are sent.
53+ Watch(context.Context, *connect.Request[ermite.WatchRequest]) (*connect.ServerStreamForClient[ermite.WatchResponse], error)
54+}
55+
56+// NewEventServiceClient constructs a client for the ermite.EventService service. By default, it
57+// uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends
58+// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or
59+// connect.WithGRPCWeb() options.
60+//
61+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
62+// http://api.acme.com or https://acme.com/grpc).
63+func NewEventServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) EventServiceClient {
64+ baseURL = strings.TrimRight(baseURL, "/")
65+ eventServiceMethods := ermite.File_ermite_event_proto.Services().ByName("EventService").Methods()
66+ return &eventServiceClient{
67+ watch: connect.NewClient[ermite.WatchRequest, ermite.WatchResponse](
68+ httpClient,
69+ baseURL+EventServiceWatchProcedure,
70+ connect.WithSchema(eventServiceMethods.ByName("Watch")),
71+ connect.WithClientOptions(opts...),
72+ ),
73+ }
74+}
75+
76+// eventServiceClient implements EventServiceClient.
77+type eventServiceClient struct {
78+ watch *connect.Client[ermite.WatchRequest, ermite.WatchResponse]
79+}
80+
81+// Watch calls ermite.EventService.Watch.
82+func (c *eventServiceClient) Watch(ctx context.Context, req *connect.Request[ermite.WatchRequest]) (*connect.ServerStreamForClient[ermite.WatchResponse], error) {
83+ return c.watch.CallServerStream(ctx, req)
84+}
85+
86+// EventServiceHandler is an implementation of the ermite.EventService service.
87+type EventServiceHandler interface {
88+ // Watch streams events until the client cancels the call or the server shuts
89+ // down. Events are filtered by the caller's access: events of a private
90+ // repository are only sent to callers that may read it.
91+ //
92+ // The server keeps a bounded buffer of recent events. With resume_after set,
93+ // buffered events after that id are replayed first, then live events follow.
94+ // When resume_after is no longer buffered (or unknown), the stream begins
95+ // with a Gap event, then continues with the oldest buffered event: the client
96+ // must reload its state. Without resume_after, only new events are sent.
97+ Watch(context.Context, *connect.Request[ermite.WatchRequest], *connect.ServerStream[ermite.WatchResponse]) error
98+}
99+
100+// NewEventServiceHandler builds an HTTP handler from the service implementation. It returns the
101+// path on which to mount the handler and the handler itself.
102+//
103+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
104+// and JSON codecs. They also support gzip compression.
105+func NewEventServiceHandler(svc EventServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
106+ eventServiceMethods := ermite.File_ermite_event_proto.Services().ByName("EventService").Methods()
107+ eventServiceWatchHandler := connect.NewServerStreamHandler(
108+ EventServiceWatchProcedure,
109+ svc.Watch,
110+ connect.WithSchema(eventServiceMethods.ByName("Watch")),
111+ connect.WithHandlerOptions(opts...),
112+ )
113+ return "/ermite.EventService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
114+ switch r.URL.Path {
115+ case EventServiceWatchProcedure:
116+ eventServiceWatchHandler.ServeHTTP(w, r)
117+ default:
118+ http.NotFound(w, r)
119+ }
120+ })
121+}
122+
123+// UnimplementedEventServiceHandler returns CodeUnimplemented from all methods.
124+type UnimplementedEventServiceHandler struct{}
125+
126+func (UnimplementedEventServiceHandler) Watch(context.Context, *connect.Request[ermite.WatchRequest], *connect.ServerStream[ermite.WatchResponse]) error {
127+ return connect.NewError(connect.CodeUnimplemented, errors.New("ermite.EventService.Watch is not implemented"))
128+}
@@ -0,0 +1,128 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/event.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+ // EventServiceName is the fully-qualified name of the EventService service.
27+ EventServiceName = "ermite.EventService"
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+ // EventServiceWatchProcedure is the fully-qualified name of the EventService's Watch RPC.
39+ EventServiceWatchProcedure = "/ermite.EventService/Watch"
40+)
41+
42+// EventServiceClient is a client for the ermite.EventService service.
43+type EventServiceClient interface {
44+ // Watch streams events until the client cancels the call or the server shuts
45+ // down. Events are filtered by the caller's access: events of a private
46+ // repository are only sent to callers that may read it.
47+ //
48+ // The server keeps a bounded buffer of recent events. With resume_after set,
49+ // buffered events after that id are replayed first, then live events follow.
50+ // When resume_after is no longer buffered (or unknown), the stream begins
51+ // with a Gap event, then continues with the oldest buffered event: the client
52+ // must reload its state. Without resume_after, only new events are sent.
53+ Watch(context.Context, *connect.Request[ermite.WatchRequest]) (*connect.ServerStreamForClient[ermite.WatchResponse], error)
54+}
55+
56+// NewEventServiceClient constructs a client for the ermite.EventService service. By default, it
57+// uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends
58+// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or
59+// connect.WithGRPCWeb() options.
60+//
61+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
62+// http://api.acme.com or https://acme.com/grpc).
63+func NewEventServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) EventServiceClient {
64+ baseURL = strings.TrimRight(baseURL, "/")
65+ eventServiceMethods := ermite.File_ermite_event_proto.Services().ByName("EventService").Methods()
66+ return &eventServiceClient{
67+ watch: connect.NewClient[ermite.WatchRequest, ermite.WatchResponse](
68+ httpClient,
69+ baseURL+EventServiceWatchProcedure,
70+ connect.WithSchema(eventServiceMethods.ByName("Watch")),
71+ connect.WithClientOptions(opts...),
72+ ),
73+ }
74+}
75+
76+// eventServiceClient implements EventServiceClient.
77+type eventServiceClient struct {
78+ watch *connect.Client[ermite.WatchRequest, ermite.WatchResponse]
79+}
80+
81+// Watch calls ermite.EventService.Watch.
82+func (c *eventServiceClient) Watch(ctx context.Context, req *connect.Request[ermite.WatchRequest]) (*connect.ServerStreamForClient[ermite.WatchResponse], error) {
83+ return c.watch.CallServerStream(ctx, req)
84+}
85+
86+// EventServiceHandler is an implementation of the ermite.EventService service.
87+type EventServiceHandler interface {
88+ // Watch streams events until the client cancels the call or the server shuts
89+ // down. Events are filtered by the caller's access: events of a private
90+ // repository are only sent to callers that may read it.
91+ //
92+ // The server keeps a bounded buffer of recent events. With resume_after set,
93+ // buffered events after that id are replayed first, then live events follow.
94+ // When resume_after is no longer buffered (or unknown), the stream begins
95+ // with a Gap event, then continues with the oldest buffered event: the client
96+ // must reload its state. Without resume_after, only new events are sent.
97+ Watch(context.Context, *connect.Request[ermite.WatchRequest], *connect.ServerStream[ermite.WatchResponse]) error
98+}
99+
100+// NewEventServiceHandler builds an HTTP handler from the service implementation. It returns the
101+// path on which to mount the handler and the handler itself.
102+//
103+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
104+// and JSON codecs. They also support gzip compression.
105+func NewEventServiceHandler(svc EventServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
106+ eventServiceMethods := ermite.File_ermite_event_proto.Services().ByName("EventService").Methods()
107+ eventServiceWatchHandler := connect.NewServerStreamHandler(
108+ EventServiceWatchProcedure,
109+ svc.Watch,
110+ connect.WithSchema(eventServiceMethods.ByName("Watch")),
111+ connect.WithHandlerOptions(opts...),
112+ )
113+ return "/ermite.EventService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
114+ switch r.URL.Path {
115+ case EventServiceWatchProcedure:
116+ eventServiceWatchHandler.ServeHTTP(w, r)
117+ default:
118+ http.NotFound(w, r)
119+ }
120+ })
121+}
122+
123+// UnimplementedEventServiceHandler returns CodeUnimplemented from all methods.
124+type UnimplementedEventServiceHandler struct{}
125+
126+func (UnimplementedEventServiceHandler) Watch(context.Context, *connect.Request[ermite.WatchRequest], *connect.ServerStream[ermite.WatchResponse]) error {
127+ return connect.NewError(connect.CodeUnimplemented, errors.New("ermite.EventService.Watch is not implemented"))
128+}
A gen/ermite/ermiteconnect/git.connect.go +281 -0
@@ -0,0 +1,281 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/git.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+ // GitServiceName is the fully-qualified name of the GitService service.
27+ GitServiceName = "ermite.GitService"
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+ // GitServiceListRefsProcedure is the fully-qualified name of the GitService's ListRefs RPC.
39+ GitServiceListRefsProcedure = "/ermite.GitService/ListRefs"
40+ // GitServiceGetTreeProcedure is the fully-qualified name of the GitService's GetTree RPC.
41+ GitServiceGetTreeProcedure = "/ermite.GitService/GetTree"
42+ // GitServiceGetBlobProcedure is the fully-qualified name of the GitService's GetBlob RPC.
43+ GitServiceGetBlobProcedure = "/ermite.GitService/GetBlob"
44+ // GitServiceListCommitsProcedure is the fully-qualified name of the GitService's ListCommits RPC.
45+ GitServiceListCommitsProcedure = "/ermite.GitService/ListCommits"
46+ // GitServiceGetCommitProcedure is the fully-qualified name of the GitService's GetCommit RPC.
47+ GitServiceGetCommitProcedure = "/ermite.GitService/GetCommit"
48+ // GitServiceResolveRevisionProcedure is the fully-qualified name of the GitService's
49+ // ResolveRevision RPC.
50+ GitServiceResolveRevisionProcedure = "/ermite.GitService/ResolveRevision"
51+)
52+
53+// GitServiceClient is a client for the ermite.GitService service.
54+type GitServiceClient interface {
55+ // ListRefs lists the branches, tags and HEAD of a repository. Refs are
56+ // ordered by kind (HEAD, branches, tags) then by name.
57+ ListRefs(context.Context, *connect.Request[ermite.ListRefsRequest]) (*connect.Response[ermite.ListRefsResponse], error)
58+ // GetTree lists the entries of a directory at a revision. Fails with
59+ // not_found if the path does not exist and invalid_argument if it is not a
60+ // directory.
61+ GetTree(context.Context, *connect.Request[ermite.GetTreeRequest]) (*connect.Response[ermite.GetTreeResponse], error)
62+ // GetBlob streams the content of a file at a revision, in chunks of at most
63+ // 64 KiB. The first message carries the metadata in info, then the chunks
64+ // follow; the memory used by the server does not depend on the file size.
65+ // Fails with not_found if the path does not exist and invalid_argument if it
66+ // is not a file.
67+ GetBlob(context.Context, *connect.Request[ermite.GetBlobRequest]) (*connect.ServerStreamForClient[ermite.GetBlobResponse], error)
68+ // ListCommits lists the history reachable from a revision, newest first
69+ // (Git's default order), optionally limited to the commits that touched a
70+ // path.
71+ ListCommits(context.Context, *connect.Request[ermite.ListCommitsRequest]) (*connect.Response[ermite.ListCommitsResponse], error)
72+ // GetCommit returns one commit with its statistics and its diff.
73+ GetCommit(context.Context, *connect.Request[ermite.GetCommitRequest]) (*connect.Response[ermite.GetCommitResponse], error)
74+ // ResolveRevision turns a revision into the id of the commit it designates.
75+ ResolveRevision(context.Context, *connect.Request[ermite.ResolveRevisionRequest]) (*connect.Response[ermite.ResolveRevisionResponse], error)
76+}
77+
78+// NewGitServiceClient constructs a client for the ermite.GitService service. By default, it uses
79+// the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends
80+// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or
81+// connect.WithGRPCWeb() options.
82+//
83+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
84+// http://api.acme.com or https://acme.com/grpc).
85+func NewGitServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) GitServiceClient {
86+ baseURL = strings.TrimRight(baseURL, "/")
87+ gitServiceMethods := ermite.File_ermite_git_proto.Services().ByName("GitService").Methods()
88+ return &gitServiceClient{
89+ listRefs: connect.NewClient[ermite.ListRefsRequest, ermite.ListRefsResponse](
90+ httpClient,
91+ baseURL+GitServiceListRefsProcedure,
92+ connect.WithSchema(gitServiceMethods.ByName("ListRefs")),
93+ connect.WithClientOptions(opts...),
94+ ),
95+ getTree: connect.NewClient[ermite.GetTreeRequest, ermite.GetTreeResponse](
96+ httpClient,
97+ baseURL+GitServiceGetTreeProcedure,
98+ connect.WithSchema(gitServiceMethods.ByName("GetTree")),
99+ connect.WithClientOptions(opts...),
100+ ),
101+ getBlob: connect.NewClient[ermite.GetBlobRequest, ermite.GetBlobResponse](
102+ httpClient,
103+ baseURL+GitServiceGetBlobProcedure,
104+ connect.WithSchema(gitServiceMethods.ByName("GetBlob")),
105+ connect.WithClientOptions(opts...),
106+ ),
107+ listCommits: connect.NewClient[ermite.ListCommitsRequest, ermite.ListCommitsResponse](
108+ httpClient,
109+ baseURL+GitServiceListCommitsProcedure,
110+ connect.WithSchema(gitServiceMethods.ByName("ListCommits")),
111+ connect.WithClientOptions(opts...),
112+ ),
113+ getCommit: connect.NewClient[ermite.GetCommitRequest, ermite.GetCommitResponse](
114+ httpClient,
115+ baseURL+GitServiceGetCommitProcedure,
116+ connect.WithSchema(gitServiceMethods.ByName("GetCommit")),
117+ connect.WithClientOptions(opts...),
118+ ),
119+ resolveRevision: connect.NewClient[ermite.ResolveRevisionRequest, ermite.ResolveRevisionResponse](
120+ httpClient,
121+ baseURL+GitServiceResolveRevisionProcedure,
122+ connect.WithSchema(gitServiceMethods.ByName("ResolveRevision")),
123+ connect.WithClientOptions(opts...),
124+ ),
125+ }
126+}
127+
128+// gitServiceClient implements GitServiceClient.
129+type gitServiceClient struct {
130+ listRefs *connect.Client[ermite.ListRefsRequest, ermite.ListRefsResponse]
131+ getTree *connect.Client[ermite.GetTreeRequest, ermite.GetTreeResponse]
132+ getBlob *connect.Client[ermite.GetBlobRequest, ermite.GetBlobResponse]
133+ listCommits *connect.Client[ermite.ListCommitsRequest, ermite.ListCommitsResponse]
134+ getCommit *connect.Client[ermite.GetCommitRequest, ermite.GetCommitResponse]
135+ resolveRevision *connect.Client[ermite.ResolveRevisionRequest, ermite.ResolveRevisionResponse]
136+}
137+
138+// ListRefs calls ermite.GitService.ListRefs.
139+func (c *gitServiceClient) ListRefs(ctx context.Context, req *connect.Request[ermite.ListRefsRequest]) (*connect.Response[ermite.ListRefsResponse], error) {
140+ return c.listRefs.CallUnary(ctx, req)
141+}
142+
143+// GetTree calls ermite.GitService.GetTree.
144+func (c *gitServiceClient) GetTree(ctx context.Context, req *connect.Request[ermite.GetTreeRequest]) (*connect.Response[ermite.GetTreeResponse], error) {
145+ return c.getTree.CallUnary(ctx, req)
146+}
147+
148+// GetBlob calls ermite.GitService.GetBlob.
149+func (c *gitServiceClient) GetBlob(ctx context.Context, req *connect.Request[ermite.GetBlobRequest]) (*connect.ServerStreamForClient[ermite.GetBlobResponse], error) {
150+ return c.getBlob.CallServerStream(ctx, req)
151+}
152+
153+// ListCommits calls ermite.GitService.ListCommits.
154+func (c *gitServiceClient) ListCommits(ctx context.Context, req *connect.Request[ermite.ListCommitsRequest]) (*connect.Response[ermite.ListCommitsResponse], error) {
155+ return c.listCommits.CallUnary(ctx, req)
156+}
157+
158+// GetCommit calls ermite.GitService.GetCommit.
159+func (c *gitServiceClient) GetCommit(ctx context.Context, req *connect.Request[ermite.GetCommitRequest]) (*connect.Response[ermite.GetCommitResponse], error) {
160+ return c.getCommit.CallUnary(ctx, req)
161+}
162+
163+// ResolveRevision calls ermite.GitService.ResolveRevision.
164+func (c *gitServiceClient) ResolveRevision(ctx context.Context, req *connect.Request[ermite.ResolveRevisionRequest]) (*connect.Response[ermite.ResolveRevisionResponse], error) {
165+ return c.resolveRevision.CallUnary(ctx, req)
166+}
167+
168+// GitServiceHandler is an implementation of the ermite.GitService service.
169+type GitServiceHandler interface {
170+ // ListRefs lists the branches, tags and HEAD of a repository. Refs are
171+ // ordered by kind (HEAD, branches, tags) then by name.
172+ ListRefs(context.Context, *connect.Request[ermite.ListRefsRequest]) (*connect.Response[ermite.ListRefsResponse], error)
173+ // GetTree lists the entries of a directory at a revision. Fails with
174+ // not_found if the path does not exist and invalid_argument if it is not a
175+ // directory.
176+ GetTree(context.Context, *connect.Request[ermite.GetTreeRequest]) (*connect.Response[ermite.GetTreeResponse], error)
177+ // GetBlob streams the content of a file at a revision, in chunks of at most
178+ // 64 KiB. The first message carries the metadata in info, then the chunks
179+ // follow; the memory used by the server does not depend on the file size.
180+ // Fails with not_found if the path does not exist and invalid_argument if it
181+ // is not a file.
182+ GetBlob(context.Context, *connect.Request[ermite.GetBlobRequest], *connect.ServerStream[ermite.GetBlobResponse]) error
183+ // ListCommits lists the history reachable from a revision, newest first
184+ // (Git's default order), optionally limited to the commits that touched a
185+ // path.
186+ ListCommits(context.Context, *connect.Request[ermite.ListCommitsRequest]) (*connect.Response[ermite.ListCommitsResponse], error)
187+ // GetCommit returns one commit with its statistics and its diff.
188+ GetCommit(context.Context, *connect.Request[ermite.GetCommitRequest]) (*connect.Response[ermite.GetCommitResponse], error)
189+ // ResolveRevision turns a revision into the id of the commit it designates.
190+ ResolveRevision(context.Context, *connect.Request[ermite.ResolveRevisionRequest]) (*connect.Response[ermite.ResolveRevisionResponse], error)
191+}
192+
193+// NewGitServiceHandler builds an HTTP handler from the service implementation. It returns the path
194+// on which to mount the handler and the handler itself.
195+//
196+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
197+// and JSON codecs. They also support gzip compression.
198+func NewGitServiceHandler(svc GitServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
199+ gitServiceMethods := ermite.File_ermite_git_proto.Services().ByName("GitService").Methods()
200+ gitServiceListRefsHandler := connect.NewUnaryHandler(
201+ GitServiceListRefsProcedure,
202+ svc.ListRefs,
203+ connect.WithSchema(gitServiceMethods.ByName("ListRefs")),
204+ connect.WithHandlerOptions(opts...),
205+ )
206+ gitServiceGetTreeHandler := connect.NewUnaryHandler(
207+ GitServiceGetTreeProcedure,
208+ svc.GetTree,
209+ connect.WithSchema(gitServiceMethods.ByName("GetTree")),
210+ connect.WithHandlerOptions(opts...),
211+ )
212+ gitServiceGetBlobHandler := connect.NewServerStreamHandler(
213+ GitServiceGetBlobProcedure,
214+ svc.GetBlob,
215+ connect.WithSchema(gitServiceMethods.ByName("GetBlob")),
216+ connect.WithHandlerOptions(opts...),
217+ )
218+ gitServiceListCommitsHandler := connect.NewUnaryHandler(
219+ GitServiceListCommitsProcedure,
220+ svc.ListCommits,
221+ connect.WithSchema(gitServiceMethods.ByName("ListCommits")),
222+ connect.WithHandlerOptions(opts...),
223+ )
224+ gitServiceGetCommitHandler := connect.NewUnaryHandler(
225+ GitServiceGetCommitProcedure,
226+ svc.GetCommit,
227+ connect.WithSchema(gitServiceMethods.ByName("GetCommit")),
228+ connect.WithHandlerOptions(opts...),
229+ )
230+ gitServiceResolveRevisionHandler := connect.NewUnaryHandler(
231+ GitServiceResolveRevisionProcedure,
232+ svc.ResolveRevision,
233+ connect.WithSchema(gitServiceMethods.ByName("ResolveRevision")),
234+ connect.WithHandlerOptions(opts...),
235+ )
236+ return "/ermite.GitService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
237+ switch r.URL.Path {
238+ case GitServiceListRefsProcedure:
239+ gitServiceListRefsHandler.ServeHTTP(w, r)
240+ case GitServiceGetTreeProcedure:
241+ gitServiceGetTreeHandler.ServeHTTP(w, r)
242+ case GitServiceGetBlobProcedure:
243+ gitServiceGetBlobHandler.ServeHTTP(w, r)
244+ case GitServiceListCommitsProcedure:
245+ gitServiceListCommitsHandler.ServeHTTP(w, r)
246+ case GitServiceGetCommitProcedure:
247+ gitServiceGetCommitHandler.ServeHTTP(w, r)
248+ case GitServiceResolveRevisionProcedure:
249+ gitServiceResolveRevisionHandler.ServeHTTP(w, r)
250+ default:
251+ http.NotFound(w, r)
252+ }
253+ })
254+}
255+
256+// UnimplementedGitServiceHandler returns CodeUnimplemented from all methods.
257+type UnimplementedGitServiceHandler struct{}
258+
259+func (UnimplementedGitServiceHandler) ListRefs(context.Context, *connect.Request[ermite.ListRefsRequest]) (*connect.Response[ermite.ListRefsResponse], error) {
260+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.GitService.ListRefs is not implemented"))
261+}
262+
263+func (UnimplementedGitServiceHandler) GetTree(context.Context, *connect.Request[ermite.GetTreeRequest]) (*connect.Response[ermite.GetTreeResponse], error) {
264+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.GitService.GetTree is not implemented"))
265+}
266+
267+func (UnimplementedGitServiceHandler) GetBlob(context.Context, *connect.Request[ermite.GetBlobRequest], *connect.ServerStream[ermite.GetBlobResponse]) error {
268+ return connect.NewError(connect.CodeUnimplemented, errors.New("ermite.GitService.GetBlob is not implemented"))
269+}
270+
271+func (UnimplementedGitServiceHandler) ListCommits(context.Context, *connect.Request[ermite.ListCommitsRequest]) (*connect.Response[ermite.ListCommitsResponse], error) {
272+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.GitService.ListCommits is not implemented"))
273+}
274+
275+func (UnimplementedGitServiceHandler) GetCommit(context.Context, *connect.Request[ermite.GetCommitRequest]) (*connect.Response[ermite.GetCommitResponse], error) {
276+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.GitService.GetCommit is not implemented"))
277+}
278+
279+func (UnimplementedGitServiceHandler) ResolveRevision(context.Context, *connect.Request[ermite.ResolveRevisionRequest]) (*connect.Response[ermite.ResolveRevisionResponse], error) {
280+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.GitService.ResolveRevision is not implemented"))
281+}
@@ -0,0 +1,281 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/git.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+ // GitServiceName is the fully-qualified name of the GitService service.
27+ GitServiceName = "ermite.GitService"
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+ // GitServiceListRefsProcedure is the fully-qualified name of the GitService's ListRefs RPC.
39+ GitServiceListRefsProcedure = "/ermite.GitService/ListRefs"
40+ // GitServiceGetTreeProcedure is the fully-qualified name of the GitService's GetTree RPC.
41+ GitServiceGetTreeProcedure = "/ermite.GitService/GetTree"
42+ // GitServiceGetBlobProcedure is the fully-qualified name of the GitService's GetBlob RPC.
43+ GitServiceGetBlobProcedure = "/ermite.GitService/GetBlob"
44+ // GitServiceListCommitsProcedure is the fully-qualified name of the GitService's ListCommits RPC.
45+ GitServiceListCommitsProcedure = "/ermite.GitService/ListCommits"
46+ // GitServiceGetCommitProcedure is the fully-qualified name of the GitService's GetCommit RPC.
47+ GitServiceGetCommitProcedure = "/ermite.GitService/GetCommit"
48+ // GitServiceResolveRevisionProcedure is the fully-qualified name of the GitService's
49+ // ResolveRevision RPC.
50+ GitServiceResolveRevisionProcedure = "/ermite.GitService/ResolveRevision"
51+)
52+
53+// GitServiceClient is a client for the ermite.GitService service.
54+type GitServiceClient interface {
55+ // ListRefs lists the branches, tags and HEAD of a repository. Refs are
56+ // ordered by kind (HEAD, branches, tags) then by name.
57+ ListRefs(context.Context, *connect.Request[ermite.ListRefsRequest]) (*connect.Response[ermite.ListRefsResponse], error)
58+ // GetTree lists the entries of a directory at a revision. Fails with
59+ // not_found if the path does not exist and invalid_argument if it is not a
60+ // directory.
61+ GetTree(context.Context, *connect.Request[ermite.GetTreeRequest]) (*connect.Response[ermite.GetTreeResponse], error)
62+ // GetBlob streams the content of a file at a revision, in chunks of at most
63+ // 64 KiB. The first message carries the metadata in info, then the chunks
64+ // follow; the memory used by the server does not depend on the file size.
65+ // Fails with not_found if the path does not exist and invalid_argument if it
66+ // is not a file.
67+ GetBlob(context.Context, *connect.Request[ermite.GetBlobRequest]) (*connect.ServerStreamForClient[ermite.GetBlobResponse], error)
68+ // ListCommits lists the history reachable from a revision, newest first
69+ // (Git's default order), optionally limited to the commits that touched a
70+ // path.
71+ ListCommits(context.Context, *connect.Request[ermite.ListCommitsRequest]) (*connect.Response[ermite.ListCommitsResponse], error)
72+ // GetCommit returns one commit with its statistics and its diff.
73+ GetCommit(context.Context, *connect.Request[ermite.GetCommitRequest]) (*connect.Response[ermite.GetCommitResponse], error)
74+ // ResolveRevision turns a revision into the id of the commit it designates.
75+ ResolveRevision(context.Context, *connect.Request[ermite.ResolveRevisionRequest]) (*connect.Response[ermite.ResolveRevisionResponse], error)
76+}
77+
78+// NewGitServiceClient constructs a client for the ermite.GitService service. By default, it uses
79+// the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends
80+// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or
81+// connect.WithGRPCWeb() options.
82+//
83+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
84+// http://api.acme.com or https://acme.com/grpc).
85+func NewGitServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) GitServiceClient {
86+ baseURL = strings.TrimRight(baseURL, "/")
87+ gitServiceMethods := ermite.File_ermite_git_proto.Services().ByName("GitService").Methods()
88+ return &gitServiceClient{
89+ listRefs: connect.NewClient[ermite.ListRefsRequest, ermite.ListRefsResponse](
90+ httpClient,
91+ baseURL+GitServiceListRefsProcedure,
92+ connect.WithSchema(gitServiceMethods.ByName("ListRefs")),
93+ connect.WithClientOptions(opts...),
94+ ),
95+ getTree: connect.NewClient[ermite.GetTreeRequest, ermite.GetTreeResponse](
96+ httpClient,
97+ baseURL+GitServiceGetTreeProcedure,
98+ connect.WithSchema(gitServiceMethods.ByName("GetTree")),
99+ connect.WithClientOptions(opts...),
100+ ),
101+ getBlob: connect.NewClient[ermite.GetBlobRequest, ermite.GetBlobResponse](
102+ httpClient,
103+ baseURL+GitServiceGetBlobProcedure,
104+ connect.WithSchema(gitServiceMethods.ByName("GetBlob")),
105+ connect.WithClientOptions(opts...),
106+ ),
107+ listCommits: connect.NewClient[ermite.ListCommitsRequest, ermite.ListCommitsResponse](
108+ httpClient,
109+ baseURL+GitServiceListCommitsProcedure,
110+ connect.WithSchema(gitServiceMethods.ByName("ListCommits")),
111+ connect.WithClientOptions(opts...),
112+ ),
113+ getCommit: connect.NewClient[ermite.GetCommitRequest, ermite.GetCommitResponse](
114+ httpClient,
115+ baseURL+GitServiceGetCommitProcedure,
116+ connect.WithSchema(gitServiceMethods.ByName("GetCommit")),
117+ connect.WithClientOptions(opts...),
118+ ),
119+ resolveRevision: connect.NewClient[ermite.ResolveRevisionRequest, ermite.ResolveRevisionResponse](
120+ httpClient,
121+ baseURL+GitServiceResolveRevisionProcedure,
122+ connect.WithSchema(gitServiceMethods.ByName("ResolveRevision")),
123+ connect.WithClientOptions(opts...),
124+ ),
125+ }
126+}
127+
128+// gitServiceClient implements GitServiceClient.
129+type gitServiceClient struct {
130+ listRefs *connect.Client[ermite.ListRefsRequest, ermite.ListRefsResponse]
131+ getTree *connect.Client[ermite.GetTreeRequest, ermite.GetTreeResponse]
132+ getBlob *connect.Client[ermite.GetBlobRequest, ermite.GetBlobResponse]
133+ listCommits *connect.Client[ermite.ListCommitsRequest, ermite.ListCommitsResponse]
134+ getCommit *connect.Client[ermite.GetCommitRequest, ermite.GetCommitResponse]
135+ resolveRevision *connect.Client[ermite.ResolveRevisionRequest, ermite.ResolveRevisionResponse]
136+}
137+
138+// ListRefs calls ermite.GitService.ListRefs.
139+func (c *gitServiceClient) ListRefs(ctx context.Context, req *connect.Request[ermite.ListRefsRequest]) (*connect.Response[ermite.ListRefsResponse], error) {
140+ return c.listRefs.CallUnary(ctx, req)
141+}
142+
143+// GetTree calls ermite.GitService.GetTree.
144+func (c *gitServiceClient) GetTree(ctx context.Context, req *connect.Request[ermite.GetTreeRequest]) (*connect.Response[ermite.GetTreeResponse], error) {
145+ return c.getTree.CallUnary(ctx, req)
146+}
147+
148+// GetBlob calls ermite.GitService.GetBlob.
149+func (c *gitServiceClient) GetBlob(ctx context.Context, req *connect.Request[ermite.GetBlobRequest]) (*connect.ServerStreamForClient[ermite.GetBlobResponse], error) {
150+ return c.getBlob.CallServerStream(ctx, req)
151+}
152+
153+// ListCommits calls ermite.GitService.ListCommits.
154+func (c *gitServiceClient) ListCommits(ctx context.Context, req *connect.Request[ermite.ListCommitsRequest]) (*connect.Response[ermite.ListCommitsResponse], error) {
155+ return c.listCommits.CallUnary(ctx, req)
156+}
157+
158+// GetCommit calls ermite.GitService.GetCommit.
159+func (c *gitServiceClient) GetCommit(ctx context.Context, req *connect.Request[ermite.GetCommitRequest]) (*connect.Response[ermite.GetCommitResponse], error) {
160+ return c.getCommit.CallUnary(ctx, req)
161+}
162+
163+// ResolveRevision calls ermite.GitService.ResolveRevision.
164+func (c *gitServiceClient) ResolveRevision(ctx context.Context, req *connect.Request[ermite.ResolveRevisionRequest]) (*connect.Response[ermite.ResolveRevisionResponse], error) {
165+ return c.resolveRevision.CallUnary(ctx, req)
166+}
167+
168+// GitServiceHandler is an implementation of the ermite.GitService service.
169+type GitServiceHandler interface {
170+ // ListRefs lists the branches, tags and HEAD of a repository. Refs are
171+ // ordered by kind (HEAD, branches, tags) then by name.
172+ ListRefs(context.Context, *connect.Request[ermite.ListRefsRequest]) (*connect.Response[ermite.ListRefsResponse], error)
173+ // GetTree lists the entries of a directory at a revision. Fails with
174+ // not_found if the path does not exist and invalid_argument if it is not a
175+ // directory.
176+ GetTree(context.Context, *connect.Request[ermite.GetTreeRequest]) (*connect.Response[ermite.GetTreeResponse], error)
177+ // GetBlob streams the content of a file at a revision, in chunks of at most
178+ // 64 KiB. The first message carries the metadata in info, then the chunks
179+ // follow; the memory used by the server does not depend on the file size.
180+ // Fails with not_found if the path does not exist and invalid_argument if it
181+ // is not a file.
182+ GetBlob(context.Context, *connect.Request[ermite.GetBlobRequest], *connect.ServerStream[ermite.GetBlobResponse]) error
183+ // ListCommits lists the history reachable from a revision, newest first
184+ // (Git's default order), optionally limited to the commits that touched a
185+ // path.
186+ ListCommits(context.Context, *connect.Request[ermite.ListCommitsRequest]) (*connect.Response[ermite.ListCommitsResponse], error)
187+ // GetCommit returns one commit with its statistics and its diff.
188+ GetCommit(context.Context, *connect.Request[ermite.GetCommitRequest]) (*connect.Response[ermite.GetCommitResponse], error)
189+ // ResolveRevision turns a revision into the id of the commit it designates.
190+ ResolveRevision(context.Context, *connect.Request[ermite.ResolveRevisionRequest]) (*connect.Response[ermite.ResolveRevisionResponse], error)
191+}
192+
193+// NewGitServiceHandler builds an HTTP handler from the service implementation. It returns the path
194+// on which to mount the handler and the handler itself.
195+//
196+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
197+// and JSON codecs. They also support gzip compression.
198+func NewGitServiceHandler(svc GitServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
199+ gitServiceMethods := ermite.File_ermite_git_proto.Services().ByName("GitService").Methods()
200+ gitServiceListRefsHandler := connect.NewUnaryHandler(
201+ GitServiceListRefsProcedure,
202+ svc.ListRefs,
203+ connect.WithSchema(gitServiceMethods.ByName("ListRefs")),
204+ connect.WithHandlerOptions(opts...),
205+ )
206+ gitServiceGetTreeHandler := connect.NewUnaryHandler(
207+ GitServiceGetTreeProcedure,
208+ svc.GetTree,
209+ connect.WithSchema(gitServiceMethods.ByName("GetTree")),
210+ connect.WithHandlerOptions(opts...),
211+ )
212+ gitServiceGetBlobHandler := connect.NewServerStreamHandler(
213+ GitServiceGetBlobProcedure,
214+ svc.GetBlob,
215+ connect.WithSchema(gitServiceMethods.ByName("GetBlob")),
216+ connect.WithHandlerOptions(opts...),
217+ )
218+ gitServiceListCommitsHandler := connect.NewUnaryHandler(
219+ GitServiceListCommitsProcedure,
220+ svc.ListCommits,
221+ connect.WithSchema(gitServiceMethods.ByName("ListCommits")),
222+ connect.WithHandlerOptions(opts...),
223+ )
224+ gitServiceGetCommitHandler := connect.NewUnaryHandler(
225+ GitServiceGetCommitProcedure,
226+ svc.GetCommit,
227+ connect.WithSchema(gitServiceMethods.ByName("GetCommit")),
228+ connect.WithHandlerOptions(opts...),
229+ )
230+ gitServiceResolveRevisionHandler := connect.NewUnaryHandler(
231+ GitServiceResolveRevisionProcedure,
232+ svc.ResolveRevision,
233+ connect.WithSchema(gitServiceMethods.ByName("ResolveRevision")),
234+ connect.WithHandlerOptions(opts...),
235+ )
236+ return "/ermite.GitService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
237+ switch r.URL.Path {
238+ case GitServiceListRefsProcedure:
239+ gitServiceListRefsHandler.ServeHTTP(w, r)
240+ case GitServiceGetTreeProcedure:
241+ gitServiceGetTreeHandler.ServeHTTP(w, r)
242+ case GitServiceGetBlobProcedure:
243+ gitServiceGetBlobHandler.ServeHTTP(w, r)
244+ case GitServiceListCommitsProcedure:
245+ gitServiceListCommitsHandler.ServeHTTP(w, r)
246+ case GitServiceGetCommitProcedure:
247+ gitServiceGetCommitHandler.ServeHTTP(w, r)
248+ case GitServiceResolveRevisionProcedure:
249+ gitServiceResolveRevisionHandler.ServeHTTP(w, r)
250+ default:
251+ http.NotFound(w, r)
252+ }
253+ })
254+}
255+
256+// UnimplementedGitServiceHandler returns CodeUnimplemented from all methods.
257+type UnimplementedGitServiceHandler struct{}
258+
259+func (UnimplementedGitServiceHandler) ListRefs(context.Context, *connect.Request[ermite.ListRefsRequest]) (*connect.Response[ermite.ListRefsResponse], error) {
260+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.GitService.ListRefs is not implemented"))
261+}
262+
263+func (UnimplementedGitServiceHandler) GetTree(context.Context, *connect.Request[ermite.GetTreeRequest]) (*connect.Response[ermite.GetTreeResponse], error) {
264+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.GitService.GetTree is not implemented"))
265+}
266+
267+func (UnimplementedGitServiceHandler) GetBlob(context.Context, *connect.Request[ermite.GetBlobRequest], *connect.ServerStream[ermite.GetBlobResponse]) error {
268+ return connect.NewError(connect.CodeUnimplemented, errors.New("ermite.GitService.GetBlob is not implemented"))
269+}
270+
271+func (UnimplementedGitServiceHandler) ListCommits(context.Context, *connect.Request[ermite.ListCommitsRequest]) (*connect.Response[ermite.ListCommitsResponse], error) {
272+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.GitService.ListCommits is not implemented"))
273+}
274+
275+func (UnimplementedGitServiceHandler) GetCommit(context.Context, *connect.Request[ermite.GetCommitRequest]) (*connect.Response[ermite.GetCommitResponse], error) {
276+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.GitService.GetCommit is not implemented"))
277+}
278+
279+func (UnimplementedGitServiceHandler) ResolveRevision(context.Context, *connect.Request[ermite.ResolveRevisionRequest]) (*connect.Response[ermite.ResolveRevisionResponse], error) {
280+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.GitService.ResolveRevision is not implemented"))
281+}
A gen/ermite/ermiteconnect/repo.connect.go +242 -0
@@ -0,0 +1,242 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/repo.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+ // RepoServiceName is the fully-qualified name of the RepoService service.
27+ RepoServiceName = "ermite.RepoService"
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+ // RepoServiceListReposProcedure is the fully-qualified name of the RepoService's ListRepos RPC.
39+ RepoServiceListReposProcedure = "/ermite.RepoService/ListRepos"
40+ // RepoServiceGetRepoProcedure is the fully-qualified name of the RepoService's GetRepo RPC.
41+ RepoServiceGetRepoProcedure = "/ermite.RepoService/GetRepo"
42+ // RepoServiceCreateRepoProcedure is the fully-qualified name of the RepoService's CreateRepo RPC.
43+ RepoServiceCreateRepoProcedure = "/ermite.RepoService/CreateRepo"
44+ // RepoServiceUpdateRepoProcedure is the fully-qualified name of the RepoService's UpdateRepo RPC.
45+ RepoServiceUpdateRepoProcedure = "/ermite.RepoService/UpdateRepo"
46+ // RepoServiceDeleteRepoProcedure is the fully-qualified name of the RepoService's DeleteRepo RPC.
47+ RepoServiceDeleteRepoProcedure = "/ermite.RepoService/DeleteRepo"
48+)
49+
50+// RepoServiceClient is a client for the ermite.RepoService service.
51+type RepoServiceClient interface {
52+ // ListRepos lists the repositories the caller may see, ordered by name.
53+ ListRepos(context.Context, *connect.Request[ermite.ListReposRequest]) (*connect.Response[ermite.ListReposResponse], error)
54+ // GetRepo returns one repository. Fails with not_found if it does not exist
55+ // or is private and not readable by the caller.
56+ GetRepo(context.Context, *connect.Request[ermite.GetRepoRequest]) (*connect.Response[ermite.GetRepoResponse], error)
57+ // CreateRepo creates an empty repository. Needs the repo:write scope. Fails
58+ // with already_exists if the name is taken and invalid_argument if the name
59+ // is not valid.
60+ CreateRepo(context.Context, *connect.Request[ermite.CreateRepoRequest]) (*connect.Response[ermite.CreateRepoResponse], error)
61+ // UpdateRepo changes the fields named in update_mask. Needs the repo:admin
62+ // scope.
63+ UpdateRepo(context.Context, *connect.Request[ermite.UpdateRepoRequest]) (*connect.Response[ermite.UpdateRepoResponse], error)
64+ // DeleteRepo deletes a repository. Needs the repo:admin scope. The server
65+ // moves the data aside rather than destroying it; there is no undelete RPC.
66+ DeleteRepo(context.Context, *connect.Request[ermite.DeleteRepoRequest]) (*connect.Response[ermite.DeleteRepoResponse], error)
67+}
68+
69+// NewRepoServiceClient constructs a client for the ermite.RepoService service. By default, it uses
70+// the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends
71+// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or
72+// connect.WithGRPCWeb() options.
73+//
74+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
75+// http://api.acme.com or https://acme.com/grpc).
76+func NewRepoServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) RepoServiceClient {
77+ baseURL = strings.TrimRight(baseURL, "/")
78+ repoServiceMethods := ermite.File_ermite_repo_proto.Services().ByName("RepoService").Methods()
79+ return &repoServiceClient{
80+ listRepos: connect.NewClient[ermite.ListReposRequest, ermite.ListReposResponse](
81+ httpClient,
82+ baseURL+RepoServiceListReposProcedure,
83+ connect.WithSchema(repoServiceMethods.ByName("ListRepos")),
84+ connect.WithClientOptions(opts...),
85+ ),
86+ getRepo: connect.NewClient[ermite.GetRepoRequest, ermite.GetRepoResponse](
87+ httpClient,
88+ baseURL+RepoServiceGetRepoProcedure,
89+ connect.WithSchema(repoServiceMethods.ByName("GetRepo")),
90+ connect.WithClientOptions(opts...),
91+ ),
92+ createRepo: connect.NewClient[ermite.CreateRepoRequest, ermite.CreateRepoResponse](
93+ httpClient,
94+ baseURL+RepoServiceCreateRepoProcedure,
95+ connect.WithSchema(repoServiceMethods.ByName("CreateRepo")),
96+ connect.WithClientOptions(opts...),
97+ ),
98+ updateRepo: connect.NewClient[ermite.UpdateRepoRequest, ermite.UpdateRepoResponse](
99+ httpClient,
100+ baseURL+RepoServiceUpdateRepoProcedure,
101+ connect.WithSchema(repoServiceMethods.ByName("UpdateRepo")),
102+ connect.WithClientOptions(opts...),
103+ ),
104+ deleteRepo: connect.NewClient[ermite.DeleteRepoRequest, ermite.DeleteRepoResponse](
105+ httpClient,
106+ baseURL+RepoServiceDeleteRepoProcedure,
107+ connect.WithSchema(repoServiceMethods.ByName("DeleteRepo")),
108+ connect.WithClientOptions(opts...),
109+ ),
110+ }
111+}
112+
113+// repoServiceClient implements RepoServiceClient.
114+type repoServiceClient struct {
115+ listRepos *connect.Client[ermite.ListReposRequest, ermite.ListReposResponse]
116+ getRepo *connect.Client[ermite.GetRepoRequest, ermite.GetRepoResponse]
117+ createRepo *connect.Client[ermite.CreateRepoRequest, ermite.CreateRepoResponse]
118+ updateRepo *connect.Client[ermite.UpdateRepoRequest, ermite.UpdateRepoResponse]
119+ deleteRepo *connect.Client[ermite.DeleteRepoRequest, ermite.DeleteRepoResponse]
120+}
121+
122+// ListRepos calls ermite.RepoService.ListRepos.
123+func (c *repoServiceClient) ListRepos(ctx context.Context, req *connect.Request[ermite.ListReposRequest]) (*connect.Response[ermite.ListReposResponse], error) {
124+ return c.listRepos.CallUnary(ctx, req)
125+}
126+
127+// GetRepo calls ermite.RepoService.GetRepo.
128+func (c *repoServiceClient) GetRepo(ctx context.Context, req *connect.Request[ermite.GetRepoRequest]) (*connect.Response[ermite.GetRepoResponse], error) {
129+ return c.getRepo.CallUnary(ctx, req)
130+}
131+
132+// CreateRepo calls ermite.RepoService.CreateRepo.
133+func (c *repoServiceClient) CreateRepo(ctx context.Context, req *connect.Request[ermite.CreateRepoRequest]) (*connect.Response[ermite.CreateRepoResponse], error) {
134+ return c.createRepo.CallUnary(ctx, req)
135+}
136+
137+// UpdateRepo calls ermite.RepoService.UpdateRepo.
138+func (c *repoServiceClient) UpdateRepo(ctx context.Context, req *connect.Request[ermite.UpdateRepoRequest]) (*connect.Response[ermite.UpdateRepoResponse], error) {
139+ return c.updateRepo.CallUnary(ctx, req)
140+}
141+
142+// DeleteRepo calls ermite.RepoService.DeleteRepo.
143+func (c *repoServiceClient) DeleteRepo(ctx context.Context, req *connect.Request[ermite.DeleteRepoRequest]) (*connect.Response[ermite.DeleteRepoResponse], error) {
144+ return c.deleteRepo.CallUnary(ctx, req)
145+}
146+
147+// RepoServiceHandler is an implementation of the ermite.RepoService service.
148+type RepoServiceHandler interface {
149+ // ListRepos lists the repositories the caller may see, ordered by name.
150+ ListRepos(context.Context, *connect.Request[ermite.ListReposRequest]) (*connect.Response[ermite.ListReposResponse], error)
151+ // GetRepo returns one repository. Fails with not_found if it does not exist
152+ // or is private and not readable by the caller.
153+ GetRepo(context.Context, *connect.Request[ermite.GetRepoRequest]) (*connect.Response[ermite.GetRepoResponse], error)
154+ // CreateRepo creates an empty repository. Needs the repo:write scope. Fails
155+ // with already_exists if the name is taken and invalid_argument if the name
156+ // is not valid.
157+ CreateRepo(context.Context, *connect.Request[ermite.CreateRepoRequest]) (*connect.Response[ermite.CreateRepoResponse], error)
158+ // UpdateRepo changes the fields named in update_mask. Needs the repo:admin
159+ // scope.
160+ UpdateRepo(context.Context, *connect.Request[ermite.UpdateRepoRequest]) (*connect.Response[ermite.UpdateRepoResponse], error)
161+ // DeleteRepo deletes a repository. Needs the repo:admin scope. The server
162+ // moves the data aside rather than destroying it; there is no undelete RPC.
163+ DeleteRepo(context.Context, *connect.Request[ermite.DeleteRepoRequest]) (*connect.Response[ermite.DeleteRepoResponse], error)
164+}
165+
166+// NewRepoServiceHandler builds an HTTP handler from the service implementation. It returns the path
167+// on which to mount the handler and the handler itself.
168+//
169+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
170+// and JSON codecs. They also support gzip compression.
171+func NewRepoServiceHandler(svc RepoServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
172+ repoServiceMethods := ermite.File_ermite_repo_proto.Services().ByName("RepoService").Methods()
173+ repoServiceListReposHandler := connect.NewUnaryHandler(
174+ RepoServiceListReposProcedure,
175+ svc.ListRepos,
176+ connect.WithSchema(repoServiceMethods.ByName("ListRepos")),
177+ connect.WithHandlerOptions(opts...),
178+ )
179+ repoServiceGetRepoHandler := connect.NewUnaryHandler(
180+ RepoServiceGetRepoProcedure,
181+ svc.GetRepo,
182+ connect.WithSchema(repoServiceMethods.ByName("GetRepo")),
183+ connect.WithHandlerOptions(opts...),
184+ )
185+ repoServiceCreateRepoHandler := connect.NewUnaryHandler(
186+ RepoServiceCreateRepoProcedure,
187+ svc.CreateRepo,
188+ connect.WithSchema(repoServiceMethods.ByName("CreateRepo")),
189+ connect.WithHandlerOptions(opts...),
190+ )
191+ repoServiceUpdateRepoHandler := connect.NewUnaryHandler(
192+ RepoServiceUpdateRepoProcedure,
193+ svc.UpdateRepo,
194+ connect.WithSchema(repoServiceMethods.ByName("UpdateRepo")),
195+ connect.WithHandlerOptions(opts...),
196+ )
197+ repoServiceDeleteRepoHandler := connect.NewUnaryHandler(
198+ RepoServiceDeleteRepoProcedure,
199+ svc.DeleteRepo,
200+ connect.WithSchema(repoServiceMethods.ByName("DeleteRepo")),
201+ connect.WithHandlerOptions(opts...),
202+ )
203+ return "/ermite.RepoService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
204+ switch r.URL.Path {
205+ case RepoServiceListReposProcedure:
206+ repoServiceListReposHandler.ServeHTTP(w, r)
207+ case RepoServiceGetRepoProcedure:
208+ repoServiceGetRepoHandler.ServeHTTP(w, r)
209+ case RepoServiceCreateRepoProcedure:
210+ repoServiceCreateRepoHandler.ServeHTTP(w, r)
211+ case RepoServiceUpdateRepoProcedure:
212+ repoServiceUpdateRepoHandler.ServeHTTP(w, r)
213+ case RepoServiceDeleteRepoProcedure:
214+ repoServiceDeleteRepoHandler.ServeHTTP(w, r)
215+ default:
216+ http.NotFound(w, r)
217+ }
218+ })
219+}
220+
221+// UnimplementedRepoServiceHandler returns CodeUnimplemented from all methods.
222+type UnimplementedRepoServiceHandler struct{}
223+
224+func (UnimplementedRepoServiceHandler) ListRepos(context.Context, *connect.Request[ermite.ListReposRequest]) (*connect.Response[ermite.ListReposResponse], error) {
225+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RepoService.ListRepos is not implemented"))
226+}
227+
228+func (UnimplementedRepoServiceHandler) GetRepo(context.Context, *connect.Request[ermite.GetRepoRequest]) (*connect.Response[ermite.GetRepoResponse], error) {
229+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RepoService.GetRepo is not implemented"))
230+}
231+
232+func (UnimplementedRepoServiceHandler) CreateRepo(context.Context, *connect.Request[ermite.CreateRepoRequest]) (*connect.Response[ermite.CreateRepoResponse], error) {
233+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RepoService.CreateRepo is not implemented"))
234+}
235+
236+func (UnimplementedRepoServiceHandler) UpdateRepo(context.Context, *connect.Request[ermite.UpdateRepoRequest]) (*connect.Response[ermite.UpdateRepoResponse], error) {
237+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RepoService.UpdateRepo is not implemented"))
238+}
239+
240+func (UnimplementedRepoServiceHandler) DeleteRepo(context.Context, *connect.Request[ermite.DeleteRepoRequest]) (*connect.Response[ermite.DeleteRepoResponse], error) {
241+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RepoService.DeleteRepo is not implemented"))
242+}
@@ -0,0 +1,242 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/repo.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+ // RepoServiceName is the fully-qualified name of the RepoService service.
27+ RepoServiceName = "ermite.RepoService"
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+ // RepoServiceListReposProcedure is the fully-qualified name of the RepoService's ListRepos RPC.
39+ RepoServiceListReposProcedure = "/ermite.RepoService/ListRepos"
40+ // RepoServiceGetRepoProcedure is the fully-qualified name of the RepoService's GetRepo RPC.
41+ RepoServiceGetRepoProcedure = "/ermite.RepoService/GetRepo"
42+ // RepoServiceCreateRepoProcedure is the fully-qualified name of the RepoService's CreateRepo RPC.
43+ RepoServiceCreateRepoProcedure = "/ermite.RepoService/CreateRepo"
44+ // RepoServiceUpdateRepoProcedure is the fully-qualified name of the RepoService's UpdateRepo RPC.
45+ RepoServiceUpdateRepoProcedure = "/ermite.RepoService/UpdateRepo"
46+ // RepoServiceDeleteRepoProcedure is the fully-qualified name of the RepoService's DeleteRepo RPC.
47+ RepoServiceDeleteRepoProcedure = "/ermite.RepoService/DeleteRepo"
48+)
49+
50+// RepoServiceClient is a client for the ermite.RepoService service.
51+type RepoServiceClient interface {
52+ // ListRepos lists the repositories the caller may see, ordered by name.
53+ ListRepos(context.Context, *connect.Request[ermite.ListReposRequest]) (*connect.Response[ermite.ListReposResponse], error)
54+ // GetRepo returns one repository. Fails with not_found if it does not exist
55+ // or is private and not readable by the caller.
56+ GetRepo(context.Context, *connect.Request[ermite.GetRepoRequest]) (*connect.Response[ermite.GetRepoResponse], error)
57+ // CreateRepo creates an empty repository. Needs the repo:write scope. Fails
58+ // with already_exists if the name is taken and invalid_argument if the name
59+ // is not valid.
60+ CreateRepo(context.Context, *connect.Request[ermite.CreateRepoRequest]) (*connect.Response[ermite.CreateRepoResponse], error)
61+ // UpdateRepo changes the fields named in update_mask. Needs the repo:admin
62+ // scope.
63+ UpdateRepo(context.Context, *connect.Request[ermite.UpdateRepoRequest]) (*connect.Response[ermite.UpdateRepoResponse], error)
64+ // DeleteRepo deletes a repository. Needs the repo:admin scope. The server
65+ // moves the data aside rather than destroying it; there is no undelete RPC.
66+ DeleteRepo(context.Context, *connect.Request[ermite.DeleteRepoRequest]) (*connect.Response[ermite.DeleteRepoResponse], error)
67+}
68+
69+// NewRepoServiceClient constructs a client for the ermite.RepoService service. By default, it uses
70+// the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends
71+// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or
72+// connect.WithGRPCWeb() options.
73+//
74+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
75+// http://api.acme.com or https://acme.com/grpc).
76+func NewRepoServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) RepoServiceClient {
77+ baseURL = strings.TrimRight(baseURL, "/")
78+ repoServiceMethods := ermite.File_ermite_repo_proto.Services().ByName("RepoService").Methods()
79+ return &repoServiceClient{
80+ listRepos: connect.NewClient[ermite.ListReposRequest, ermite.ListReposResponse](
81+ httpClient,
82+ baseURL+RepoServiceListReposProcedure,
83+ connect.WithSchema(repoServiceMethods.ByName("ListRepos")),
84+ connect.WithClientOptions(opts...),
85+ ),
86+ getRepo: connect.NewClient[ermite.GetRepoRequest, ermite.GetRepoResponse](
87+ httpClient,
88+ baseURL+RepoServiceGetRepoProcedure,
89+ connect.WithSchema(repoServiceMethods.ByName("GetRepo")),
90+ connect.WithClientOptions(opts...),
91+ ),
92+ createRepo: connect.NewClient[ermite.CreateRepoRequest, ermite.CreateRepoResponse](
93+ httpClient,
94+ baseURL+RepoServiceCreateRepoProcedure,
95+ connect.WithSchema(repoServiceMethods.ByName("CreateRepo")),
96+ connect.WithClientOptions(opts...),
97+ ),
98+ updateRepo: connect.NewClient[ermite.UpdateRepoRequest, ermite.UpdateRepoResponse](
99+ httpClient,
100+ baseURL+RepoServiceUpdateRepoProcedure,
101+ connect.WithSchema(repoServiceMethods.ByName("UpdateRepo")),
102+ connect.WithClientOptions(opts...),
103+ ),
104+ deleteRepo: connect.NewClient[ermite.DeleteRepoRequest, ermite.DeleteRepoResponse](
105+ httpClient,
106+ baseURL+RepoServiceDeleteRepoProcedure,
107+ connect.WithSchema(repoServiceMethods.ByName("DeleteRepo")),
108+ connect.WithClientOptions(opts...),
109+ ),
110+ }
111+}
112+
113+// repoServiceClient implements RepoServiceClient.
114+type repoServiceClient struct {
115+ listRepos *connect.Client[ermite.ListReposRequest, ermite.ListReposResponse]
116+ getRepo *connect.Client[ermite.GetRepoRequest, ermite.GetRepoResponse]
117+ createRepo *connect.Client[ermite.CreateRepoRequest, ermite.CreateRepoResponse]
118+ updateRepo *connect.Client[ermite.UpdateRepoRequest, ermite.UpdateRepoResponse]
119+ deleteRepo *connect.Client[ermite.DeleteRepoRequest, ermite.DeleteRepoResponse]
120+}
121+
122+// ListRepos calls ermite.RepoService.ListRepos.
123+func (c *repoServiceClient) ListRepos(ctx context.Context, req *connect.Request[ermite.ListReposRequest]) (*connect.Response[ermite.ListReposResponse], error) {
124+ return c.listRepos.CallUnary(ctx, req)
125+}
126+
127+// GetRepo calls ermite.RepoService.GetRepo.
128+func (c *repoServiceClient) GetRepo(ctx context.Context, req *connect.Request[ermite.GetRepoRequest]) (*connect.Response[ermite.GetRepoResponse], error) {
129+ return c.getRepo.CallUnary(ctx, req)
130+}
131+
132+// CreateRepo calls ermite.RepoService.CreateRepo.
133+func (c *repoServiceClient) CreateRepo(ctx context.Context, req *connect.Request[ermite.CreateRepoRequest]) (*connect.Response[ermite.CreateRepoResponse], error) {
134+ return c.createRepo.CallUnary(ctx, req)
135+}
136+
137+// UpdateRepo calls ermite.RepoService.UpdateRepo.
138+func (c *repoServiceClient) UpdateRepo(ctx context.Context, req *connect.Request[ermite.UpdateRepoRequest]) (*connect.Response[ermite.UpdateRepoResponse], error) {
139+ return c.updateRepo.CallUnary(ctx, req)
140+}
141+
142+// DeleteRepo calls ermite.RepoService.DeleteRepo.
143+func (c *repoServiceClient) DeleteRepo(ctx context.Context, req *connect.Request[ermite.DeleteRepoRequest]) (*connect.Response[ermite.DeleteRepoResponse], error) {
144+ return c.deleteRepo.CallUnary(ctx, req)
145+}
146+
147+// RepoServiceHandler is an implementation of the ermite.RepoService service.
148+type RepoServiceHandler interface {
149+ // ListRepos lists the repositories the caller may see, ordered by name.
150+ ListRepos(context.Context, *connect.Request[ermite.ListReposRequest]) (*connect.Response[ermite.ListReposResponse], error)
151+ // GetRepo returns one repository. Fails with not_found if it does not exist
152+ // or is private and not readable by the caller.
153+ GetRepo(context.Context, *connect.Request[ermite.GetRepoRequest]) (*connect.Response[ermite.GetRepoResponse], error)
154+ // CreateRepo creates an empty repository. Needs the repo:write scope. Fails
155+ // with already_exists if the name is taken and invalid_argument if the name
156+ // is not valid.
157+ CreateRepo(context.Context, *connect.Request[ermite.CreateRepoRequest]) (*connect.Response[ermite.CreateRepoResponse], error)
158+ // UpdateRepo changes the fields named in update_mask. Needs the repo:admin
159+ // scope.
160+ UpdateRepo(context.Context, *connect.Request[ermite.UpdateRepoRequest]) (*connect.Response[ermite.UpdateRepoResponse], error)
161+ // DeleteRepo deletes a repository. Needs the repo:admin scope. The server
162+ // moves the data aside rather than destroying it; there is no undelete RPC.
163+ DeleteRepo(context.Context, *connect.Request[ermite.DeleteRepoRequest]) (*connect.Response[ermite.DeleteRepoResponse], error)
164+}
165+
166+// NewRepoServiceHandler builds an HTTP handler from the service implementation. It returns the path
167+// on which to mount the handler and the handler itself.
168+//
169+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
170+// and JSON codecs. They also support gzip compression.
171+func NewRepoServiceHandler(svc RepoServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
172+ repoServiceMethods := ermite.File_ermite_repo_proto.Services().ByName("RepoService").Methods()
173+ repoServiceListReposHandler := connect.NewUnaryHandler(
174+ RepoServiceListReposProcedure,
175+ svc.ListRepos,
176+ connect.WithSchema(repoServiceMethods.ByName("ListRepos")),
177+ connect.WithHandlerOptions(opts...),
178+ )
179+ repoServiceGetRepoHandler := connect.NewUnaryHandler(
180+ RepoServiceGetRepoProcedure,
181+ svc.GetRepo,
182+ connect.WithSchema(repoServiceMethods.ByName("GetRepo")),
183+ connect.WithHandlerOptions(opts...),
184+ )
185+ repoServiceCreateRepoHandler := connect.NewUnaryHandler(
186+ RepoServiceCreateRepoProcedure,
187+ svc.CreateRepo,
188+ connect.WithSchema(repoServiceMethods.ByName("CreateRepo")),
189+ connect.WithHandlerOptions(opts...),
190+ )
191+ repoServiceUpdateRepoHandler := connect.NewUnaryHandler(
192+ RepoServiceUpdateRepoProcedure,
193+ svc.UpdateRepo,
194+ connect.WithSchema(repoServiceMethods.ByName("UpdateRepo")),
195+ connect.WithHandlerOptions(opts...),
196+ )
197+ repoServiceDeleteRepoHandler := connect.NewUnaryHandler(
198+ RepoServiceDeleteRepoProcedure,
199+ svc.DeleteRepo,
200+ connect.WithSchema(repoServiceMethods.ByName("DeleteRepo")),
201+ connect.WithHandlerOptions(opts...),
202+ )
203+ return "/ermite.RepoService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
204+ switch r.URL.Path {
205+ case RepoServiceListReposProcedure:
206+ repoServiceListReposHandler.ServeHTTP(w, r)
207+ case RepoServiceGetRepoProcedure:
208+ repoServiceGetRepoHandler.ServeHTTP(w, r)
209+ case RepoServiceCreateRepoProcedure:
210+ repoServiceCreateRepoHandler.ServeHTTP(w, r)
211+ case RepoServiceUpdateRepoProcedure:
212+ repoServiceUpdateRepoHandler.ServeHTTP(w, r)
213+ case RepoServiceDeleteRepoProcedure:
214+ repoServiceDeleteRepoHandler.ServeHTTP(w, r)
215+ default:
216+ http.NotFound(w, r)
217+ }
218+ })
219+}
220+
221+// UnimplementedRepoServiceHandler returns CodeUnimplemented from all methods.
222+type UnimplementedRepoServiceHandler struct{}
223+
224+func (UnimplementedRepoServiceHandler) ListRepos(context.Context, *connect.Request[ermite.ListReposRequest]) (*connect.Response[ermite.ListReposResponse], error) {
225+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RepoService.ListRepos is not implemented"))
226+}
227+
228+func (UnimplementedRepoServiceHandler) GetRepo(context.Context, *connect.Request[ermite.GetRepoRequest]) (*connect.Response[ermite.GetRepoResponse], error) {
229+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RepoService.GetRepo is not implemented"))
230+}
231+
232+func (UnimplementedRepoServiceHandler) CreateRepo(context.Context, *connect.Request[ermite.CreateRepoRequest]) (*connect.Response[ermite.CreateRepoResponse], error) {
233+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RepoService.CreateRepo is not implemented"))
234+}
235+
236+func (UnimplementedRepoServiceHandler) UpdateRepo(context.Context, *connect.Request[ermite.UpdateRepoRequest]) (*connect.Response[ermite.UpdateRepoResponse], error) {
237+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RepoService.UpdateRepo is not implemented"))
238+}
239+
240+func (UnimplementedRepoServiceHandler) DeleteRepo(context.Context, *connect.Request[ermite.DeleteRepoRequest]) (*connect.Response[ermite.DeleteRepoResponse], error) {
241+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RepoService.DeleteRepo is not implemented"))
242+}
A gen/ermite/ermiteconnect/server.connect.go +117 -0
@@ -0,0 +1,117 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/server.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+ // ServerServiceName is the fully-qualified name of the ServerService service.
27+ ServerServiceName = "ermite.ServerService"
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+ // ServerServiceGetVersionProcedure is the fully-qualified name of the ServerService's GetVersion
39+ // RPC.
40+ ServerServiceGetVersionProcedure = "/ermite.ServerService/GetVersion"
41+)
42+
43+// ServerServiceClient is a client for the ermite.ServerService service.
44+type ServerServiceClient interface {
45+ // GetVersion returns the server version and the optional capabilities of the
46+ // contract it implements. It needs no authentication, so a client can call
47+ // it first to check compatibility.
48+ GetVersion(context.Context, *connect.Request[ermite.GetVersionRequest]) (*connect.Response[ermite.GetVersionResponse], error)
49+}
50+
51+// NewServerServiceClient constructs a client for the ermite.ServerService service. By default, it
52+// uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends
53+// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or
54+// connect.WithGRPCWeb() options.
55+//
56+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
57+// http://api.acme.com or https://acme.com/grpc).
58+func NewServerServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) ServerServiceClient {
59+ baseURL = strings.TrimRight(baseURL, "/")
60+ serverServiceMethods := ermite.File_ermite_server_proto.Services().ByName("ServerService").Methods()
61+ return &serverServiceClient{
62+ getVersion: connect.NewClient[ermite.GetVersionRequest, ermite.GetVersionResponse](
63+ httpClient,
64+ baseURL+ServerServiceGetVersionProcedure,
65+ connect.WithSchema(serverServiceMethods.ByName("GetVersion")),
66+ connect.WithClientOptions(opts...),
67+ ),
68+ }
69+}
70+
71+// serverServiceClient implements ServerServiceClient.
72+type serverServiceClient struct {
73+ getVersion *connect.Client[ermite.GetVersionRequest, ermite.GetVersionResponse]
74+}
75+
76+// GetVersion calls ermite.ServerService.GetVersion.
77+func (c *serverServiceClient) GetVersion(ctx context.Context, req *connect.Request[ermite.GetVersionRequest]) (*connect.Response[ermite.GetVersionResponse], error) {
78+ return c.getVersion.CallUnary(ctx, req)
79+}
80+
81+// ServerServiceHandler is an implementation of the ermite.ServerService service.
82+type ServerServiceHandler interface {
83+ // GetVersion returns the server version and the optional capabilities of the
84+ // contract it implements. It needs no authentication, so a client can call
85+ // it first to check compatibility.
86+ GetVersion(context.Context, *connect.Request[ermite.GetVersionRequest]) (*connect.Response[ermite.GetVersionResponse], error)
87+}
88+
89+// NewServerServiceHandler builds an HTTP handler from the service implementation. It returns the
90+// path on which to mount the handler and the handler itself.
91+//
92+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
93+// and JSON codecs. They also support gzip compression.
94+func NewServerServiceHandler(svc ServerServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
95+ serverServiceMethods := ermite.File_ermite_server_proto.Services().ByName("ServerService").Methods()
96+ serverServiceGetVersionHandler := connect.NewUnaryHandler(
97+ ServerServiceGetVersionProcedure,
98+ svc.GetVersion,
99+ connect.WithSchema(serverServiceMethods.ByName("GetVersion")),
100+ connect.WithHandlerOptions(opts...),
101+ )
102+ return "/ermite.ServerService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
103+ switch r.URL.Path {
104+ case ServerServiceGetVersionProcedure:
105+ serverServiceGetVersionHandler.ServeHTTP(w, r)
106+ default:
107+ http.NotFound(w, r)
108+ }
109+ })
110+}
111+
112+// UnimplementedServerServiceHandler returns CodeUnimplemented from all methods.
113+type UnimplementedServerServiceHandler struct{}
114+
115+func (UnimplementedServerServiceHandler) GetVersion(context.Context, *connect.Request[ermite.GetVersionRequest]) (*connect.Response[ermite.GetVersionResponse], error) {
116+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.ServerService.GetVersion is not implemented"))
117+}
@@ -0,0 +1,117 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/server.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+ // ServerServiceName is the fully-qualified name of the ServerService service.
27+ ServerServiceName = "ermite.ServerService"
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+ // ServerServiceGetVersionProcedure is the fully-qualified name of the ServerService's GetVersion
39+ // RPC.
40+ ServerServiceGetVersionProcedure = "/ermite.ServerService/GetVersion"
41+)
42+
43+// ServerServiceClient is a client for the ermite.ServerService service.
44+type ServerServiceClient interface {
45+ // GetVersion returns the server version and the optional capabilities of the
46+ // contract it implements. It needs no authentication, so a client can call
47+ // it first to check compatibility.
48+ GetVersion(context.Context, *connect.Request[ermite.GetVersionRequest]) (*connect.Response[ermite.GetVersionResponse], error)
49+}
50+
51+// NewServerServiceClient constructs a client for the ermite.ServerService service. By default, it
52+// uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends
53+// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or
54+// connect.WithGRPCWeb() options.
55+//
56+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
57+// http://api.acme.com or https://acme.com/grpc).
58+func NewServerServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) ServerServiceClient {
59+ baseURL = strings.TrimRight(baseURL, "/")
60+ serverServiceMethods := ermite.File_ermite_server_proto.Services().ByName("ServerService").Methods()
61+ return &serverServiceClient{
62+ getVersion: connect.NewClient[ermite.GetVersionRequest, ermite.GetVersionResponse](
63+ httpClient,
64+ baseURL+ServerServiceGetVersionProcedure,
65+ connect.WithSchema(serverServiceMethods.ByName("GetVersion")),
66+ connect.WithClientOptions(opts...),
67+ ),
68+ }
69+}
70+
71+// serverServiceClient implements ServerServiceClient.
72+type serverServiceClient struct {
73+ getVersion *connect.Client[ermite.GetVersionRequest, ermite.GetVersionResponse]
74+}
75+
76+// GetVersion calls ermite.ServerService.GetVersion.
77+func (c *serverServiceClient) GetVersion(ctx context.Context, req *connect.Request[ermite.GetVersionRequest]) (*connect.Response[ermite.GetVersionResponse], error) {
78+ return c.getVersion.CallUnary(ctx, req)
79+}
80+
81+// ServerServiceHandler is an implementation of the ermite.ServerService service.
82+type ServerServiceHandler interface {
83+ // GetVersion returns the server version and the optional capabilities of the
84+ // contract it implements. It needs no authentication, so a client can call
85+ // it first to check compatibility.
86+ GetVersion(context.Context, *connect.Request[ermite.GetVersionRequest]) (*connect.Response[ermite.GetVersionResponse], error)
87+}
88+
89+// NewServerServiceHandler builds an HTTP handler from the service implementation. It returns the
90+// path on which to mount the handler and the handler itself.
91+//
92+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
93+// and JSON codecs. They also support gzip compression.
94+func NewServerServiceHandler(svc ServerServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
95+ serverServiceMethods := ermite.File_ermite_server_proto.Services().ByName("ServerService").Methods()
96+ serverServiceGetVersionHandler := connect.NewUnaryHandler(
97+ ServerServiceGetVersionProcedure,
98+ svc.GetVersion,
99+ connect.WithSchema(serverServiceMethods.ByName("GetVersion")),
100+ connect.WithHandlerOptions(opts...),
101+ )
102+ return "/ermite.ServerService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
103+ switch r.URL.Path {
104+ case ServerServiceGetVersionProcedure:
105+ serverServiceGetVersionHandler.ServeHTTP(w, r)
106+ default:
107+ http.NotFound(w, r)
108+ }
109+ })
110+}
111+
112+// UnimplementedServerServiceHandler returns CodeUnimplemented from all methods.
113+type UnimplementedServerServiceHandler struct{}
114+
115+func (UnimplementedServerServiceHandler) GetVersion(context.Context, *connect.Request[ermite.GetVersionRequest]) (*connect.Response[ermite.GetVersionResponse], error) {
116+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.ServerService.GetVersion is not implemented"))
117+}
A gen/ermite/ermiteconnect/token.connect.go +182 -0
@@ -0,0 +1,182 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/token.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+ // TokenServiceName is the fully-qualified name of the TokenService service.
27+ TokenServiceName = "ermite.TokenService"
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+ // TokenServiceCreateTokenProcedure is the fully-qualified name of the TokenService's CreateToken
39+ // RPC.
40+ TokenServiceCreateTokenProcedure = "/ermite.TokenService/CreateToken"
41+ // TokenServiceListTokensProcedure is the fully-qualified name of the TokenService's ListTokens RPC.
42+ TokenServiceListTokensProcedure = "/ermite.TokenService/ListTokens"
43+ // TokenServiceRevokeTokenProcedure is the fully-qualified name of the TokenService's RevokeToken
44+ // RPC.
45+ TokenServiceRevokeTokenProcedure = "/ermite.TokenService/RevokeToken"
46+)
47+
48+// TokenServiceClient is a client for the ermite.TokenService service.
49+type TokenServiceClient interface {
50+ // CreateToken creates a token and returns its secret. The secret is shown
51+ // only in this response and cannot be retrieved later. Fails with
52+ // permission_denied when the new token would exceed the caller's limits and
53+ // with invalid_argument when scopes is empty or contains SCOPE_UNSPECIFIED.
54+ CreateToken(context.Context, *connect.Request[ermite.CreateTokenRequest]) (*connect.Response[ermite.CreateTokenResponse], error)
55+ // ListTokens lists stored tokens, newest first.
56+ ListTokens(context.Context, *connect.Request[ermite.ListTokensRequest]) (*connect.Response[ermite.ListTokensResponse], error)
57+ // RevokeToken deletes a token; it stops working immediately. Fails with
58+ // not_found if the id is unknown.
59+ RevokeToken(context.Context, *connect.Request[ermite.RevokeTokenRequest]) (*connect.Response[ermite.RevokeTokenResponse], error)
60+}
61+
62+// NewTokenServiceClient constructs a client for the ermite.TokenService service. By default, it
63+// uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends
64+// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or
65+// connect.WithGRPCWeb() options.
66+//
67+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
68+// http://api.acme.com or https://acme.com/grpc).
69+func NewTokenServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) TokenServiceClient {
70+ baseURL = strings.TrimRight(baseURL, "/")
71+ tokenServiceMethods := ermite.File_ermite_token_proto.Services().ByName("TokenService").Methods()
72+ return &tokenServiceClient{
73+ createToken: connect.NewClient[ermite.CreateTokenRequest, ermite.CreateTokenResponse](
74+ httpClient,
75+ baseURL+TokenServiceCreateTokenProcedure,
76+ connect.WithSchema(tokenServiceMethods.ByName("CreateToken")),
77+ connect.WithClientOptions(opts...),
78+ ),
79+ listTokens: connect.NewClient[ermite.ListTokensRequest, ermite.ListTokensResponse](
80+ httpClient,
81+ baseURL+TokenServiceListTokensProcedure,
82+ connect.WithSchema(tokenServiceMethods.ByName("ListTokens")),
83+ connect.WithClientOptions(opts...),
84+ ),
85+ revokeToken: connect.NewClient[ermite.RevokeTokenRequest, ermite.RevokeTokenResponse](
86+ httpClient,
87+ baseURL+TokenServiceRevokeTokenProcedure,
88+ connect.WithSchema(tokenServiceMethods.ByName("RevokeToken")),
89+ connect.WithClientOptions(opts...),
90+ ),
91+ }
92+}
93+
94+// tokenServiceClient implements TokenServiceClient.
95+type tokenServiceClient struct {
96+ createToken *connect.Client[ermite.CreateTokenRequest, ermite.CreateTokenResponse]
97+ listTokens *connect.Client[ermite.ListTokensRequest, ermite.ListTokensResponse]
98+ revokeToken *connect.Client[ermite.RevokeTokenRequest, ermite.RevokeTokenResponse]
99+}
100+
101+// CreateToken calls ermite.TokenService.CreateToken.
102+func (c *tokenServiceClient) CreateToken(ctx context.Context, req *connect.Request[ermite.CreateTokenRequest]) (*connect.Response[ermite.CreateTokenResponse], error) {
103+ return c.createToken.CallUnary(ctx, req)
104+}
105+
106+// ListTokens calls ermite.TokenService.ListTokens.
107+func (c *tokenServiceClient) ListTokens(ctx context.Context, req *connect.Request[ermite.ListTokensRequest]) (*connect.Response[ermite.ListTokensResponse], error) {
108+ return c.listTokens.CallUnary(ctx, req)
109+}
110+
111+// RevokeToken calls ermite.TokenService.RevokeToken.
112+func (c *tokenServiceClient) RevokeToken(ctx context.Context, req *connect.Request[ermite.RevokeTokenRequest]) (*connect.Response[ermite.RevokeTokenResponse], error) {
113+ return c.revokeToken.CallUnary(ctx, req)
114+}
115+
116+// TokenServiceHandler is an implementation of the ermite.TokenService service.
117+type TokenServiceHandler interface {
118+ // CreateToken creates a token and returns its secret. The secret is shown
119+ // only in this response and cannot be retrieved later. Fails with
120+ // permission_denied when the new token would exceed the caller's limits and
121+ // with invalid_argument when scopes is empty or contains SCOPE_UNSPECIFIED.
122+ CreateToken(context.Context, *connect.Request[ermite.CreateTokenRequest]) (*connect.Response[ermite.CreateTokenResponse], error)
123+ // ListTokens lists stored tokens, newest first.
124+ ListTokens(context.Context, *connect.Request[ermite.ListTokensRequest]) (*connect.Response[ermite.ListTokensResponse], error)
125+ // RevokeToken deletes a token; it stops working immediately. Fails with
126+ // not_found if the id is unknown.
127+ RevokeToken(context.Context, *connect.Request[ermite.RevokeTokenRequest]) (*connect.Response[ermite.RevokeTokenResponse], error)
128+}
129+
130+// NewTokenServiceHandler builds an HTTP handler from the service implementation. It returns the
131+// path on which to mount the handler and the handler itself.
132+//
133+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
134+// and JSON codecs. They also support gzip compression.
135+func NewTokenServiceHandler(svc TokenServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
136+ tokenServiceMethods := ermite.File_ermite_token_proto.Services().ByName("TokenService").Methods()
137+ tokenServiceCreateTokenHandler := connect.NewUnaryHandler(
138+ TokenServiceCreateTokenProcedure,
139+ svc.CreateToken,
140+ connect.WithSchema(tokenServiceMethods.ByName("CreateToken")),
141+ connect.WithHandlerOptions(opts...),
142+ )
143+ tokenServiceListTokensHandler := connect.NewUnaryHandler(
144+ TokenServiceListTokensProcedure,
145+ svc.ListTokens,
146+ connect.WithSchema(tokenServiceMethods.ByName("ListTokens")),
147+ connect.WithHandlerOptions(opts...),
148+ )
149+ tokenServiceRevokeTokenHandler := connect.NewUnaryHandler(
150+ TokenServiceRevokeTokenProcedure,
151+ svc.RevokeToken,
152+ connect.WithSchema(tokenServiceMethods.ByName("RevokeToken")),
153+ connect.WithHandlerOptions(opts...),
154+ )
155+ return "/ermite.TokenService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
156+ switch r.URL.Path {
157+ case TokenServiceCreateTokenProcedure:
158+ tokenServiceCreateTokenHandler.ServeHTTP(w, r)
159+ case TokenServiceListTokensProcedure:
160+ tokenServiceListTokensHandler.ServeHTTP(w, r)
161+ case TokenServiceRevokeTokenProcedure:
162+ tokenServiceRevokeTokenHandler.ServeHTTP(w, r)
163+ default:
164+ http.NotFound(w, r)
165+ }
166+ })
167+}
168+
169+// UnimplementedTokenServiceHandler returns CodeUnimplemented from all methods.
170+type UnimplementedTokenServiceHandler struct{}
171+
172+func (UnimplementedTokenServiceHandler) CreateToken(context.Context, *connect.Request[ermite.CreateTokenRequest]) (*connect.Response[ermite.CreateTokenResponse], error) {
173+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.TokenService.CreateToken is not implemented"))
174+}
175+
176+func (UnimplementedTokenServiceHandler) ListTokens(context.Context, *connect.Request[ermite.ListTokensRequest]) (*connect.Response[ermite.ListTokensResponse], error) {
177+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.TokenService.ListTokens is not implemented"))
178+}
179+
180+func (UnimplementedTokenServiceHandler) RevokeToken(context.Context, *connect.Request[ermite.RevokeTokenRequest]) (*connect.Response[ermite.RevokeTokenResponse], error) {
181+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.TokenService.RevokeToken is not implemented"))
182+}
@@ -0,0 +1,182 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/token.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+ // TokenServiceName is the fully-qualified name of the TokenService service.
27+ TokenServiceName = "ermite.TokenService"
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+ // TokenServiceCreateTokenProcedure is the fully-qualified name of the TokenService's CreateToken
39+ // RPC.
40+ TokenServiceCreateTokenProcedure = "/ermite.TokenService/CreateToken"
41+ // TokenServiceListTokensProcedure is the fully-qualified name of the TokenService's ListTokens RPC.
42+ TokenServiceListTokensProcedure = "/ermite.TokenService/ListTokens"
43+ // TokenServiceRevokeTokenProcedure is the fully-qualified name of the TokenService's RevokeToken
44+ // RPC.
45+ TokenServiceRevokeTokenProcedure = "/ermite.TokenService/RevokeToken"
46+)
47+
48+// TokenServiceClient is a client for the ermite.TokenService service.
49+type TokenServiceClient interface {
50+ // CreateToken creates a token and returns its secret. The secret is shown
51+ // only in this response and cannot be retrieved later. Fails with
52+ // permission_denied when the new token would exceed the caller's limits and
53+ // with invalid_argument when scopes is empty or contains SCOPE_UNSPECIFIED.
54+ CreateToken(context.Context, *connect.Request[ermite.CreateTokenRequest]) (*connect.Response[ermite.CreateTokenResponse], error)
55+ // ListTokens lists stored tokens, newest first.
56+ ListTokens(context.Context, *connect.Request[ermite.ListTokensRequest]) (*connect.Response[ermite.ListTokensResponse], error)
57+ // RevokeToken deletes a token; it stops working immediately. Fails with
58+ // not_found if the id is unknown.
59+ RevokeToken(context.Context, *connect.Request[ermite.RevokeTokenRequest]) (*connect.Response[ermite.RevokeTokenResponse], error)
60+}
61+
62+// NewTokenServiceClient constructs a client for the ermite.TokenService service. By default, it
63+// uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends
64+// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or
65+// connect.WithGRPCWeb() options.
66+//
67+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
68+// http://api.acme.com or https://acme.com/grpc).
69+func NewTokenServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) TokenServiceClient {
70+ baseURL = strings.TrimRight(baseURL, "/")
71+ tokenServiceMethods := ermite.File_ermite_token_proto.Services().ByName("TokenService").Methods()
72+ return &tokenServiceClient{
73+ createToken: connect.NewClient[ermite.CreateTokenRequest, ermite.CreateTokenResponse](
74+ httpClient,
75+ baseURL+TokenServiceCreateTokenProcedure,
76+ connect.WithSchema(tokenServiceMethods.ByName("CreateToken")),
77+ connect.WithClientOptions(opts...),
78+ ),
79+ listTokens: connect.NewClient[ermite.ListTokensRequest, ermite.ListTokensResponse](
80+ httpClient,
81+ baseURL+TokenServiceListTokensProcedure,
82+ connect.WithSchema(tokenServiceMethods.ByName("ListTokens")),
83+ connect.WithClientOptions(opts...),
84+ ),
85+ revokeToken: connect.NewClient[ermite.RevokeTokenRequest, ermite.RevokeTokenResponse](
86+ httpClient,
87+ baseURL+TokenServiceRevokeTokenProcedure,
88+ connect.WithSchema(tokenServiceMethods.ByName("RevokeToken")),
89+ connect.WithClientOptions(opts...),
90+ ),
91+ }
92+}
93+
94+// tokenServiceClient implements TokenServiceClient.
95+type tokenServiceClient struct {
96+ createToken *connect.Client[ermite.CreateTokenRequest, ermite.CreateTokenResponse]
97+ listTokens *connect.Client[ermite.ListTokensRequest, ermite.ListTokensResponse]
98+ revokeToken *connect.Client[ermite.RevokeTokenRequest, ermite.RevokeTokenResponse]
99+}
100+
101+// CreateToken calls ermite.TokenService.CreateToken.
102+func (c *tokenServiceClient) CreateToken(ctx context.Context, req *connect.Request[ermite.CreateTokenRequest]) (*connect.Response[ermite.CreateTokenResponse], error) {
103+ return c.createToken.CallUnary(ctx, req)
104+}
105+
106+// ListTokens calls ermite.TokenService.ListTokens.
107+func (c *tokenServiceClient) ListTokens(ctx context.Context, req *connect.Request[ermite.ListTokensRequest]) (*connect.Response[ermite.ListTokensResponse], error) {
108+ return c.listTokens.CallUnary(ctx, req)
109+}
110+
111+// RevokeToken calls ermite.TokenService.RevokeToken.
112+func (c *tokenServiceClient) RevokeToken(ctx context.Context, req *connect.Request[ermite.RevokeTokenRequest]) (*connect.Response[ermite.RevokeTokenResponse], error) {
113+ return c.revokeToken.CallUnary(ctx, req)
114+}
115+
116+// TokenServiceHandler is an implementation of the ermite.TokenService service.
117+type TokenServiceHandler interface {
118+ // CreateToken creates a token and returns its secret. The secret is shown
119+ // only in this response and cannot be retrieved later. Fails with
120+ // permission_denied when the new token would exceed the caller's limits and
121+ // with invalid_argument when scopes is empty or contains SCOPE_UNSPECIFIED.
122+ CreateToken(context.Context, *connect.Request[ermite.CreateTokenRequest]) (*connect.Response[ermite.CreateTokenResponse], error)
123+ // ListTokens lists stored tokens, newest first.
124+ ListTokens(context.Context, *connect.Request[ermite.ListTokensRequest]) (*connect.Response[ermite.ListTokensResponse], error)
125+ // RevokeToken deletes a token; it stops working immediately. Fails with
126+ // not_found if the id is unknown.
127+ RevokeToken(context.Context, *connect.Request[ermite.RevokeTokenRequest]) (*connect.Response[ermite.RevokeTokenResponse], error)
128+}
129+
130+// NewTokenServiceHandler builds an HTTP handler from the service implementation. It returns the
131+// path on which to mount the handler and the handler itself.
132+//
133+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
134+// and JSON codecs. They also support gzip compression.
135+func NewTokenServiceHandler(svc TokenServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
136+ tokenServiceMethods := ermite.File_ermite_token_proto.Services().ByName("TokenService").Methods()
137+ tokenServiceCreateTokenHandler := connect.NewUnaryHandler(
138+ TokenServiceCreateTokenProcedure,
139+ svc.CreateToken,
140+ connect.WithSchema(tokenServiceMethods.ByName("CreateToken")),
141+ connect.WithHandlerOptions(opts...),
142+ )
143+ tokenServiceListTokensHandler := connect.NewUnaryHandler(
144+ TokenServiceListTokensProcedure,
145+ svc.ListTokens,
146+ connect.WithSchema(tokenServiceMethods.ByName("ListTokens")),
147+ connect.WithHandlerOptions(opts...),
148+ )
149+ tokenServiceRevokeTokenHandler := connect.NewUnaryHandler(
150+ TokenServiceRevokeTokenProcedure,
151+ svc.RevokeToken,
152+ connect.WithSchema(tokenServiceMethods.ByName("RevokeToken")),
153+ connect.WithHandlerOptions(opts...),
154+ )
155+ return "/ermite.TokenService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
156+ switch r.URL.Path {
157+ case TokenServiceCreateTokenProcedure:
158+ tokenServiceCreateTokenHandler.ServeHTTP(w, r)
159+ case TokenServiceListTokensProcedure:
160+ tokenServiceListTokensHandler.ServeHTTP(w, r)
161+ case TokenServiceRevokeTokenProcedure:
162+ tokenServiceRevokeTokenHandler.ServeHTTP(w, r)
163+ default:
164+ http.NotFound(w, r)
165+ }
166+ })
167+}
168+
169+// UnimplementedTokenServiceHandler returns CodeUnimplemented from all methods.
170+type UnimplementedTokenServiceHandler struct{}
171+
172+func (UnimplementedTokenServiceHandler) CreateToken(context.Context, *connect.Request[ermite.CreateTokenRequest]) (*connect.Response[ermite.CreateTokenResponse], error) {
173+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.TokenService.CreateToken is not implemented"))
174+}
175+
176+func (UnimplementedTokenServiceHandler) ListTokens(context.Context, *connect.Request[ermite.ListTokensRequest]) (*connect.Response[ermite.ListTokensResponse], error) {
177+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.TokenService.ListTokens is not implemented"))
178+}
179+
180+func (UnimplementedTokenServiceHandler) RevokeToken(context.Context, *connect.Request[ermite.RevokeTokenRequest]) (*connect.Response[ermite.RevokeTokenResponse], error) {
181+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.TokenService.RevokeToken is not implemented"))
182+}
A gen/ermite/event.pb.go +703 -0 generated file: collapsed
A gen/ermite/git.pb.go +2046 -0 generated file: collapsed
A gen/ermite/repo.pb.go +857 -0
@@ -0,0 +1,857 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-go. DO NOT EDIT.
4+// versions:
5+// protoc-gen-go v1.36.12
6+// protoc (unknown)
7+// source: ermite/repo.proto
8+
9+package ermite
10+
11+import (
12+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
13+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
14+ fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb"
15+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
16+ reflect "reflect"
17+ sync "sync"
18+ unsafe "unsafe"
19+)
20+
21+const (
22+ // Verify that this generated code is sufficiently up-to-date.
23+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
24+ // Verify that runtime/protoimpl is sufficiently up-to-date.
25+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
26+)
27+
28+// Visibility says who may read a repository.
29+type Visibility int32
30+
31+const (
32+ // Not set. In requests, the server applies its default (private on create,
33+ // unchanged on update). Never returned by the server.
34+ Visibility_VISIBILITY_UNSPECIFIED Visibility = 0
35+ // Anyone, including anonymous callers, may read the repository.
36+ Visibility_VISIBILITY_PUBLIC Visibility = 1
37+ // Only callers holding the repo:read scope on the repository may read it.
38+ // Everyone else gets not_found, never permission_denied.
39+ Visibility_VISIBILITY_PRIVATE Visibility = 2
40+)
41+
42+// Enum value maps for Visibility.
43+var (
44+ Visibility_name = map[int32]string{
45+ 0: "VISIBILITY_UNSPECIFIED",
46+ 1: "VISIBILITY_PUBLIC",
47+ 2: "VISIBILITY_PRIVATE",
48+ }
49+ Visibility_value = map[string]int32{
50+ "VISIBILITY_UNSPECIFIED": 0,
51+ "VISIBILITY_PUBLIC": 1,
52+ "VISIBILITY_PRIVATE": 2,
53+ }
54+)
55+
56+func (x Visibility) Enum() *Visibility {
57+ p := new(Visibility)
58+ *p = x
59+ return p
60+}
61+
62+func (x Visibility) String() string {
63+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
64+}
65+
66+func (Visibility) Descriptor() protoreflect.EnumDescriptor {
67+ return file_ermite_repo_proto_enumTypes[0].Descriptor()
68+}
69+
70+func (Visibility) Type() protoreflect.EnumType {
71+ return &file_ermite_repo_proto_enumTypes[0]
72+}
73+
74+func (x Visibility) Number() protoreflect.EnumNumber {
75+ return protoreflect.EnumNumber(x)
76+}
77+
78+// Deprecated: Use Visibility.Descriptor instead.
79+func (Visibility) EnumDescriptor() ([]byte, []int) {
80+ return file_ermite_repo_proto_rawDescGZIP(), []int{0}
81+}
82+
83+// Repo is the metadata of a repository. Git-owned state (refs, trees, history)
84+// is read through GitService.
85+type Repo struct {
86+ state protoimpl.MessageState `protogen:"open.v1"`
87+ // Name is the unique, lowercase repository name: 1-100 characters from
88+ // [a-z0-9._-], without a ".git" suffix. It is also the URL path: /<name>.
89+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
90+ // Description is a free one-line description. It may be empty.
91+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
92+ // Visibility is who may read the repository.
93+ Visibility Visibility `protobuf:"varint,3,opt,name=visibility,proto3,enum=ermite.Visibility" json:"visibility,omitempty"`
94+ // DefaultBranch is the short name of the branch HEAD points to, for example
95+ // "main". It is set even when the branch does not exist yet (empty
96+ // repository).
97+ DefaultBranch string `protobuf:"bytes,4,opt,name=default_branch,json=defaultBranch,proto3" json:"default_branch,omitempty"`
98+ // CreatedAt is when the repository was created.
99+ CreatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
100+ // PushedAt is the time of the last push. It is unset until the first push.
101+ PushedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=pushed_at,json=pushedAt,proto3" json:"pushed_at,omitempty"`
102+ unknownFields protoimpl.UnknownFields
103+ sizeCache protoimpl.SizeCache
104+}
105+
106+func (x *Repo) Reset() {
107+ *x = Repo{}
108+ mi := &file_ermite_repo_proto_msgTypes[0]
109+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
110+ ms.StoreMessageInfo(mi)
111+}
112+
113+func (x *Repo) String() string {
114+ return protoimpl.X.MessageStringOf(x)
115+}
116+
117+func (*Repo) ProtoMessage() {}
118+
119+func (x *Repo) ProtoReflect() protoreflect.Message {
120+ mi := &file_ermite_repo_proto_msgTypes[0]
121+ if x != nil {
122+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
123+ if ms.LoadMessageInfo() == nil {
124+ ms.StoreMessageInfo(mi)
125+ }
126+ return ms
127+ }
128+ return mi.MessageOf(x)
129+}
130+
131+// Deprecated: Use Repo.ProtoReflect.Descriptor instead.
132+func (*Repo) Descriptor() ([]byte, []int) {
133+ return file_ermite_repo_proto_rawDescGZIP(), []int{0}
134+}
135+
136+func (x *Repo) GetName() string {
137+ if x != nil {
138+ return x.Name
139+ }
140+ return ""
141+}
142+
143+func (x *Repo) GetDescription() string {
144+ if x != nil {
145+ return x.Description
146+ }
147+ return ""
148+}
149+
150+func (x *Repo) GetVisibility() Visibility {
151+ if x != nil {
152+ return x.Visibility
153+ }
154+ return Visibility_VISIBILITY_UNSPECIFIED
155+}
156+
157+func (x *Repo) GetDefaultBranch() string {
158+ if x != nil {
159+ return x.DefaultBranch
160+ }
161+ return ""
162+}
163+
164+func (x *Repo) GetCreatedAt() *timestamppb.Timestamp {
165+ if x != nil {
166+ return x.CreatedAt
167+ }
168+ return nil
169+}
170+
171+func (x *Repo) GetPushedAt() *timestamppb.Timestamp {
172+ if x != nil {
173+ return x.PushedAt
174+ }
175+ return nil
176+}
177+
178+// ListReposRequest selects a page of repositories.
179+type ListReposRequest struct {
180+ state protoimpl.MessageState `protogen:"open.v1"`
181+ // PageSize is the maximum number of repositories to return. 0 means the
182+ // server default; values above the server maximum are lowered to it.
183+ PageSize int32 `protobuf:"varint,1,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
184+ // PageToken is the next_page_token of a previous response, to get the page
185+ // after it. Empty for the first page.
186+ PageToken string `protobuf:"bytes,2,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
187+ unknownFields protoimpl.UnknownFields
188+ sizeCache protoimpl.SizeCache
189+}
190+
191+func (x *ListReposRequest) Reset() {
192+ *x = ListReposRequest{}
193+ mi := &file_ermite_repo_proto_msgTypes[1]
194+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
195+ ms.StoreMessageInfo(mi)
196+}
197+
198+func (x *ListReposRequest) String() string {
199+ return protoimpl.X.MessageStringOf(x)
200+}
201+
202+func (*ListReposRequest) ProtoMessage() {}
203+
204+func (x *ListReposRequest) ProtoReflect() protoreflect.Message {
205+ mi := &file_ermite_repo_proto_msgTypes[1]
206+ if x != nil {
207+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
208+ if ms.LoadMessageInfo() == nil {
209+ ms.StoreMessageInfo(mi)
210+ }
211+ return ms
212+ }
213+ return mi.MessageOf(x)
214+}
215+
216+// Deprecated: Use ListReposRequest.ProtoReflect.Descriptor instead.
217+func (*ListReposRequest) Descriptor() ([]byte, []int) {
218+ return file_ermite_repo_proto_rawDescGZIP(), []int{1}
219+}
220+
221+func (x *ListReposRequest) GetPageSize() int32 {
222+ if x != nil {
223+ return x.PageSize
224+ }
225+ return 0
226+}
227+
228+func (x *ListReposRequest) GetPageToken() string {
229+ if x != nil {
230+ return x.PageToken
231+ }
232+ return ""
233+}
234+
235+// ListReposResponse is one page of repositories.
236+type ListReposResponse struct {
237+ state protoimpl.MessageState `protogen:"open.v1"`
238+ // Repos are the repositories of this page, ordered by name.
239+ Repos []*Repo `protobuf:"bytes,1,rep,name=repos,proto3" json:"repos,omitempty"`
240+ // NextPageToken is passed as page_token to get the next page. Empty when
241+ // there is no next page.
242+ NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
243+ unknownFields protoimpl.UnknownFields
244+ sizeCache protoimpl.SizeCache
245+}
246+
247+func (x *ListReposResponse) Reset() {
248+ *x = ListReposResponse{}
249+ mi := &file_ermite_repo_proto_msgTypes[2]
250+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
251+ ms.StoreMessageInfo(mi)
252+}
253+
254+func (x *ListReposResponse) String() string {
255+ return protoimpl.X.MessageStringOf(x)
256+}
257+
258+func (*ListReposResponse) ProtoMessage() {}
259+
260+func (x *ListReposResponse) ProtoReflect() protoreflect.Message {
261+ mi := &file_ermite_repo_proto_msgTypes[2]
262+ if x != nil {
263+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
264+ if ms.LoadMessageInfo() == nil {
265+ ms.StoreMessageInfo(mi)
266+ }
267+ return ms
268+ }
269+ return mi.MessageOf(x)
270+}
271+
272+// Deprecated: Use ListReposResponse.ProtoReflect.Descriptor instead.
273+func (*ListReposResponse) Descriptor() ([]byte, []int) {
274+ return file_ermite_repo_proto_rawDescGZIP(), []int{2}
275+}
276+
277+func (x *ListReposResponse) GetRepos() []*Repo {
278+ if x != nil {
279+ return x.Repos
280+ }
281+ return nil
282+}
283+
284+func (x *ListReposResponse) GetNextPageToken() string {
285+ if x != nil {
286+ return x.NextPageToken
287+ }
288+ return ""
289+}
290+
291+// GetRepoRequest names the repository to read.
292+type GetRepoRequest struct {
293+ state protoimpl.MessageState `protogen:"open.v1"`
294+ // Repo is the repository name.
295+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
296+ unknownFields protoimpl.UnknownFields
297+ sizeCache protoimpl.SizeCache
298+}
299+
300+func (x *GetRepoRequest) Reset() {
301+ *x = GetRepoRequest{}
302+ mi := &file_ermite_repo_proto_msgTypes[3]
303+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
304+ ms.StoreMessageInfo(mi)
305+}
306+
307+func (x *GetRepoRequest) String() string {
308+ return protoimpl.X.MessageStringOf(x)
309+}
310+
311+func (*GetRepoRequest) ProtoMessage() {}
312+
313+func (x *GetRepoRequest) ProtoReflect() protoreflect.Message {
314+ mi := &file_ermite_repo_proto_msgTypes[3]
315+ if x != nil {
316+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
317+ if ms.LoadMessageInfo() == nil {
318+ ms.StoreMessageInfo(mi)
319+ }
320+ return ms
321+ }
322+ return mi.MessageOf(x)
323+}
324+
325+// Deprecated: Use GetRepoRequest.ProtoReflect.Descriptor instead.
326+func (*GetRepoRequest) Descriptor() ([]byte, []int) {
327+ return file_ermite_repo_proto_rawDescGZIP(), []int{3}
328+}
329+
330+func (x *GetRepoRequest) GetRepo() string {
331+ if x != nil {
332+ return x.Repo
333+ }
334+ return ""
335+}
336+
337+// GetRepoResponse holds the repository.
338+type GetRepoResponse struct {
339+ state protoimpl.MessageState `protogen:"open.v1"`
340+ // Repo is the repository metadata.
341+ Repo *Repo `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
342+ unknownFields protoimpl.UnknownFields
343+ sizeCache protoimpl.SizeCache
344+}
345+
346+func (x *GetRepoResponse) Reset() {
347+ *x = GetRepoResponse{}
348+ mi := &file_ermite_repo_proto_msgTypes[4]
349+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
350+ ms.StoreMessageInfo(mi)
351+}
352+
353+func (x *GetRepoResponse) String() string {
354+ return protoimpl.X.MessageStringOf(x)
355+}
356+
357+func (*GetRepoResponse) ProtoMessage() {}
358+
359+func (x *GetRepoResponse) ProtoReflect() protoreflect.Message {
360+ mi := &file_ermite_repo_proto_msgTypes[4]
361+ if x != nil {
362+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
363+ if ms.LoadMessageInfo() == nil {
364+ ms.StoreMessageInfo(mi)
365+ }
366+ return ms
367+ }
368+ return mi.MessageOf(x)
369+}
370+
371+// Deprecated: Use GetRepoResponse.ProtoReflect.Descriptor instead.
372+func (*GetRepoResponse) Descriptor() ([]byte, []int) {
373+ return file_ermite_repo_proto_rawDescGZIP(), []int{4}
374+}
375+
376+func (x *GetRepoResponse) GetRepo() *Repo {
377+ if x != nil {
378+ return x.Repo
379+ }
380+ return nil
381+}
382+
383+// CreateRepoRequest describes the repository to create.
384+type CreateRepoRequest struct {
385+ state protoimpl.MessageState `protogen:"open.v1"`
386+ // Name is the name of the new repository. Names are lowercase; an uppercase
387+ // name is rejected with invalid_argument.
388+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
389+ // Description is an optional one-line description.
390+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
391+ // Visibility of the new repository. VISIBILITY_UNSPECIFIED means private.
392+ Visibility Visibility `protobuf:"varint,3,opt,name=visibility,proto3,enum=ermite.Visibility" json:"visibility,omitempty"`
393+ unknownFields protoimpl.UnknownFields
394+ sizeCache protoimpl.SizeCache
395+}
396+
397+func (x *CreateRepoRequest) Reset() {
398+ *x = CreateRepoRequest{}
399+ mi := &file_ermite_repo_proto_msgTypes[5]
400+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
401+ ms.StoreMessageInfo(mi)
402+}
403+
404+func (x *CreateRepoRequest) String() string {
405+ return protoimpl.X.MessageStringOf(x)
406+}
407+
408+func (*CreateRepoRequest) ProtoMessage() {}
409+
410+func (x *CreateRepoRequest) ProtoReflect() protoreflect.Message {
411+ mi := &file_ermite_repo_proto_msgTypes[5]
412+ if x != nil {
413+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
414+ if ms.LoadMessageInfo() == nil {
415+ ms.StoreMessageInfo(mi)
416+ }
417+ return ms
418+ }
419+ return mi.MessageOf(x)
420+}
421+
422+// Deprecated: Use CreateRepoRequest.ProtoReflect.Descriptor instead.
423+func (*CreateRepoRequest) Descriptor() ([]byte, []int) {
424+ return file_ermite_repo_proto_rawDescGZIP(), []int{5}
425+}
426+
427+func (x *CreateRepoRequest) GetName() string {
428+ if x != nil {
429+ return x.Name
430+ }
431+ return ""
432+}
433+
434+func (x *CreateRepoRequest) GetDescription() string {
435+ if x != nil {
436+ return x.Description
437+ }
438+ return ""
439+}
440+
441+func (x *CreateRepoRequest) GetVisibility() Visibility {
442+ if x != nil {
443+ return x.Visibility
444+ }
445+ return Visibility_VISIBILITY_UNSPECIFIED
446+}
447+
448+// CreateRepoResponse holds the new repository.
449+type CreateRepoResponse struct {
450+ state protoimpl.MessageState `protogen:"open.v1"`
451+ // Repo is the created repository.
452+ Repo *Repo `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
453+ unknownFields protoimpl.UnknownFields
454+ sizeCache protoimpl.SizeCache
455+}
456+
457+func (x *CreateRepoResponse) Reset() {
458+ *x = CreateRepoResponse{}
459+ mi := &file_ermite_repo_proto_msgTypes[6]
460+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
461+ ms.StoreMessageInfo(mi)
462+}
463+
464+func (x *CreateRepoResponse) String() string {
465+ return protoimpl.X.MessageStringOf(x)
466+}
467+
468+func (*CreateRepoResponse) ProtoMessage() {}
469+
470+func (x *CreateRepoResponse) ProtoReflect() protoreflect.Message {
471+ mi := &file_ermite_repo_proto_msgTypes[6]
472+ if x != nil {
473+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
474+ if ms.LoadMessageInfo() == nil {
475+ ms.StoreMessageInfo(mi)
476+ }
477+ return ms
478+ }
479+ return mi.MessageOf(x)
480+}
481+
482+// Deprecated: Use CreateRepoResponse.ProtoReflect.Descriptor instead.
483+func (*CreateRepoResponse) Descriptor() ([]byte, []int) {
484+ return file_ermite_repo_proto_rawDescGZIP(), []int{6}
485+}
486+
487+func (x *CreateRepoResponse) GetRepo() *Repo {
488+ if x != nil {
489+ return x.Repo
490+ }
491+ return nil
492+}
493+
494+// UpdateRepoRequest changes some fields of a repository.
495+type UpdateRepoRequest struct {
496+ state protoimpl.MessageState `protogen:"open.v1"`
497+ // Repo is the name of the repository to change. Repositories cannot be
498+ // renamed.
499+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
500+ // Description is the new description. Used only if update_mask contains
501+ // "description"; an empty value then clears it.
502+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
503+ // Visibility is the new visibility. Used only if update_mask contains
504+ // "visibility"; it must not be VISIBILITY_UNSPECIFIED then.
505+ Visibility Visibility `protobuf:"varint,3,opt,name=visibility,proto3,enum=ermite.Visibility" json:"visibility,omitempty"`
506+ // DefaultBranch is the short name of the new default branch. Used only if
507+ // update_mask contains "default_branch". The branch must exist, otherwise
508+ // the call fails with failed_precondition.
509+ DefaultBranch string `protobuf:"bytes,4,opt,name=default_branch,json=defaultBranch,proto3" json:"default_branch,omitempty"`
510+ // UpdateMask lists the fields to change: "description", "visibility" and/or
511+ // "default_branch". It must not be empty. Other paths are invalid_argument.
512+ UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,5,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"`
513+ unknownFields protoimpl.UnknownFields
514+ sizeCache protoimpl.SizeCache
515+}
516+
517+func (x *UpdateRepoRequest) Reset() {
518+ *x = UpdateRepoRequest{}
519+ mi := &file_ermite_repo_proto_msgTypes[7]
520+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
521+ ms.StoreMessageInfo(mi)
522+}
523+
524+func (x *UpdateRepoRequest) String() string {
525+ return protoimpl.X.MessageStringOf(x)
526+}
527+
528+func (*UpdateRepoRequest) ProtoMessage() {}
529+
530+func (x *UpdateRepoRequest) ProtoReflect() protoreflect.Message {
531+ mi := &file_ermite_repo_proto_msgTypes[7]
532+ if x != nil {
533+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
534+ if ms.LoadMessageInfo() == nil {
535+ ms.StoreMessageInfo(mi)
536+ }
537+ return ms
538+ }
539+ return mi.MessageOf(x)
540+}
541+
542+// Deprecated: Use UpdateRepoRequest.ProtoReflect.Descriptor instead.
543+func (*UpdateRepoRequest) Descriptor() ([]byte, []int) {
544+ return file_ermite_repo_proto_rawDescGZIP(), []int{7}
545+}
546+
547+func (x *UpdateRepoRequest) GetRepo() string {
548+ if x != nil {
549+ return x.Repo
550+ }
551+ return ""
552+}
553+
554+func (x *UpdateRepoRequest) GetDescription() string {
555+ if x != nil {
556+ return x.Description
557+ }
558+ return ""
559+}
560+
561+func (x *UpdateRepoRequest) GetVisibility() Visibility {
562+ if x != nil {
563+ return x.Visibility
564+ }
565+ return Visibility_VISIBILITY_UNSPECIFIED
566+}
567+
568+func (x *UpdateRepoRequest) GetDefaultBranch() string {
569+ if x != nil {
570+ return x.DefaultBranch
571+ }
572+ return ""
573+}
574+
575+func (x *UpdateRepoRequest) GetUpdateMask() *fieldmaskpb.FieldMask {
576+ if x != nil {
577+ return x.UpdateMask
578+ }
579+ return nil
580+}
581+
582+// UpdateRepoResponse holds the repository after the update.
583+type UpdateRepoResponse struct {
584+ state protoimpl.MessageState `protogen:"open.v1"`
585+ // Repo is the updated repository.
586+ Repo *Repo `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
587+ unknownFields protoimpl.UnknownFields
588+ sizeCache protoimpl.SizeCache
589+}
590+
591+func (x *UpdateRepoResponse) Reset() {
592+ *x = UpdateRepoResponse{}
593+ mi := &file_ermite_repo_proto_msgTypes[8]
594+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
595+ ms.StoreMessageInfo(mi)
596+}
597+
598+func (x *UpdateRepoResponse) String() string {
599+ return protoimpl.X.MessageStringOf(x)
600+}
601+
602+func (*UpdateRepoResponse) ProtoMessage() {}
603+
604+func (x *UpdateRepoResponse) ProtoReflect() protoreflect.Message {
605+ mi := &file_ermite_repo_proto_msgTypes[8]
606+ if x != nil {
607+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
608+ if ms.LoadMessageInfo() == nil {
609+ ms.StoreMessageInfo(mi)
610+ }
611+ return ms
612+ }
613+ return mi.MessageOf(x)
614+}
615+
616+// Deprecated: Use UpdateRepoResponse.ProtoReflect.Descriptor instead.
617+func (*UpdateRepoResponse) Descriptor() ([]byte, []int) {
618+ return file_ermite_repo_proto_rawDescGZIP(), []int{8}
619+}
620+
621+func (x *UpdateRepoResponse) GetRepo() *Repo {
622+ if x != nil {
623+ return x.Repo
624+ }
625+ return nil
626+}
627+
628+// DeleteRepoRequest names the repository to delete.
629+type DeleteRepoRequest struct {
630+ state protoimpl.MessageState `protogen:"open.v1"`
631+ // Repo is the repository name.
632+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
633+ unknownFields protoimpl.UnknownFields
634+ sizeCache protoimpl.SizeCache
635+}
636+
637+func (x *DeleteRepoRequest) Reset() {
638+ *x = DeleteRepoRequest{}
639+ mi := &file_ermite_repo_proto_msgTypes[9]
640+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
641+ ms.StoreMessageInfo(mi)
642+}
643+
644+func (x *DeleteRepoRequest) String() string {
645+ return protoimpl.X.MessageStringOf(x)
646+}
647+
648+func (*DeleteRepoRequest) ProtoMessage() {}
649+
650+func (x *DeleteRepoRequest) ProtoReflect() protoreflect.Message {
651+ mi := &file_ermite_repo_proto_msgTypes[9]
652+ if x != nil {
653+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
654+ if ms.LoadMessageInfo() == nil {
655+ ms.StoreMessageInfo(mi)
656+ }
657+ return ms
658+ }
659+ return mi.MessageOf(x)
660+}
661+
662+// Deprecated: Use DeleteRepoRequest.ProtoReflect.Descriptor instead.
663+func (*DeleteRepoRequest) Descriptor() ([]byte, []int) {
664+ return file_ermite_repo_proto_rawDescGZIP(), []int{9}
665+}
666+
667+func (x *DeleteRepoRequest) GetRepo() string {
668+ if x != nil {
669+ return x.Repo
670+ }
671+ return ""
672+}
673+
674+// DeleteRepoResponse is empty.
675+type DeleteRepoResponse struct {
676+ state protoimpl.MessageState `protogen:"open.v1"`
677+ unknownFields protoimpl.UnknownFields
678+ sizeCache protoimpl.SizeCache
679+}
680+
681+func (x *DeleteRepoResponse) Reset() {
682+ *x = DeleteRepoResponse{}
683+ mi := &file_ermite_repo_proto_msgTypes[10]
684+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
685+ ms.StoreMessageInfo(mi)
686+}
687+
688+func (x *DeleteRepoResponse) String() string {
689+ return protoimpl.X.MessageStringOf(x)
690+}
691+
692+func (*DeleteRepoResponse) ProtoMessage() {}
693+
694+func (x *DeleteRepoResponse) ProtoReflect() protoreflect.Message {
695+ mi := &file_ermite_repo_proto_msgTypes[10]
696+ if x != nil {
697+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
698+ if ms.LoadMessageInfo() == nil {
699+ ms.StoreMessageInfo(mi)
700+ }
701+ return ms
702+ }
703+ return mi.MessageOf(x)
704+}
705+
706+// Deprecated: Use DeleteRepoResponse.ProtoReflect.Descriptor instead.
707+func (*DeleteRepoResponse) Descriptor() ([]byte, []int) {
708+ return file_ermite_repo_proto_rawDescGZIP(), []int{10}
709+}
710+
711+var File_ermite_repo_proto protoreflect.FileDescriptor
712+
713+const file_ermite_repo_proto_rawDesc = "" +
714+ "\n" +
715+ "\x11ermite/repo.proto\x12\x06ermite\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x8b\x02\n" +
716+ "\x04Repo\x12\x12\n" +
717+ "\x04name\x18\x01 \x01(\tR\x04name\x12 \n" +
718+ "\vdescription\x18\x02 \x01(\tR\vdescription\x122\n" +
719+ "\n" +
720+ "visibility\x18\x03 \x01(\x0e2\x12.ermite.VisibilityR\n" +
721+ "visibility\x12%\n" +
722+ "\x0edefault_branch\x18\x04 \x01(\tR\rdefaultBranch\x129\n" +
723+ "\n" +
724+ "created_at\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x127\n" +
725+ "\tpushed_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\bpushedAt\"N\n" +
726+ "\x10ListReposRequest\x12\x1b\n" +
727+ "\tpage_size\x18\x01 \x01(\x05R\bpageSize\x12\x1d\n" +
728+ "\n" +
729+ "page_token\x18\x02 \x01(\tR\tpageToken\"_\n" +
730+ "\x11ListReposResponse\x12\"\n" +
731+ "\x05repos\x18\x01 \x03(\v2\f.ermite.RepoR\x05repos\x12&\n" +
732+ "\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken\"$\n" +
733+ "\x0eGetRepoRequest\x12\x12\n" +
734+ "\x04repo\x18\x01 \x01(\tR\x04repo\"3\n" +
735+ "\x0fGetRepoResponse\x12 \n" +
736+ "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"}\n" +
737+ "\x11CreateRepoRequest\x12\x12\n" +
738+ "\x04name\x18\x01 \x01(\tR\x04name\x12 \n" +
739+ "\vdescription\x18\x02 \x01(\tR\vdescription\x122\n" +
740+ "\n" +
741+ "visibility\x18\x03 \x01(\x0e2\x12.ermite.VisibilityR\n" +
742+ "visibility\"6\n" +
743+ "\x12CreateRepoResponse\x12 \n" +
744+ "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"\xe1\x01\n" +
745+ "\x11UpdateRepoRequest\x12\x12\n" +
746+ "\x04repo\x18\x01 \x01(\tR\x04repo\x12 \n" +
747+ "\vdescription\x18\x02 \x01(\tR\vdescription\x122\n" +
748+ "\n" +
749+ "visibility\x18\x03 \x01(\x0e2\x12.ermite.VisibilityR\n" +
750+ "visibility\x12%\n" +
751+ "\x0edefault_branch\x18\x04 \x01(\tR\rdefaultBranch\x12;\n" +
752+ "\vupdate_mask\x18\x05 \x01(\v2\x1a.google.protobuf.FieldMaskR\n" +
753+ "updateMask\"6\n" +
754+ "\x12UpdateRepoResponse\x12 \n" +
755+ "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"'\n" +
756+ "\x11DeleteRepoRequest\x12\x12\n" +
757+ "\x04repo\x18\x01 \x01(\tR\x04repo\"\x14\n" +
758+ "\x12DeleteRepoResponse*W\n" +
759+ "\n" +
760+ "Visibility\x12\x1a\n" +
761+ "\x16VISIBILITY_UNSPECIFIED\x10\x00\x12\x15\n" +
762+ "\x11VISIBILITY_PUBLIC\x10\x01\x12\x16\n" +
763+ "\x12VISIBILITY_PRIVATE\x10\x022\xda\x02\n" +
764+ "\vRepoService\x12@\n" +
765+ "\tListRepos\x12\x18.ermite.ListReposRequest\x1a\x19.ermite.ListReposResponse\x12:\n" +
766+ "\aGetRepo\x12\x16.ermite.GetRepoRequest\x1a\x17.ermite.GetRepoResponse\x12C\n" +
767+ "\n" +
768+ "CreateRepo\x12\x19.ermite.CreateRepoRequest\x1a\x1a.ermite.CreateRepoResponse\x12C\n" +
769+ "\n" +
770+ "UpdateRepo\x12\x19.ermite.UpdateRepoRequest\x1a\x1a.ermite.UpdateRepoResponse\x12C\n" +
771+ "\n" +
772+ "DeleteRepo\x12\x19.ermite.DeleteRepoRequest\x1a\x1a.ermite.DeleteRepoResponseBp\n" +
773+ "\n" +
774+ "com.ermiteB\tRepoProtoP\x01Z\x1fbnema.dev/ermite-api/gen/ermite\xa2\x02\x03EXX\xaa\x02\x06Ermite\xca\x02\x06Ermite\xe2\x02\x12Ermite\\GPBMetadata\xea\x02\x06Ermiteb\x06proto3"
775+
776+var (
777+ file_ermite_repo_proto_rawDescOnce sync.Once
778+ file_ermite_repo_proto_rawDescData []byte
779+)
780+
781+func file_ermite_repo_proto_rawDescGZIP() []byte {
782+ file_ermite_repo_proto_rawDescOnce.Do(func() {
783+ file_ermite_repo_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ermite_repo_proto_rawDesc), len(file_ermite_repo_proto_rawDesc)))
784+ })
785+ return file_ermite_repo_proto_rawDescData
786+}
787+
788+var file_ermite_repo_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
789+var file_ermite_repo_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
790+var file_ermite_repo_proto_goTypes = []any{
791+ (Visibility)(0), // 0: ermite.Visibility
792+ (*Repo)(nil), // 1: ermite.Repo
793+ (*ListReposRequest)(nil), // 2: ermite.ListReposRequest
794+ (*ListReposResponse)(nil), // 3: ermite.ListReposResponse
795+ (*GetRepoRequest)(nil), // 4: ermite.GetRepoRequest
796+ (*GetRepoResponse)(nil), // 5: ermite.GetRepoResponse
797+ (*CreateRepoRequest)(nil), // 6: ermite.CreateRepoRequest
798+ (*CreateRepoResponse)(nil), // 7: ermite.CreateRepoResponse
799+ (*UpdateRepoRequest)(nil), // 8: ermite.UpdateRepoRequest
800+ (*UpdateRepoResponse)(nil), // 9: ermite.UpdateRepoResponse
801+ (*DeleteRepoRequest)(nil), // 10: ermite.DeleteRepoRequest
802+ (*DeleteRepoResponse)(nil), // 11: ermite.DeleteRepoResponse
803+ (*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp
804+ (*fieldmaskpb.FieldMask)(nil), // 13: google.protobuf.FieldMask
805+}
806+var file_ermite_repo_proto_depIdxs = []int32{
807+ 0, // 0: ermite.Repo.visibility:type_name -> ermite.Visibility
808+ 12, // 1: ermite.Repo.created_at:type_name -> google.protobuf.Timestamp
809+ 12, // 2: ermite.Repo.pushed_at:type_name -> google.protobuf.Timestamp
810+ 1, // 3: ermite.ListReposResponse.repos:type_name -> ermite.Repo
811+ 1, // 4: ermite.GetRepoResponse.repo:type_name -> ermite.Repo
812+ 0, // 5: ermite.CreateRepoRequest.visibility:type_name -> ermite.Visibility
813+ 1, // 6: ermite.CreateRepoResponse.repo:type_name -> ermite.Repo
814+ 0, // 7: ermite.UpdateRepoRequest.visibility:type_name -> ermite.Visibility
815+ 13, // 8: ermite.UpdateRepoRequest.update_mask:type_name -> google.protobuf.FieldMask
816+ 1, // 9: ermite.UpdateRepoResponse.repo:type_name -> ermite.Repo
817+ 2, // 10: ermite.RepoService.ListRepos:input_type -> ermite.ListReposRequest
818+ 4, // 11: ermite.RepoService.GetRepo:input_type -> ermite.GetRepoRequest
819+ 6, // 12: ermite.RepoService.CreateRepo:input_type -> ermite.CreateRepoRequest
820+ 8, // 13: ermite.RepoService.UpdateRepo:input_type -> ermite.UpdateRepoRequest
821+ 10, // 14: ermite.RepoService.DeleteRepo:input_type -> ermite.DeleteRepoRequest
822+ 3, // 15: ermite.RepoService.ListRepos:output_type -> ermite.ListReposResponse
823+ 5, // 16: ermite.RepoService.GetRepo:output_type -> ermite.GetRepoResponse
824+ 7, // 17: ermite.RepoService.CreateRepo:output_type -> ermite.CreateRepoResponse
825+ 9, // 18: ermite.RepoService.UpdateRepo:output_type -> ermite.UpdateRepoResponse
826+ 11, // 19: ermite.RepoService.DeleteRepo:output_type -> ermite.DeleteRepoResponse
827+ 15, // [15:20] is the sub-list for method output_type
828+ 10, // [10:15] is the sub-list for method input_type
829+ 10, // [10:10] is the sub-list for extension type_name
830+ 10, // [10:10] is the sub-list for extension extendee
831+ 0, // [0:10] is the sub-list for field type_name
832+}
833+
834+func init() { file_ermite_repo_proto_init() }
835+func file_ermite_repo_proto_init() {
836+ if File_ermite_repo_proto != nil {
837+ return
838+ }
839+ type x struct{}
840+ out := protoimpl.TypeBuilder{
841+ File: protoimpl.DescBuilder{
842+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
843+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_repo_proto_rawDesc), len(file_ermite_repo_proto_rawDesc)),
844+ NumEnums: 1,
845+ NumMessages: 11,
846+ NumExtensions: 0,
847+ NumServices: 1,
848+ },
849+ GoTypes: file_ermite_repo_proto_goTypes,
850+ DependencyIndexes: file_ermite_repo_proto_depIdxs,
851+ EnumInfos: file_ermite_repo_proto_enumTypes,
852+ MessageInfos: file_ermite_repo_proto_msgTypes,
853+ }.Build()
854+ File_ermite_repo_proto = out.File
855+ file_ermite_repo_proto_goTypes = nil
856+ file_ermite_repo_proto_depIdxs = nil
857+}
@@ -0,0 +1,857 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-go. DO NOT EDIT.
4+// versions:
5+// protoc-gen-go v1.36.12
6+// protoc (unknown)
7+// source: ermite/repo.proto
8+
9+package ermite
10+
11+import (
12+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
13+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
14+ fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb"
15+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
16+ reflect "reflect"
17+ sync "sync"
18+ unsafe "unsafe"
19+)
20+
21+const (
22+ // Verify that this generated code is sufficiently up-to-date.
23+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
24+ // Verify that runtime/protoimpl is sufficiently up-to-date.
25+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
26+)
27+
28+// Visibility says who may read a repository.
29+type Visibility int32
30+
31+const (
32+ // Not set. In requests, the server applies its default (private on create,
33+ // unchanged on update). Never returned by the server.
34+ Visibility_VISIBILITY_UNSPECIFIED Visibility = 0
35+ // Anyone, including anonymous callers, may read the repository.
36+ Visibility_VISIBILITY_PUBLIC Visibility = 1
37+ // Only callers holding the repo:read scope on the repository may read it.
38+ // Everyone else gets not_found, never permission_denied.
39+ Visibility_VISIBILITY_PRIVATE Visibility = 2
40+)
41+
42+// Enum value maps for Visibility.
43+var (
44+ Visibility_name = map[int32]string{
45+ 0: "VISIBILITY_UNSPECIFIED",
46+ 1: "VISIBILITY_PUBLIC",
47+ 2: "VISIBILITY_PRIVATE",
48+ }
49+ Visibility_value = map[string]int32{
50+ "VISIBILITY_UNSPECIFIED": 0,
51+ "VISIBILITY_PUBLIC": 1,
52+ "VISIBILITY_PRIVATE": 2,
53+ }
54+)
55+
56+func (x Visibility) Enum() *Visibility {
57+ p := new(Visibility)
58+ *p = x
59+ return p
60+}
61+
62+func (x Visibility) String() string {
63+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
64+}
65+
66+func (Visibility) Descriptor() protoreflect.EnumDescriptor {
67+ return file_ermite_repo_proto_enumTypes[0].Descriptor()
68+}
69+
70+func (Visibility) Type() protoreflect.EnumType {
71+ return &file_ermite_repo_proto_enumTypes[0]
72+}
73+
74+func (x Visibility) Number() protoreflect.EnumNumber {
75+ return protoreflect.EnumNumber(x)
76+}
77+
78+// Deprecated: Use Visibility.Descriptor instead.
79+func (Visibility) EnumDescriptor() ([]byte, []int) {
80+ return file_ermite_repo_proto_rawDescGZIP(), []int{0}
81+}
82+
83+// Repo is the metadata of a repository. Git-owned state (refs, trees, history)
84+// is read through GitService.
85+type Repo struct {
86+ state protoimpl.MessageState `protogen:"open.v1"`
87+ // Name is the unique, lowercase repository name: 1-100 characters from
88+ // [a-z0-9._-], without a ".git" suffix. It is also the URL path: /<name>.
89+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
90+ // Description is a free one-line description. It may be empty.
91+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
92+ // Visibility is who may read the repository.
93+ Visibility Visibility `protobuf:"varint,3,opt,name=visibility,proto3,enum=ermite.Visibility" json:"visibility,omitempty"`
94+ // DefaultBranch is the short name of the branch HEAD points to, for example
95+ // "main". It is set even when the branch does not exist yet (empty
96+ // repository).
97+ DefaultBranch string `protobuf:"bytes,4,opt,name=default_branch,json=defaultBranch,proto3" json:"default_branch,omitempty"`
98+ // CreatedAt is when the repository was created.
99+ CreatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
100+ // PushedAt is the time of the last push. It is unset until the first push.
101+ PushedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=pushed_at,json=pushedAt,proto3" json:"pushed_at,omitempty"`
102+ unknownFields protoimpl.UnknownFields
103+ sizeCache protoimpl.SizeCache
104+}
105+
106+func (x *Repo) Reset() {
107+ *x = Repo{}
108+ mi := &file_ermite_repo_proto_msgTypes[0]
109+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
110+ ms.StoreMessageInfo(mi)
111+}
112+
113+func (x *Repo) String() string {
114+ return protoimpl.X.MessageStringOf(x)
115+}
116+
117+func (*Repo) ProtoMessage() {}
118+
119+func (x *Repo) ProtoReflect() protoreflect.Message {
120+ mi := &file_ermite_repo_proto_msgTypes[0]
121+ if x != nil {
122+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
123+ if ms.LoadMessageInfo() == nil {
124+ ms.StoreMessageInfo(mi)
125+ }
126+ return ms
127+ }
128+ return mi.MessageOf(x)
129+}
130+
131+// Deprecated: Use Repo.ProtoReflect.Descriptor instead.
132+func (*Repo) Descriptor() ([]byte, []int) {
133+ return file_ermite_repo_proto_rawDescGZIP(), []int{0}
134+}
135+
136+func (x *Repo) GetName() string {
137+ if x != nil {
138+ return x.Name
139+ }
140+ return ""
141+}
142+
143+func (x *Repo) GetDescription() string {
144+ if x != nil {
145+ return x.Description
146+ }
147+ return ""
148+}
149+
150+func (x *Repo) GetVisibility() Visibility {
151+ if x != nil {
152+ return x.Visibility
153+ }
154+ return Visibility_VISIBILITY_UNSPECIFIED
155+}
156+
157+func (x *Repo) GetDefaultBranch() string {
158+ if x != nil {
159+ return x.DefaultBranch
160+ }
161+ return ""
162+}
163+
164+func (x *Repo) GetCreatedAt() *timestamppb.Timestamp {
165+ if x != nil {
166+ return x.CreatedAt
167+ }
168+ return nil
169+}
170+
171+func (x *Repo) GetPushedAt() *timestamppb.Timestamp {
172+ if x != nil {
173+ return x.PushedAt
174+ }
175+ return nil
176+}
177+
178+// ListReposRequest selects a page of repositories.
179+type ListReposRequest struct {
180+ state protoimpl.MessageState `protogen:"open.v1"`
181+ // PageSize is the maximum number of repositories to return. 0 means the
182+ // server default; values above the server maximum are lowered to it.
183+ PageSize int32 `protobuf:"varint,1,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
184+ // PageToken is the next_page_token of a previous response, to get the page
185+ // after it. Empty for the first page.
186+ PageToken string `protobuf:"bytes,2,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
187+ unknownFields protoimpl.UnknownFields
188+ sizeCache protoimpl.SizeCache
189+}
190+
191+func (x *ListReposRequest) Reset() {
192+ *x = ListReposRequest{}
193+ mi := &file_ermite_repo_proto_msgTypes[1]
194+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
195+ ms.StoreMessageInfo(mi)
196+}
197+
198+func (x *ListReposRequest) String() string {
199+ return protoimpl.X.MessageStringOf(x)
200+}
201+
202+func (*ListReposRequest) ProtoMessage() {}
203+
204+func (x *ListReposRequest) ProtoReflect() protoreflect.Message {
205+ mi := &file_ermite_repo_proto_msgTypes[1]
206+ if x != nil {
207+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
208+ if ms.LoadMessageInfo() == nil {
209+ ms.StoreMessageInfo(mi)
210+ }
211+ return ms
212+ }
213+ return mi.MessageOf(x)
214+}
215+
216+// Deprecated: Use ListReposRequest.ProtoReflect.Descriptor instead.
217+func (*ListReposRequest) Descriptor() ([]byte, []int) {
218+ return file_ermite_repo_proto_rawDescGZIP(), []int{1}
219+}
220+
221+func (x *ListReposRequest) GetPageSize() int32 {
222+ if x != nil {
223+ return x.PageSize
224+ }
225+ return 0
226+}
227+
228+func (x *ListReposRequest) GetPageToken() string {
229+ if x != nil {
230+ return x.PageToken
231+ }
232+ return ""
233+}
234+
235+// ListReposResponse is one page of repositories.
236+type ListReposResponse struct {
237+ state protoimpl.MessageState `protogen:"open.v1"`
238+ // Repos are the repositories of this page, ordered by name.
239+ Repos []*Repo `protobuf:"bytes,1,rep,name=repos,proto3" json:"repos,omitempty"`
240+ // NextPageToken is passed as page_token to get the next page. Empty when
241+ // there is no next page.
242+ NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
243+ unknownFields protoimpl.UnknownFields
244+ sizeCache protoimpl.SizeCache
245+}
246+
247+func (x *ListReposResponse) Reset() {
248+ *x = ListReposResponse{}
249+ mi := &file_ermite_repo_proto_msgTypes[2]
250+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
251+ ms.StoreMessageInfo(mi)
252+}
253+
254+func (x *ListReposResponse) String() string {
255+ return protoimpl.X.MessageStringOf(x)
256+}
257+
258+func (*ListReposResponse) ProtoMessage() {}
259+
260+func (x *ListReposResponse) ProtoReflect() protoreflect.Message {
261+ mi := &file_ermite_repo_proto_msgTypes[2]
262+ if x != nil {
263+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
264+ if ms.LoadMessageInfo() == nil {
265+ ms.StoreMessageInfo(mi)
266+ }
267+ return ms
268+ }
269+ return mi.MessageOf(x)
270+}
271+
272+// Deprecated: Use ListReposResponse.ProtoReflect.Descriptor instead.
273+func (*ListReposResponse) Descriptor() ([]byte, []int) {
274+ return file_ermite_repo_proto_rawDescGZIP(), []int{2}
275+}
276+
277+func (x *ListReposResponse) GetRepos() []*Repo {
278+ if x != nil {
279+ return x.Repos
280+ }
281+ return nil
282+}
283+
284+func (x *ListReposResponse) GetNextPageToken() string {
285+ if x != nil {
286+ return x.NextPageToken
287+ }
288+ return ""
289+}
290+
291+// GetRepoRequest names the repository to read.
292+type GetRepoRequest struct {
293+ state protoimpl.MessageState `protogen:"open.v1"`
294+ // Repo is the repository name.
295+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
296+ unknownFields protoimpl.UnknownFields
297+ sizeCache protoimpl.SizeCache
298+}
299+
300+func (x *GetRepoRequest) Reset() {
301+ *x = GetRepoRequest{}
302+ mi := &file_ermite_repo_proto_msgTypes[3]
303+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
304+ ms.StoreMessageInfo(mi)
305+}
306+
307+func (x *GetRepoRequest) String() string {
308+ return protoimpl.X.MessageStringOf(x)
309+}
310+
311+func (*GetRepoRequest) ProtoMessage() {}
312+
313+func (x *GetRepoRequest) ProtoReflect() protoreflect.Message {
314+ mi := &file_ermite_repo_proto_msgTypes[3]
315+ if x != nil {
316+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
317+ if ms.LoadMessageInfo() == nil {
318+ ms.StoreMessageInfo(mi)
319+ }
320+ return ms
321+ }
322+ return mi.MessageOf(x)
323+}
324+
325+// Deprecated: Use GetRepoRequest.ProtoReflect.Descriptor instead.
326+func (*GetRepoRequest) Descriptor() ([]byte, []int) {
327+ return file_ermite_repo_proto_rawDescGZIP(), []int{3}
328+}
329+
330+func (x *GetRepoRequest) GetRepo() string {
331+ if x != nil {
332+ return x.Repo
333+ }
334+ return ""
335+}
336+
337+// GetRepoResponse holds the repository.
338+type GetRepoResponse struct {
339+ state protoimpl.MessageState `protogen:"open.v1"`
340+ // Repo is the repository metadata.
341+ Repo *Repo `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
342+ unknownFields protoimpl.UnknownFields
343+ sizeCache protoimpl.SizeCache
344+}
345+
346+func (x *GetRepoResponse) Reset() {
347+ *x = GetRepoResponse{}
348+ mi := &file_ermite_repo_proto_msgTypes[4]
349+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
350+ ms.StoreMessageInfo(mi)
351+}
352+
353+func (x *GetRepoResponse) String() string {
354+ return protoimpl.X.MessageStringOf(x)
355+}
356+
357+func (*GetRepoResponse) ProtoMessage() {}
358+
359+func (x *GetRepoResponse) ProtoReflect() protoreflect.Message {
360+ mi := &file_ermite_repo_proto_msgTypes[4]
361+ if x != nil {
362+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
363+ if ms.LoadMessageInfo() == nil {
364+ ms.StoreMessageInfo(mi)
365+ }
366+ return ms
367+ }
368+ return mi.MessageOf(x)
369+}
370+
371+// Deprecated: Use GetRepoResponse.ProtoReflect.Descriptor instead.
372+func (*GetRepoResponse) Descriptor() ([]byte, []int) {
373+ return file_ermite_repo_proto_rawDescGZIP(), []int{4}
374+}
375+
376+func (x *GetRepoResponse) GetRepo() *Repo {
377+ if x != nil {
378+ return x.Repo
379+ }
380+ return nil
381+}
382+
383+// CreateRepoRequest describes the repository to create.
384+type CreateRepoRequest struct {
385+ state protoimpl.MessageState `protogen:"open.v1"`
386+ // Name is the name of the new repository. Names are lowercase; an uppercase
387+ // name is rejected with invalid_argument.
388+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
389+ // Description is an optional one-line description.
390+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
391+ // Visibility of the new repository. VISIBILITY_UNSPECIFIED means private.
392+ Visibility Visibility `protobuf:"varint,3,opt,name=visibility,proto3,enum=ermite.Visibility" json:"visibility,omitempty"`
393+ unknownFields protoimpl.UnknownFields
394+ sizeCache protoimpl.SizeCache
395+}
396+
397+func (x *CreateRepoRequest) Reset() {
398+ *x = CreateRepoRequest{}
399+ mi := &file_ermite_repo_proto_msgTypes[5]
400+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
401+ ms.StoreMessageInfo(mi)
402+}
403+
404+func (x *CreateRepoRequest) String() string {
405+ return protoimpl.X.MessageStringOf(x)
406+}
407+
408+func (*CreateRepoRequest) ProtoMessage() {}
409+
410+func (x *CreateRepoRequest) ProtoReflect() protoreflect.Message {
411+ mi := &file_ermite_repo_proto_msgTypes[5]
412+ if x != nil {
413+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
414+ if ms.LoadMessageInfo() == nil {
415+ ms.StoreMessageInfo(mi)
416+ }
417+ return ms
418+ }
419+ return mi.MessageOf(x)
420+}
421+
422+// Deprecated: Use CreateRepoRequest.ProtoReflect.Descriptor instead.
423+func (*CreateRepoRequest) Descriptor() ([]byte, []int) {
424+ return file_ermite_repo_proto_rawDescGZIP(), []int{5}
425+}
426+
427+func (x *CreateRepoRequest) GetName() string {
428+ if x != nil {
429+ return x.Name
430+ }
431+ return ""
432+}
433+
434+func (x *CreateRepoRequest) GetDescription() string {
435+ if x != nil {
436+ return x.Description
437+ }
438+ return ""
439+}
440+
441+func (x *CreateRepoRequest) GetVisibility() Visibility {
442+ if x != nil {
443+ return x.Visibility
444+ }
445+ return Visibility_VISIBILITY_UNSPECIFIED
446+}
447+
448+// CreateRepoResponse holds the new repository.
449+type CreateRepoResponse struct {
450+ state protoimpl.MessageState `protogen:"open.v1"`
451+ // Repo is the created repository.
452+ Repo *Repo `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
453+ unknownFields protoimpl.UnknownFields
454+ sizeCache protoimpl.SizeCache
455+}
456+
457+func (x *CreateRepoResponse) Reset() {
458+ *x = CreateRepoResponse{}
459+ mi := &file_ermite_repo_proto_msgTypes[6]
460+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
461+ ms.StoreMessageInfo(mi)
462+}
463+
464+func (x *CreateRepoResponse) String() string {
465+ return protoimpl.X.MessageStringOf(x)
466+}
467+
468+func (*CreateRepoResponse) ProtoMessage() {}
469+
470+func (x *CreateRepoResponse) ProtoReflect() protoreflect.Message {
471+ mi := &file_ermite_repo_proto_msgTypes[6]
472+ if x != nil {
473+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
474+ if ms.LoadMessageInfo() == nil {
475+ ms.StoreMessageInfo(mi)
476+ }
477+ return ms
478+ }
479+ return mi.MessageOf(x)
480+}
481+
482+// Deprecated: Use CreateRepoResponse.ProtoReflect.Descriptor instead.
483+func (*CreateRepoResponse) Descriptor() ([]byte, []int) {
484+ return file_ermite_repo_proto_rawDescGZIP(), []int{6}
485+}
486+
487+func (x *CreateRepoResponse) GetRepo() *Repo {
488+ if x != nil {
489+ return x.Repo
490+ }
491+ return nil
492+}
493+
494+// UpdateRepoRequest changes some fields of a repository.
495+type UpdateRepoRequest struct {
496+ state protoimpl.MessageState `protogen:"open.v1"`
497+ // Repo is the name of the repository to change. Repositories cannot be
498+ // renamed.
499+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
500+ // Description is the new description. Used only if update_mask contains
501+ // "description"; an empty value then clears it.
502+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
503+ // Visibility is the new visibility. Used only if update_mask contains
504+ // "visibility"; it must not be VISIBILITY_UNSPECIFIED then.
505+ Visibility Visibility `protobuf:"varint,3,opt,name=visibility,proto3,enum=ermite.Visibility" json:"visibility,omitempty"`
506+ // DefaultBranch is the short name of the new default branch. Used only if
507+ // update_mask contains "default_branch". The branch must exist, otherwise
508+ // the call fails with failed_precondition.
509+ DefaultBranch string `protobuf:"bytes,4,opt,name=default_branch,json=defaultBranch,proto3" json:"default_branch,omitempty"`
510+ // UpdateMask lists the fields to change: "description", "visibility" and/or
511+ // "default_branch". It must not be empty. Other paths are invalid_argument.
512+ UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,5,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"`
513+ unknownFields protoimpl.UnknownFields
514+ sizeCache protoimpl.SizeCache
515+}
516+
517+func (x *UpdateRepoRequest) Reset() {
518+ *x = UpdateRepoRequest{}
519+ mi := &file_ermite_repo_proto_msgTypes[7]
520+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
521+ ms.StoreMessageInfo(mi)
522+}
523+
524+func (x *UpdateRepoRequest) String() string {
525+ return protoimpl.X.MessageStringOf(x)
526+}
527+
528+func (*UpdateRepoRequest) ProtoMessage() {}
529+
530+func (x *UpdateRepoRequest) ProtoReflect() protoreflect.Message {
531+ mi := &file_ermite_repo_proto_msgTypes[7]
532+ if x != nil {
533+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
534+ if ms.LoadMessageInfo() == nil {
535+ ms.StoreMessageInfo(mi)
536+ }
537+ return ms
538+ }
539+ return mi.MessageOf(x)
540+}
541+
542+// Deprecated: Use UpdateRepoRequest.ProtoReflect.Descriptor instead.
543+func (*UpdateRepoRequest) Descriptor() ([]byte, []int) {
544+ return file_ermite_repo_proto_rawDescGZIP(), []int{7}
545+}
546+
547+func (x *UpdateRepoRequest) GetRepo() string {
548+ if x != nil {
549+ return x.Repo
550+ }
551+ return ""
552+}
553+
554+func (x *UpdateRepoRequest) GetDescription() string {
555+ if x != nil {
556+ return x.Description
557+ }
558+ return ""
559+}
560+
561+func (x *UpdateRepoRequest) GetVisibility() Visibility {
562+ if x != nil {
563+ return x.Visibility
564+ }
565+ return Visibility_VISIBILITY_UNSPECIFIED
566+}
567+
568+func (x *UpdateRepoRequest) GetDefaultBranch() string {
569+ if x != nil {
570+ return x.DefaultBranch
571+ }
572+ return ""
573+}
574+
575+func (x *UpdateRepoRequest) GetUpdateMask() *fieldmaskpb.FieldMask {
576+ if x != nil {
577+ return x.UpdateMask
578+ }
579+ return nil
580+}
581+
582+// UpdateRepoResponse holds the repository after the update.
583+type UpdateRepoResponse struct {
584+ state protoimpl.MessageState `protogen:"open.v1"`
585+ // Repo is the updated repository.
586+ Repo *Repo `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
587+ unknownFields protoimpl.UnknownFields
588+ sizeCache protoimpl.SizeCache
589+}
590+
591+func (x *UpdateRepoResponse) Reset() {
592+ *x = UpdateRepoResponse{}
593+ mi := &file_ermite_repo_proto_msgTypes[8]
594+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
595+ ms.StoreMessageInfo(mi)
596+}
597+
598+func (x *UpdateRepoResponse) String() string {
599+ return protoimpl.X.MessageStringOf(x)
600+}
601+
602+func (*UpdateRepoResponse) ProtoMessage() {}
603+
604+func (x *UpdateRepoResponse) ProtoReflect() protoreflect.Message {
605+ mi := &file_ermite_repo_proto_msgTypes[8]
606+ if x != nil {
607+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
608+ if ms.LoadMessageInfo() == nil {
609+ ms.StoreMessageInfo(mi)
610+ }
611+ return ms
612+ }
613+ return mi.MessageOf(x)
614+}
615+
616+// Deprecated: Use UpdateRepoResponse.ProtoReflect.Descriptor instead.
617+func (*UpdateRepoResponse) Descriptor() ([]byte, []int) {
618+ return file_ermite_repo_proto_rawDescGZIP(), []int{8}
619+}
620+
621+func (x *UpdateRepoResponse) GetRepo() *Repo {
622+ if x != nil {
623+ return x.Repo
624+ }
625+ return nil
626+}
627+
628+// DeleteRepoRequest names the repository to delete.
629+type DeleteRepoRequest struct {
630+ state protoimpl.MessageState `protogen:"open.v1"`
631+ // Repo is the repository name.
632+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
633+ unknownFields protoimpl.UnknownFields
634+ sizeCache protoimpl.SizeCache
635+}
636+
637+func (x *DeleteRepoRequest) Reset() {
638+ *x = DeleteRepoRequest{}
639+ mi := &file_ermite_repo_proto_msgTypes[9]
640+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
641+ ms.StoreMessageInfo(mi)
642+}
643+
644+func (x *DeleteRepoRequest) String() string {
645+ return protoimpl.X.MessageStringOf(x)
646+}
647+
648+func (*DeleteRepoRequest) ProtoMessage() {}
649+
650+func (x *DeleteRepoRequest) ProtoReflect() protoreflect.Message {
651+ mi := &file_ermite_repo_proto_msgTypes[9]
652+ if x != nil {
653+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
654+ if ms.LoadMessageInfo() == nil {
655+ ms.StoreMessageInfo(mi)
656+ }
657+ return ms
658+ }
659+ return mi.MessageOf(x)
660+}
661+
662+// Deprecated: Use DeleteRepoRequest.ProtoReflect.Descriptor instead.
663+func (*DeleteRepoRequest) Descriptor() ([]byte, []int) {
664+ return file_ermite_repo_proto_rawDescGZIP(), []int{9}
665+}
666+
667+func (x *DeleteRepoRequest) GetRepo() string {
668+ if x != nil {
669+ return x.Repo
670+ }
671+ return ""
672+}
673+
674+// DeleteRepoResponse is empty.
675+type DeleteRepoResponse struct {
676+ state protoimpl.MessageState `protogen:"open.v1"`
677+ unknownFields protoimpl.UnknownFields
678+ sizeCache protoimpl.SizeCache
679+}
680+
681+func (x *DeleteRepoResponse) Reset() {
682+ *x = DeleteRepoResponse{}
683+ mi := &file_ermite_repo_proto_msgTypes[10]
684+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
685+ ms.StoreMessageInfo(mi)
686+}
687+
688+func (x *DeleteRepoResponse) String() string {
689+ return protoimpl.X.MessageStringOf(x)
690+}
691+
692+func (*DeleteRepoResponse) ProtoMessage() {}
693+
694+func (x *DeleteRepoResponse) ProtoReflect() protoreflect.Message {
695+ mi := &file_ermite_repo_proto_msgTypes[10]
696+ if x != nil {
697+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
698+ if ms.LoadMessageInfo() == nil {
699+ ms.StoreMessageInfo(mi)
700+ }
701+ return ms
702+ }
703+ return mi.MessageOf(x)
704+}
705+
706+// Deprecated: Use DeleteRepoResponse.ProtoReflect.Descriptor instead.
707+func (*DeleteRepoResponse) Descriptor() ([]byte, []int) {
708+ return file_ermite_repo_proto_rawDescGZIP(), []int{10}
709+}
710+
711+var File_ermite_repo_proto protoreflect.FileDescriptor
712+
713+const file_ermite_repo_proto_rawDesc = "" +
714+ "\n" +
715+ "\x11ermite/repo.proto\x12\x06ermite\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x8b\x02\n" +
716+ "\x04Repo\x12\x12\n" +
717+ "\x04name\x18\x01 \x01(\tR\x04name\x12 \n" +
718+ "\vdescription\x18\x02 \x01(\tR\vdescription\x122\n" +
719+ "\n" +
720+ "visibility\x18\x03 \x01(\x0e2\x12.ermite.VisibilityR\n" +
721+ "visibility\x12%\n" +
722+ "\x0edefault_branch\x18\x04 \x01(\tR\rdefaultBranch\x129\n" +
723+ "\n" +
724+ "created_at\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x127\n" +
725+ "\tpushed_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\bpushedAt\"N\n" +
726+ "\x10ListReposRequest\x12\x1b\n" +
727+ "\tpage_size\x18\x01 \x01(\x05R\bpageSize\x12\x1d\n" +
728+ "\n" +
729+ "page_token\x18\x02 \x01(\tR\tpageToken\"_\n" +
730+ "\x11ListReposResponse\x12\"\n" +
731+ "\x05repos\x18\x01 \x03(\v2\f.ermite.RepoR\x05repos\x12&\n" +
732+ "\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken\"$\n" +
733+ "\x0eGetRepoRequest\x12\x12\n" +
734+ "\x04repo\x18\x01 \x01(\tR\x04repo\"3\n" +
735+ "\x0fGetRepoResponse\x12 \n" +
736+ "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"}\n" +
737+ "\x11CreateRepoRequest\x12\x12\n" +
738+ "\x04name\x18\x01 \x01(\tR\x04name\x12 \n" +
739+ "\vdescription\x18\x02 \x01(\tR\vdescription\x122\n" +
740+ "\n" +
741+ "visibility\x18\x03 \x01(\x0e2\x12.ermite.VisibilityR\n" +
742+ "visibility\"6\n" +
743+ "\x12CreateRepoResponse\x12 \n" +
744+ "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"\xe1\x01\n" +
745+ "\x11UpdateRepoRequest\x12\x12\n" +
746+ "\x04repo\x18\x01 \x01(\tR\x04repo\x12 \n" +
747+ "\vdescription\x18\x02 \x01(\tR\vdescription\x122\n" +
748+ "\n" +
749+ "visibility\x18\x03 \x01(\x0e2\x12.ermite.VisibilityR\n" +
750+ "visibility\x12%\n" +
751+ "\x0edefault_branch\x18\x04 \x01(\tR\rdefaultBranch\x12;\n" +
752+ "\vupdate_mask\x18\x05 \x01(\v2\x1a.google.protobuf.FieldMaskR\n" +
753+ "updateMask\"6\n" +
754+ "\x12UpdateRepoResponse\x12 \n" +
755+ "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"'\n" +
756+ "\x11DeleteRepoRequest\x12\x12\n" +
757+ "\x04repo\x18\x01 \x01(\tR\x04repo\"\x14\n" +
758+ "\x12DeleteRepoResponse*W\n" +
759+ "\n" +
760+ "Visibility\x12\x1a\n" +
761+ "\x16VISIBILITY_UNSPECIFIED\x10\x00\x12\x15\n" +
762+ "\x11VISIBILITY_PUBLIC\x10\x01\x12\x16\n" +
763+ "\x12VISIBILITY_PRIVATE\x10\x022\xda\x02\n" +
764+ "\vRepoService\x12@\n" +
765+ "\tListRepos\x12\x18.ermite.ListReposRequest\x1a\x19.ermite.ListReposResponse\x12:\n" +
766+ "\aGetRepo\x12\x16.ermite.GetRepoRequest\x1a\x17.ermite.GetRepoResponse\x12C\n" +
767+ "\n" +
768+ "CreateRepo\x12\x19.ermite.CreateRepoRequest\x1a\x1a.ermite.CreateRepoResponse\x12C\n" +
769+ "\n" +
770+ "UpdateRepo\x12\x19.ermite.UpdateRepoRequest\x1a\x1a.ermite.UpdateRepoResponse\x12C\n" +
771+ "\n" +
772+ "DeleteRepo\x12\x19.ermite.DeleteRepoRequest\x1a\x1a.ermite.DeleteRepoResponseBp\n" +
773+ "\n" +
774+ "com.ermiteB\tRepoProtoP\x01Z\x1fbnema.dev/ermite-api/gen/ermite\xa2\x02\x03EXX\xaa\x02\x06Ermite\xca\x02\x06Ermite\xe2\x02\x12Ermite\\GPBMetadata\xea\x02\x06Ermiteb\x06proto3"
775+
776+var (
777+ file_ermite_repo_proto_rawDescOnce sync.Once
778+ file_ermite_repo_proto_rawDescData []byte
779+)
780+
781+func file_ermite_repo_proto_rawDescGZIP() []byte {
782+ file_ermite_repo_proto_rawDescOnce.Do(func() {
783+ file_ermite_repo_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ermite_repo_proto_rawDesc), len(file_ermite_repo_proto_rawDesc)))
784+ })
785+ return file_ermite_repo_proto_rawDescData
786+}
787+
788+var file_ermite_repo_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
789+var file_ermite_repo_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
790+var file_ermite_repo_proto_goTypes = []any{
791+ (Visibility)(0), // 0: ermite.Visibility
792+ (*Repo)(nil), // 1: ermite.Repo
793+ (*ListReposRequest)(nil), // 2: ermite.ListReposRequest
794+ (*ListReposResponse)(nil), // 3: ermite.ListReposResponse
795+ (*GetRepoRequest)(nil), // 4: ermite.GetRepoRequest
796+ (*GetRepoResponse)(nil), // 5: ermite.GetRepoResponse
797+ (*CreateRepoRequest)(nil), // 6: ermite.CreateRepoRequest
798+ (*CreateRepoResponse)(nil), // 7: ermite.CreateRepoResponse
799+ (*UpdateRepoRequest)(nil), // 8: ermite.UpdateRepoRequest
800+ (*UpdateRepoResponse)(nil), // 9: ermite.UpdateRepoResponse
801+ (*DeleteRepoRequest)(nil), // 10: ermite.DeleteRepoRequest
802+ (*DeleteRepoResponse)(nil), // 11: ermite.DeleteRepoResponse
803+ (*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp
804+ (*fieldmaskpb.FieldMask)(nil), // 13: google.protobuf.FieldMask
805+}
806+var file_ermite_repo_proto_depIdxs = []int32{
807+ 0, // 0: ermite.Repo.visibility:type_name -> ermite.Visibility
808+ 12, // 1: ermite.Repo.created_at:type_name -> google.protobuf.Timestamp
809+ 12, // 2: ermite.Repo.pushed_at:type_name -> google.protobuf.Timestamp
810+ 1, // 3: ermite.ListReposResponse.repos:type_name -> ermite.Repo
811+ 1, // 4: ermite.GetRepoResponse.repo:type_name -> ermite.Repo
812+ 0, // 5: ermite.CreateRepoRequest.visibility:type_name -> ermite.Visibility
813+ 1, // 6: ermite.CreateRepoResponse.repo:type_name -> ermite.Repo
814+ 0, // 7: ermite.UpdateRepoRequest.visibility:type_name -> ermite.Visibility
815+ 13, // 8: ermite.UpdateRepoRequest.update_mask:type_name -> google.protobuf.FieldMask
816+ 1, // 9: ermite.UpdateRepoResponse.repo:type_name -> ermite.Repo
817+ 2, // 10: ermite.RepoService.ListRepos:input_type -> ermite.ListReposRequest
818+ 4, // 11: ermite.RepoService.GetRepo:input_type -> ermite.GetRepoRequest
819+ 6, // 12: ermite.RepoService.CreateRepo:input_type -> ermite.CreateRepoRequest
820+ 8, // 13: ermite.RepoService.UpdateRepo:input_type -> ermite.UpdateRepoRequest
821+ 10, // 14: ermite.RepoService.DeleteRepo:input_type -> ermite.DeleteRepoRequest
822+ 3, // 15: ermite.RepoService.ListRepos:output_type -> ermite.ListReposResponse
823+ 5, // 16: ermite.RepoService.GetRepo:output_type -> ermite.GetRepoResponse
824+ 7, // 17: ermite.RepoService.CreateRepo:output_type -> ermite.CreateRepoResponse
825+ 9, // 18: ermite.RepoService.UpdateRepo:output_type -> ermite.UpdateRepoResponse
826+ 11, // 19: ermite.RepoService.DeleteRepo:output_type -> ermite.DeleteRepoResponse
827+ 15, // [15:20] is the sub-list for method output_type
828+ 10, // [10:15] is the sub-list for method input_type
829+ 10, // [10:10] is the sub-list for extension type_name
830+ 10, // [10:10] is the sub-list for extension extendee
831+ 0, // [0:10] is the sub-list for field type_name
832+}
833+
834+func init() { file_ermite_repo_proto_init() }
835+func file_ermite_repo_proto_init() {
836+ if File_ermite_repo_proto != nil {
837+ return
838+ }
839+ type x struct{}
840+ out := protoimpl.TypeBuilder{
841+ File: protoimpl.DescBuilder{
842+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
843+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_repo_proto_rawDesc), len(file_ermite_repo_proto_rawDesc)),
844+ NumEnums: 1,
845+ NumMessages: 11,
846+ NumExtensions: 0,
847+ NumServices: 1,
848+ },
849+ GoTypes: file_ermite_repo_proto_goTypes,
850+ DependencyIndexes: file_ermite_repo_proto_depIdxs,
851+ EnumInfos: file_ermite_repo_proto_enumTypes,
852+ MessageInfos: file_ermite_repo_proto_msgTypes,
853+ }.Build()
854+ File_ermite_repo_proto = out.File
855+ file_ermite_repo_proto_goTypes = nil
856+ file_ermite_repo_proto_depIdxs = nil
857+}
A gen/ermite/server.pb.go +188 -0 generated file: collapsed
A gen/ermite/token.pb.go +673 -0 generated file: collapsed
A gen/ermite/types.pb.go +258 -0 generated file: collapsed
A gen_test.go +92 -0
@@ -0,0 +1,92 @@
1+// SPDX-License-Identifier: MIT
2+
3+package api_test
4+
5+import (
6+ "testing"
7+
8+ "google.golang.org/protobuf/proto"
9+ "google.golang.org/protobuf/types/known/fieldmaskpb"
10+
11+ "bnema.dev/ermite-api/gen/ermite"
12+ "bnema.dev/ermite-api/gen/ermite/ermiteconnect"
13+)
14+
15+// TestProcedures pins the procedure paths: they are the wire contract.
16+func TestProcedures(t *testing.T) {
17+ tests := []struct{ got, want string }{
18+ {ermiteconnect.RepoServiceListReposProcedure, "/ermite.RepoService/ListRepos"},
19+ {ermiteconnect.RepoServiceGetRepoProcedure, "/ermite.RepoService/GetRepo"},
20+ {ermiteconnect.RepoServiceCreateRepoProcedure, "/ermite.RepoService/CreateRepo"},
21+ {ermiteconnect.RepoServiceUpdateRepoProcedure, "/ermite.RepoService/UpdateRepo"},
22+ {ermiteconnect.RepoServiceDeleteRepoProcedure, "/ermite.RepoService/DeleteRepo"},
23+ {ermiteconnect.GitServiceListRefsProcedure, "/ermite.GitService/ListRefs"},
24+ {ermiteconnect.GitServiceGetTreeProcedure, "/ermite.GitService/GetTree"},
25+ {ermiteconnect.GitServiceGetBlobProcedure, "/ermite.GitService/GetBlob"},
26+ {ermiteconnect.GitServiceListCommitsProcedure, "/ermite.GitService/ListCommits"},
27+ {ermiteconnect.GitServiceGetCommitProcedure, "/ermite.GitService/GetCommit"},
28+ {ermiteconnect.GitServiceResolveRevisionProcedure, "/ermite.GitService/ResolveRevision"},
29+ {ermiteconnect.TokenServiceCreateTokenProcedure, "/ermite.TokenService/CreateToken"},
30+ {ermiteconnect.TokenServiceListTokensProcedure, "/ermite.TokenService/ListTokens"},
31+ {ermiteconnect.TokenServiceRevokeTokenProcedure, "/ermite.TokenService/RevokeToken"},
32+ {ermiteconnect.EventServiceWatchProcedure, "/ermite.EventService/Watch"},
33+ {ermiteconnect.ServerServiceGetVersionProcedure, "/ermite.ServerService/GetVersion"},
34+ }
35+ for _, tt := range tests {
36+ if tt.got != tt.want {
37+ t.Errorf("procedure = %q, want %q", tt.got, tt.want)
38+ }
39+ }
40+}
41+
42+// TestEnumNumbers pins enum numbers: they are part of the wire contract.
43+func TestEnumNumbers(t *testing.T) {
44+ if got := ermite.Scope_SCOPE_TOKEN_ADMIN; got != 9 {
45+ t.Errorf("SCOPE_TOKEN_ADMIN = %d, want 9", got)
46+ }
47+ if got := ermite.FileStatus_FILE_STATUS_TYPE_CHANGED; got != 6 {
48+ t.Errorf("FILE_STATUS_TYPE_CHANGED = %d, want 6", got)
49+ }
50+ if got := ermite.Visibility_VISIBILITY_PRIVATE; got != 2 {
51+ t.Errorf("VISIBILITY_PRIVATE = %d, want 2", got)
52+ }
53+}
54+
55+// TestEventRoundTrip checks that an event with a oneof kind survives the wire.
56+func TestEventRoundTrip(t *testing.T) {
57+ in := &ermite.WatchResponse{Event: &ermite.Event{
58+ Id: "42",
59+ Kind: &ermite.Event_Pushed{Pushed: &ermite.Pushed{
60+ Repo: "ermite",
61+ RefUpdates: []*ermite.RefUpdate{
62+ {Ref: "refs/heads/main", OldId: "a", NewId: "b"},
63+ },
64+ }},
65+ }}
66+ b, err := proto.Marshal(in)
67+ if err != nil {
68+ t.Fatal(err)
69+ }
70+ var out ermite.WatchResponse
71+ if err := proto.Unmarshal(b, &out); err != nil {
72+ t.Fatal(err)
73+ }
74+ if !proto.Equal(in, &out) {
75+ t.Errorf("round trip mismatch: %v != %v", &out, in)
76+ }
77+ if out.GetEvent().GetPushed().GetRefUpdates()[0].GetNewId() != "b" {
78+ t.Errorf("unexpected ref update: %v", &out)
79+ }
80+}
81+
82+// TestUpdateRepoMask checks that the request carries a field mask.
83+func TestUpdateRepoMask(t *testing.T) {
84+ req := &ermite.UpdateRepoRequest{
85+ Repo: "ermite",
86+ Visibility: ermite.Visibility_VISIBILITY_PUBLIC,
87+ UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"visibility"}},
88+ }
89+ if got := req.GetUpdateMask().GetPaths(); len(got) != 1 || got[0] != "visibility" {
90+ t.Errorf("paths = %v", got)
91+ }
92+}
@@ -0,0 +1,92 @@
1+// SPDX-License-Identifier: MIT
2+
3+package api_test
4+
5+import (
6+ "testing"
7+
8+ "google.golang.org/protobuf/proto"
9+ "google.golang.org/protobuf/types/known/fieldmaskpb"
10+
11+ "bnema.dev/ermite-api/gen/ermite"
12+ "bnema.dev/ermite-api/gen/ermite/ermiteconnect"
13+)
14+
15+// TestProcedures pins the procedure paths: they are the wire contract.
16+func TestProcedures(t *testing.T) {
17+ tests := []struct{ got, want string }{
18+ {ermiteconnect.RepoServiceListReposProcedure, "/ermite.RepoService/ListRepos"},
19+ {ermiteconnect.RepoServiceGetRepoProcedure, "/ermite.RepoService/GetRepo"},
20+ {ermiteconnect.RepoServiceCreateRepoProcedure, "/ermite.RepoService/CreateRepo"},
21+ {ermiteconnect.RepoServiceUpdateRepoProcedure, "/ermite.RepoService/UpdateRepo"},
22+ {ermiteconnect.RepoServiceDeleteRepoProcedure, "/ermite.RepoService/DeleteRepo"},
23+ {ermiteconnect.GitServiceListRefsProcedure, "/ermite.GitService/ListRefs"},
24+ {ermiteconnect.GitServiceGetTreeProcedure, "/ermite.GitService/GetTree"},
25+ {ermiteconnect.GitServiceGetBlobProcedure, "/ermite.GitService/GetBlob"},
26+ {ermiteconnect.GitServiceListCommitsProcedure, "/ermite.GitService/ListCommits"},
27+ {ermiteconnect.GitServiceGetCommitProcedure, "/ermite.GitService/GetCommit"},
28+ {ermiteconnect.GitServiceResolveRevisionProcedure, "/ermite.GitService/ResolveRevision"},
29+ {ermiteconnect.TokenServiceCreateTokenProcedure, "/ermite.TokenService/CreateToken"},
30+ {ermiteconnect.TokenServiceListTokensProcedure, "/ermite.TokenService/ListTokens"},
31+ {ermiteconnect.TokenServiceRevokeTokenProcedure, "/ermite.TokenService/RevokeToken"},
32+ {ermiteconnect.EventServiceWatchProcedure, "/ermite.EventService/Watch"},
33+ {ermiteconnect.ServerServiceGetVersionProcedure, "/ermite.ServerService/GetVersion"},
34+ }
35+ for _, tt := range tests {
36+ if tt.got != tt.want {
37+ t.Errorf("procedure = %q, want %q", tt.got, tt.want)
38+ }
39+ }
40+}
41+
42+// TestEnumNumbers pins enum numbers: they are part of the wire contract.
43+func TestEnumNumbers(t *testing.T) {
44+ if got := ermite.Scope_SCOPE_TOKEN_ADMIN; got != 9 {
45+ t.Errorf("SCOPE_TOKEN_ADMIN = %d, want 9", got)
46+ }
47+ if got := ermite.FileStatus_FILE_STATUS_TYPE_CHANGED; got != 6 {
48+ t.Errorf("FILE_STATUS_TYPE_CHANGED = %d, want 6", got)
49+ }
50+ if got := ermite.Visibility_VISIBILITY_PRIVATE; got != 2 {
51+ t.Errorf("VISIBILITY_PRIVATE = %d, want 2", got)
52+ }
53+}
54+
55+// TestEventRoundTrip checks that an event with a oneof kind survives the wire.
56+func TestEventRoundTrip(t *testing.T) {
57+ in := &ermite.WatchResponse{Event: &ermite.Event{
58+ Id: "42",
59+ Kind: &ermite.Event_Pushed{Pushed: &ermite.Pushed{
60+ Repo: "ermite",
61+ RefUpdates: []*ermite.RefUpdate{
62+ {Ref: "refs/heads/main", OldId: "a", NewId: "b"},
63+ },
64+ }},
65+ }}
66+ b, err := proto.Marshal(in)
67+ if err != nil {
68+ t.Fatal(err)
69+ }
70+ var out ermite.WatchResponse
71+ if err := proto.Unmarshal(b, &out); err != nil {
72+ t.Fatal(err)
73+ }
74+ if !proto.Equal(in, &out) {
75+ t.Errorf("round trip mismatch: %v != %v", &out, in)
76+ }
77+ if out.GetEvent().GetPushed().GetRefUpdates()[0].GetNewId() != "b" {
78+ t.Errorf("unexpected ref update: %v", &out)
79+ }
80+}
81+
82+// TestUpdateRepoMask checks that the request carries a field mask.
83+func TestUpdateRepoMask(t *testing.T) {
84+ req := &ermite.UpdateRepoRequest{
85+ Repo: "ermite",
86+ Visibility: ermite.Visibility_VISIBILITY_PUBLIC,
87+ UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"visibility"}},
88+ }
89+ if got := req.GetUpdateMask().GetPaths(); len(got) != 1 || got[0] != "visibility" {
90+ t.Errorf("paths = %v", got)
91+ }
92+}
M go.mod +2 -2
@@ -8,6 +8,6 @@ tool (
88 )
99
1010 require (
11- connectrpc.com/connect v1.21.0 // indirect
12- google.golang.org/protobuf v1.36.12 // indirect
11+ connectrpc.com/connect v1.21.0
12+ google.golang.org/protobuf v1.36.12
1313 )
@@ -8,6 +8,6 @@ tool (
8 )8 )
9 9
10 require (10 require (
11- connectrpc.com/connect v1.21.0 // indirect11+ connectrpc.com/connect v1.21.0
12- google.golang.org/protobuf v1.36.12 // indirect12+ google.golang.org/protobuf v1.36.12
13 )13 )
A proto/ermite/event.proto +105 -0
@@ -0,0 +1,105 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "ermite/repo.proto";
8+import "google/protobuf/timestamp.proto";
9+
10+// EventService streams what happens on the forge.
11+service EventService {
12+ // Watch streams events until the client cancels the call or the server shuts
13+ // down. Events are filtered by the caller's access: events of a private
14+ // repository are only sent to callers that may read it.
15+ //
16+ // The server keeps a bounded buffer of recent events. With resume_after set,
17+ // buffered events after that id are replayed first, then live events follow.
18+ // When resume_after is no longer buffered (or unknown), the stream begins
19+ // with a Gap event, then continues with the oldest buffered event: the client
20+ // must reload its state. Without resume_after, only new events are sent.
21+ rpc Watch(WatchRequest) returns (stream WatchResponse);
22+}
23+
24+// WatchRequest selects the events to receive.
25+message WatchRequest {
26+ // Topics are the subjects to follow: "home" for every repository visible to
27+ // the caller, or "repo:<name>" for one repository. Empty means "home".
28+ // Unknown topics are invalid_argument. A "repo:<name>" topic for a repository
29+ // that does not exist or is not visible is not_found.
30+ repeated string topics = 1;
31+ // ResumeAfter is the Event.id of the last event the client has seen. Empty
32+ // to receive only new events.
33+ string resume_after = 2;
34+}
35+
36+// WatchResponse carries one event of the stream.
37+message WatchResponse {
38+ // Event is the event.
39+ Event event = 1;
40+}
41+
42+// Event is something that happened on the forge.
43+message Event {
44+ // Id identifies the event and is passed as resume_after to resume a stream.
45+ // It is opaque and only comparable for equality; clients must not parse it.
46+ // Empty on a Gap event.
47+ string id = 1;
48+ // Time is when the event happened.
49+ google.protobuf.Timestamp time = 2;
50+ // Kind is the type and payload of the event. New kinds may be added; clients
51+ // must ignore kinds they do not know.
52+ oneof kind {
53+ // RepoCreated: a repository was created.
54+ RepoCreated repo_created = 3;
55+ // RepoUpdated: repository metadata changed.
56+ RepoUpdated repo_updated = 4;
57+ // RepoDeleted: a repository was deleted.
58+ RepoDeleted repo_deleted = 5;
59+ // Pushed: refs of a repository were updated by a push.
60+ Pushed pushed = 6;
61+ // Gap: events were lost, reload state.
62+ Gap gap = 7;
63+ }
64+}
65+
66+// RepoCreated reports a new repository.
67+message RepoCreated {
68+ // Repo is the new repository.
69+ Repo repo = 1;
70+}
71+
72+// RepoUpdated reports a metadata change.
73+message RepoUpdated {
74+ // Repo is the repository after the change.
75+ Repo repo = 1;
76+}
77+
78+// RepoDeleted reports a deleted repository.
79+message RepoDeleted {
80+ // Repo is the name of the deleted repository.
81+ string repo = 1;
82+}
83+
84+// Pushed reports the ref updates of one push.
85+message Pushed {
86+ // Repo is the name of the repository.
87+ string repo = 1;
88+ // RefUpdates are the refs changed by the push.
89+ repeated RefUpdate ref_updates = 2;
90+}
91+
92+// RefUpdate is the change of one ref.
93+message RefUpdate {
94+ // Ref is the full ref name, for example "refs/heads/main".
95+ string ref = 1;
96+ // OldId is the object id before the update. Empty when the ref was created.
97+ string old_id = 2;
98+ // NewId is the object id after the update. Empty when the ref was deleted.
99+ string new_id = 3;
100+}
101+
102+// Gap tells the client that events were lost: the requested resume point is
103+// older than the server's buffer. It has no fields. The client should reload
104+// the state it displays (repositories, refs) and carry on with the next events.
105+message Gap {}
@@ -0,0 +1,105 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "ermite/repo.proto";
8+import "google/protobuf/timestamp.proto";
9+
10+// EventService streams what happens on the forge.
11+service EventService {
12+ // Watch streams events until the client cancels the call or the server shuts
13+ // down. Events are filtered by the caller's access: events of a private
14+ // repository are only sent to callers that may read it.
15+ //
16+ // The server keeps a bounded buffer of recent events. With resume_after set,
17+ // buffered events after that id are replayed first, then live events follow.
18+ // When resume_after is no longer buffered (or unknown), the stream begins
19+ // with a Gap event, then continues with the oldest buffered event: the client
20+ // must reload its state. Without resume_after, only new events are sent.
21+ rpc Watch(WatchRequest) returns (stream WatchResponse);
22+}
23+
24+// WatchRequest selects the events to receive.
25+message WatchRequest {
26+ // Topics are the subjects to follow: "home" for every repository visible to
27+ // the caller, or "repo:<name>" for one repository. Empty means "home".
28+ // Unknown topics are invalid_argument. A "repo:<name>" topic for a repository
29+ // that does not exist or is not visible is not_found.
30+ repeated string topics = 1;
31+ // ResumeAfter is the Event.id of the last event the client has seen. Empty
32+ // to receive only new events.
33+ string resume_after = 2;
34+}
35+
36+// WatchResponse carries one event of the stream.
37+message WatchResponse {
38+ // Event is the event.
39+ Event event = 1;
40+}
41+
42+// Event is something that happened on the forge.
43+message Event {
44+ // Id identifies the event and is passed as resume_after to resume a stream.
45+ // It is opaque and only comparable for equality; clients must not parse it.
46+ // Empty on a Gap event.
47+ string id = 1;
48+ // Time is when the event happened.
49+ google.protobuf.Timestamp time = 2;
50+ // Kind is the type and payload of the event. New kinds may be added; clients
51+ // must ignore kinds they do not know.
52+ oneof kind {
53+ // RepoCreated: a repository was created.
54+ RepoCreated repo_created = 3;
55+ // RepoUpdated: repository metadata changed.
56+ RepoUpdated repo_updated = 4;
57+ // RepoDeleted: a repository was deleted.
58+ RepoDeleted repo_deleted = 5;
59+ // Pushed: refs of a repository were updated by a push.
60+ Pushed pushed = 6;
61+ // Gap: events were lost, reload state.
62+ Gap gap = 7;
63+ }
64+}
65+
66+// RepoCreated reports a new repository.
67+message RepoCreated {
68+ // Repo is the new repository.
69+ Repo repo = 1;
70+}
71+
72+// RepoUpdated reports a metadata change.
73+message RepoUpdated {
74+ // Repo is the repository after the change.
75+ Repo repo = 1;
76+}
77+
78+// RepoDeleted reports a deleted repository.
79+message RepoDeleted {
80+ // Repo is the name of the deleted repository.
81+ string repo = 1;
82+}
83+
84+// Pushed reports the ref updates of one push.
85+message Pushed {
86+ // Repo is the name of the repository.
87+ string repo = 1;
88+ // RefUpdates are the refs changed by the push.
89+ repeated RefUpdate ref_updates = 2;
90+}
91+
92+// RefUpdate is the change of one ref.
93+message RefUpdate {
94+ // Ref is the full ref name, for example "refs/heads/main".
95+ string ref = 1;
96+ // OldId is the object id before the update. Empty when the ref was created.
97+ string old_id = 2;
98+ // NewId is the object id after the update. Empty when the ref was deleted.
99+ string new_id = 3;
100+}
101+
102+// Gap tells the client that events were lost: the requested resume point is
103+// older than the server's buffer. It has no fields. The client should reload
104+// the state it displays (repositories, refs) and carry on with the next events.
105+message Gap {}
A proto/ermite/git.proto +388 -0
@@ -0,0 +1,388 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "ermite/types.proto";
8+
9+// RefKind is the kind of a Git ref.
10+enum RefKind {
11+ // Not set. In ListRefsRequest.kinds it is rejected; never returned.
12+ REF_KIND_UNSPECIFIED = 0;
13+ // A branch (refs/heads/*).
14+ REF_KIND_BRANCH = 1;
15+ // A tag (refs/tags/*), lightweight or annotated.
16+ REF_KIND_TAG = 2;
17+ // The symbolic ref HEAD, that is the default branch.
18+ REF_KIND_HEAD = 3;
19+}
20+
21+// EntryKind is the kind of an entry of a Git tree.
22+enum EntryKind {
23+ // Not set. Never returned.
24+ ENTRY_KIND_UNSPECIFIED = 0;
25+ // A regular, non-executable file (mode 100644).
26+ ENTRY_KIND_FILE = 1;
27+ // An executable file (mode 100755).
28+ ENTRY_KIND_EXECUTABLE = 2;
29+ // A directory (mode 040000).
30+ ENTRY_KIND_DIRECTORY = 3;
31+ // A symbolic link (mode 120000). The blob content is the link target.
32+ ENTRY_KIND_SYMLINK = 4;
33+ // A submodule commit (mode 160000). The id is a commit of another
34+ // repository, which this one does not contain.
35+ ENTRY_KIND_SUBMODULE = 5;
36+}
37+
38+// FileStatus tells what a commit did to a file.
39+enum FileStatus {
40+ // Not set. Never returned.
41+ FILE_STATUS_UNSPECIFIED = 0;
42+ // The file was added.
43+ FILE_STATUS_ADDED = 1;
44+ // The file was deleted.
45+ FILE_STATUS_DELETED = 2;
46+ // The content or the mode of the file changed.
47+ FILE_STATUS_MODIFIED = 3;
48+ // The file was moved, possibly with changes. Rename detection is done by Git.
49+ FILE_STATUS_RENAMED = 4;
50+ // The file was copied from another file, possibly with changes.
51+ FILE_STATUS_COPIED = 5;
52+ // The type of the entry changed, for example a file became a symbolic link.
53+ FILE_STATUS_TYPE_CHANGED = 6;
54+}
55+
56+// LineKind tells how a line of a hunk relates to the two sides of a diff.
57+enum LineKind {
58+ // Not set. Never returned.
59+ LINE_KIND_UNSPECIFIED = 0;
60+ // The line is present, unchanged, on both sides.
61+ LINE_KIND_CONTEXT = 1;
62+ // The line exists only on the new side.
63+ LINE_KIND_ADDITION = 2;
64+ // The line exists only on the old side.
65+ LINE_KIND_DELETION = 3;
66+}
67+
68+// GitService reads the Git data of repositories. It is read-only: pushes go
69+// through Git itself.
70+//
71+// Every RPC takes the repository name. A repository that does not exist or
72+// that the caller cannot read gives not_found. A revision is a branch name, a
73+// tag name or a commit id (full, or an unambiguous abbreviation of at least 7
74+// characters); empty means HEAD. A revision or path that does not exist gives
75+// not_found; so does an empty repository, which has no commit to resolve.
76+service GitService {
77+ // ListRefs lists the branches, tags and HEAD of a repository. Refs are
78+ // ordered by kind (HEAD, branches, tags) then by name.
79+ rpc ListRefs(ListRefsRequest) returns (ListRefsResponse);
80+ // GetTree lists the entries of a directory at a revision. Fails with
81+ // not_found if the path does not exist and invalid_argument if it is not a
82+ // directory.
83+ rpc GetTree(GetTreeRequest) returns (GetTreeResponse);
84+ // GetBlob streams the content of a file at a revision, in chunks of at most
85+ // 64 KiB. The first message carries the metadata in info, then the chunks
86+ // follow; the memory used by the server does not depend on the file size.
87+ // Fails with not_found if the path does not exist and invalid_argument if it
88+ // is not a file.
89+ rpc GetBlob(GetBlobRequest) returns (stream GetBlobResponse);
90+ // ListCommits lists the history reachable from a revision, newest first
91+ // (Git's default order), optionally limited to the commits that touched a
92+ // path.
93+ rpc ListCommits(ListCommitsRequest) returns (ListCommitsResponse);
94+ // GetCommit returns one commit with its statistics and its diff.
95+ rpc GetCommit(GetCommitRequest) returns (GetCommitResponse);
96+ // ResolveRevision turns a revision into the id of the commit it designates.
97+ rpc ResolveRevision(ResolveRevisionRequest) returns (ResolveRevisionResponse);
98+}
99+
100+// Ref is a branch, a tag or HEAD.
101+message Ref {
102+ // Name is the full ref name, for example "refs/heads/main" or
103+ // "refs/tags/v1.0.0". For HEAD it is "HEAD".
104+ string name = 1;
105+ // ShortName is the name without its "refs/heads/" or "refs/tags/" prefix. For
106+ // HEAD it is the short name of the default branch, or empty if HEAD points
107+ // to a branch that does not exist yet.
108+ string short_name = 2;
109+ // Kind is the kind of the ref.
110+ RefKind kind = 3;
111+ // Id is the id of the object the ref points to. For an annotated tag it is
112+ // the id of the tag object.
113+ string id = 4;
114+ // CommitId is the id of the commit the ref designates once annotated tags are
115+ // followed. It equals id for branches and lightweight tags. It is empty for
116+ // a tag that points to something other than a commit.
117+ string commit_id = 5;
118+}
119+
120+// ListRefsRequest selects the refs to list.
121+message ListRefsRequest {
122+ // Repo is the repository name.
123+ string repo = 1;
124+ // Kinds restricts the result to these kinds. Empty means all kinds.
125+ repeated RefKind kinds = 2;
126+ // PageSize is the maximum number of refs to return. 0 means the server
127+ // default; values above the server maximum are lowered to it.
128+ int32 page_size = 3;
129+ // PageToken is the next_page_token of a previous response. Empty for the
130+ // first page.
131+ string page_token = 4;
132+}
133+
134+// ListRefsResponse is one page of refs.
135+message ListRefsResponse {
136+ // Refs are the refs of this page.
137+ repeated Ref refs = 1;
138+ // NextPageToken is passed as page_token to get the next page. Empty when
139+ // there is no next page.
140+ string next_page_token = 2;
141+}
142+
143+// TreeEntry is one entry of a directory.
144+message TreeEntry {
145+ // Name is the name of the entry in its directory, without slash.
146+ string name = 1;
147+ // Path is the path of the entry from the repository root, with "/"
148+ // separators and no leading slash.
149+ string path = 2;
150+ // Kind is the kind of the entry.
151+ EntryKind kind = 3;
152+ // Mode is the Git file mode, for example 0o100644 (33188 in decimal).
153+ uint32 mode = 4;
154+ // Id is the object id of the blob, tree or submodule commit.
155+ string id = 5;
156+ // Size is the size in bytes of a file or symbolic link. It is 0 for
157+ // directories and submodules.
158+ int64 size = 6;
159+ // LastCommit is the latest commit that changed the entry. Set only when the
160+ // request asked for it with include_last_commit.
161+ Commit last_commit = 7;
162+}
163+
164+// GetTreeRequest selects a directory.
165+message GetTreeRequest {
166+ // Repo is the repository name.
167+ string repo = 1;
168+ // Revision is a branch, a tag or a commit id. Empty means HEAD.
169+ string revision = 2;
170+ // Path is the directory, from the repository root, with "/" separators.
171+ // Empty means the root.
172+ string path = 3;
173+ // IncludeLastCommit asks for the last commit of every entry in last_commit.
174+ // It costs one history walk, so it is off by default and the server may be
175+ // slow on large directories.
176+ bool include_last_commit = 4;
177+}
178+
179+// GetTreeResponse lists a directory.
180+message GetTreeResponse {
181+ // CommitId is the id of the commit the revision resolved to.
182+ string commit_id = 1;
183+ // TreeId is the object id of the listed directory.
184+ string tree_id = 2;
185+ // Entries are the entries of the directory: directories first, then the other
186+ // entries, each group ordered by name.
187+ repeated TreeEntry entries = 3;
188+}
189+
190+// BlobInfo describes a file.
191+message BlobInfo {
192+ // Id is the object id of the blob.
193+ string id = 1;
194+ // Path is the path of the file from the repository root.
195+ string path = 2;
196+ // Size is the size of the whole content in bytes.
197+ int64 size = 3;
198+ // Binary is true if the content is binary, with Git's rule: a NUL byte in the
199+ // first 8,000 bytes.
200+ bool binary = 4;
201+ // MediaType is the detected media type, for example "text/plain" or
202+ // "image/png", from the file name and the first bytes. It is
203+ // "application/octet-stream" when unknown.
204+ string media_type = 5;
205+ // Mode is the Git file mode, for example 0o100644 (33188 in decimal).
206+ uint32 mode = 6;
207+}
208+
209+// GetBlobRequest selects a file.
210+message GetBlobRequest {
211+ // Repo is the repository name.
212+ string repo = 1;
213+ // Revision is a branch, a tag or a commit id. Empty means HEAD.
214+ string revision = 2;
215+ // Path is the file, from the repository root. It is required.
216+ string path = 3;
217+}
218+
219+// GetBlobResponse is one message of the content stream.
220+message GetBlobResponse {
221+ // Info describes the file. Set in the first message of the stream only.
222+ BlobInfo info = 1;
223+ // Chunk is the next part of the content, at most 64 KiB, in order. The first
224+ // message may have an empty chunk. The chunks of a stream add up to
225+ // info.size bytes.
226+ bytes chunk = 2;
227+}
228+
229+// ListCommitsRequest selects a page of history.
230+message ListCommitsRequest {
231+ // Repo is the repository name.
232+ string repo = 1;
233+ // Revision is where the history starts: a branch, a tag or a commit id.
234+ // Empty means HEAD.
235+ string revision = 2;
236+ // Path restricts the result to the commits that changed this file or
237+ // directory. Empty means the whole history.
238+ string path = 3;
239+ // PageSize is the maximum number of commits to return. 0 means the server
240+ // default; values above 100 are lowered to 100.
241+ int32 page_size = 4;
242+ // PageToken is the next_page_token of a previous response, to continue the
243+ // same listing. Empty for the first page. Other fields must be unchanged.
244+ string page_token = 5;
245+}
246+
247+// ListCommitsResponse is one page of commits.
248+message ListCommitsResponse {
249+ // Commits are the commits of this page, newest first.
250+ repeated Commit commits = 1;
251+ // NextPageToken is passed as page_token to get the next page. Empty when
252+ // there is no next page.
253+ string next_page_token = 2;
254+}
255+
256+// GetCommitRequest selects a commit.
257+message GetCommitRequest {
258+ // Repo is the repository name.
259+ string repo = 1;
260+ // Revision is a branch, a tag or a commit id. Empty means HEAD.
261+ string revision = 2;
262+}
263+
264+// GetCommitResponse holds a commit, its statistics and its diff.
265+message GetCommitResponse {
266+ // Commit is the commit metadata.
267+ Commit commit = 1;
268+ // Stats are the totals over all the changed files, including files that the
269+ // diff omits or truncates.
270+ DiffStats stats = 2;
271+ // Diff is the structured diff against the first parent, or against the empty
272+ // tree for a root commit. For a merge commit this is the change relative to
273+ // the first parent.
274+ Diff diff = 3;
275+}
276+
277+// DiffStats are the totals of a diff.
278+message DiffStats {
279+ // FilesChanged is the number of changed files.
280+ int32 files_changed = 1;
281+ // Additions is the number of added lines. Binary files count for 0.
282+ int32 additions = 2;
283+ // Deletions is the number of deleted lines. Binary files count for 0.
284+ int32 deletions = 3;
285+}
286+
287+// Diff is the structured difference introduced by a commit.
288+//
289+// The server limits its size: at most 300 files, at most 2,000 lines in one
290+// file and at most 20,000 lines in total (hunk lines, context included). These
291+// numbers are server behaviour and may change; clients must rely on the
292+// truncated flags, not on the numbers.
293+message Diff {
294+ // Files are the changed files, ordered by path. Files past the file limit are
295+ // omitted.
296+ repeated FileDiff files = 1;
297+ // Truncated is true when the diff is incomplete: files were omitted, or at
298+ // least one listed file has truncated set. DiffStats still count everything.
299+ bool truncated = 2;
300+}
301+
302+// FileDiff is the change of one file.
303+message FileDiff {
304+ // OldPath is the path before the commit. Empty for an added file.
305+ string old_path = 1;
306+ // NewPath is the path after the commit. Empty for a deleted file.
307+ string new_path = 2;
308+ // Status tells what happened to the file.
309+ FileStatus status = 3;
310+ // OldMode is the Git file mode before the commit, or 0 for an added file.
311+ uint32 old_mode = 4;
312+ // NewMode is the Git file mode after the commit, or 0 for a deleted file.
313+ uint32 new_mode = 5;
314+ // OldId is the blob id before the commit. Empty for an added file.
315+ string old_id = 6;
316+ // NewId is the blob id after the commit. Empty for a deleted file.
317+ string new_id = 7;
318+ // Binary is true if Git treats the file as binary (numstat reports "-"). A
319+ // binary file has no hunks and additions and deletions are 0.
320+ bool binary = 8;
321+ // Additions is the number of added lines.
322+ int32 additions = 9;
323+ // Deletions is the number of deleted lines.
324+ int32 deletions = 10;
325+ // Similarity is the percentage (0-100) of unchanged content for a renamed or
326+ // copied file, and 0 otherwise.
327+ int32 similarity = 11;
328+ // Truncated is true when the file exceeded a diff limit: hunks is then empty
329+ // although the file changed. Additions and deletions remain accurate.
330+ bool truncated = 12;
331+ // Hunks are the changed regions, in file order. Empty for a binary file, a
332+ // truncated file, a pure rename and a mode-only change.
333+ repeated Hunk hunks = 13;
334+}
335+
336+// Hunk is a contiguous changed region with its context.
337+message Hunk {
338+ // OldStart is the 1-based first line of the region in the old file. 0 when
339+ // old_lines is 0 and the file was added.
340+ int32 old_start = 1;
341+ // OldLines is the number of old-side lines in the hunk.
342+ int32 old_lines = 2;
343+ // NewStart is the 1-based first line of the region in the new file. 0 when
344+ // new_lines is 0 and the file was deleted.
345+ int32 new_start = 3;
346+ // NewLines is the number of new-side lines in the hunk.
347+ int32 new_lines = 4;
348+ // Header is the text after the second "@@" of the hunk header, usually the
349+ // enclosing function. It may be empty.
350+ string header = 5;
351+ // Lines are the lines of the hunk, in order.
352+ repeated Line lines = 6;
353+}
354+
355+// Line is one line of a hunk.
356+message Line {
357+ // Kind tells which side the line belongs to.
358+ LineKind kind = 1;
359+ // OldNumber is the 1-based line number on the old side. 0 for an addition.
360+ int32 old_number = 2;
361+ // NewNumber is the 1-based line number on the new side. 0 for a deletion.
362+ int32 new_number = 3;
363+ // Text is the content without the line terminator. Bytes that are not valid
364+ // UTF-8 are replaced by the replacement character.
365+ string text = 4;
366+ // NoNewlineAtEof is true when this is the last line of its side and the file
367+ // does not end with a line break there.
368+ bool no_newline_at_eof = 5;
369+}
370+
371+// ResolveRevisionRequest names a revision.
372+message ResolveRevisionRequest {
373+ // Repo is the repository name.
374+ string repo = 1;
375+ // Revision is a branch, a tag or a commit id. Empty means HEAD.
376+ string revision = 2;
377+}
378+
379+// ResolveRevisionResponse holds the resolved commit.
380+message ResolveRevisionResponse {
381+ // CommitId is the full id of the commit the revision designates, after
382+ // following annotated tags.
383+ string commit_id = 1;
384+ // Ref is the full name of the ref the revision matched, for example
385+ // "refs/heads/main". Empty when the revision was a commit id or for HEAD
386+ // when it is resolved by default.
387+ string ref = 2;
388+}
@@ -0,0 +1,388 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "ermite/types.proto";
8+
9+// RefKind is the kind of a Git ref.
10+enum RefKind {
11+ // Not set. In ListRefsRequest.kinds it is rejected; never returned.
12+ REF_KIND_UNSPECIFIED = 0;
13+ // A branch (refs/heads/*).
14+ REF_KIND_BRANCH = 1;
15+ // A tag (refs/tags/*), lightweight or annotated.
16+ REF_KIND_TAG = 2;
17+ // The symbolic ref HEAD, that is the default branch.
18+ REF_KIND_HEAD = 3;
19+}
20+
21+// EntryKind is the kind of an entry of a Git tree.
22+enum EntryKind {
23+ // Not set. Never returned.
24+ ENTRY_KIND_UNSPECIFIED = 0;
25+ // A regular, non-executable file (mode 100644).
26+ ENTRY_KIND_FILE = 1;
27+ // An executable file (mode 100755).
28+ ENTRY_KIND_EXECUTABLE = 2;
29+ // A directory (mode 040000).
30+ ENTRY_KIND_DIRECTORY = 3;
31+ // A symbolic link (mode 120000). The blob content is the link target.
32+ ENTRY_KIND_SYMLINK = 4;
33+ // A submodule commit (mode 160000). The id is a commit of another
34+ // repository, which this one does not contain.
35+ ENTRY_KIND_SUBMODULE = 5;
36+}
37+
38+// FileStatus tells what a commit did to a file.
39+enum FileStatus {
40+ // Not set. Never returned.
41+ FILE_STATUS_UNSPECIFIED = 0;
42+ // The file was added.
43+ FILE_STATUS_ADDED = 1;
44+ // The file was deleted.
45+ FILE_STATUS_DELETED = 2;
46+ // The content or the mode of the file changed.
47+ FILE_STATUS_MODIFIED = 3;
48+ // The file was moved, possibly with changes. Rename detection is done by Git.
49+ FILE_STATUS_RENAMED = 4;
50+ // The file was copied from another file, possibly with changes.
51+ FILE_STATUS_COPIED = 5;
52+ // The type of the entry changed, for example a file became a symbolic link.
53+ FILE_STATUS_TYPE_CHANGED = 6;
54+}
55+
56+// LineKind tells how a line of a hunk relates to the two sides of a diff.
57+enum LineKind {
58+ // Not set. Never returned.
59+ LINE_KIND_UNSPECIFIED = 0;
60+ // The line is present, unchanged, on both sides.
61+ LINE_KIND_CONTEXT = 1;
62+ // The line exists only on the new side.
63+ LINE_KIND_ADDITION = 2;
64+ // The line exists only on the old side.
65+ LINE_KIND_DELETION = 3;
66+}
67+
68+// GitService reads the Git data of repositories. It is read-only: pushes go
69+// through Git itself.
70+//
71+// Every RPC takes the repository name. A repository that does not exist or
72+// that the caller cannot read gives not_found. A revision is a branch name, a
73+// tag name or a commit id (full, or an unambiguous abbreviation of at least 7
74+// characters); empty means HEAD. A revision or path that does not exist gives
75+// not_found; so does an empty repository, which has no commit to resolve.
76+service GitService {
77+ // ListRefs lists the branches, tags and HEAD of a repository. Refs are
78+ // ordered by kind (HEAD, branches, tags) then by name.
79+ rpc ListRefs(ListRefsRequest) returns (ListRefsResponse);
80+ // GetTree lists the entries of a directory at a revision. Fails with
81+ // not_found if the path does not exist and invalid_argument if it is not a
82+ // directory.
83+ rpc GetTree(GetTreeRequest) returns (GetTreeResponse);
84+ // GetBlob streams the content of a file at a revision, in chunks of at most
85+ // 64 KiB. The first message carries the metadata in info, then the chunks
86+ // follow; the memory used by the server does not depend on the file size.
87+ // Fails with not_found if the path does not exist and invalid_argument if it
88+ // is not a file.
89+ rpc GetBlob(GetBlobRequest) returns (stream GetBlobResponse);
90+ // ListCommits lists the history reachable from a revision, newest first
91+ // (Git's default order), optionally limited to the commits that touched a
92+ // path.
93+ rpc ListCommits(ListCommitsRequest) returns (ListCommitsResponse);
94+ // GetCommit returns one commit with its statistics and its diff.
95+ rpc GetCommit(GetCommitRequest) returns (GetCommitResponse);
96+ // ResolveRevision turns a revision into the id of the commit it designates.
97+ rpc ResolveRevision(ResolveRevisionRequest) returns (ResolveRevisionResponse);
98+}
99+
100+// Ref is a branch, a tag or HEAD.
101+message Ref {
102+ // Name is the full ref name, for example "refs/heads/main" or
103+ // "refs/tags/v1.0.0". For HEAD it is "HEAD".
104+ string name = 1;
105+ // ShortName is the name without its "refs/heads/" or "refs/tags/" prefix. For
106+ // HEAD it is the short name of the default branch, or empty if HEAD points
107+ // to a branch that does not exist yet.
108+ string short_name = 2;
109+ // Kind is the kind of the ref.
110+ RefKind kind = 3;
111+ // Id is the id of the object the ref points to. For an annotated tag it is
112+ // the id of the tag object.
113+ string id = 4;
114+ // CommitId is the id of the commit the ref designates once annotated tags are
115+ // followed. It equals id for branches and lightweight tags. It is empty for
116+ // a tag that points to something other than a commit.
117+ string commit_id = 5;
118+}
119+
120+// ListRefsRequest selects the refs to list.
121+message ListRefsRequest {
122+ // Repo is the repository name.
123+ string repo = 1;
124+ // Kinds restricts the result to these kinds. Empty means all kinds.
125+ repeated RefKind kinds = 2;
126+ // PageSize is the maximum number of refs to return. 0 means the server
127+ // default; values above the server maximum are lowered to it.
128+ int32 page_size = 3;
129+ // PageToken is the next_page_token of a previous response. Empty for the
130+ // first page.
131+ string page_token = 4;
132+}
133+
134+// ListRefsResponse is one page of refs.
135+message ListRefsResponse {
136+ // Refs are the refs of this page.
137+ repeated Ref refs = 1;
138+ // NextPageToken is passed as page_token to get the next page. Empty when
139+ // there is no next page.
140+ string next_page_token = 2;
141+}
142+
143+// TreeEntry is one entry of a directory.
144+message TreeEntry {
145+ // Name is the name of the entry in its directory, without slash.
146+ string name = 1;
147+ // Path is the path of the entry from the repository root, with "/"
148+ // separators and no leading slash.
149+ string path = 2;
150+ // Kind is the kind of the entry.
151+ EntryKind kind = 3;
152+ // Mode is the Git file mode, for example 0o100644 (33188 in decimal).
153+ uint32 mode = 4;
154+ // Id is the object id of the blob, tree or submodule commit.
155+ string id = 5;
156+ // Size is the size in bytes of a file or symbolic link. It is 0 for
157+ // directories and submodules.
158+ int64 size = 6;
159+ // LastCommit is the latest commit that changed the entry. Set only when the
160+ // request asked for it with include_last_commit.
161+ Commit last_commit = 7;
162+}
163+
164+// GetTreeRequest selects a directory.
165+message GetTreeRequest {
166+ // Repo is the repository name.
167+ string repo = 1;
168+ // Revision is a branch, a tag or a commit id. Empty means HEAD.
169+ string revision = 2;
170+ // Path is the directory, from the repository root, with "/" separators.
171+ // Empty means the root.
172+ string path = 3;
173+ // IncludeLastCommit asks for the last commit of every entry in last_commit.
174+ // It costs one history walk, so it is off by default and the server may be
175+ // slow on large directories.
176+ bool include_last_commit = 4;
177+}
178+
179+// GetTreeResponse lists a directory.
180+message GetTreeResponse {
181+ // CommitId is the id of the commit the revision resolved to.
182+ string commit_id = 1;
183+ // TreeId is the object id of the listed directory.
184+ string tree_id = 2;
185+ // Entries are the entries of the directory: directories first, then the other
186+ // entries, each group ordered by name.
187+ repeated TreeEntry entries = 3;
188+}
189+
190+// BlobInfo describes a file.
191+message BlobInfo {
192+ // Id is the object id of the blob.
193+ string id = 1;
194+ // Path is the path of the file from the repository root.
195+ string path = 2;
196+ // Size is the size of the whole content in bytes.
197+ int64 size = 3;
198+ // Binary is true if the content is binary, with Git's rule: a NUL byte in the
199+ // first 8,000 bytes.
200+ bool binary = 4;
201+ // MediaType is the detected media type, for example "text/plain" or
202+ // "image/png", from the file name and the first bytes. It is
203+ // "application/octet-stream" when unknown.
204+ string media_type = 5;
205+ // Mode is the Git file mode, for example 0o100644 (33188 in decimal).
206+ uint32 mode = 6;
207+}
208+
209+// GetBlobRequest selects a file.
210+message GetBlobRequest {
211+ // Repo is the repository name.
212+ string repo = 1;
213+ // Revision is a branch, a tag or a commit id. Empty means HEAD.
214+ string revision = 2;
215+ // Path is the file, from the repository root. It is required.
216+ string path = 3;
217+}
218+
219+// GetBlobResponse is one message of the content stream.
220+message GetBlobResponse {
221+ // Info describes the file. Set in the first message of the stream only.
222+ BlobInfo info = 1;
223+ // Chunk is the next part of the content, at most 64 KiB, in order. The first
224+ // message may have an empty chunk. The chunks of a stream add up to
225+ // info.size bytes.
226+ bytes chunk = 2;
227+}
228+
229+// ListCommitsRequest selects a page of history.
230+message ListCommitsRequest {
231+ // Repo is the repository name.
232+ string repo = 1;
233+ // Revision is where the history starts: a branch, a tag or a commit id.
234+ // Empty means HEAD.
235+ string revision = 2;
236+ // Path restricts the result to the commits that changed this file or
237+ // directory. Empty means the whole history.
238+ string path = 3;
239+ // PageSize is the maximum number of commits to return. 0 means the server
240+ // default; values above 100 are lowered to 100.
241+ int32 page_size = 4;
242+ // PageToken is the next_page_token of a previous response, to continue the
243+ // same listing. Empty for the first page. Other fields must be unchanged.
244+ string page_token = 5;
245+}
246+
247+// ListCommitsResponse is one page of commits.
248+message ListCommitsResponse {
249+ // Commits are the commits of this page, newest first.
250+ repeated Commit commits = 1;
251+ // NextPageToken is passed as page_token to get the next page. Empty when
252+ // there is no next page.
253+ string next_page_token = 2;
254+}
255+
256+// GetCommitRequest selects a commit.
257+message GetCommitRequest {
258+ // Repo is the repository name.
259+ string repo = 1;
260+ // Revision is a branch, a tag or a commit id. Empty means HEAD.
261+ string revision = 2;
262+}
263+
264+// GetCommitResponse holds a commit, its statistics and its diff.
265+message GetCommitResponse {
266+ // Commit is the commit metadata.
267+ Commit commit = 1;
268+ // Stats are the totals over all the changed files, including files that the
269+ // diff omits or truncates.
270+ DiffStats stats = 2;
271+ // Diff is the structured diff against the first parent, or against the empty
272+ // tree for a root commit. For a merge commit this is the change relative to
273+ // the first parent.
274+ Diff diff = 3;
275+}
276+
277+// DiffStats are the totals of a diff.
278+message DiffStats {
279+ // FilesChanged is the number of changed files.
280+ int32 files_changed = 1;
281+ // Additions is the number of added lines. Binary files count for 0.
282+ int32 additions = 2;
283+ // Deletions is the number of deleted lines. Binary files count for 0.
284+ int32 deletions = 3;
285+}
286+
287+// Diff is the structured difference introduced by a commit.
288+//
289+// The server limits its size: at most 300 files, at most 2,000 lines in one
290+// file and at most 20,000 lines in total (hunk lines, context included). These
291+// numbers are server behaviour and may change; clients must rely on the
292+// truncated flags, not on the numbers.
293+message Diff {
294+ // Files are the changed files, ordered by path. Files past the file limit are
295+ // omitted.
296+ repeated FileDiff files = 1;
297+ // Truncated is true when the diff is incomplete: files were omitted, or at
298+ // least one listed file has truncated set. DiffStats still count everything.
299+ bool truncated = 2;
300+}
301+
302+// FileDiff is the change of one file.
303+message FileDiff {
304+ // OldPath is the path before the commit. Empty for an added file.
305+ string old_path = 1;
306+ // NewPath is the path after the commit. Empty for a deleted file.
307+ string new_path = 2;
308+ // Status tells what happened to the file.
309+ FileStatus status = 3;
310+ // OldMode is the Git file mode before the commit, or 0 for an added file.
311+ uint32 old_mode = 4;
312+ // NewMode is the Git file mode after the commit, or 0 for a deleted file.
313+ uint32 new_mode = 5;
314+ // OldId is the blob id before the commit. Empty for an added file.
315+ string old_id = 6;
316+ // NewId is the blob id after the commit. Empty for a deleted file.
317+ string new_id = 7;
318+ // Binary is true if Git treats the file as binary (numstat reports "-"). A
319+ // binary file has no hunks and additions and deletions are 0.
320+ bool binary = 8;
321+ // Additions is the number of added lines.
322+ int32 additions = 9;
323+ // Deletions is the number of deleted lines.
324+ int32 deletions = 10;
325+ // Similarity is the percentage (0-100) of unchanged content for a renamed or
326+ // copied file, and 0 otherwise.
327+ int32 similarity = 11;
328+ // Truncated is true when the file exceeded a diff limit: hunks is then empty
329+ // although the file changed. Additions and deletions remain accurate.
330+ bool truncated = 12;
331+ // Hunks are the changed regions, in file order. Empty for a binary file, a
332+ // truncated file, a pure rename and a mode-only change.
333+ repeated Hunk hunks = 13;
334+}
335+
336+// Hunk is a contiguous changed region with its context.
337+message Hunk {
338+ // OldStart is the 1-based first line of the region in the old file. 0 when
339+ // old_lines is 0 and the file was added.
340+ int32 old_start = 1;
341+ // OldLines is the number of old-side lines in the hunk.
342+ int32 old_lines = 2;
343+ // NewStart is the 1-based first line of the region in the new file. 0 when
344+ // new_lines is 0 and the file was deleted.
345+ int32 new_start = 3;
346+ // NewLines is the number of new-side lines in the hunk.
347+ int32 new_lines = 4;
348+ // Header is the text after the second "@@" of the hunk header, usually the
349+ // enclosing function. It may be empty.
350+ string header = 5;
351+ // Lines are the lines of the hunk, in order.
352+ repeated Line lines = 6;
353+}
354+
355+// Line is one line of a hunk.
356+message Line {
357+ // Kind tells which side the line belongs to.
358+ LineKind kind = 1;
359+ // OldNumber is the 1-based line number on the old side. 0 for an addition.
360+ int32 old_number = 2;
361+ // NewNumber is the 1-based line number on the new side. 0 for a deletion.
362+ int32 new_number = 3;
363+ // Text is the content without the line terminator. Bytes that are not valid
364+ // UTF-8 are replaced by the replacement character.
365+ string text = 4;
366+ // NoNewlineAtEof is true when this is the last line of its side and the file
367+ // does not end with a line break there.
368+ bool no_newline_at_eof = 5;
369+}
370+
371+// ResolveRevisionRequest names a revision.
372+message ResolveRevisionRequest {
373+ // Repo is the repository name.
374+ string repo = 1;
375+ // Revision is a branch, a tag or a commit id. Empty means HEAD.
376+ string revision = 2;
377+}
378+
379+// ResolveRevisionResponse holds the resolved commit.
380+message ResolveRevisionResponse {
381+ // CommitId is the full id of the commit the revision designates, after
382+ // following annotated tags.
383+ string commit_id = 1;
384+ // Ref is the full name of the ref the revision matched, for example
385+ // "refs/heads/main". Empty when the revision was a commit id or for HEAD
386+ // when it is resolved by default.
387+ string ref = 2;
388+}
A proto/ermite/repo.proto +145 -0
@@ -0,0 +1,145 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "google/protobuf/field_mask.proto";
8+import "google/protobuf/timestamp.proto";
9+
10+// Visibility says who may read a repository.
11+enum Visibility {
12+ // Not set. In requests, the server applies its default (private on create,
13+ // unchanged on update). Never returned by the server.
14+ VISIBILITY_UNSPECIFIED = 0;
15+ // Anyone, including anonymous callers, may read the repository.
16+ VISIBILITY_PUBLIC = 1;
17+ // Only callers holding the repo:read scope on the repository may read it.
18+ // Everyone else gets not_found, never permission_denied.
19+ VISIBILITY_PRIVATE = 2;
20+}
21+
22+// Repo is the metadata of a repository. Git-owned state (refs, trees, history)
23+// is read through GitService.
24+message Repo {
25+ // Name is the unique, lowercase repository name: 1-100 characters from
26+ // [a-z0-9._-], without a ".git" suffix. It is also the URL path: /<name>.
27+ string name = 1;
28+ // Description is a free one-line description. It may be empty.
29+ string description = 2;
30+ // Visibility is who may read the repository.
31+ Visibility visibility = 3;
32+ // DefaultBranch is the short name of the branch HEAD points to, for example
33+ // "main". It is set even when the branch does not exist yet (empty
34+ // repository).
35+ string default_branch = 4;
36+ // CreatedAt is when the repository was created.
37+ google.protobuf.Timestamp created_at = 5;
38+ // PushedAt is the time of the last push. It is unset until the first push.
39+ google.protobuf.Timestamp pushed_at = 6;
40+}
41+
42+// RepoService manages repositories and their metadata.
43+//
44+// Anonymous callers see public repositories only. A private repository that the
45+// caller cannot read is reported as not_found.
46+service RepoService {
47+ // ListRepos lists the repositories the caller may see, ordered by name.
48+ rpc ListRepos(ListReposRequest) returns (ListReposResponse);
49+ // GetRepo returns one repository. Fails with not_found if it does not exist
50+ // or is private and not readable by the caller.
51+ rpc GetRepo(GetRepoRequest) returns (GetRepoResponse);
52+ // CreateRepo creates an empty repository. Needs the repo:write scope. Fails
53+ // with already_exists if the name is taken and invalid_argument if the name
54+ // is not valid.
55+ rpc CreateRepo(CreateRepoRequest) returns (CreateRepoResponse);
56+ // UpdateRepo changes the fields named in update_mask. Needs the repo:admin
57+ // scope.
58+ rpc UpdateRepo(UpdateRepoRequest) returns (UpdateRepoResponse);
59+ // DeleteRepo deletes a repository. Needs the repo:admin scope. The server
60+ // moves the data aside rather than destroying it; there is no undelete RPC.
61+ rpc DeleteRepo(DeleteRepoRequest) returns (DeleteRepoResponse);
62+}
63+
64+// ListReposRequest selects a page of repositories.
65+message ListReposRequest {
66+ // PageSize is the maximum number of repositories to return. 0 means the
67+ // server default; values above the server maximum are lowered to it.
68+ int32 page_size = 1;
69+ // PageToken is the next_page_token of a previous response, to get the page
70+ // after it. Empty for the first page.
71+ string page_token = 2;
72+}
73+
74+// ListReposResponse is one page of repositories.
75+message ListReposResponse {
76+ // Repos are the repositories of this page, ordered by name.
77+ repeated Repo repos = 1;
78+ // NextPageToken is passed as page_token to get the next page. Empty when
79+ // there is no next page.
80+ string next_page_token = 2;
81+}
82+
83+// GetRepoRequest names the repository to read.
84+message GetRepoRequest {
85+ // Repo is the repository name.
86+ string repo = 1;
87+}
88+
89+// GetRepoResponse holds the repository.
90+message GetRepoResponse {
91+ // Repo is the repository metadata.
92+ Repo repo = 1;
93+}
94+
95+// CreateRepoRequest describes the repository to create.
96+message CreateRepoRequest {
97+ // Name is the name of the new repository. Names are lowercase; an uppercase
98+ // name is rejected with invalid_argument.
99+ string name = 1;
100+ // Description is an optional one-line description.
101+ string description = 2;
102+ // Visibility of the new repository. VISIBILITY_UNSPECIFIED means private.
103+ Visibility visibility = 3;
104+}
105+
106+// CreateRepoResponse holds the new repository.
107+message CreateRepoResponse {
108+ // Repo is the created repository.
109+ Repo repo = 1;
110+}
111+
112+// UpdateRepoRequest changes some fields of a repository.
113+message UpdateRepoRequest {
114+ // Repo is the name of the repository to change. Repositories cannot be
115+ // renamed.
116+ string repo = 1;
117+ // Description is the new description. Used only if update_mask contains
118+ // "description"; an empty value then clears it.
119+ string description = 2;
120+ // Visibility is the new visibility. Used only if update_mask contains
121+ // "visibility"; it must not be VISIBILITY_UNSPECIFIED then.
122+ Visibility visibility = 3;
123+ // DefaultBranch is the short name of the new default branch. Used only if
124+ // update_mask contains "default_branch". The branch must exist, otherwise
125+ // the call fails with failed_precondition.
126+ string default_branch = 4;
127+ // UpdateMask lists the fields to change: "description", "visibility" and/or
128+ // "default_branch". It must not be empty. Other paths are invalid_argument.
129+ google.protobuf.FieldMask update_mask = 5;
130+}
131+
132+// UpdateRepoResponse holds the repository after the update.
133+message UpdateRepoResponse {
134+ // Repo is the updated repository.
135+ Repo repo = 1;
136+}
137+
138+// DeleteRepoRequest names the repository to delete.
139+message DeleteRepoRequest {
140+ // Repo is the repository name.
141+ string repo = 1;
142+}
143+
144+// DeleteRepoResponse is empty.
145+message DeleteRepoResponse {}
@@ -0,0 +1,145 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "google/protobuf/field_mask.proto";
8+import "google/protobuf/timestamp.proto";
9+
10+// Visibility says who may read a repository.
11+enum Visibility {
12+ // Not set. In requests, the server applies its default (private on create,
13+ // unchanged on update). Never returned by the server.
14+ VISIBILITY_UNSPECIFIED = 0;
15+ // Anyone, including anonymous callers, may read the repository.
16+ VISIBILITY_PUBLIC = 1;
17+ // Only callers holding the repo:read scope on the repository may read it.
18+ // Everyone else gets not_found, never permission_denied.
19+ VISIBILITY_PRIVATE = 2;
20+}
21+
22+// Repo is the metadata of a repository. Git-owned state (refs, trees, history)
23+// is read through GitService.
24+message Repo {
25+ // Name is the unique, lowercase repository name: 1-100 characters from
26+ // [a-z0-9._-], without a ".git" suffix. It is also the URL path: /<name>.
27+ string name = 1;
28+ // Description is a free one-line description. It may be empty.
29+ string description = 2;
30+ // Visibility is who may read the repository.
31+ Visibility visibility = 3;
32+ // DefaultBranch is the short name of the branch HEAD points to, for example
33+ // "main". It is set even when the branch does not exist yet (empty
34+ // repository).
35+ string default_branch = 4;
36+ // CreatedAt is when the repository was created.
37+ google.protobuf.Timestamp created_at = 5;
38+ // PushedAt is the time of the last push. It is unset until the first push.
39+ google.protobuf.Timestamp pushed_at = 6;
40+}
41+
42+// RepoService manages repositories and their metadata.
43+//
44+// Anonymous callers see public repositories only. A private repository that the
45+// caller cannot read is reported as not_found.
46+service RepoService {
47+ // ListRepos lists the repositories the caller may see, ordered by name.
48+ rpc ListRepos(ListReposRequest) returns (ListReposResponse);
49+ // GetRepo returns one repository. Fails with not_found if it does not exist
50+ // or is private and not readable by the caller.
51+ rpc GetRepo(GetRepoRequest) returns (GetRepoResponse);
52+ // CreateRepo creates an empty repository. Needs the repo:write scope. Fails
53+ // with already_exists if the name is taken and invalid_argument if the name
54+ // is not valid.
55+ rpc CreateRepo(CreateRepoRequest) returns (CreateRepoResponse);
56+ // UpdateRepo changes the fields named in update_mask. Needs the repo:admin
57+ // scope.
58+ rpc UpdateRepo(UpdateRepoRequest) returns (UpdateRepoResponse);
59+ // DeleteRepo deletes a repository. Needs the repo:admin scope. The server
60+ // moves the data aside rather than destroying it; there is no undelete RPC.
61+ rpc DeleteRepo(DeleteRepoRequest) returns (DeleteRepoResponse);
62+}
63+
64+// ListReposRequest selects a page of repositories.
65+message ListReposRequest {
66+ // PageSize is the maximum number of repositories to return. 0 means the
67+ // server default; values above the server maximum are lowered to it.
68+ int32 page_size = 1;
69+ // PageToken is the next_page_token of a previous response, to get the page
70+ // after it. Empty for the first page.
71+ string page_token = 2;
72+}
73+
74+// ListReposResponse is one page of repositories.
75+message ListReposResponse {
76+ // Repos are the repositories of this page, ordered by name.
77+ repeated Repo repos = 1;
78+ // NextPageToken is passed as page_token to get the next page. Empty when
79+ // there is no next page.
80+ string next_page_token = 2;
81+}
82+
83+// GetRepoRequest names the repository to read.
84+message GetRepoRequest {
85+ // Repo is the repository name.
86+ string repo = 1;
87+}
88+
89+// GetRepoResponse holds the repository.
90+message GetRepoResponse {
91+ // Repo is the repository metadata.
92+ Repo repo = 1;
93+}
94+
95+// CreateRepoRequest describes the repository to create.
96+message CreateRepoRequest {
97+ // Name is the name of the new repository. Names are lowercase; an uppercase
98+ // name is rejected with invalid_argument.
99+ string name = 1;
100+ // Description is an optional one-line description.
101+ string description = 2;
102+ // Visibility of the new repository. VISIBILITY_UNSPECIFIED means private.
103+ Visibility visibility = 3;
104+}
105+
106+// CreateRepoResponse holds the new repository.
107+message CreateRepoResponse {
108+ // Repo is the created repository.
109+ Repo repo = 1;
110+}
111+
112+// UpdateRepoRequest changes some fields of a repository.
113+message UpdateRepoRequest {
114+ // Repo is the name of the repository to change. Repositories cannot be
115+ // renamed.
116+ string repo = 1;
117+ // Description is the new description. Used only if update_mask contains
118+ // "description"; an empty value then clears it.
119+ string description = 2;
120+ // Visibility is the new visibility. Used only if update_mask contains
121+ // "visibility"; it must not be VISIBILITY_UNSPECIFIED then.
122+ Visibility visibility = 3;
123+ // DefaultBranch is the short name of the new default branch. Used only if
124+ // update_mask contains "default_branch". The branch must exist, otherwise
125+ // the call fails with failed_precondition.
126+ string default_branch = 4;
127+ // UpdateMask lists the fields to change: "description", "visibility" and/or
128+ // "default_branch". It must not be empty. Other paths are invalid_argument.
129+ google.protobuf.FieldMask update_mask = 5;
130+}
131+
132+// UpdateRepoResponse holds the repository after the update.
133+message UpdateRepoResponse {
134+ // Repo is the updated repository.
135+ Repo repo = 1;
136+}
137+
138+// DeleteRepoRequest names the repository to delete.
139+message DeleteRepoRequest {
140+ // Repo is the repository name.
141+ string repo = 1;
142+}
143+
144+// DeleteRepoResponse is empty.
145+message DeleteRepoResponse {}
A proto/ermite/server.proto +30 -0
@@ -0,0 +1,30 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+// ServerService describes the server itself.
8+service ServerService {
9+ // GetVersion returns the server version and the optional capabilities of the
10+ // contract it implements. It needs no authentication, so a client can call
11+ // it first to check compatibility.
12+ rpc GetVersion(GetVersionRequest) returns (GetVersionResponse);
13+}
14+
15+// GetVersionRequest is empty.
16+message GetVersionRequest {}
17+
18+// GetVersionResponse describes the running server.
19+message GetVersionResponse {
20+ // Version is the server release, for example "v0.4.0", or "devel" for an
21+ // untagged build. Informational: clients must not compare it to decide what
22+ // is supported, they use features instead.
23+ string version = 1;
24+ // Features lists identifiers of the optional capabilities of the contract
25+ // that this server implements, for example "repo.update" or
26+ // "events.resume". A client that needs a capability missing from this list
27+ // should warn instead of failing on an unimplemented RPC or ignored field.
28+ // Identifiers are lowercase, dot-separated and never reused.
29+ repeated string features = 2;
30+}
@@ -0,0 +1,30 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+// ServerService describes the server itself.
8+service ServerService {
9+ // GetVersion returns the server version and the optional capabilities of the
10+ // contract it implements. It needs no authentication, so a client can call
11+ // it first to check compatibility.
12+ rpc GetVersion(GetVersionRequest) returns (GetVersionResponse);
13+}
14+
15+// GetVersionRequest is empty.
16+message GetVersionRequest {}
17+
18+// GetVersionResponse describes the running server.
19+message GetVersionResponse {
20+ // Version is the server release, for example "v0.4.0", or "devel" for an
21+ // untagged build. Informational: clients must not compare it to decide what
22+ // is supported, they use features instead.
23+ string version = 1;
24+ // Features lists identifiers of the optional capabilities of the contract
25+ // that this server implements, for example "repo.update" or
26+ // "events.resume". A client that needs a capability missing from this list
27+ // should warn instead of failing on an unimplemented RPC or ignored field.
28+ // Identifiers are lowercase, dot-separated and never reused.
29+ repeated string features = 2;
30+}
A proto/ermite/token.proto +132 -0
@@ -0,0 +1,132 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "google/protobuf/timestamp.proto";
8+
9+// Scope is a permission carried by a token. The API knows scopes only; any
10+// grouping into presets is a client concern.
11+enum Scope {
12+ // Not set. Rejected in requests, never returned by the server.
13+ SCOPE_UNSPECIFIED = 0;
14+ // SCOPE_REPO_READ allows reading private repositories (public ones need no
15+ // token). Wire name: repo:read.
16+ SCOPE_REPO_READ = 1;
17+ // SCOPE_REPO_WRITE allows pushing and creating repositories. Wire name:
18+ // repo:write.
19+ SCOPE_REPO_WRITE = 2;
20+ // SCOPE_REPO_ADMIN allows deleting a repository and changing its visibility,
21+ // description or default branch. Wire name: repo:admin.
22+ SCOPE_REPO_ADMIN = 3;
23+ // SCOPE_MR_WRITE allows creating, commenting on and closing merge requests.
24+ // Wire name: mr:write.
25+ SCOPE_MR_WRITE = 4;
26+ // SCOPE_MR_MERGE allows merging merge requests. Wire name: mr:merge.
27+ SCOPE_MR_MERGE = 5;
28+ // SCOPE_CI_WRITE allows re-running or cancelling CI runs. Wire name:
29+ // ci:write.
30+ SCOPE_CI_WRITE = 6;
31+ // SCOPE_SECRETS_WRITE allows setting and deleting secrets and variables.
32+ // Wire name: secrets:write.
33+ SCOPE_SECRETS_WRITE = 7;
34+ // SCOPE_RUNNER_REGISTER allows registering a CI runner. Wire name:
35+ // runner:register.
36+ SCOPE_RUNNER_REGISTER = 8;
37+ // SCOPE_TOKEN_ADMIN allows creating, listing and revoking tokens. Wire name:
38+ // token:admin.
39+ SCOPE_TOKEN_ADMIN = 9;
40+}
41+
42+// Token describes a stored token. It never contains the secret nor its hash.
43+message Token {
44+ // Id identifies the token in ListTokens and RevokeToken. It is not the
45+ // secret and cannot be used to authenticate.
46+ string id = 1;
47+ // Label is a human-readable name chosen at creation.
48+ string label = 2;
49+ // Scopes are the permissions of the token. Never empty.
50+ repeated Scope scopes = 3;
51+ // Repos restricts the token to these repository names. Empty means every
52+ // repository.
53+ repeated string repos = 4;
54+ // ExpiresAt is when the token stops working. Unset means it never expires.
55+ google.protobuf.Timestamp expires_at = 5;
56+ // CreatedAt is when the token was created.
57+ google.protobuf.Timestamp created_at = 6;
58+ // LastUsedAt is when the token last authenticated a request. Unset if never
59+ // used. It may lag behind the real time by a short delay.
60+ google.protobuf.Timestamp last_used_at = 7;
61+}
62+
63+// TokenService manages stored tokens. Every RPC needs the token:admin scope.
64+//
65+// A token can only create tokens that are within its own limits: scopes that
66+// it holds, repositories that it may access and an expiry no later than its
67+// own. The root token (ERMITE_ADMIN_TOKEN) is not a stored token and is never
68+// listed.
69+service TokenService {
70+ // CreateToken creates a token and returns its secret. The secret is shown
71+ // only in this response and cannot be retrieved later. Fails with
72+ // permission_denied when the new token would exceed the caller's limits and
73+ // with invalid_argument when scopes is empty or contains SCOPE_UNSPECIFIED.
74+ rpc CreateToken(CreateTokenRequest) returns (CreateTokenResponse);
75+ // ListTokens lists stored tokens, newest first.
76+ rpc ListTokens(ListTokensRequest) returns (ListTokensResponse);
77+ // RevokeToken deletes a token; it stops working immediately. Fails with
78+ // not_found if the id is unknown.
79+ rpc RevokeToken(RevokeTokenRequest) returns (RevokeTokenResponse);
80+}
81+
82+// CreateTokenRequest describes the token to create.
83+message CreateTokenRequest {
84+ // Label is a human-readable name, for example "laptop". Not required to be
85+ // unique.
86+ string label = 1;
87+ // Scopes are the permissions to grant. At least one is required.
88+ repeated Scope scopes = 2;
89+ // Repos restricts the token to these repository names. Empty means every
90+ // repository.
91+ repeated string repos = 3;
92+ // ExpiresAt is when the token stops working. Unset means no expiry. It must
93+ // be in the future.
94+ google.protobuf.Timestamp expires_at = 4;
95+}
96+
97+// CreateTokenResponse holds the new token and its secret.
98+message CreateTokenResponse {
99+ // Token describes the created token.
100+ Token token = 1;
101+ // Secret is the bearer secret to present as "Authorization: Bearer <secret>".
102+ // It is returned once and never stored in clear text by the server.
103+ string secret = 2;
104+}
105+
106+// ListTokensRequest selects a page of tokens.
107+message ListTokensRequest {
108+ // PageSize is the maximum number of tokens to return. 0 means the server
109+ // default; values above the server maximum are lowered to it.
110+ int32 page_size = 1;
111+ // PageToken is the next_page_token of a previous response. Empty for the
112+ // first page.
113+ string page_token = 2;
114+}
115+
116+// ListTokensResponse is one page of tokens.
117+message ListTokensResponse {
118+ // Tokens are the tokens of this page, newest first.
119+ repeated Token tokens = 1;
120+ // NextPageToken is passed as page_token to get the next page. Empty when
121+ // there is no next page.
122+ string next_page_token = 2;
123+}
124+
125+// RevokeTokenRequest names the token to revoke.
126+message RevokeTokenRequest {
127+ // Id is the Token.id to revoke.
128+ string id = 1;
129+}
130+
131+// RevokeTokenResponse is empty.
132+message RevokeTokenResponse {}
@@ -0,0 +1,132 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "google/protobuf/timestamp.proto";
8+
9+// Scope is a permission carried by a token. The API knows scopes only; any
10+// grouping into presets is a client concern.
11+enum Scope {
12+ // Not set. Rejected in requests, never returned by the server.
13+ SCOPE_UNSPECIFIED = 0;
14+ // SCOPE_REPO_READ allows reading private repositories (public ones need no
15+ // token). Wire name: repo:read.
16+ SCOPE_REPO_READ = 1;
17+ // SCOPE_REPO_WRITE allows pushing and creating repositories. Wire name:
18+ // repo:write.
19+ SCOPE_REPO_WRITE = 2;
20+ // SCOPE_REPO_ADMIN allows deleting a repository and changing its visibility,
21+ // description or default branch. Wire name: repo:admin.
22+ SCOPE_REPO_ADMIN = 3;
23+ // SCOPE_MR_WRITE allows creating, commenting on and closing merge requests.
24+ // Wire name: mr:write.
25+ SCOPE_MR_WRITE = 4;
26+ // SCOPE_MR_MERGE allows merging merge requests. Wire name: mr:merge.
27+ SCOPE_MR_MERGE = 5;
28+ // SCOPE_CI_WRITE allows re-running or cancelling CI runs. Wire name:
29+ // ci:write.
30+ SCOPE_CI_WRITE = 6;
31+ // SCOPE_SECRETS_WRITE allows setting and deleting secrets and variables.
32+ // Wire name: secrets:write.
33+ SCOPE_SECRETS_WRITE = 7;
34+ // SCOPE_RUNNER_REGISTER allows registering a CI runner. Wire name:
35+ // runner:register.
36+ SCOPE_RUNNER_REGISTER = 8;
37+ // SCOPE_TOKEN_ADMIN allows creating, listing and revoking tokens. Wire name:
38+ // token:admin.
39+ SCOPE_TOKEN_ADMIN = 9;
40+}
41+
42+// Token describes a stored token. It never contains the secret nor its hash.
43+message Token {
44+ // Id identifies the token in ListTokens and RevokeToken. It is not the
45+ // secret and cannot be used to authenticate.
46+ string id = 1;
47+ // Label is a human-readable name chosen at creation.
48+ string label = 2;
49+ // Scopes are the permissions of the token. Never empty.
50+ repeated Scope scopes = 3;
51+ // Repos restricts the token to these repository names. Empty means every
52+ // repository.
53+ repeated string repos = 4;
54+ // ExpiresAt is when the token stops working. Unset means it never expires.
55+ google.protobuf.Timestamp expires_at = 5;
56+ // CreatedAt is when the token was created.
57+ google.protobuf.Timestamp created_at = 6;
58+ // LastUsedAt is when the token last authenticated a request. Unset if never
59+ // used. It may lag behind the real time by a short delay.
60+ google.protobuf.Timestamp last_used_at = 7;
61+}
62+
63+// TokenService manages stored tokens. Every RPC needs the token:admin scope.
64+//
65+// A token can only create tokens that are within its own limits: scopes that
66+// it holds, repositories that it may access and an expiry no later than its
67+// own. The root token (ERMITE_ADMIN_TOKEN) is not a stored token and is never
68+// listed.
69+service TokenService {
70+ // CreateToken creates a token and returns its secret. The secret is shown
71+ // only in this response and cannot be retrieved later. Fails with
72+ // permission_denied when the new token would exceed the caller's limits and
73+ // with invalid_argument when scopes is empty or contains SCOPE_UNSPECIFIED.
74+ rpc CreateToken(CreateTokenRequest) returns (CreateTokenResponse);
75+ // ListTokens lists stored tokens, newest first.
76+ rpc ListTokens(ListTokensRequest) returns (ListTokensResponse);
77+ // RevokeToken deletes a token; it stops working immediately. Fails with
78+ // not_found if the id is unknown.
79+ rpc RevokeToken(RevokeTokenRequest) returns (RevokeTokenResponse);
80+}
81+
82+// CreateTokenRequest describes the token to create.
83+message CreateTokenRequest {
84+ // Label is a human-readable name, for example "laptop". Not required to be
85+ // unique.
86+ string label = 1;
87+ // Scopes are the permissions to grant. At least one is required.
88+ repeated Scope scopes = 2;
89+ // Repos restricts the token to these repository names. Empty means every
90+ // repository.
91+ repeated string repos = 3;
92+ // ExpiresAt is when the token stops working. Unset means no expiry. It must
93+ // be in the future.
94+ google.protobuf.Timestamp expires_at = 4;
95+}
96+
97+// CreateTokenResponse holds the new token and its secret.
98+message CreateTokenResponse {
99+ // Token describes the created token.
100+ Token token = 1;
101+ // Secret is the bearer secret to present as "Authorization: Bearer <secret>".
102+ // It is returned once and never stored in clear text by the server.
103+ string secret = 2;
104+}
105+
106+// ListTokensRequest selects a page of tokens.
107+message ListTokensRequest {
108+ // PageSize is the maximum number of tokens to return. 0 means the server
109+ // default; values above the server maximum are lowered to it.
110+ int32 page_size = 1;
111+ // PageToken is the next_page_token of a previous response. Empty for the
112+ // first page.
113+ string page_token = 2;
114+}
115+
116+// ListTokensResponse is one page of tokens.
117+message ListTokensResponse {
118+ // Tokens are the tokens of this page, newest first.
119+ repeated Token tokens = 1;
120+ // NextPageToken is passed as page_token to get the next page. Empty when
121+ // there is no next page.
122+ string next_page_token = 2;
123+}
124+
125+// RevokeTokenRequest names the token to revoke.
126+message RevokeTokenRequest {
127+ // Id is the Token.id to revoke.
128+ string id = 1;
129+}
130+
131+// RevokeTokenResponse is empty.
132+message RevokeTokenResponse {}
A proto/ermite/types.proto +37 -0
@@ -0,0 +1,37 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "google/protobuf/timestamp.proto";
8+
9+// Signature identifies who did something in Git and when: the author or the
10+// committer of a commit.
11+message Signature {
12+ // Name is the person's name as recorded in the commit.
13+ string name = 1;
14+ // Email is the person's email address as recorded in the commit.
15+ string email = 2;
16+ // Time is when the action happened. The time zone offset of the commit is
17+ // not kept.
18+ google.protobuf.Timestamp time = 3;
19+}
20+
21+// Commit is the metadata of one Git commit.
22+message Commit {
23+ // Id is the full object id (40 lowercase hexadecimal characters for SHA-1).
24+ string id = 1;
25+ // ParentIds are the ids of the parent commits, first parent first. Empty for
26+ // a root commit.
27+ repeated string parent_ids = 2;
28+ // Author is who wrote the change.
29+ Signature author = 3;
30+ // Committer is who recorded the commit.
31+ Signature committer = 4;
32+ // Summary is the first line of the message, without the line break.
33+ string summary = 5;
34+ // Message is the full commit message, including the summary. Text that is
35+ // not valid UTF-8 is converted with the replacement character.
36+ string message = 6;
37+}
@@ -0,0 +1,37 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "google/protobuf/timestamp.proto";
8+
9+// Signature identifies who did something in Git and when: the author or the
10+// committer of a commit.
11+message Signature {
12+ // Name is the person's name as recorded in the commit.
13+ string name = 1;
14+ // Email is the person's email address as recorded in the commit.
15+ string email = 2;
16+ // Time is when the action happened. The time zone offset of the commit is
17+ // not kept.
18+ google.protobuf.Timestamp time = 3;
19+}
20+
21+// Commit is the metadata of one Git commit.
22+message Commit {
23+ // Id is the full object id (40 lowercase hexadecimal characters for SHA-1).
24+ string id = 1;
25+ // ParentIds are the ids of the parent commits, first parent first. Empty for
26+ // a root commit.
27+ repeated string parent_ids = 2;
28+ // Author is who wrote the change.
29+ Signature author = 3;
30+ // Committer is who recorded the commit.
31+ Signature committer = 4;
32+ // Summary is the first line of the message, without the line break.
33+ string summary = 5;
34+ // Message is the full commit message, including the summary. Text that is
35+ // not valid UTF-8 is converted with the replacement character.
36+ string message = 6;
37+}

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