Merge 2aff1f72c9fe3e30cef3a2f5509e92ca1143118f into 11411cf5b9c2107e005d98d274d8bd850f607970
13 files · +3034 -128
M README.md +1 -0
| @@ -33,6 +33,7 @@ Status: early development. | |||
| 33 | 33 | | `GitService` | refs, trees, blobs, commits and diffs | | |
| 34 | 34 | | `TokenService` | API tokens | | |
| 35 | 35 | | `MergeRequestService` | merge requests, comments, merge | | |
| 36 | + | | `IssueService` | issues, comments, owner moderation of public submissions | | |
| 36 | 37 | | `SessionService` | web sign-in links (owner only) | | |
| 37 | 38 | | `EventService` | live event stream, resumable | | |
| 38 | 39 | | `ServerService` | version, features, signing key, OIDC key rotation | | |
| @@ -33,6 +33,7 @@ Status: early development. | |||||
| 33 | | `GitService` | refs, trees, blobs, commits and diffs | | 33 | | `GitService` | refs, trees, blobs, commits and diffs | | ||
| 34 | | `TokenService` | API tokens | | 34 | | `TokenService` | API tokens | | ||
| 35 | | `MergeRequestService` | merge requests, comments, merge | | 35 | | `MergeRequestService` | merge requests, comments, merge | | ||
| 36 | + | | `IssueService` | issues, comments, owner moderation of public submissions | | |||
| 36 | | `SessionService` | web sign-in links (owner only) | | 37 | | `SessionService` | web sign-in links (owner only) | | ||
| 37 | | `EventService` | live event stream, resumable | | 38 | | `EventService` | live event stream, resumable | | ||
| 38 | | `ServerService` | version, features, signing key, OIDC key rotation | | 39 | | `ServerService` | version, features, signing key, OIDC key rotation | | ||
M docs/services.md +2 -1
| @@ -6,8 +6,9 @@ | |||
| 6 | 6 | | `GitService` | `ListRefs`, `GetTree`, `ListPaths`, `GetBlob` (streamed), `ListCommits`, `GetCommit` (structured diff), `ResolveRevision` | | |
| 7 | 7 | | `TokenService` | `CreateToken` (secret shown once), `ListTokens`, `RevokeToken` | | |
| 8 | 8 | | `MergeRequestService` | `CreateMergeRequest`, `ListMergeRequests`, `GetMergeRequest` (commits, diff, comments), `AddComment`, `EditComment`, `DeleteComment`, `ResolveComment`, `CloseMergeRequest`, `MergeMergeRequest`, `MarkRead` | | |
| 9 | + | | `IssueService` | `CreateIssue`, `ListIssues`, `GetIssue` (comments), `AddIssueComment`, `CloseIssue`, `ReopenIssue`; owner only: `ListPendingIssues`, `ApproveIssue`, `RejectIssue`. Feature `issues`. Issues share numbers with merge requests | | |
| 9 | 10 | | `SessionService` | `CreateLoginLink`, `SignOutEverywhere` (owner only) | | |
| 10 | - | | `EventService` | `Watch` (streamed, resumable) | | |
| 11 | + | | `EventService` | `Watch` (streamed, resumable). Topics `home`, `repo:<name>` and `owner` (owner rights only). Events 17–21: `issue_opened`, `issue_closed`, `issue_reopened`, `issue_commented`, and `issue_submitted` (only on `owner`, no content) | | |
| 11 | 12 | | `ServerService` | `GetVersion` (version and features), `GetSigningKey`, `RotateOIDCKey` (owner only) | | |
| 12 | 13 | | `TrustedKeyService` | `ListTrustedKeys`, `AddTrustedKey` and `RemoveTrustedKey` (owner only). `Commit.verification` carries the result of the check (feature `commit_signatures`) | | |
| 13 | 14 | | `RunService` | `ListRuns`, `GetRun`, `GetJob`, `GetJobLog` (streamed, follow), `ListAnnotations`, `GetStepSummaries`, `CancelRun`, `RerunRun`, `DispatchWorkflow`, `ListWorkflows`, `DisableWorkflow`, `EnableWorkflow`, `ListChecks`, `ListRunners`, `RemoveRunner` | | |
| @@ -6,8 +6,9 @@ | |||||
| 6 | | `GitService` | `ListRefs`, `GetTree`, `ListPaths`, `GetBlob` (streamed), `ListCommits`, `GetCommit` (structured diff), `ResolveRevision` | | 6 | | `GitService` | `ListRefs`, `GetTree`, `ListPaths`, `GetBlob` (streamed), `ListCommits`, `GetCommit` (structured diff), `ResolveRevision` | | ||
| 7 | | `TokenService` | `CreateToken` (secret shown once), `ListTokens`, `RevokeToken` | | 7 | | `TokenService` | `CreateToken` (secret shown once), `ListTokens`, `RevokeToken` | | ||
| 8 | | `MergeRequestService` | `CreateMergeRequest`, `ListMergeRequests`, `GetMergeRequest` (commits, diff, comments), `AddComment`, `EditComment`, `DeleteComment`, `ResolveComment`, `CloseMergeRequest`, `MergeMergeRequest`, `MarkRead` | | 8 | | `MergeRequestService` | `CreateMergeRequest`, `ListMergeRequests`, `GetMergeRequest` (commits, diff, comments), `AddComment`, `EditComment`, `DeleteComment`, `ResolveComment`, `CloseMergeRequest`, `MergeMergeRequest`, `MarkRead` | | ||
| 9 | + | | `IssueService` | `CreateIssue`, `ListIssues`, `GetIssue` (comments), `AddIssueComment`, `CloseIssue`, `ReopenIssue`; owner only: `ListPendingIssues`, `ApproveIssue`, `RejectIssue`. Feature `issues`. Issues share numbers with merge requests | | |||
| 9 | | `SessionService` | `CreateLoginLink`, `SignOutEverywhere` (owner only) | | 10 | | `SessionService` | `CreateLoginLink`, `SignOutEverywhere` (owner only) | | ||
| 10 | - | | `EventService` | `Watch` (streamed, resumable) | | 11 | + | | `EventService` | `Watch` (streamed, resumable). Topics `home`, `repo:<name>` and `owner` (owner rights only). Events 17–21: `issue_opened`, `issue_closed`, `issue_reopened`, `issue_commented`, and `issue_submitted` (only on `owner`, no content) | |
| 11 | | `ServerService` | `GetVersion` (version and features), `GetSigningKey`, `RotateOIDCKey` (owner only) | | 12 | | `ServerService` | `GetVersion` (version and features), `GetSigningKey`, `RotateOIDCKey` (owner only) | | ||
| 12 | | `TrustedKeyService` | `ListTrustedKeys`, `AddTrustedKey` and `RemoveTrustedKey` (owner only). `Commit.verification` carries the result of the check (feature `commit_signatures`) | | 13 | | `TrustedKeyService` | `ListTrustedKeys`, `AddTrustedKey` and `RemoveTrustedKey` (owner only). `Commit.verification` carries the result of the check (feature `commit_signatures`) | | ||
| 13 | | `RunService` | `ListRuns`, `GetRun`, `GetJob`, `GetJobLog` (streamed, follow), `ListAnnotations`, `GetStepSummaries`, `CancelRun`, `RerunRun`, `DispatchWorkflow`, `ListWorkflows`, `DisableWorkflow`, `EnableWorkflow`, `ListChecks`, `ListRunners`, `RemoveRunner` | | 14 | | `RunService` | `ListRuns`, `GetRun`, `GetJob`, `GetJobLog` (streamed, follow), `ListAnnotations`, `GetStepSummaries`, `CancelRun`, `RerunRun`, `DispatchWorkflow`, `ListWorkflows`, `DisableWorkflow`, `EnableWorkflow`, `ListChecks`, `ListRunners`, `RemoveRunner` | | ||
M gen/ermite/ermiteconnect/event.connect.go +12 -6
| @@ -48,9 +48,12 @@ type EventServiceClient interface { | |||
| 48 | 48 | // The events are repo_created, repo_updated, repo_deleted, pushed, gap and, | |
| 49 | 49 | // for merge requests, merge_request_opened, merge_request_merged, | |
| 50 | 50 | // merge_request_closed, comment_added, comment_edited, comment_deleted and | |
| 51 | - | // comment_resolved (a thread resolved or reopened). Each one is delivered on the | |
| 52 | - | // "repo:<name>" topic of its repository and on "home", subject to the | |
| 53 | - | // visibility of the repository. | |
| 51 | + | // comment_resolved (a thread resolved or reopened); for issues, issue_opened, | |
| 52 | + | // issue_closed, issue_reopened and issue_commented, and issue_submitted. Each | |
| 53 | + | // one is delivered on the "repo:<name>" topic of its repository and on | |
| 54 | + | // "home", subject to the visibility of the repository, except | |
| 55 | + | // issue_submitted: it is delivered only on the "owner" topic, never on | |
| 56 | + | // "home" or "repo:<name>", and carries no content (see IssueSubmitted). | |
| 54 | 57 | // | |
| 55 | 58 | // Servers with the feature "ci.runs" also publish run_updated and | |
| 56 | 59 | // job_updated, only on the "repo:<name>" topic of their repository (never on | |
| @@ -121,9 +124,12 @@ type EventServiceHandler interface { | |||
| 121 | 124 | // The events are repo_created, repo_updated, repo_deleted, pushed, gap and, | |
| 122 | 125 | // for merge requests, merge_request_opened, merge_request_merged, | |
| 123 | 126 | // merge_request_closed, comment_added, comment_edited, comment_deleted and | |
| 124 | - | // comment_resolved (a thread resolved or reopened). Each one is delivered on the | |
| 125 | - | // "repo:<name>" topic of its repository and on "home", subject to the | |
| 126 | - | // visibility of the repository. | |
| 127 | + | // comment_resolved (a thread resolved or reopened); for issues, issue_opened, | |
| 128 | + | // issue_closed, issue_reopened and issue_commented, and issue_submitted. Each | |
| 129 | + | // one is delivered on the "repo:<name>" topic of its repository and on | |
| 130 | + | // "home", subject to the visibility of the repository, except | |
| 131 | + | // issue_submitted: it is delivered only on the "owner" topic, never on | |
| 132 | + | // "home" or "repo:<name>", and carries no content (see IssueSubmitted). | |
| 127 | 133 | // | |
| 128 | 134 | // Servers with the feature "ci.runs" also publish run_updated and | |
| 129 | 135 | // job_updated, only on the "repo:<name>" topic of their repository (never on | |
| @@ -48,9 +48,12 @@ type EventServiceClient interface { | |||||
| 48 | // The events are repo_created, repo_updated, repo_deleted, pushed, gap and, | 48 | // The events are repo_created, repo_updated, repo_deleted, pushed, gap and, | ||
| 49 | // for merge requests, merge_request_opened, merge_request_merged, | 49 | // for merge requests, merge_request_opened, merge_request_merged, | ||
| 50 | // merge_request_closed, comment_added, comment_edited, comment_deleted and | 50 | // merge_request_closed, comment_added, comment_edited, comment_deleted and | ||
| 51 | - | // comment_resolved (a thread resolved or reopened). Each one is delivered on the | 51 | + | // comment_resolved (a thread resolved or reopened); for issues, issue_opened, |
| 52 | - | // "repo:<name>" topic of its repository and on "home", subject to the | 52 | + | // issue_closed, issue_reopened and issue_commented, and issue_submitted. Each |
| 53 | - | // visibility of the repository. | 53 | + | // one is delivered on the "repo:<name>" topic of its repository and on |
| 54 | + | // "home", subject to the visibility of the repository, except | |||
| 55 | + | // issue_submitted: it is delivered only on the "owner" topic, never on | |||
| 56 | + | // "home" or "repo:<name>", and carries no content (see IssueSubmitted). | |||
| 54 | // | 57 | // | ||
| 55 | // Servers with the feature "ci.runs" also publish run_updated and | 58 | // Servers with the feature "ci.runs" also publish run_updated and | ||
| 56 | // job_updated, only on the "repo:<name>" topic of their repository (never on | 59 | // job_updated, only on the "repo:<name>" topic of their repository (never on | ||
| @@ -121,9 +124,12 @@ type EventServiceHandler interface { | |||||
| 121 | // The events are repo_created, repo_updated, repo_deleted, pushed, gap and, | 124 | // The events are repo_created, repo_updated, repo_deleted, pushed, gap and, | ||
| 122 | // for merge requests, merge_request_opened, merge_request_merged, | 125 | // for merge requests, merge_request_opened, merge_request_merged, | ||
| 123 | // merge_request_closed, comment_added, comment_edited, comment_deleted and | 126 | // merge_request_closed, comment_added, comment_edited, comment_deleted and | ||
| 124 | - | // comment_resolved (a thread resolved or reopened). Each one is delivered on the | 127 | + | // comment_resolved (a thread resolved or reopened); for issues, issue_opened, |
| 125 | - | // "repo:<name>" topic of its repository and on "home", subject to the | 128 | + | // issue_closed, issue_reopened and issue_commented, and issue_submitted. Each |
| 126 | - | // visibility of the repository. | 129 | + | // one is delivered on the "repo:<name>" topic of its repository and on |
| 130 | + | // "home", subject to the visibility of the repository, except | |||
| 131 | + | // issue_submitted: it is delivered only on the "owner" topic, never on | |||
| 132 | + | // "home" or "repo:<name>", and carries no content (see IssueSubmitted). | |||
| 127 | // | 133 | // | ||
| 128 | // Servers with the feature "ci.runs" also publish run_updated and | 134 | // Servers with the feature "ci.runs" also publish run_updated and | ||
| 129 | // job_updated, only on the "repo:<name>" topic of their repository (never on | 135 | // job_updated, only on the "repo:<name>" topic of their repository (never on | ||
A gen/ermite/ermiteconnect/issue.connect.go +364 -0
| @@ -0,0 +1,364 @@ | |||
| 1 | + | // SPDX-License-Identifier: MIT | |
| 2 | + | ||
| 3 | + | // Code generated by protoc-gen-connect-go. DO NOT EDIT. | |
| 4 | + | // | |
| 5 | + | // Source: ermite/issue.proto | |
| 6 | + | ||
| 7 | + | package ermiteconnect | |
| 8 | + | ||
| 9 | + | import ( | |
| 10 | + | ermite "bnema.dev/ermite-api/gen/ermite" | |
| 11 | + | connect "connectrpc.com/connect" | |
| 12 | + | context "context" | |
| 13 | + | errors "errors" | |
| 14 | + | http "net/http" | |
| 15 | + | strings "strings" | |
| 16 | + | ) | |
| 17 | + | ||
| 18 | + | // This is a compile-time assertion to ensure that this generated file and the connect package are | |
| 19 | + | // compatible. If you get a compiler error that this constant is not defined, this code was | |
| 20 | + | // generated with a version of connect newer than the one compiled into your binary. You can fix the | |
| 21 | + | // problem by either regenerating this code with an older version of connect or updating the connect | |
| 22 | + | // version compiled into your binary. | |
| 23 | + | const _ = connect.IsAtLeastVersion1_13_0 | |
| 24 | + | ||
| 25 | + | const ( | |
| 26 | + | // IssueServiceName is the fully-qualified name of the IssueService service. | |
| 27 | + | IssueServiceName = "ermite.IssueService" | |
| 28 | + | ) | |
| 29 | + | ||
| 30 | + | // These constants are the fully-qualified names of the RPCs defined in this package. They're | |
| 31 | + | // exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. | |
| 32 | + | // | |
| 33 | + | // Note that these are different from the fully-qualified method names used by | |
| 34 | + | // google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to | |
| 35 | + | // reflection-formatted method names, remove the leading slash and convert the remaining slash to a | |
| 36 | + | // period. | |
| 37 | + | const ( | |
| 38 | + | // IssueServiceCreateIssueProcedure is the fully-qualified name of the IssueService's CreateIssue | |
| 39 | + | // RPC. | |
| 40 | + | IssueServiceCreateIssueProcedure = "/ermite.IssueService/CreateIssue" | |
| 41 | + | // IssueServiceListIssuesProcedure is the fully-qualified name of the IssueService's ListIssues RPC. | |
| 42 | + | IssueServiceListIssuesProcedure = "/ermite.IssueService/ListIssues" | |
| 43 | + | // IssueServiceGetIssueProcedure is the fully-qualified name of the IssueService's GetIssue RPC. | |
| 44 | + | IssueServiceGetIssueProcedure = "/ermite.IssueService/GetIssue" | |
| 45 | + | // IssueServiceAddIssueCommentProcedure is the fully-qualified name of the IssueService's | |
| 46 | + | // AddIssueComment RPC. | |
| 47 | + | IssueServiceAddIssueCommentProcedure = "/ermite.IssueService/AddIssueComment" | |
| 48 | + | // IssueServiceCloseIssueProcedure is the fully-qualified name of the IssueService's CloseIssue RPC. | |
| 49 | + | IssueServiceCloseIssueProcedure = "/ermite.IssueService/CloseIssue" | |
| 50 | + | // IssueServiceReopenIssueProcedure is the fully-qualified name of the IssueService's ReopenIssue | |
| 51 | + | // RPC. | |
| 52 | + | IssueServiceReopenIssueProcedure = "/ermite.IssueService/ReopenIssue" | |
| 53 | + | // IssueServiceListPendingIssuesProcedure is the fully-qualified name of the IssueService's | |
| 54 | + | // ListPendingIssues RPC. | |
| 55 | + | IssueServiceListPendingIssuesProcedure = "/ermite.IssueService/ListPendingIssues" | |
| 56 | + | // IssueServiceApproveIssueProcedure is the fully-qualified name of the IssueService's ApproveIssue | |
| 57 | + | // RPC. | |
| 58 | + | IssueServiceApproveIssueProcedure = "/ermite.IssueService/ApproveIssue" | |
| 59 | + | // IssueServiceRejectIssueProcedure is the fully-qualified name of the IssueService's RejectIssue | |
| 60 | + | // RPC. | |
| 61 | + | IssueServiceRejectIssueProcedure = "/ermite.IssueService/RejectIssue" | |
| 62 | + | ) | |
| 63 | + | ||
| 64 | + | // IssueServiceClient is a client for the ermite.IssueService service. | |
| 65 | + | type IssueServiceClient interface { | |
| 66 | + | // CreateIssue opens an issue. Needs the issue:write scope. | |
| 67 | + | CreateIssue(context.Context, *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error) | |
| 68 | + | // ListIssues lists issues, highest number first, optionally in one state. | |
| 69 | + | ListIssues(context.Context, *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error) | |
| 70 | + | // GetIssue returns an issue with its comments. | |
| 71 | + | GetIssue(context.Context, *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error) | |
| 72 | + | // AddIssueComment adds a comment. Needs the issue:write scope. | |
| 73 | + | AddIssueComment(context.Context, *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error) | |
| 74 | + | // CloseIssue closes an issue. Needs the issue:write scope. | |
| 75 | + | CloseIssue(context.Context, *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error) | |
| 76 | + | // ReopenIssue reopens an issue. Needs the issue:write scope. | |
| 77 | + | ReopenIssue(context.Context, *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error) | |
| 78 | + | // ListPendingIssues lists issues awaiting moderation, oldest first. Owner | |
| 79 | + | // rights only; anyone else gets NOT_FOUND. | |
| 80 | + | ListPendingIssues(context.Context, *connect.Request[ermite.ListPendingIssuesRequest]) (*connect.Response[ermite.ListPendingIssuesResponse], error) | |
| 81 | + | // ApproveIssue turns a pending issue into an open issue with a new number. | |
| 82 | + | // Owner rights only; anyone else gets NOT_FOUND. | |
| 83 | + | ApproveIssue(context.Context, *connect.Request[ermite.ApproveIssueRequest]) (*connect.Response[ermite.ApproveIssueResponse], error) | |
| 84 | + | // RejectIssue discards a pending issue, optionally banning its submitter. | |
| 85 | + | // Owner rights only; anyone else gets NOT_FOUND. | |
| 86 | + | RejectIssue(context.Context, *connect.Request[ermite.RejectIssueRequest]) (*connect.Response[ermite.RejectIssueResponse], error) | |
| 87 | + | } | |
| 88 | + | ||
| 89 | + | // NewIssueServiceClient constructs a client for the ermite.IssueService service. By default, it | |
| 90 | + | // uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends | |
| 91 | + | // uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or | |
| 92 | + | // connect.WithGRPCWeb() options. | |
| 93 | + | // | |
| 94 | + | // The URL supplied here should be the base URL for the Connect or gRPC server (for example, | |
| 95 | + | // http://api.acme.com or https://acme.com/grpc). | |
| 96 | + | func NewIssueServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) IssueServiceClient { | |
| 97 | + | baseURL = strings.TrimRight(baseURL, "/") | |
| 98 | + | issueServiceMethods := ermite.File_ermite_issue_proto.Services().ByName("IssueService").Methods() | |
| 99 | + | return &issueServiceClient{ | |
| 100 | + | createIssue: connect.NewClient[ermite.CreateIssueRequest, ermite.CreateIssueResponse]( | |
| 101 | + | httpClient, | |
| 102 | + | baseURL+IssueServiceCreateIssueProcedure, | |
| 103 | + | connect.WithSchema(issueServiceMethods.ByName("CreateIssue")), | |
| 104 | + | connect.WithClientOptions(opts...), | |
| 105 | + | ), | |
| 106 | + | listIssues: connect.NewClient[ermite.ListIssuesRequest, ermite.ListIssuesResponse]( | |
| 107 | + | httpClient, | |
| 108 | + | baseURL+IssueServiceListIssuesProcedure, | |
| 109 | + | connect.WithSchema(issueServiceMethods.ByName("ListIssues")), | |
| 110 | + | connect.WithClientOptions(opts...), | |
| 111 | + | ), | |
| 112 | + | getIssue: connect.NewClient[ermite.GetIssueRequest, ermite.GetIssueResponse]( | |
| 113 | + | httpClient, | |
| 114 | + | baseURL+IssueServiceGetIssueProcedure, | |
| 115 | + | connect.WithSchema(issueServiceMethods.ByName("GetIssue")), | |
| 116 | + | connect.WithClientOptions(opts...), | |
| 117 | + | ), | |
| 118 | + | addIssueComment: connect.NewClient[ermite.AddIssueCommentRequest, ermite.AddIssueCommentResponse]( | |
| 119 | + | httpClient, | |
| 120 | + | baseURL+IssueServiceAddIssueCommentProcedure, | |
| 121 | + | connect.WithSchema(issueServiceMethods.ByName("AddIssueComment")), | |
| 122 | + | connect.WithClientOptions(opts...), | |
| 123 | + | ), | |
| 124 | + | closeIssue: connect.NewClient[ermite.CloseIssueRequest, ermite.CloseIssueResponse]( | |
| 125 | + | httpClient, | |
| 126 | + | baseURL+IssueServiceCloseIssueProcedure, | |
| 127 | + | connect.WithSchema(issueServiceMethods.ByName("CloseIssue")), | |
| 128 | + | connect.WithClientOptions(opts...), | |
| 129 | + | ), | |
| 130 | + | reopenIssue: connect.NewClient[ermite.ReopenIssueRequest, ermite.ReopenIssueResponse]( | |
| 131 | + | httpClient, | |
| 132 | + | baseURL+IssueServiceReopenIssueProcedure, | |
| 133 | + | connect.WithSchema(issueServiceMethods.ByName("ReopenIssue")), | |
| 134 | + | connect.WithClientOptions(opts...), | |
| 135 | + | ), | |
| 136 | + | listPendingIssues: connect.NewClient[ermite.ListPendingIssuesRequest, ermite.ListPendingIssuesResponse]( | |
| 137 | + | httpClient, | |
| 138 | + | baseURL+IssueServiceListPendingIssuesProcedure, | |
| 139 | + | connect.WithSchema(issueServiceMethods.ByName("ListPendingIssues")), | |
| 140 | + | connect.WithClientOptions(opts...), | |
| 141 | + | ), | |
| 142 | + | approveIssue: connect.NewClient[ermite.ApproveIssueRequest, ermite.ApproveIssueResponse]( | |
| 143 | + | httpClient, | |
| 144 | + | baseURL+IssueServiceApproveIssueProcedure, | |
| 145 | + | connect.WithSchema(issueServiceMethods.ByName("ApproveIssue")), | |
| 146 | + | connect.WithClientOptions(opts...), | |
| 147 | + | ), | |
| 148 | + | rejectIssue: connect.NewClient[ermite.RejectIssueRequest, ermite.RejectIssueResponse]( | |
| 149 | + | httpClient, | |
| 150 | + | baseURL+IssueServiceRejectIssueProcedure, | |
| 151 | + | connect.WithSchema(issueServiceMethods.ByName("RejectIssue")), | |
| 152 | + | connect.WithClientOptions(opts...), | |
| 153 | + | ), | |
| 154 | + | } | |
| 155 | + | } | |
| 156 | + | ||
| 157 | + | // issueServiceClient implements IssueServiceClient. | |
| 158 | + | type issueServiceClient struct { | |
| 159 | + | createIssue *connect.Client[ermite.CreateIssueRequest, ermite.CreateIssueResponse] | |
| 160 | + | listIssues *connect.Client[ermite.ListIssuesRequest, ermite.ListIssuesResponse] | |
| 161 | + | getIssue *connect.Client[ermite.GetIssueRequest, ermite.GetIssueResponse] | |
| 162 | + | addIssueComment *connect.Client[ermite.AddIssueCommentRequest, ermite.AddIssueCommentResponse] | |
| 163 | + | closeIssue *connect.Client[ermite.CloseIssueRequest, ermite.CloseIssueResponse] | |
| 164 | + | reopenIssue *connect.Client[ermite.ReopenIssueRequest, ermite.ReopenIssueResponse] | |
| 165 | + | listPendingIssues *connect.Client[ermite.ListPendingIssuesRequest, ermite.ListPendingIssuesResponse] | |
| 166 | + | approveIssue *connect.Client[ermite.ApproveIssueRequest, ermite.ApproveIssueResponse] | |
| 167 | + | rejectIssue *connect.Client[ermite.RejectIssueRequest, ermite.RejectIssueResponse] | |
| 168 | + | } | |
| 169 | + | ||
| 170 | + | // CreateIssue calls ermite.IssueService.CreateIssue. | |
| 171 | + | func (c *issueServiceClient) CreateIssue(ctx context.Context, req *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error) { | |
| 172 | + | return c.createIssue.CallUnary(ctx, req) | |
| 173 | + | } | |
| 174 | + | ||
| 175 | + | // ListIssues calls ermite.IssueService.ListIssues. | |
| 176 | + | func (c *issueServiceClient) ListIssues(ctx context.Context, req *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error) { | |
| 177 | + | return c.listIssues.CallUnary(ctx, req) | |
| 178 | + | } | |
| 179 | + | ||
| 180 | + | // GetIssue calls ermite.IssueService.GetIssue. | |
| 181 | + | func (c *issueServiceClient) GetIssue(ctx context.Context, req *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error) { | |
| 182 | + | return c.getIssue.CallUnary(ctx, req) | |
| 183 | + | } | |
| 184 | + | ||
| 185 | + | // AddIssueComment calls ermite.IssueService.AddIssueComment. | |
| 186 | + | func (c *issueServiceClient) AddIssueComment(ctx context.Context, req *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error) { | |
| 187 | + | return c.addIssueComment.CallUnary(ctx, req) | |
| 188 | + | } | |
| 189 | + | ||
| 190 | + | // CloseIssue calls ermite.IssueService.CloseIssue. | |
| 191 | + | func (c *issueServiceClient) CloseIssue(ctx context.Context, req *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error) { | |
| 192 | + | return c.closeIssue.CallUnary(ctx, req) | |
| 193 | + | } | |
| 194 | + | ||
| 195 | + | // ReopenIssue calls ermite.IssueService.ReopenIssue. | |
| 196 | + | func (c *issueServiceClient) ReopenIssue(ctx context.Context, req *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error) { | |
| 197 | + | return c.reopenIssue.CallUnary(ctx, req) | |
| 198 | + | } | |
| 199 | + | ||
| 200 | + | // ListPendingIssues calls ermite.IssueService.ListPendingIssues. | |
| 201 | + | func (c *issueServiceClient) ListPendingIssues(ctx context.Context, req *connect.Request[ermite.ListPendingIssuesRequest]) (*connect.Response[ermite.ListPendingIssuesResponse], error) { | |
| 202 | + | return c.listPendingIssues.CallUnary(ctx, req) | |
| 203 | + | } | |
| 204 | + | ||
| 205 | + | // ApproveIssue calls ermite.IssueService.ApproveIssue. | |
| 206 | + | func (c *issueServiceClient) ApproveIssue(ctx context.Context, req *connect.Request[ermite.ApproveIssueRequest]) (*connect.Response[ermite.ApproveIssueResponse], error) { | |
| 207 | + | return c.approveIssue.CallUnary(ctx, req) | |
| 208 | + | } | |
| 209 | + | ||
| 210 | + | // RejectIssue calls ermite.IssueService.RejectIssue. | |
| 211 | + | func (c *issueServiceClient) RejectIssue(ctx context.Context, req *connect.Request[ermite.RejectIssueRequest]) (*connect.Response[ermite.RejectIssueResponse], error) { | |
| 212 | + | return c.rejectIssue.CallUnary(ctx, req) | |
| 213 | + | } | |
| 214 | + | ||
| 215 | + | // IssueServiceHandler is an implementation of the ermite.IssueService service. | |
| 216 | + | type IssueServiceHandler interface { | |
| 217 | + | // CreateIssue opens an issue. Needs the issue:write scope. | |
| 218 | + | CreateIssue(context.Context, *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error) | |
| 219 | + | // ListIssues lists issues, highest number first, optionally in one state. | |
| 220 | + | ListIssues(context.Context, *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error) | |
| 221 | + | // GetIssue returns an issue with its comments. | |
| 222 | + | GetIssue(context.Context, *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error) | |
| 223 | + | // AddIssueComment adds a comment. Needs the issue:write scope. | |
| 224 | + | AddIssueComment(context.Context, *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error) | |
| 225 | + | // CloseIssue closes an issue. Needs the issue:write scope. | |
| 226 | + | CloseIssue(context.Context, *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error) | |
| 227 | + | // ReopenIssue reopens an issue. Needs the issue:write scope. | |
| 228 | + | ReopenIssue(context.Context, *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error) | |
| 229 | + | // ListPendingIssues lists issues awaiting moderation, oldest first. Owner | |
| 230 | + | // rights only; anyone else gets NOT_FOUND. | |
| 231 | + | ListPendingIssues(context.Context, *connect.Request[ermite.ListPendingIssuesRequest]) (*connect.Response[ermite.ListPendingIssuesResponse], error) | |
| 232 | + | // ApproveIssue turns a pending issue into an open issue with a new number. | |
| 233 | + | // Owner rights only; anyone else gets NOT_FOUND. | |
| 234 | + | ApproveIssue(context.Context, *connect.Request[ermite.ApproveIssueRequest]) (*connect.Response[ermite.ApproveIssueResponse], error) | |
| 235 | + | // RejectIssue discards a pending issue, optionally banning its submitter. | |
| 236 | + | // Owner rights only; anyone else gets NOT_FOUND. | |
| 237 | + | RejectIssue(context.Context, *connect.Request[ermite.RejectIssueRequest]) (*connect.Response[ermite.RejectIssueResponse], error) | |
| 238 | + | } | |
| 239 | + | ||
| 240 | + | // NewIssueServiceHandler builds an HTTP handler from the service implementation. It returns the | |
| 241 | + | // path on which to mount the handler and the handler itself. | |
| 242 | + | // | |
| 243 | + | // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf | |
| 244 | + | // and JSON codecs. They also support gzip compression. | |
| 245 | + | func NewIssueServiceHandler(svc IssueServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { | |
| 246 | + | issueServiceMethods := ermite.File_ermite_issue_proto.Services().ByName("IssueService").Methods() | |
| 247 | + | issueServiceCreateIssueHandler := connect.NewUnaryHandler( | |
| 248 | + | IssueServiceCreateIssueProcedure, | |
| 249 | + | svc.CreateIssue, | |
| 250 | + | connect.WithSchema(issueServiceMethods.ByName("CreateIssue")), | |
| 251 | + | connect.WithHandlerOptions(opts...), | |
| 252 | + | ) | |
| 253 | + | issueServiceListIssuesHandler := connect.NewUnaryHandler( | |
| 254 | + | IssueServiceListIssuesProcedure, | |
| 255 | + | svc.ListIssues, | |
| 256 | + | connect.WithSchema(issueServiceMethods.ByName("ListIssues")), | |
| 257 | + | connect.WithHandlerOptions(opts...), | |
| 258 | + | ) | |
| 259 | + | issueServiceGetIssueHandler := connect.NewUnaryHandler( | |
| 260 | + | IssueServiceGetIssueProcedure, | |
| 261 | + | svc.GetIssue, | |
| 262 | + | connect.WithSchema(issueServiceMethods.ByName("GetIssue")), | |
| 263 | + | connect.WithHandlerOptions(opts...), | |
| 264 | + | ) | |
| 265 | + | issueServiceAddIssueCommentHandler := connect.NewUnaryHandler( | |
| 266 | + | IssueServiceAddIssueCommentProcedure, | |
| 267 | + | svc.AddIssueComment, | |
| 268 | + | connect.WithSchema(issueServiceMethods.ByName("AddIssueComment")), | |
| 269 | + | connect.WithHandlerOptions(opts...), | |
| 270 | + | ) | |
| 271 | + | issueServiceCloseIssueHandler := connect.NewUnaryHandler( | |
| 272 | + | IssueServiceCloseIssueProcedure, | |
| 273 | + | svc.CloseIssue, | |
| 274 | + | connect.WithSchema(issueServiceMethods.ByName("CloseIssue")), | |
| 275 | + | connect.WithHandlerOptions(opts...), | |
| 276 | + | ) | |
| 277 | + | issueServiceReopenIssueHandler := connect.NewUnaryHandler( | |
| 278 | + | IssueServiceReopenIssueProcedure, | |
| 279 | + | svc.ReopenIssue, | |
| 280 | + | connect.WithSchema(issueServiceMethods.ByName("ReopenIssue")), | |
| 281 | + | connect.WithHandlerOptions(opts...), | |
| 282 | + | ) | |
| 283 | + | issueServiceListPendingIssuesHandler := connect.NewUnaryHandler( | |
| 284 | + | IssueServiceListPendingIssuesProcedure, | |
| 285 | + | svc.ListPendingIssues, | |
| 286 | + | connect.WithSchema(issueServiceMethods.ByName("ListPendingIssues")), | |
| 287 | + | connect.WithHandlerOptions(opts...), | |
| 288 | + | ) | |
| 289 | + | issueServiceApproveIssueHandler := connect.NewUnaryHandler( | |
| 290 | + | IssueServiceApproveIssueProcedure, | |
| 291 | + | svc.ApproveIssue, | |
| 292 | + | connect.WithSchema(issueServiceMethods.ByName("ApproveIssue")), | |
| 293 | + | connect.WithHandlerOptions(opts...), | |
| 294 | + | ) | |
| 295 | + | issueServiceRejectIssueHandler := connect.NewUnaryHandler( | |
| 296 | + | IssueServiceRejectIssueProcedure, | |
| 297 | + | svc.RejectIssue, | |
| 298 | + | connect.WithSchema(issueServiceMethods.ByName("RejectIssue")), | |
| 299 | + | connect.WithHandlerOptions(opts...), | |
| 300 | + | ) | |
| 301 | + | return "/ermite.IssueService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| 302 | + | switch r.URL.Path { | |
| 303 | + | case IssueServiceCreateIssueProcedure: | |
| 304 | + | issueServiceCreateIssueHandler.ServeHTTP(w, r) | |
| 305 | + | case IssueServiceListIssuesProcedure: | |
| 306 | + | issueServiceListIssuesHandler.ServeHTTP(w, r) | |
| 307 | + | case IssueServiceGetIssueProcedure: | |
| 308 | + | issueServiceGetIssueHandler.ServeHTTP(w, r) | |
| 309 | + | case IssueServiceAddIssueCommentProcedure: | |
| 310 | + | issueServiceAddIssueCommentHandler.ServeHTTP(w, r) | |
| 311 | + | case IssueServiceCloseIssueProcedure: | |
| 312 | + | issueServiceCloseIssueHandler.ServeHTTP(w, r) | |
| 313 | + | case IssueServiceReopenIssueProcedure: | |
| 314 | + | issueServiceReopenIssueHandler.ServeHTTP(w, r) | |
| 315 | + | case IssueServiceListPendingIssuesProcedure: | |
| 316 | + | issueServiceListPendingIssuesHandler.ServeHTTP(w, r) | |
| 317 | + | case IssueServiceApproveIssueProcedure: | |
| 318 | + | issueServiceApproveIssueHandler.ServeHTTP(w, r) | |
| 319 | + | case IssueServiceRejectIssueProcedure: | |
| 320 | + | issueServiceRejectIssueHandler.ServeHTTP(w, r) | |
| 321 | + | default: | |
| 322 | + | http.NotFound(w, r) | |
| 323 | + | } | |
| 324 | + | }) | |
| 325 | + | } | |
| 326 | + | ||
| 327 | + | // UnimplementedIssueServiceHandler returns CodeUnimplemented from all methods. | |
| 328 | + | type UnimplementedIssueServiceHandler struct{} | |
| 329 | + | ||
| 330 | + | func (UnimplementedIssueServiceHandler) CreateIssue(context.Context, *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error) { | |
| 331 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.CreateIssue is not implemented")) | |
| 332 | + | } | |
| 333 | + | ||
| 334 | + | func (UnimplementedIssueServiceHandler) ListIssues(context.Context, *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error) { | |
| 335 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.ListIssues is not implemented")) | |
| 336 | + | } | |
| 337 | + | ||
| 338 | + | func (UnimplementedIssueServiceHandler) GetIssue(context.Context, *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error) { | |
| 339 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.GetIssue is not implemented")) | |
| 340 | + | } | |
| 341 | + | ||
| 342 | + | func (UnimplementedIssueServiceHandler) AddIssueComment(context.Context, *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error) { | |
| 343 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.AddIssueComment is not implemented")) | |
| 344 | + | } | |
| 345 | + | ||
| 346 | + | func (UnimplementedIssueServiceHandler) CloseIssue(context.Context, *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error) { | |
| 347 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.CloseIssue is not implemented")) | |
| 348 | + | } | |
| 349 | + | ||
| 350 | + | func (UnimplementedIssueServiceHandler) ReopenIssue(context.Context, *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error) { | |
| 351 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.ReopenIssue is not implemented")) | |
| 352 | + | } | |
| 353 | + | ||
| 354 | + | func (UnimplementedIssueServiceHandler) ListPendingIssues(context.Context, *connect.Request[ermite.ListPendingIssuesRequest]) (*connect.Response[ermite.ListPendingIssuesResponse], error) { | |
| 355 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.ListPendingIssues is not implemented")) | |
| 356 | + | } | |
| 357 | + | ||
| 358 | + | func (UnimplementedIssueServiceHandler) ApproveIssue(context.Context, *connect.Request[ermite.ApproveIssueRequest]) (*connect.Response[ermite.ApproveIssueResponse], error) { | |
| 359 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.ApproveIssue is not implemented")) | |
| 360 | + | } | |
| 361 | + | ||
| 362 | + | func (UnimplementedIssueServiceHandler) RejectIssue(context.Context, *connect.Request[ermite.RejectIssueRequest]) (*connect.Response[ermite.RejectIssueResponse], error) { | |
| 363 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.RejectIssue is not implemented")) | |
| 364 | + | } | |
| @@ -0,0 +1,364 @@ | |||||
| 1 | + | // SPDX-License-Identifier: MIT | |||
| 2 | + | ||||
| 3 | + | // Code generated by protoc-gen-connect-go. DO NOT EDIT. | |||
| 4 | + | // | |||
| 5 | + | // Source: ermite/issue.proto | |||
| 6 | + | ||||
| 7 | + | package ermiteconnect | |||
| 8 | + | ||||
| 9 | + | import ( | |||
| 10 | + | ermite "bnema.dev/ermite-api/gen/ermite" | |||
| 11 | + | connect "connectrpc.com/connect" | |||
| 12 | + | context "context" | |||
| 13 | + | errors "errors" | |||
| 14 | + | http "net/http" | |||
| 15 | + | strings "strings" | |||
| 16 | + | ) | |||
| 17 | + | ||||
| 18 | + | // This is a compile-time assertion to ensure that this generated file and the connect package are | |||
| 19 | + | // compatible. If you get a compiler error that this constant is not defined, this code was | |||
| 20 | + | // generated with a version of connect newer than the one compiled into your binary. You can fix the | |||
| 21 | + | // problem by either regenerating this code with an older version of connect or updating the connect | |||
| 22 | + | // version compiled into your binary. | |||
| 23 | + | const _ = connect.IsAtLeastVersion1_13_0 | |||
| 24 | + | ||||
| 25 | + | const ( | |||
| 26 | + | // IssueServiceName is the fully-qualified name of the IssueService service. | |||
| 27 | + | IssueServiceName = "ermite.IssueService" | |||
| 28 | + | ) | |||
| 29 | + | ||||
| 30 | + | // These constants are the fully-qualified names of the RPCs defined in this package. They're | |||
| 31 | + | // exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. | |||
| 32 | + | // | |||
| 33 | + | // Note that these are different from the fully-qualified method names used by | |||
| 34 | + | // google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to | |||
| 35 | + | // reflection-formatted method names, remove the leading slash and convert the remaining slash to a | |||
| 36 | + | // period. | |||
| 37 | + | const ( | |||
| 38 | + | // IssueServiceCreateIssueProcedure is the fully-qualified name of the IssueService's CreateIssue | |||
| 39 | + | // RPC. | |||
| 40 | + | IssueServiceCreateIssueProcedure = "/ermite.IssueService/CreateIssue" | |||
| 41 | + | // IssueServiceListIssuesProcedure is the fully-qualified name of the IssueService's ListIssues RPC. | |||
| 42 | + | IssueServiceListIssuesProcedure = "/ermite.IssueService/ListIssues" | |||
| 43 | + | // IssueServiceGetIssueProcedure is the fully-qualified name of the IssueService's GetIssue RPC. | |||
| 44 | + | IssueServiceGetIssueProcedure = "/ermite.IssueService/GetIssue" | |||
| 45 | + | // IssueServiceAddIssueCommentProcedure is the fully-qualified name of the IssueService's | |||
| 46 | + | // AddIssueComment RPC. | |||
| 47 | + | IssueServiceAddIssueCommentProcedure = "/ermite.IssueService/AddIssueComment" | |||
| 48 | + | // IssueServiceCloseIssueProcedure is the fully-qualified name of the IssueService's CloseIssue RPC. | |||
| 49 | + | IssueServiceCloseIssueProcedure = "/ermite.IssueService/CloseIssue" | |||
| 50 | + | // IssueServiceReopenIssueProcedure is the fully-qualified name of the IssueService's ReopenIssue | |||
| 51 | + | // RPC. | |||
| 52 | + | IssueServiceReopenIssueProcedure = "/ermite.IssueService/ReopenIssue" | |||
| 53 | + | // IssueServiceListPendingIssuesProcedure is the fully-qualified name of the IssueService's | |||
| 54 | + | // ListPendingIssues RPC. | |||
| 55 | + | IssueServiceListPendingIssuesProcedure = "/ermite.IssueService/ListPendingIssues" | |||
| 56 | + | // IssueServiceApproveIssueProcedure is the fully-qualified name of the IssueService's ApproveIssue | |||
| 57 | + | // RPC. | |||
| 58 | + | IssueServiceApproveIssueProcedure = "/ermite.IssueService/ApproveIssue" | |||
| 59 | + | // IssueServiceRejectIssueProcedure is the fully-qualified name of the IssueService's RejectIssue | |||
| 60 | + | // RPC. | |||
| 61 | + | IssueServiceRejectIssueProcedure = "/ermite.IssueService/RejectIssue" | |||
| 62 | + | ) | |||
| 63 | + | ||||
| 64 | + | // IssueServiceClient is a client for the ermite.IssueService service. | |||
| 65 | + | type IssueServiceClient interface { | |||
| 66 | + | // CreateIssue opens an issue. Needs the issue:write scope. | |||
| 67 | + | CreateIssue(context.Context, *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error) | |||
| 68 | + | // ListIssues lists issues, highest number first, optionally in one state. | |||
| 69 | + | ListIssues(context.Context, *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error) | |||
| 70 | + | // GetIssue returns an issue with its comments. | |||
| 71 | + | GetIssue(context.Context, *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error) | |||
| 72 | + | // AddIssueComment adds a comment. Needs the issue:write scope. | |||
| 73 | + | AddIssueComment(context.Context, *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error) | |||
| 74 | + | // CloseIssue closes an issue. Needs the issue:write scope. | |||
| 75 | + | CloseIssue(context.Context, *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error) | |||
| 76 | + | // ReopenIssue reopens an issue. Needs the issue:write scope. | |||
| 77 | + | ReopenIssue(context.Context, *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error) | |||
| 78 | + | // ListPendingIssues lists issues awaiting moderation, oldest first. Owner | |||
| 79 | + | // rights only; anyone else gets NOT_FOUND. | |||
| 80 | + | ListPendingIssues(context.Context, *connect.Request[ermite.ListPendingIssuesRequest]) (*connect.Response[ermite.ListPendingIssuesResponse], error) | |||
| 81 | + | // ApproveIssue turns a pending issue into an open issue with a new number. | |||
| 82 | + | // Owner rights only; anyone else gets NOT_FOUND. | |||
| 83 | + | ApproveIssue(context.Context, *connect.Request[ermite.ApproveIssueRequest]) (*connect.Response[ermite.ApproveIssueResponse], error) | |||
| 84 | + | // RejectIssue discards a pending issue, optionally banning its submitter. | |||
| 85 | + | // Owner rights only; anyone else gets NOT_FOUND. | |||
| 86 | + | RejectIssue(context.Context, *connect.Request[ermite.RejectIssueRequest]) (*connect.Response[ermite.RejectIssueResponse], error) | |||
| 87 | + | } | |||
| 88 | + | ||||
| 89 | + | // NewIssueServiceClient constructs a client for the ermite.IssueService service. By default, it | |||
| 90 | + | // uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends | |||
| 91 | + | // uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or | |||
| 92 | + | // connect.WithGRPCWeb() options. | |||
| 93 | + | // | |||
| 94 | + | // The URL supplied here should be the base URL for the Connect or gRPC server (for example, | |||
| 95 | + | // http://api.acme.com or https://acme.com/grpc). | |||
| 96 | + | func NewIssueServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) IssueServiceClient { | |||
| 97 | + | baseURL = strings.TrimRight(baseURL, "/") | |||
| 98 | + | issueServiceMethods := ermite.File_ermite_issue_proto.Services().ByName("IssueService").Methods() | |||
| 99 | + | return &issueServiceClient{ | |||
| 100 | + | createIssue: connect.NewClient[ermite.CreateIssueRequest, ermite.CreateIssueResponse]( | |||
| 101 | + | httpClient, | |||
| 102 | + | baseURL+IssueServiceCreateIssueProcedure, | |||
| 103 | + | connect.WithSchema(issueServiceMethods.ByName("CreateIssue")), | |||
| 104 | + | connect.WithClientOptions(opts...), | |||
| 105 | + | ), | |||
| 106 | + | listIssues: connect.NewClient[ermite.ListIssuesRequest, ermite.ListIssuesResponse]( | |||
| 107 | + | httpClient, | |||
| 108 | + | baseURL+IssueServiceListIssuesProcedure, | |||
| 109 | + | connect.WithSchema(issueServiceMethods.ByName("ListIssues")), | |||
| 110 | + | connect.WithClientOptions(opts...), | |||
| 111 | + | ), | |||
| 112 | + | getIssue: connect.NewClient[ermite.GetIssueRequest, ermite.GetIssueResponse]( | |||
| 113 | + | httpClient, | |||
| 114 | + | baseURL+IssueServiceGetIssueProcedure, | |||
| 115 | + | connect.WithSchema(issueServiceMethods.ByName("GetIssue")), | |||
| 116 | + | connect.WithClientOptions(opts...), | |||
| 117 | + | ), | |||
| 118 | + | addIssueComment: connect.NewClient[ermite.AddIssueCommentRequest, ermite.AddIssueCommentResponse]( | |||
| 119 | + | httpClient, | |||
| 120 | + | baseURL+IssueServiceAddIssueCommentProcedure, | |||
| 121 | + | connect.WithSchema(issueServiceMethods.ByName("AddIssueComment")), | |||
| 122 | + | connect.WithClientOptions(opts...), | |||
| 123 | + | ), | |||
| 124 | + | closeIssue: connect.NewClient[ermite.CloseIssueRequest, ermite.CloseIssueResponse]( | |||
| 125 | + | httpClient, | |||
| 126 | + | baseURL+IssueServiceCloseIssueProcedure, | |||
| 127 | + | connect.WithSchema(issueServiceMethods.ByName("CloseIssue")), | |||
| 128 | + | connect.WithClientOptions(opts...), | |||
| 129 | + | ), | |||
| 130 | + | reopenIssue: connect.NewClient[ermite.ReopenIssueRequest, ermite.ReopenIssueResponse]( | |||
| 131 | + | httpClient, | |||
| 132 | + | baseURL+IssueServiceReopenIssueProcedure, | |||
| 133 | + | connect.WithSchema(issueServiceMethods.ByName("ReopenIssue")), | |||
| 134 | + | connect.WithClientOptions(opts...), | |||
| 135 | + | ), | |||
| 136 | + | listPendingIssues: connect.NewClient[ermite.ListPendingIssuesRequest, ermite.ListPendingIssuesResponse]( | |||
| 137 | + | httpClient, | |||
| 138 | + | baseURL+IssueServiceListPendingIssuesProcedure, | |||
| 139 | + | connect.WithSchema(issueServiceMethods.ByName("ListPendingIssues")), | |||
| 140 | + | connect.WithClientOptions(opts...), | |||
| 141 | + | ), | |||
| 142 | + | approveIssue: connect.NewClient[ermite.ApproveIssueRequest, ermite.ApproveIssueResponse]( | |||
| 143 | + | httpClient, | |||
| 144 | + | baseURL+IssueServiceApproveIssueProcedure, | |||
| 145 | + | connect.WithSchema(issueServiceMethods.ByName("ApproveIssue")), | |||
| 146 | + | connect.WithClientOptions(opts...), | |||
| 147 | + | ), | |||
| 148 | + | rejectIssue: connect.NewClient[ermite.RejectIssueRequest, ermite.RejectIssueResponse]( | |||
| 149 | + | httpClient, | |||
| 150 | + | baseURL+IssueServiceRejectIssueProcedure, | |||
| 151 | + | connect.WithSchema(issueServiceMethods.ByName("RejectIssue")), | |||
| 152 | + | connect.WithClientOptions(opts...), | |||
| 153 | + | ), | |||
| 154 | + | } | |||
| 155 | + | } | |||
| 156 | + | ||||
| 157 | + | // issueServiceClient implements IssueServiceClient. | |||
| 158 | + | type issueServiceClient struct { | |||
| 159 | + | createIssue *connect.Client[ermite.CreateIssueRequest, ermite.CreateIssueResponse] | |||
| 160 | + | listIssues *connect.Client[ermite.ListIssuesRequest, ermite.ListIssuesResponse] | |||
| 161 | + | getIssue *connect.Client[ermite.GetIssueRequest, ermite.GetIssueResponse] | |||
| 162 | + | addIssueComment *connect.Client[ermite.AddIssueCommentRequest, ermite.AddIssueCommentResponse] | |||
| 163 | + | closeIssue *connect.Client[ermite.CloseIssueRequest, ermite.CloseIssueResponse] | |||
| 164 | + | reopenIssue *connect.Client[ermite.ReopenIssueRequest, ermite.ReopenIssueResponse] | |||
| 165 | + | listPendingIssues *connect.Client[ermite.ListPendingIssuesRequest, ermite.ListPendingIssuesResponse] | |||
| 166 | + | approveIssue *connect.Client[ermite.ApproveIssueRequest, ermite.ApproveIssueResponse] | |||
| 167 | + | rejectIssue *connect.Client[ermite.RejectIssueRequest, ermite.RejectIssueResponse] | |||
| 168 | + | } | |||
| 169 | + | ||||
| 170 | + | // CreateIssue calls ermite.IssueService.CreateIssue. | |||
| 171 | + | func (c *issueServiceClient) CreateIssue(ctx context.Context, req *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error) { | |||
| 172 | + | return c.createIssue.CallUnary(ctx, req) | |||
| 173 | + | } | |||
| 174 | + | ||||
| 175 | + | // ListIssues calls ermite.IssueService.ListIssues. | |||
| 176 | + | func (c *issueServiceClient) ListIssues(ctx context.Context, req *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error) { | |||
| 177 | + | return c.listIssues.CallUnary(ctx, req) | |||
| 178 | + | } | |||
| 179 | + | ||||
| 180 | + | // GetIssue calls ermite.IssueService.GetIssue. | |||
| 181 | + | func (c *issueServiceClient) GetIssue(ctx context.Context, req *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error) { | |||
| 182 | + | return c.getIssue.CallUnary(ctx, req) | |||
| 183 | + | } | |||
| 184 | + | ||||
| 185 | + | // AddIssueComment calls ermite.IssueService.AddIssueComment. | |||
| 186 | + | func (c *issueServiceClient) AddIssueComment(ctx context.Context, req *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error) { | |||
| 187 | + | return c.addIssueComment.CallUnary(ctx, req) | |||
| 188 | + | } | |||
| 189 | + | ||||
| 190 | + | // CloseIssue calls ermite.IssueService.CloseIssue. | |||
| 191 | + | func (c *issueServiceClient) CloseIssue(ctx context.Context, req *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error) { | |||
| 192 | + | return c.closeIssue.CallUnary(ctx, req) | |||
| 193 | + | } | |||
| 194 | + | ||||
| 195 | + | // ReopenIssue calls ermite.IssueService.ReopenIssue. | |||
| 196 | + | func (c *issueServiceClient) ReopenIssue(ctx context.Context, req *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error) { | |||
| 197 | + | return c.reopenIssue.CallUnary(ctx, req) | |||
| 198 | + | } | |||
| 199 | + | ||||
| 200 | + | // ListPendingIssues calls ermite.IssueService.ListPendingIssues. | |||
| 201 | + | func (c *issueServiceClient) ListPendingIssues(ctx context.Context, req *connect.Request[ermite.ListPendingIssuesRequest]) (*connect.Response[ermite.ListPendingIssuesResponse], error) { | |||
| 202 | + | return c.listPendingIssues.CallUnary(ctx, req) | |||
| 203 | + | } | |||
| 204 | + | ||||
| 205 | + | // ApproveIssue calls ermite.IssueService.ApproveIssue. | |||
| 206 | + | func (c *issueServiceClient) ApproveIssue(ctx context.Context, req *connect.Request[ermite.ApproveIssueRequest]) (*connect.Response[ermite.ApproveIssueResponse], error) { | |||
| 207 | + | return c.approveIssue.CallUnary(ctx, req) | |||
| 208 | + | } | |||
| 209 | + | ||||
| 210 | + | // RejectIssue calls ermite.IssueService.RejectIssue. | |||
| 211 | + | func (c *issueServiceClient) RejectIssue(ctx context.Context, req *connect.Request[ermite.RejectIssueRequest]) (*connect.Response[ermite.RejectIssueResponse], error) { | |||
| 212 | + | return c.rejectIssue.CallUnary(ctx, req) | |||
| 213 | + | } | |||
| 214 | + | ||||
| 215 | + | // IssueServiceHandler is an implementation of the ermite.IssueService service. | |||
| 216 | + | type IssueServiceHandler interface { | |||
| 217 | + | // CreateIssue opens an issue. Needs the issue:write scope. | |||
| 218 | + | CreateIssue(context.Context, *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error) | |||
| 219 | + | // ListIssues lists issues, highest number first, optionally in one state. | |||
| 220 | + | ListIssues(context.Context, *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error) | |||
| 221 | + | // GetIssue returns an issue with its comments. | |||
| 222 | + | GetIssue(context.Context, *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error) | |||
| 223 | + | // AddIssueComment adds a comment. Needs the issue:write scope. | |||
| 224 | + | AddIssueComment(context.Context, *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error) | |||
| 225 | + | // CloseIssue closes an issue. Needs the issue:write scope. | |||
| 226 | + | CloseIssue(context.Context, *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error) | |||
| 227 | + | // ReopenIssue reopens an issue. Needs the issue:write scope. | |||
| 228 | + | ReopenIssue(context.Context, *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error) | |||
| 229 | + | // ListPendingIssues lists issues awaiting moderation, oldest first. Owner | |||
| 230 | + | // rights only; anyone else gets NOT_FOUND. | |||
| 231 | + | ListPendingIssues(context.Context, *connect.Request[ermite.ListPendingIssuesRequest]) (*connect.Response[ermite.ListPendingIssuesResponse], error) | |||
| 232 | + | // ApproveIssue turns a pending issue into an open issue with a new number. | |||
| 233 | + | // Owner rights only; anyone else gets NOT_FOUND. | |||
| 234 | + | ApproveIssue(context.Context, *connect.Request[ermite.ApproveIssueRequest]) (*connect.Response[ermite.ApproveIssueResponse], error) | |||
| 235 | + | // RejectIssue discards a pending issue, optionally banning its submitter. | |||
| 236 | + | // Owner rights only; anyone else gets NOT_FOUND. | |||
| 237 | + | RejectIssue(context.Context, *connect.Request[ermite.RejectIssueRequest]) (*connect.Response[ermite.RejectIssueResponse], error) | |||
| 238 | + | } | |||
| 239 | + | ||||
| 240 | + | // NewIssueServiceHandler builds an HTTP handler from the service implementation. It returns the | |||
| 241 | + | // path on which to mount the handler and the handler itself. | |||
| 242 | + | // | |||
| 243 | + | // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf | |||
| 244 | + | // and JSON codecs. They also support gzip compression. | |||
| 245 | + | func NewIssueServiceHandler(svc IssueServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { | |||
| 246 | + | issueServiceMethods := ermite.File_ermite_issue_proto.Services().ByName("IssueService").Methods() | |||
| 247 | + | issueServiceCreateIssueHandler := connect.NewUnaryHandler( | |||
| 248 | + | IssueServiceCreateIssueProcedure, | |||
| 249 | + | svc.CreateIssue, | |||
| 250 | + | connect.WithSchema(issueServiceMethods.ByName("CreateIssue")), | |||
| 251 | + | connect.WithHandlerOptions(opts...), | |||
| 252 | + | ) | |||
| 253 | + | issueServiceListIssuesHandler := connect.NewUnaryHandler( | |||
| 254 | + | IssueServiceListIssuesProcedure, | |||
| 255 | + | svc.ListIssues, | |||
| 256 | + | connect.WithSchema(issueServiceMethods.ByName("ListIssues")), | |||
| 257 | + | connect.WithHandlerOptions(opts...), | |||
| 258 | + | ) | |||
| 259 | + | issueServiceGetIssueHandler := connect.NewUnaryHandler( | |||
| 260 | + | IssueServiceGetIssueProcedure, | |||
| 261 | + | svc.GetIssue, | |||
| 262 | + | connect.WithSchema(issueServiceMethods.ByName("GetIssue")), | |||
| 263 | + | connect.WithHandlerOptions(opts...), | |||
| 264 | + | ) | |||
| 265 | + | issueServiceAddIssueCommentHandler := connect.NewUnaryHandler( | |||
| 266 | + | IssueServiceAddIssueCommentProcedure, | |||
| 267 | + | svc.AddIssueComment, | |||
| 268 | + | connect.WithSchema(issueServiceMethods.ByName("AddIssueComment")), | |||
| 269 | + | connect.WithHandlerOptions(opts...), | |||
| 270 | + | ) | |||
| 271 | + | issueServiceCloseIssueHandler := connect.NewUnaryHandler( | |||
| 272 | + | IssueServiceCloseIssueProcedure, | |||
| 273 | + | svc.CloseIssue, | |||
| 274 | + | connect.WithSchema(issueServiceMethods.ByName("CloseIssue")), | |||
| 275 | + | connect.WithHandlerOptions(opts...), | |||
| 276 | + | ) | |||
| 277 | + | issueServiceReopenIssueHandler := connect.NewUnaryHandler( | |||
| 278 | + | IssueServiceReopenIssueProcedure, | |||
| 279 | + | svc.ReopenIssue, | |||
| 280 | + | connect.WithSchema(issueServiceMethods.ByName("ReopenIssue")), | |||
| 281 | + | connect.WithHandlerOptions(opts...), | |||
| 282 | + | ) | |||
| 283 | + | issueServiceListPendingIssuesHandler := connect.NewUnaryHandler( | |||
| 284 | + | IssueServiceListPendingIssuesProcedure, | |||
| 285 | + | svc.ListPendingIssues, | |||
| 286 | + | connect.WithSchema(issueServiceMethods.ByName("ListPendingIssues")), | |||
| 287 | + | connect.WithHandlerOptions(opts...), | |||
| 288 | + | ) | |||
| 289 | + | issueServiceApproveIssueHandler := connect.NewUnaryHandler( | |||
| 290 | + | IssueServiceApproveIssueProcedure, | |||
| 291 | + | svc.ApproveIssue, | |||
| 292 | + | connect.WithSchema(issueServiceMethods.ByName("ApproveIssue")), | |||
| 293 | + | connect.WithHandlerOptions(opts...), | |||
| 294 | + | ) | |||
| 295 | + | issueServiceRejectIssueHandler := connect.NewUnaryHandler( | |||
| 296 | + | IssueServiceRejectIssueProcedure, | |||
| 297 | + | svc.RejectIssue, | |||
| 298 | + | connect.WithSchema(issueServiceMethods.ByName("RejectIssue")), | |||
| 299 | + | connect.WithHandlerOptions(opts...), | |||
| 300 | + | ) | |||
| 301 | + | return "/ermite.IssueService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |||
| 302 | + | switch r.URL.Path { | |||
| 303 | + | case IssueServiceCreateIssueProcedure: | |||
| 304 | + | issueServiceCreateIssueHandler.ServeHTTP(w, r) | |||
| 305 | + | case IssueServiceListIssuesProcedure: | |||
| 306 | + | issueServiceListIssuesHandler.ServeHTTP(w, r) | |||
| 307 | + | case IssueServiceGetIssueProcedure: | |||
| 308 | + | issueServiceGetIssueHandler.ServeHTTP(w, r) | |||
| 309 | + | case IssueServiceAddIssueCommentProcedure: | |||
| 310 | + | issueServiceAddIssueCommentHandler.ServeHTTP(w, r) | |||
| 311 | + | case IssueServiceCloseIssueProcedure: | |||
| 312 | + | issueServiceCloseIssueHandler.ServeHTTP(w, r) | |||
| 313 | + | case IssueServiceReopenIssueProcedure: | |||
| 314 | + | issueServiceReopenIssueHandler.ServeHTTP(w, r) | |||
| 315 | + | case IssueServiceListPendingIssuesProcedure: | |||
| 316 | + | issueServiceListPendingIssuesHandler.ServeHTTP(w, r) | |||
| 317 | + | case IssueServiceApproveIssueProcedure: | |||
| 318 | + | issueServiceApproveIssueHandler.ServeHTTP(w, r) | |||
| 319 | + | case IssueServiceRejectIssueProcedure: | |||
| 320 | + | issueServiceRejectIssueHandler.ServeHTTP(w, r) | |||
| 321 | + | default: | |||
| 322 | + | http.NotFound(w, r) | |||
| 323 | + | } | |||
| 324 | + | }) | |||
| 325 | + | } | |||
| 326 | + | ||||
| 327 | + | // UnimplementedIssueServiceHandler returns CodeUnimplemented from all methods. | |||
| 328 | + | type UnimplementedIssueServiceHandler struct{} | |||
| 329 | + | ||||
| 330 | + | func (UnimplementedIssueServiceHandler) CreateIssue(context.Context, *connect.Request[ermite.CreateIssueRequest]) (*connect.Response[ermite.CreateIssueResponse], error) { | |||
| 331 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.CreateIssue is not implemented")) | |||
| 332 | + | } | |||
| 333 | + | ||||
| 334 | + | func (UnimplementedIssueServiceHandler) ListIssues(context.Context, *connect.Request[ermite.ListIssuesRequest]) (*connect.Response[ermite.ListIssuesResponse], error) { | |||
| 335 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.ListIssues is not implemented")) | |||
| 336 | + | } | |||
| 337 | + | ||||
| 338 | + | func (UnimplementedIssueServiceHandler) GetIssue(context.Context, *connect.Request[ermite.GetIssueRequest]) (*connect.Response[ermite.GetIssueResponse], error) { | |||
| 339 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.GetIssue is not implemented")) | |||
| 340 | + | } | |||
| 341 | + | ||||
| 342 | + | func (UnimplementedIssueServiceHandler) AddIssueComment(context.Context, *connect.Request[ermite.AddIssueCommentRequest]) (*connect.Response[ermite.AddIssueCommentResponse], error) { | |||
| 343 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.AddIssueComment is not implemented")) | |||
| 344 | + | } | |||
| 345 | + | ||||
| 346 | + | func (UnimplementedIssueServiceHandler) CloseIssue(context.Context, *connect.Request[ermite.CloseIssueRequest]) (*connect.Response[ermite.CloseIssueResponse], error) { | |||
| 347 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.CloseIssue is not implemented")) | |||
| 348 | + | } | |||
| 349 | + | ||||
| 350 | + | func (UnimplementedIssueServiceHandler) ReopenIssue(context.Context, *connect.Request[ermite.ReopenIssueRequest]) (*connect.Response[ermite.ReopenIssueResponse], error) { | |||
| 351 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.ReopenIssue is not implemented")) | |||
| 352 | + | } | |||
| 353 | + | ||||
| 354 | + | func (UnimplementedIssueServiceHandler) ListPendingIssues(context.Context, *connect.Request[ermite.ListPendingIssuesRequest]) (*connect.Response[ermite.ListPendingIssuesResponse], error) { | |||
| 355 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.ListPendingIssues is not implemented")) | |||
| 356 | + | } | |||
| 357 | + | ||||
| 358 | + | func (UnimplementedIssueServiceHandler) ApproveIssue(context.Context, *connect.Request[ermite.ApproveIssueRequest]) (*connect.Response[ermite.ApproveIssueResponse], error) { | |||
| 359 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.ApproveIssue is not implemented")) | |||
| 360 | + | } | |||
| 361 | + | ||||
| 362 | + | func (UnimplementedIssueServiceHandler) RejectIssue(context.Context, *connect.Request[ermite.RejectIssueRequest]) (*connect.Response[ermite.RejectIssueResponse], error) { | |||
| 363 | + | return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.IssueService.RejectIssue is not implemented")) | |||
| 364 | + | } | |||
M gen/ermite/event.pb.go +445 -51 generated file: collapsed
A gen/ermite/issue.pb.go +1574 -0 generated file: collapsed
M gen/ermite/repo.pb.go +151 -57
| @@ -80,8 +80,65 @@ func (Visibility) EnumDescriptor() ([]byte, []int) { | |||
| 80 | 80 | return file_ermite_repo_proto_rawDescGZIP(), []int{0} | |
| 81 | 81 | } | |
| 82 | 82 | ||
| 83 | + | // IssuesMode says who may write issues in a repository. | |
| 84 | + | type IssuesMode int32 | |
| 85 | + | ||
| 86 | + | const ( | |
| 87 | + | // Not set. | |
| 88 | + | IssuesMode_ISSUES_MODE_UNSPECIFIED IssuesMode = 0 | |
| 89 | + | // Issues are disabled. | |
| 90 | + | IssuesMode_ISSUES_MODE_OFF IssuesMode = 1 | |
| 91 | + | // Only the owner may write issues. | |
| 92 | + | IssuesMode_ISSUES_MODE_OWNER IssuesMode = 2 | |
| 93 | + | // Issues are open to public participation. | |
| 94 | + | IssuesMode_ISSUES_MODE_PUBLIC IssuesMode = 3 | |
| 95 | + | ) | |
| 96 | + | ||
| 97 | + | // Enum value maps for IssuesMode. | |
| 98 | + | var ( | |
| 99 | + | IssuesMode_name = map[int32]string{ | |
| 100 | + | 0: "ISSUES_MODE_UNSPECIFIED", | |
| 101 | + | 1: "ISSUES_MODE_OFF", | |
| 102 | + | 2: "ISSUES_MODE_OWNER", | |
| 103 | + | 3: "ISSUES_MODE_PUBLIC", | |
| 104 | + | } | |
| 105 | + | IssuesMode_value = map[string]int32{ | |
| 106 | + | "ISSUES_MODE_UNSPECIFIED": 0, | |
| 107 | + | "ISSUES_MODE_OFF": 1, | |
| 108 | + | "ISSUES_MODE_OWNER": 2, | |
| 109 | + | "ISSUES_MODE_PUBLIC": 3, | |
| 110 | + | } | |
| 111 | + | ) | |
| 112 | + | ||
| 113 | + | func (x IssuesMode) Enum() *IssuesMode { | |
| 114 | + | p := new(IssuesMode) | |
| 115 | + | *p = x | |
| 116 | + | return p | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | func (x IssuesMode) String() string { | |
| 120 | + | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) | |
| 121 | + | } | |
| 122 | + | ||
| 123 | + | func (IssuesMode) Descriptor() protoreflect.EnumDescriptor { | |
| 124 | + | return file_ermite_repo_proto_enumTypes[1].Descriptor() | |
| 125 | + | } | |
| 126 | + | ||
| 127 | + | func (IssuesMode) Type() protoreflect.EnumType { | |
| 128 | + | return &file_ermite_repo_proto_enumTypes[1] | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | func (x IssuesMode) Number() protoreflect.EnumNumber { | |
| 132 | + | return protoreflect.EnumNumber(x) | |
| 133 | + | } | |
| 134 | + | ||
| 135 | + | // Deprecated: Use IssuesMode.Descriptor instead. | |
| 136 | + | func (IssuesMode) EnumDescriptor() ([]byte, []int) { | |
| 137 | + | return file_ermite_repo_proto_rawDescGZIP(), []int{1} | |
| 138 | + | } | |
| 139 | + | ||
| 83 | 140 | // RepoSettings are the settings of a repository that govern its merge | |
| 84 | - | // requests. | |
| 141 | + | // requests and issues. | |
| 85 | 142 | type RepoSettings struct { | |
| 86 | 143 | state protoimpl.MessageState `protogen:"open.v1"` | |
| 87 | 144 | // AllowedMergeModes are the modes with which a merge request of the | |
| @@ -94,8 +151,10 @@ type RepoSettings struct { | |||
| 94 | 151 | // explicitly, so a later change of the server default never alters an | |
| 95 | 152 | // existing repository. | |
| 96 | 153 | FailingChecksBlock bool `protobuf:"varint,2,opt,name=failing_checks_block,json=failingChecksBlock,proto3" json:"failing_checks_block,omitempty"` | |
| 97 | - | unknownFields protoimpl.UnknownFields | |
| 98 | - | sizeCache protoimpl.SizeCache | |
| 154 | + | // Issues is the issue participation mode of the repository. | |
| 155 | + | Issues IssuesMode `protobuf:"varint,3,opt,name=issues,proto3,enum=ermite.IssuesMode" json:"issues,omitempty"` | |
| 156 | + | unknownFields protoimpl.UnknownFields | |
| 157 | + | sizeCache protoimpl.SizeCache | |
| 99 | 158 | } | |
| 100 | 159 | ||
| 101 | 160 | func (x *RepoSettings) Reset() { | |
| @@ -142,6 +201,13 @@ func (x *RepoSettings) GetFailingChecksBlock() bool { | |||
| 142 | 201 | return false | |
| 143 | 202 | } | |
| 144 | 203 | ||
| 204 | + | func (x *RepoSettings) GetIssues() IssuesMode { | |
| 205 | + | if x != nil { | |
| 206 | + | return x.Issues | |
| 207 | + | } | |
| 208 | + | return IssuesMode_ISSUES_MODE_UNSPECIFIED | |
| 209 | + | } | |
| 210 | + | ||
| 145 | 211 | // Repo is the metadata of a repository. Git-owned state (refs, trees, history) | |
| 146 | 212 | // is read through GitService. | |
| 147 | 213 | type Repo struct { | |
| @@ -161,7 +227,7 @@ type Repo struct { | |||
| 161 | 227 | CreatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` | |
| 162 | 228 | // PushedAt is the time of the last push. It is unset until the first push. | |
| 163 | 229 | PushedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=pushed_at,json=pushedAt,proto3" json:"pushed_at,omitempty"` | |
| 164 | - | // Settings are the merge settings of the repository. Always set in a | |
| 230 | + | // Settings are the settings of the repository. Always set in a | |
| 165 | 231 | // response, with the defaults for a repository that never changed them. | |
| 166 | 232 | Settings *RepoSettings `protobuf:"bytes,7,opt,name=settings,proto3" json:"settings,omitempty"` | |
| 167 | 233 | // Topics classify the repository, as on GitHub: at most 20, each 1-50 | |
| @@ -602,8 +668,10 @@ type UpdateRepoRequest struct { | |||
| 602 | 668 | DefaultBranch string `protobuf:"bytes,4,opt,name=default_branch,json=defaultBranch,proto3" json:"default_branch,omitempty"` | |
| 603 | 669 | // UpdateMask lists the fields to change: "description", "visibility", | |
| 604 | 670 | // "default_branch", "topics", "settings.allowed_merge_modes" and/or | |
| 605 | - | // "settings.failing_checks_block". "settings" stands for both settings | |
| 606 | - | // paths. It must not be empty. Other paths are invalid_argument. | |
| 671 | + | // "settings.failing_checks_block". "settings" stands for both merge settings | |
| 672 | + | // paths. It must not be empty unless issues is set. Other paths are | |
| 673 | + | // invalid_argument, including "settings.issues" and "issues": the issues | |
| 674 | + | // field is applied outside the mask. | |
| 607 | 675 | UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,5,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` | |
| 608 | 676 | // Settings holds the new merge settings. Only the fields named in | |
| 609 | 677 | // update_mask are used. allowed_merge_modes must then not be empty nor | |
| @@ -613,7 +681,13 @@ type UpdateRepoRequest struct { | |||
| 613 | 681 | Settings *RepoSettings `protobuf:"bytes,6,opt,name=settings,proto3" json:"settings,omitempty"` | |
| 614 | 682 | // Topics replace the topics of the repository (see Repo.topics). Used only | |
| 615 | 683 | // if update_mask contains "topics"; an empty list then clears them. | |
| 616 | - | Topics []string `protobuf:"bytes,7,rep,name=topics,proto3" json:"topics,omitempty"` | |
| 684 | + | Topics []string `protobuf:"bytes,7,rep,name=topics,proto3" json:"topics,omitempty"` | |
| 685 | + | // Issues is the new issue participation mode. When absent it is unchanged. | |
| 686 | + | // It is applied whatever update_mask contains, and may be the only change | |
| 687 | + | // (an empty update_mask is then valid). When present it must not be | |
| 688 | + | // ISSUES_MODE_UNSPECIFIED: that is invalid_argument. Changing it needs the | |
| 689 | + | // repo:admin scope and a token with no branch limit, like any other field. | |
| 690 | + | Issues *IssuesMode `protobuf:"varint,8,opt,name=issues,proto3,enum=ermite.IssuesMode,oneof" json:"issues,omitempty"` | |
| 617 | 691 | unknownFields protoimpl.UnknownFields | |
| 618 | 692 | sizeCache protoimpl.SizeCache | |
| 619 | 693 | } | |
| @@ -697,6 +771,13 @@ func (x *UpdateRepoRequest) GetTopics() []string { | |||
| 697 | 771 | return nil | |
| 698 | 772 | } | |
| 699 | 773 | ||
| 774 | + | func (x *UpdateRepoRequest) GetIssues() IssuesMode { | |
| 775 | + | if x != nil && x.Issues != nil { | |
| 776 | + | return *x.Issues | |
| 777 | + | } | |
| 778 | + | return IssuesMode_ISSUES_MODE_UNSPECIFIED | |
| 779 | + | } | |
| 780 | + | ||
| 700 | 781 | // UpdateRepoResponse holds the repository after the update. | |
| 701 | 782 | type UpdateRepoResponse struct { | |
| 702 | 783 | state protoimpl.MessageState `protogen:"open.v1"` | |
| @@ -830,10 +911,11 @@ var File_ermite_repo_proto protoreflect.FileDescriptor | |||
| 830 | 911 | ||
| 831 | 912 | const file_ermite_repo_proto_rawDesc = "" + | |
| 832 | 913 | "\n" + | |
| 833 | - | "\x11ermite/repo.proto\x12\x06ermite\x1a google/protobuf/field_mask.proto\x1a\x12ermite/types.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x83\x01\n" + | |
| 914 | + | "\x11ermite/repo.proto\x12\x06ermite\x1a google/protobuf/field_mask.proto\x1a\x12ermite/types.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xaf\x01\n" + | |
| 834 | 915 | "\fRepoSettings\x12A\n" + | |
| 835 | 916 | "\x13allowed_merge_modes\x18\x01 \x03(\x0e2\x11.ermite.MergeModeR\x11allowedMergeModes\x120\n" + | |
| 836 | - | "\x14failing_checks_block\x18\x02 \x01(\bR\x12failingChecksBlock\"\xd5\x02\n" + | |
| 917 | + | "\x14failing_checks_block\x18\x02 \x01(\bR\x12failingChecksBlock\x12*\n" + | |
| 918 | + | "\x06issues\x18\x03 \x01(\x0e2\x12.ermite.IssuesModeR\x06issues\"\xd5\x02\n" + | |
| 837 | 919 | "\x04Repo\x12\x12\n" + | |
| 838 | 920 | "\x04name\x18\x01 \x01(\tR\x04name\x12 \n" + | |
| 839 | 921 | "\vdescription\x18\x02 \x01(\tR\vdescription\x122\n" + | |
| @@ -865,7 +947,7 @@ const file_ermite_repo_proto_rawDesc = "" + | |||
| 865 | 947 | "visibility\x12\x16\n" + | |
| 866 | 948 | "\x06topics\x18\x04 \x03(\tR\x06topics\"6\n" + | |
| 867 | 949 | "\x12CreateRepoResponse\x12 \n" + | |
| 868 | - | "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"\xab\x02\n" + | |
| 950 | + | "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"\xe7\x02\n" + | |
| 869 | 951 | "\x11UpdateRepoRequest\x12\x12\n" + | |
| 870 | 952 | "\x04repo\x18\x01 \x01(\tR\x04repo\x12 \n" + | |
| 871 | 953 | "\vdescription\x18\x02 \x01(\tR\vdescription\x122\n" + | |
| @@ -876,7 +958,9 @@ const file_ermite_repo_proto_rawDesc = "" + | |||
| 876 | 958 | "\vupdate_mask\x18\x05 \x01(\v2\x1a.google.protobuf.FieldMaskR\n" + | |
| 877 | 959 | "updateMask\x120\n" + | |
| 878 | 960 | "\bsettings\x18\x06 \x01(\v2\x14.ermite.RepoSettingsR\bsettings\x12\x16\n" + | |
| 879 | - | "\x06topics\x18\a \x03(\tR\x06topics\"6\n" + | |
| 961 | + | "\x06topics\x18\a \x03(\tR\x06topics\x12/\n" + | |
| 962 | + | "\x06issues\x18\b \x01(\x0e2\x12.ermite.IssuesModeH\x00R\x06issues\x88\x01\x01B\t\n" + | |
| 963 | + | "\a_issues\"6\n" + | |
| 880 | 964 | "\x12UpdateRepoResponse\x12 \n" + | |
| 881 | 965 | "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"'\n" + | |
| 882 | 966 | "\x11DeleteRepoRequest\x12\x12\n" + | |
| @@ -886,7 +970,13 @@ const file_ermite_repo_proto_rawDesc = "" + | |||
| 886 | 970 | "Visibility\x12\x1a\n" + | |
| 887 | 971 | "\x16VISIBILITY_UNSPECIFIED\x10\x00\x12\x15\n" + | |
| 888 | 972 | "\x11VISIBILITY_PUBLIC\x10\x01\x12\x16\n" + | |
| 889 | - | "\x12VISIBILITY_PRIVATE\x10\x022\xda\x02\n" + | |
| 973 | + | "\x12VISIBILITY_PRIVATE\x10\x02*m\n" + | |
| 974 | + | "\n" + | |
| 975 | + | "IssuesMode\x12\x1b\n" + | |
| 976 | + | "\x17ISSUES_MODE_UNSPECIFIED\x10\x00\x12\x13\n" + | |
| 977 | + | "\x0fISSUES_MODE_OFF\x10\x01\x12\x15\n" + | |
| 978 | + | "\x11ISSUES_MODE_OWNER\x10\x02\x12\x16\n" + | |
| 979 | + | "\x12ISSUES_MODE_PUBLIC\x10\x032\xda\x02\n" + | |
| 890 | 980 | "\vRepoService\x12@\n" + | |
| 891 | 981 | "\tListRepos\x12\x18.ermite.ListReposRequest\x1a\x19.ermite.ListReposResponse\x12:\n" + | |
| 892 | 982 | "\aGetRepo\x12\x16.ermite.GetRepoRequest\x1a\x17.ermite.GetRepoResponse\x12C\n" + | |
| @@ -911,55 +1001,58 @@ func file_ermite_repo_proto_rawDescGZIP() []byte { | |||
| 911 | 1001 | return file_ermite_repo_proto_rawDescData | |
| 912 | 1002 | } | |
| 913 | 1003 | ||
| 914 | - | var file_ermite_repo_proto_enumTypes = make([]protoimpl.EnumInfo, 1) | |
| 1004 | + | var file_ermite_repo_proto_enumTypes = make([]protoimpl.EnumInfo, 2) | |
| 915 | 1005 | var file_ermite_repo_proto_msgTypes = make([]protoimpl.MessageInfo, 12) | |
| 916 | 1006 | var file_ermite_repo_proto_goTypes = []any{ | |
| 917 | 1007 | (Visibility)(0), // 0: ermite.Visibility | |
| 918 | - | (*RepoSettings)(nil), // 1: ermite.RepoSettings | |
| 919 | - | (*Repo)(nil), // 2: ermite.Repo | |
| 920 | - | (*ListReposRequest)(nil), // 3: ermite.ListReposRequest | |
| 921 | - | (*ListReposResponse)(nil), // 4: ermite.ListReposResponse | |
| 922 | - | (*GetRepoRequest)(nil), // 5: ermite.GetRepoRequest | |
| 923 | - | (*GetRepoResponse)(nil), // 6: ermite.GetRepoResponse | |
| 924 | - | (*CreateRepoRequest)(nil), // 7: ermite.CreateRepoRequest | |
| 925 | - | (*CreateRepoResponse)(nil), // 8: ermite.CreateRepoResponse | |
| 926 | - | (*UpdateRepoRequest)(nil), // 9: ermite.UpdateRepoRequest | |
| 927 | - | (*UpdateRepoResponse)(nil), // 10: ermite.UpdateRepoResponse | |
| 928 | - | (*DeleteRepoRequest)(nil), // 11: ermite.DeleteRepoRequest | |
| 929 | - | (*DeleteRepoResponse)(nil), // 12: ermite.DeleteRepoResponse | |
| 930 | - | (MergeMode)(0), // 13: ermite.MergeMode | |
| 931 | - | (*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp | |
| 932 | - | (*fieldmaskpb.FieldMask)(nil), // 15: google.protobuf.FieldMask | |
| 1008 | + | (IssuesMode)(0), // 1: ermite.IssuesMode | |
| 1009 | + | (*RepoSettings)(nil), // 2: ermite.RepoSettings | |
| 1010 | + | (*Repo)(nil), // 3: ermite.Repo | |
| 1011 | + | (*ListReposRequest)(nil), // 4: ermite.ListReposRequest | |
| 1012 | + | (*ListReposResponse)(nil), // 5: ermite.ListReposResponse | |
| 1013 | + | (*GetRepoRequest)(nil), // 6: ermite.GetRepoRequest | |
| 1014 | + | (*GetRepoResponse)(nil), // 7: ermite.GetRepoResponse | |
| 1015 | + | (*CreateRepoRequest)(nil), // 8: ermite.CreateRepoRequest | |
| 1016 | + | (*CreateRepoResponse)(nil), // 9: ermite.CreateRepoResponse | |
| 1017 | + | (*UpdateRepoRequest)(nil), // 10: ermite.UpdateRepoRequest | |
| 1018 | + | (*UpdateRepoResponse)(nil), // 11: ermite.UpdateRepoResponse | |
| 1019 | + | (*DeleteRepoRequest)(nil), // 12: ermite.DeleteRepoRequest | |
| 1020 | + | (*DeleteRepoResponse)(nil), // 13: ermite.DeleteRepoResponse | |
| 1021 | + | (MergeMode)(0), // 14: ermite.MergeMode | |
| 1022 | + | (*timestamppb.Timestamp)(nil), // 15: google.protobuf.Timestamp | |
| 1023 | + | (*fieldmaskpb.FieldMask)(nil), // 16: google.protobuf.FieldMask | |
| 933 | 1024 | } | |
| 934 | 1025 | var file_ermite_repo_proto_depIdxs = []int32{ | |
| 935 | - | 13, // 0: ermite.RepoSettings.allowed_merge_modes:type_name -> ermite.MergeMode | |
| 936 | - | 0, // 1: ermite.Repo.visibility:type_name -> ermite.Visibility | |
| 937 | - | 14, // 2: ermite.Repo.created_at:type_name -> google.protobuf.Timestamp | |
| 938 | - | 14, // 3: ermite.Repo.pushed_at:type_name -> google.protobuf.Timestamp | |
| 939 | - | 1, // 4: ermite.Repo.settings:type_name -> ermite.RepoSettings | |
| 940 | - | 2, // 5: ermite.ListReposResponse.repos:type_name -> ermite.Repo | |
| 941 | - | 2, // 6: ermite.GetRepoResponse.repo:type_name -> ermite.Repo | |
| 942 | - | 0, // 7: ermite.CreateRepoRequest.visibility:type_name -> ermite.Visibility | |
| 943 | - | 2, // 8: ermite.CreateRepoResponse.repo:type_name -> ermite.Repo | |
| 944 | - | 0, // 9: ermite.UpdateRepoRequest.visibility:type_name -> ermite.Visibility | |
| 945 | - | 15, // 10: ermite.UpdateRepoRequest.update_mask:type_name -> google.protobuf.FieldMask | |
| 946 | - | 1, // 11: ermite.UpdateRepoRequest.settings:type_name -> ermite.RepoSettings | |
| 947 | - | 2, // 12: ermite.UpdateRepoResponse.repo:type_name -> ermite.Repo | |
| 948 | - | 3, // 13: ermite.RepoService.ListRepos:input_type -> ermite.ListReposRequest | |
| 949 | - | 5, // 14: ermite.RepoService.GetRepo:input_type -> ermite.GetRepoRequest | |
| 950 | - | 7, // 15: ermite.RepoService.CreateRepo:input_type -> ermite.CreateRepoRequest | |
| 951 | - | 9, // 16: ermite.RepoService.UpdateRepo:input_type -> ermite.UpdateRepoRequest | |
| 952 | - | 11, // 17: ermite.RepoService.DeleteRepo:input_type -> ermite.DeleteRepoRequest | |
| 953 | - | 4, // 18: ermite.RepoService.ListRepos:output_type -> ermite.ListReposResponse | |
| 954 | - | 6, // 19: ermite.RepoService.GetRepo:output_type -> ermite.GetRepoResponse | |
| 955 | - | 8, // 20: ermite.RepoService.CreateRepo:output_type -> ermite.CreateRepoResponse | |
| 956 | - | 10, // 21: ermite.RepoService.UpdateRepo:output_type -> ermite.UpdateRepoResponse | |
| 957 | - | 12, // 22: ermite.RepoService.DeleteRepo:output_type -> ermite.DeleteRepoResponse | |
| 958 | - | 18, // [18:23] is the sub-list for method output_type | |
| 959 | - | 13, // [13:18] is the sub-list for method input_type | |
| 960 | - | 13, // [13:13] is the sub-list for extension type_name | |
| 961 | - | 13, // [13:13] is the sub-list for extension extendee | |
| 962 | - | 0, // [0:13] is the sub-list for field type_name | |
| 1026 | + | 14, // 0: ermite.RepoSettings.allowed_merge_modes:type_name -> ermite.MergeMode | |
| 1027 | + | 1, // 1: ermite.RepoSettings.issues:type_name -> ermite.IssuesMode | |
| 1028 | + | 0, // 2: ermite.Repo.visibility:type_name -> ermite.Visibility | |
| 1029 | + | 15, // 3: ermite.Repo.created_at:type_name -> google.protobuf.Timestamp | |
| 1030 | + | 15, // 4: ermite.Repo.pushed_at:type_name -> google.protobuf.Timestamp | |
| 1031 | + | 2, // 5: ermite.Repo.settings:type_name -> ermite.RepoSettings | |
| 1032 | + | 3, // 6: ermite.ListReposResponse.repos:type_name -> ermite.Repo | |
| 1033 | + | 3, // 7: ermite.GetRepoResponse.repo:type_name -> ermite.Repo | |
| 1034 | + | 0, // 8: ermite.CreateRepoRequest.visibility:type_name -> ermite.Visibility | |
| 1035 | + | 3, // 9: ermite.CreateRepoResponse.repo:type_name -> ermite.Repo | |
| 1036 | + | 0, // 10: ermite.UpdateRepoRequest.visibility:type_name -> ermite.Visibility | |
| 1037 | + | 16, // 11: ermite.UpdateRepoRequest.update_mask:type_name -> google.protobuf.FieldMask | |
| 1038 | + | 2, // 12: ermite.UpdateRepoRequest.settings:type_name -> ermite.RepoSettings | |
| 1039 | + | 1, // 13: ermite.UpdateRepoRequest.issues:type_name -> ermite.IssuesMode | |
| 1040 | + | 3, // 14: ermite.UpdateRepoResponse.repo:type_name -> ermite.Repo | |
| 1041 | + | 4, // 15: ermite.RepoService.ListRepos:input_type -> ermite.ListReposRequest | |
| 1042 | + | 6, // 16: ermite.RepoService.GetRepo:input_type -> ermite.GetRepoRequest | |
| 1043 | + | 8, // 17: ermite.RepoService.CreateRepo:input_type -> ermite.CreateRepoRequest | |
| 1044 | + | 10, // 18: ermite.RepoService.UpdateRepo:input_type -> ermite.UpdateRepoRequest | |
| 1045 | + | 12, // 19: ermite.RepoService.DeleteRepo:input_type -> ermite.DeleteRepoRequest | |
| 1046 | + | 5, // 20: ermite.RepoService.ListRepos:output_type -> ermite.ListReposResponse | |
| 1047 | + | 7, // 21: ermite.RepoService.GetRepo:output_type -> ermite.GetRepoResponse | |
| 1048 | + | 9, // 22: ermite.RepoService.CreateRepo:output_type -> ermite.CreateRepoResponse | |
| 1049 | + | 11, // 23: ermite.RepoService.UpdateRepo:output_type -> ermite.UpdateRepoResponse | |
| 1050 | + | 13, // 24: ermite.RepoService.DeleteRepo:output_type -> ermite.DeleteRepoResponse | |
| 1051 | + | 20, // [20:25] is the sub-list for method output_type | |
| 1052 | + | 15, // [15:20] is the sub-list for method input_type | |
| 1053 | + | 15, // [15:15] is the sub-list for extension type_name | |
| 1054 | + | 15, // [15:15] is the sub-list for extension extendee | |
| 1055 | + | 0, // [0:15] is the sub-list for field type_name | |
| 963 | 1056 | } | |
| 964 | 1057 | ||
| 965 | 1058 | func init() { file_ermite_repo_proto_init() } | |
| @@ -968,12 +1061,13 @@ func file_ermite_repo_proto_init() { | |||
| 968 | 1061 | return | |
| 969 | 1062 | } | |
| 970 | 1063 | file_ermite_types_proto_init() | |
| 1064 | + | file_ermite_repo_proto_msgTypes[8].OneofWrappers = []any{} | |
| 971 | 1065 | type x struct{} | |
| 972 | 1066 | out := protoimpl.TypeBuilder{ | |
| 973 | 1067 | File: protoimpl.DescBuilder{ | |
| 974 | 1068 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), | |
| 975 | 1069 | RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_repo_proto_rawDesc), len(file_ermite_repo_proto_rawDesc)), | |
| 976 | - | NumEnums: 1, | |
| 1070 | + | NumEnums: 2, | |
| 977 | 1071 | NumMessages: 12, | |
| 978 | 1072 | NumExtensions: 0, | |
| 979 | 1073 | NumServices: 1, | |
| @@ -80,8 +80,65 @@ func (Visibility) EnumDescriptor() ([]byte, []int) { | |||||
| 80 | return file_ermite_repo_proto_rawDescGZIP(), []int{0} | 80 | return file_ermite_repo_proto_rawDescGZIP(), []int{0} | ||
| 81 | } | 81 | } | ||
| 82 | 82 | ||||
| 83 | + | // IssuesMode says who may write issues in a repository. | |||
| 84 | + | type IssuesMode int32 | |||
| 85 | + | ||||
| 86 | + | const ( | |||
| 87 | + | // Not set. | |||
| 88 | + | IssuesMode_ISSUES_MODE_UNSPECIFIED IssuesMode = 0 | |||
| 89 | + | // Issues are disabled. | |||
| 90 | + | IssuesMode_ISSUES_MODE_OFF IssuesMode = 1 | |||
| 91 | + | // Only the owner may write issues. | |||
| 92 | + | IssuesMode_ISSUES_MODE_OWNER IssuesMode = 2 | |||
| 93 | + | // Issues are open to public participation. | |||
| 94 | + | IssuesMode_ISSUES_MODE_PUBLIC IssuesMode = 3 | |||
| 95 | + | ) | |||
| 96 | + | ||||
| 97 | + | // Enum value maps for IssuesMode. | |||
| 98 | + | var ( | |||
| 99 | + | IssuesMode_name = map[int32]string{ | |||
| 100 | + | 0: "ISSUES_MODE_UNSPECIFIED", | |||
| 101 | + | 1: "ISSUES_MODE_OFF", | |||
| 102 | + | 2: "ISSUES_MODE_OWNER", | |||
| 103 | + | 3: "ISSUES_MODE_PUBLIC", | |||
| 104 | + | } | |||
| 105 | + | IssuesMode_value = map[string]int32{ | |||
| 106 | + | "ISSUES_MODE_UNSPECIFIED": 0, | |||
| 107 | + | "ISSUES_MODE_OFF": 1, | |||
| 108 | + | "ISSUES_MODE_OWNER": 2, | |||
| 109 | + | "ISSUES_MODE_PUBLIC": 3, | |||
| 110 | + | } | |||
| 111 | + | ) | |||
| 112 | + | ||||
| 113 | + | func (x IssuesMode) Enum() *IssuesMode { | |||
| 114 | + | p := new(IssuesMode) | |||
| 115 | + | *p = x | |||
| 116 | + | return p | |||
| 117 | + | } | |||
| 118 | + | ||||
| 119 | + | func (x IssuesMode) String() string { | |||
| 120 | + | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) | |||
| 121 | + | } | |||
| 122 | + | ||||
| 123 | + | func (IssuesMode) Descriptor() protoreflect.EnumDescriptor { | |||
| 124 | + | return file_ermite_repo_proto_enumTypes[1].Descriptor() | |||
| 125 | + | } | |||
| 126 | + | ||||
| 127 | + | func (IssuesMode) Type() protoreflect.EnumType { | |||
| 128 | + | return &file_ermite_repo_proto_enumTypes[1] | |||
| 129 | + | } | |||
| 130 | + | ||||
| 131 | + | func (x IssuesMode) Number() protoreflect.EnumNumber { | |||
| 132 | + | return protoreflect.EnumNumber(x) | |||
| 133 | + | } | |||
| 134 | + | ||||
| 135 | + | // Deprecated: Use IssuesMode.Descriptor instead. | |||
| 136 | + | func (IssuesMode) EnumDescriptor() ([]byte, []int) { | |||
| 137 | + | return file_ermite_repo_proto_rawDescGZIP(), []int{1} | |||
| 138 | + | } | |||
| 139 | + | ||||
| 83 | // RepoSettings are the settings of a repository that govern its merge | 140 | // RepoSettings are the settings of a repository that govern its merge | ||
| 84 | - | // requests. | 141 | + | // requests and issues. |
| 85 | type RepoSettings struct { | 142 | type RepoSettings struct { | ||
| 86 | state protoimpl.MessageState `protogen:"open.v1"` | 143 | state protoimpl.MessageState `protogen:"open.v1"` | ||
| 87 | // AllowedMergeModes are the modes with which a merge request of the | 144 | // AllowedMergeModes are the modes with which a merge request of the | ||
| @@ -94,8 +151,10 @@ type RepoSettings struct { | |||||
| 94 | // explicitly, so a later change of the server default never alters an | 151 | // explicitly, so a later change of the server default never alters an | ||
| 95 | // existing repository. | 152 | // existing repository. | ||
| 96 | FailingChecksBlock bool `protobuf:"varint,2,opt,name=failing_checks_block,json=failingChecksBlock,proto3" json:"failing_checks_block,omitempty"` | 153 | FailingChecksBlock bool `protobuf:"varint,2,opt,name=failing_checks_block,json=failingChecksBlock,proto3" json:"failing_checks_block,omitempty"` | ||
| 97 | - | unknownFields protoimpl.UnknownFields | 154 | + | // Issues is the issue participation mode of the repository. |
| 98 | - | sizeCache protoimpl.SizeCache | 155 | + | Issues IssuesMode `protobuf:"varint,3,opt,name=issues,proto3,enum=ermite.IssuesMode" json:"issues,omitempty"` |
| 156 | + | unknownFields protoimpl.UnknownFields | |||
| 157 | + | sizeCache protoimpl.SizeCache | |||
| 99 | } | 158 | } | ||
| 100 | 159 | ||||
| 101 | func (x *RepoSettings) Reset() { | 160 | func (x *RepoSettings) Reset() { | ||
| @@ -142,6 +201,13 @@ func (x *RepoSettings) GetFailingChecksBlock() bool { | |||||
| 142 | return false | 201 | return false | ||
| 143 | } | 202 | } | ||
| 144 | 203 | ||||
| 204 | + | func (x *RepoSettings) GetIssues() IssuesMode { | |||
| 205 | + | if x != nil { | |||
| 206 | + | return x.Issues | |||
| 207 | + | } | |||
| 208 | + | return IssuesMode_ISSUES_MODE_UNSPECIFIED | |||
| 209 | + | } | |||
| 210 | + | ||||
| 145 | // Repo is the metadata of a repository. Git-owned state (refs, trees, history) | 211 | // Repo is the metadata of a repository. Git-owned state (refs, trees, history) | ||
| 146 | // is read through GitService. | 212 | // is read through GitService. | ||
| 147 | type Repo struct { | 213 | type Repo struct { | ||
| @@ -161,7 +227,7 @@ type Repo struct { | |||||
| 161 | CreatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` | 227 | CreatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` | ||
| 162 | // PushedAt is the time of the last push. It is unset until the first push. | 228 | // PushedAt is the time of the last push. It is unset until the first push. | ||
| 163 | PushedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=pushed_at,json=pushedAt,proto3" json:"pushed_at,omitempty"` | 229 | PushedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=pushed_at,json=pushedAt,proto3" json:"pushed_at,omitempty"` | ||
| 164 | - | // Settings are the merge settings of the repository. Always set in a | 230 | + | // Settings are the settings of the repository. Always set in a |
| 165 | // response, with the defaults for a repository that never changed them. | 231 | // response, with the defaults for a repository that never changed them. | ||
| 166 | Settings *RepoSettings `protobuf:"bytes,7,opt,name=settings,proto3" json:"settings,omitempty"` | 232 | Settings *RepoSettings `protobuf:"bytes,7,opt,name=settings,proto3" json:"settings,omitempty"` | ||
| 167 | // Topics classify the repository, as on GitHub: at most 20, each 1-50 | 233 | // Topics classify the repository, as on GitHub: at most 20, each 1-50 | ||
| @@ -602,8 +668,10 @@ type UpdateRepoRequest struct { | |||||
| 602 | DefaultBranch string `protobuf:"bytes,4,opt,name=default_branch,json=defaultBranch,proto3" json:"default_branch,omitempty"` | 668 | DefaultBranch string `protobuf:"bytes,4,opt,name=default_branch,json=defaultBranch,proto3" json:"default_branch,omitempty"` | ||
| 603 | // UpdateMask lists the fields to change: "description", "visibility", | 669 | // UpdateMask lists the fields to change: "description", "visibility", | ||
| 604 | // "default_branch", "topics", "settings.allowed_merge_modes" and/or | 670 | // "default_branch", "topics", "settings.allowed_merge_modes" and/or | ||
| 605 | - | // "settings.failing_checks_block". "settings" stands for both settings | 671 | + | // "settings.failing_checks_block". "settings" stands for both merge settings |
| 606 | - | // paths. It must not be empty. Other paths are invalid_argument. | 672 | + | // paths. It must not be empty unless issues is set. Other paths are |
| 673 | + | // invalid_argument, including "settings.issues" and "issues": the issues | |||
| 674 | + | // field is applied outside the mask. | |||
| 607 | UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,5,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` | 675 | UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,5,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` | ||
| 608 | // Settings holds the new merge settings. Only the fields named in | 676 | // Settings holds the new merge settings. Only the fields named in | ||
| 609 | // update_mask are used. allowed_merge_modes must then not be empty nor | 677 | // update_mask are used. allowed_merge_modes must then not be empty nor | ||
| @@ -613,7 +681,13 @@ type UpdateRepoRequest struct { | |||||
| 613 | Settings *RepoSettings `protobuf:"bytes,6,opt,name=settings,proto3" json:"settings,omitempty"` | 681 | Settings *RepoSettings `protobuf:"bytes,6,opt,name=settings,proto3" json:"settings,omitempty"` | ||
| 614 | // Topics replace the topics of the repository (see Repo.topics). Used only | 682 | // Topics replace the topics of the repository (see Repo.topics). Used only | ||
| 615 | // if update_mask contains "topics"; an empty list then clears them. | 683 | // if update_mask contains "topics"; an empty list then clears them. | ||
| 616 | - | Topics []string `protobuf:"bytes,7,rep,name=topics,proto3" json:"topics,omitempty"` | 684 | + | Topics []string `protobuf:"bytes,7,rep,name=topics,proto3" json:"topics,omitempty"` |
| 685 | + | // Issues is the new issue participation mode. When absent it is unchanged. | |||
| 686 | + | // It is applied whatever update_mask contains, and may be the only change | |||
| 687 | + | // (an empty update_mask is then valid). When present it must not be | |||
| 688 | + | // ISSUES_MODE_UNSPECIFIED: that is invalid_argument. Changing it needs the | |||
| 689 | + | // repo:admin scope and a token with no branch limit, like any other field. | |||
| 690 | + | Issues *IssuesMode `protobuf:"varint,8,opt,name=issues,proto3,enum=ermite.IssuesMode,oneof" json:"issues,omitempty"` | |||
| 617 | unknownFields protoimpl.UnknownFields | 691 | unknownFields protoimpl.UnknownFields | ||
| 618 | sizeCache protoimpl.SizeCache | 692 | sizeCache protoimpl.SizeCache | ||
| 619 | } | 693 | } | ||
| @@ -697,6 +771,13 @@ func (x *UpdateRepoRequest) GetTopics() []string { | |||||
| 697 | return nil | 771 | return nil | ||
| 698 | } | 772 | } | ||
| 699 | 773 | ||||
| 774 | + | func (x *UpdateRepoRequest) GetIssues() IssuesMode { | |||
| 775 | + | if x != nil && x.Issues != nil { | |||
| 776 | + | return *x.Issues | |||
| 777 | + | } | |||
| 778 | + | return IssuesMode_ISSUES_MODE_UNSPECIFIED | |||
| 779 | + | } | |||
| 780 | + | ||||
| 700 | // UpdateRepoResponse holds the repository after the update. | 781 | // UpdateRepoResponse holds the repository after the update. | ||
| 701 | type UpdateRepoResponse struct { | 782 | type UpdateRepoResponse struct { | ||
| 702 | state protoimpl.MessageState `protogen:"open.v1"` | 783 | state protoimpl.MessageState `protogen:"open.v1"` | ||
| @@ -830,10 +911,11 @@ var File_ermite_repo_proto protoreflect.FileDescriptor | |||||
| 830 | 911 | ||||
| 831 | const file_ermite_repo_proto_rawDesc = "" + | 912 | const file_ermite_repo_proto_rawDesc = "" + | ||
| 832 | "\n" + | 913 | "\n" + | ||
| 833 | - | "\x11ermite/repo.proto\x12\x06ermite\x1a google/protobuf/field_mask.proto\x1a\x12ermite/types.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x83\x01\n" + | 914 | + | "\x11ermite/repo.proto\x12\x06ermite\x1a google/protobuf/field_mask.proto\x1a\x12ermite/types.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xaf\x01\n" + |
| 834 | "\fRepoSettings\x12A\n" + | 915 | "\fRepoSettings\x12A\n" + | ||
| 835 | "\x13allowed_merge_modes\x18\x01 \x03(\x0e2\x11.ermite.MergeModeR\x11allowedMergeModes\x120\n" + | 916 | "\x13allowed_merge_modes\x18\x01 \x03(\x0e2\x11.ermite.MergeModeR\x11allowedMergeModes\x120\n" + | ||
| 836 | - | "\x14failing_checks_block\x18\x02 \x01(\bR\x12failingChecksBlock\"\xd5\x02\n" + | 917 | + | "\x14failing_checks_block\x18\x02 \x01(\bR\x12failingChecksBlock\x12*\n" + |
| 918 | + | "\x06issues\x18\x03 \x01(\x0e2\x12.ermite.IssuesModeR\x06issues\"\xd5\x02\n" + | |||
| 837 | "\x04Repo\x12\x12\n" + | 919 | "\x04Repo\x12\x12\n" + | ||
| 838 | "\x04name\x18\x01 \x01(\tR\x04name\x12 \n" + | 920 | "\x04name\x18\x01 \x01(\tR\x04name\x12 \n" + | ||
| 839 | "\vdescription\x18\x02 \x01(\tR\vdescription\x122\n" + | 921 | "\vdescription\x18\x02 \x01(\tR\vdescription\x122\n" + | ||
| @@ -865,7 +947,7 @@ const file_ermite_repo_proto_rawDesc = "" + | |||||
| 865 | "visibility\x12\x16\n" + | 947 | "visibility\x12\x16\n" + | ||
| 866 | "\x06topics\x18\x04 \x03(\tR\x06topics\"6\n" + | 948 | "\x06topics\x18\x04 \x03(\tR\x06topics\"6\n" + | ||
| 867 | "\x12CreateRepoResponse\x12 \n" + | 949 | "\x12CreateRepoResponse\x12 \n" + | ||
| 868 | - | "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"\xab\x02\n" + | 950 | + | "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"\xe7\x02\n" + |
| 869 | "\x11UpdateRepoRequest\x12\x12\n" + | 951 | "\x11UpdateRepoRequest\x12\x12\n" + | ||
| 870 | "\x04repo\x18\x01 \x01(\tR\x04repo\x12 \n" + | 952 | "\x04repo\x18\x01 \x01(\tR\x04repo\x12 \n" + | ||
| 871 | "\vdescription\x18\x02 \x01(\tR\vdescription\x122\n" + | 953 | "\vdescription\x18\x02 \x01(\tR\vdescription\x122\n" + | ||
| @@ -876,7 +958,9 @@ const file_ermite_repo_proto_rawDesc = "" + | |||||
| 876 | "\vupdate_mask\x18\x05 \x01(\v2\x1a.google.protobuf.FieldMaskR\n" + | 958 | "\vupdate_mask\x18\x05 \x01(\v2\x1a.google.protobuf.FieldMaskR\n" + | ||
| 877 | "updateMask\x120\n" + | 959 | "updateMask\x120\n" + | ||
| 878 | "\bsettings\x18\x06 \x01(\v2\x14.ermite.RepoSettingsR\bsettings\x12\x16\n" + | 960 | "\bsettings\x18\x06 \x01(\v2\x14.ermite.RepoSettingsR\bsettings\x12\x16\n" + | ||
| 879 | - | "\x06topics\x18\a \x03(\tR\x06topics\"6\n" + | 961 | + | "\x06topics\x18\a \x03(\tR\x06topics\x12/\n" + |
| 962 | + | "\x06issues\x18\b \x01(\x0e2\x12.ermite.IssuesModeH\x00R\x06issues\x88\x01\x01B\t\n" + | |||
| 963 | + | "\a_issues\"6\n" + | |||
| 880 | "\x12UpdateRepoResponse\x12 \n" + | 964 | "\x12UpdateRepoResponse\x12 \n" + | ||
| 881 | "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"'\n" + | 965 | "\x04repo\x18\x01 \x01(\v2\f.ermite.RepoR\x04repo\"'\n" + | ||
| 882 | "\x11DeleteRepoRequest\x12\x12\n" + | 966 | "\x11DeleteRepoRequest\x12\x12\n" + | ||
| @@ -886,7 +970,13 @@ const file_ermite_repo_proto_rawDesc = "" + | |||||
| 886 | "Visibility\x12\x1a\n" + | 970 | "Visibility\x12\x1a\n" + | ||
| 887 | "\x16VISIBILITY_UNSPECIFIED\x10\x00\x12\x15\n" + | 971 | "\x16VISIBILITY_UNSPECIFIED\x10\x00\x12\x15\n" + | ||
| 888 | "\x11VISIBILITY_PUBLIC\x10\x01\x12\x16\n" + | 972 | "\x11VISIBILITY_PUBLIC\x10\x01\x12\x16\n" + | ||
| 889 | - | "\x12VISIBILITY_PRIVATE\x10\x022\xda\x02\n" + | 973 | + | "\x12VISIBILITY_PRIVATE\x10\x02*m\n" + |
| 974 | + | "\n" + | |||
| 975 | + | "IssuesMode\x12\x1b\n" + | |||
| 976 | + | "\x17ISSUES_MODE_UNSPECIFIED\x10\x00\x12\x13\n" + | |||
| 977 | + | "\x0fISSUES_MODE_OFF\x10\x01\x12\x15\n" + | |||
| 978 | + | "\x11ISSUES_MODE_OWNER\x10\x02\x12\x16\n" + | |||
| 979 | + | "\x12ISSUES_MODE_PUBLIC\x10\x032\xda\x02\n" + | |||
| 890 | "\vRepoService\x12@\n" + | 980 | "\vRepoService\x12@\n" + | ||
| 891 | "\tListRepos\x12\x18.ermite.ListReposRequest\x1a\x19.ermite.ListReposResponse\x12:\n" + | 981 | "\tListRepos\x12\x18.ermite.ListReposRequest\x1a\x19.ermite.ListReposResponse\x12:\n" + | ||
| 892 | "\aGetRepo\x12\x16.ermite.GetRepoRequest\x1a\x17.ermite.GetRepoResponse\x12C\n" + | 982 | "\aGetRepo\x12\x16.ermite.GetRepoRequest\x1a\x17.ermite.GetRepoResponse\x12C\n" + | ||
| @@ -911,55 +1001,58 @@ func file_ermite_repo_proto_rawDescGZIP() []byte { | |||||
| 911 | return file_ermite_repo_proto_rawDescData | 1001 | return file_ermite_repo_proto_rawDescData | ||
| 912 | } | 1002 | } | ||
| 913 | 1003 | ||||
| 914 | - | var file_ermite_repo_proto_enumTypes = make([]protoimpl.EnumInfo, 1) | 1004 | + | var file_ermite_repo_proto_enumTypes = make([]protoimpl.EnumInfo, 2) |
| 915 | var file_ermite_repo_proto_msgTypes = make([]protoimpl.MessageInfo, 12) | 1005 | var file_ermite_repo_proto_msgTypes = make([]protoimpl.MessageInfo, 12) | ||
| 916 | var file_ermite_repo_proto_goTypes = []any{ | 1006 | var file_ermite_repo_proto_goTypes = []any{ | ||
| 917 | (Visibility)(0), // 0: ermite.Visibility | 1007 | (Visibility)(0), // 0: ermite.Visibility | ||
| 918 | - | (*RepoSettings)(nil), // 1: ermite.RepoSettings | 1008 | + | (IssuesMode)(0), // 1: ermite.IssuesMode |
| 919 | - | (*Repo)(nil), // 2: ermite.Repo | 1009 | + | (*RepoSettings)(nil), // 2: ermite.RepoSettings |
| 920 | - | (*ListReposRequest)(nil), // 3: ermite.ListReposRequest | 1010 | + | (*Repo)(nil), // 3: ermite.Repo |
| 921 | - | (*ListReposResponse)(nil), // 4: ermite.ListReposResponse | 1011 | + | (*ListReposRequest)(nil), // 4: ermite.ListReposRequest |
| 922 | - | (*GetRepoRequest)(nil), // 5: ermite.GetRepoRequest | 1012 | + | (*ListReposResponse)(nil), // 5: ermite.ListReposResponse |
| 923 | - | (*GetRepoResponse)(nil), // 6: ermite.GetRepoResponse | 1013 | + | (*GetRepoRequest)(nil), // 6: ermite.GetRepoRequest |
| 924 | - | (*CreateRepoRequest)(nil), // 7: ermite.CreateRepoRequest | 1014 | + | (*GetRepoResponse)(nil), // 7: ermite.GetRepoResponse |
| 925 | - | (*CreateRepoResponse)(nil), // 8: ermite.CreateRepoResponse | 1015 | + | (*CreateRepoRequest)(nil), // 8: ermite.CreateRepoRequest |
| 926 | - | (*UpdateRepoRequest)(nil), // 9: ermite.UpdateRepoRequest | 1016 | + | (*CreateRepoResponse)(nil), // 9: ermite.CreateRepoResponse |
| 927 | - | (*UpdateRepoResponse)(nil), // 10: ermite.UpdateRepoResponse | 1017 | + | (*UpdateRepoRequest)(nil), // 10: ermite.UpdateRepoRequest |
| 928 | - | (*DeleteRepoRequest)(nil), // 11: ermite.DeleteRepoRequest | 1018 | + | (*UpdateRepoResponse)(nil), // 11: ermite.UpdateRepoResponse |
| 929 | - | (*DeleteRepoResponse)(nil), // 12: ermite.DeleteRepoResponse | 1019 | + | (*DeleteRepoRequest)(nil), // 12: ermite.DeleteRepoRequest |
| 930 | - | (MergeMode)(0), // 13: ermite.MergeMode | 1020 | + | (*DeleteRepoResponse)(nil), // 13: ermite.DeleteRepoResponse |
| 931 | - | (*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp | 1021 | + | (MergeMode)(0), // 14: ermite.MergeMode |
| 932 | - | (*fieldmaskpb.FieldMask)(nil), // 15: google.protobuf.FieldMask | 1022 | + | (*timestamppb.Timestamp)(nil), // 15: google.protobuf.Timestamp |
| 1023 | + | (*fieldmaskpb.FieldMask)(nil), // 16: google.protobuf.FieldMask | |||
| 933 | } | 1024 | } | ||
| 934 | var file_ermite_repo_proto_depIdxs = []int32{ | 1025 | var file_ermite_repo_proto_depIdxs = []int32{ | ||
| 935 | - | 13, // 0: ermite.RepoSettings.allowed_merge_modes:type_name -> ermite.MergeMode | 1026 | + | 14, // 0: ermite.RepoSettings.allowed_merge_modes:type_name -> ermite.MergeMode |
| 936 | - | 0, // 1: ermite.Repo.visibility:type_name -> ermite.Visibility | 1027 | + | 1, // 1: ermite.RepoSettings.issues:type_name -> ermite.IssuesMode |
| 937 | - | 14, // 2: ermite.Repo.created_at:type_name -> google.protobuf.Timestamp | 1028 | + | 0, // 2: ermite.Repo.visibility:type_name -> ermite.Visibility |
| 938 | - | 14, // 3: ermite.Repo.pushed_at:type_name -> google.protobuf.Timestamp | 1029 | + | 15, // 3: ermite.Repo.created_at:type_name -> google.protobuf.Timestamp |
| 939 | - | 1, // 4: ermite.Repo.settings:type_name -> ermite.RepoSettings | 1030 | + | 15, // 4: ermite.Repo.pushed_at:type_name -> google.protobuf.Timestamp |
| 940 | - | 2, // 5: ermite.ListReposResponse.repos:type_name -> ermite.Repo | 1031 | + | 2, // 5: ermite.Repo.settings:type_name -> ermite.RepoSettings |
| 941 | - | 2, // 6: ermite.GetRepoResponse.repo:type_name -> ermite.Repo | 1032 | + | 3, // 6: ermite.ListReposResponse.repos:type_name -> ermite.Repo |
| 942 | - | 0, // 7: ermite.CreateRepoRequest.visibility:type_name -> ermite.Visibility | 1033 | + | 3, // 7: ermite.GetRepoResponse.repo:type_name -> ermite.Repo |
| 943 | - | 2, // 8: ermite.CreateRepoResponse.repo:type_name -> ermite.Repo | 1034 | + | 0, // 8: ermite.CreateRepoRequest.visibility:type_name -> ermite.Visibility |
| 944 | - | 0, // 9: ermite.UpdateRepoRequest.visibility:type_name -> ermite.Visibility | 1035 | + | 3, // 9: ermite.CreateRepoResponse.repo:type_name -> ermite.Repo |
| 945 | - | 15, // 10: ermite.UpdateRepoRequest.update_mask:type_name -> google.protobuf.FieldMask | 1036 | + | 0, // 10: ermite.UpdateRepoRequest.visibility:type_name -> ermite.Visibility |
| 946 | - | 1, // 11: ermite.UpdateRepoRequest.settings:type_name -> ermite.RepoSettings | 1037 | + | 16, // 11: ermite.UpdateRepoRequest.update_mask:type_name -> google.protobuf.FieldMask |
| 947 | - | 2, // 12: ermite.UpdateRepoResponse.repo:type_name -> ermite.Repo | 1038 | + | 2, // 12: ermite.UpdateRepoRequest.settings:type_name -> ermite.RepoSettings |
| 948 | - | 3, // 13: ermite.RepoService.ListRepos:input_type -> ermite.ListReposRequest | 1039 | + | 1, // 13: ermite.UpdateRepoRequest.issues:type_name -> ermite.IssuesMode |
| 949 | - | 5, // 14: ermite.RepoService.GetRepo:input_type -> ermite.GetRepoRequest | 1040 | + | 3, // 14: ermite.UpdateRepoResponse.repo:type_name -> ermite.Repo |
| 950 | - | 7, // 15: ermite.RepoService.CreateRepo:input_type -> ermite.CreateRepoRequest | 1041 | + | 4, // 15: ermite.RepoService.ListRepos:input_type -> ermite.ListReposRequest |
| 951 | - | 9, // 16: ermite.RepoService.UpdateRepo:input_type -> ermite.UpdateRepoRequest | 1042 | + | 6, // 16: ermite.RepoService.GetRepo:input_type -> ermite.GetRepoRequest |
| 952 | - | 11, // 17: ermite.RepoService.DeleteRepo:input_type -> ermite.DeleteRepoRequest | 1043 | + | 8, // 17: ermite.RepoService.CreateRepo:input_type -> ermite.CreateRepoRequest |
| 953 | - | 4, // 18: ermite.RepoService.ListRepos:output_type -> ermite.ListReposResponse | 1044 | + | 10, // 18: ermite.RepoService.UpdateRepo:input_type -> ermite.UpdateRepoRequest |
| 954 | - | 6, // 19: ermite.RepoService.GetRepo:output_type -> ermite.GetRepoResponse | 1045 | + | 12, // 19: ermite.RepoService.DeleteRepo:input_type -> ermite.DeleteRepoRequest |
| 955 | - | 8, // 20: ermite.RepoService.CreateRepo:output_type -> ermite.CreateRepoResponse | 1046 | + | 5, // 20: ermite.RepoService.ListRepos:output_type -> ermite.ListReposResponse |
| 956 | - | 10, // 21: ermite.RepoService.UpdateRepo:output_type -> ermite.UpdateRepoResponse | 1047 | + | 7, // 21: ermite.RepoService.GetRepo:output_type -> ermite.GetRepoResponse |
| 957 | - | 12, // 22: ermite.RepoService.DeleteRepo:output_type -> ermite.DeleteRepoResponse | 1048 | + | 9, // 22: ermite.RepoService.CreateRepo:output_type -> ermite.CreateRepoResponse |
| 958 | - | 18, // [18:23] is the sub-list for method output_type | 1049 | + | 11, // 23: ermite.RepoService.UpdateRepo:output_type -> ermite.UpdateRepoResponse |
| 959 | - | 13, // [13:18] is the sub-list for method input_type | 1050 | + | 13, // 24: ermite.RepoService.DeleteRepo:output_type -> ermite.DeleteRepoResponse |
| 960 | - | 13, // [13:13] is the sub-list for extension type_name | 1051 | + | 20, // [20:25] is the sub-list for method output_type |
| 961 | - | 13, // [13:13] is the sub-list for extension extendee | 1052 | + | 15, // [15:20] is the sub-list for method input_type |
| 962 | - | 0, // [0:13] is the sub-list for field type_name | 1053 | + | 15, // [15:15] is the sub-list for extension type_name |
| 1054 | + | 15, // [15:15] is the sub-list for extension extendee | |||
| 1055 | + | 0, // [0:15] is the sub-list for field type_name | |||
| 963 | } | 1056 | } | ||
| 964 | 1057 | ||||
| 965 | func init() { file_ermite_repo_proto_init() } | 1058 | func init() { file_ermite_repo_proto_init() } | ||
| @@ -968,12 +1061,13 @@ func file_ermite_repo_proto_init() { | |||||
| 968 | return | 1061 | return | ||
| 969 | } | 1062 | } | ||
| 970 | file_ermite_types_proto_init() | 1063 | file_ermite_types_proto_init() | ||
| 1064 | + | file_ermite_repo_proto_msgTypes[8].OneofWrappers = []any{} | |||
| 971 | type x struct{} | 1065 | type x struct{} | ||
| 972 | out := protoimpl.TypeBuilder{ | 1066 | out := protoimpl.TypeBuilder{ | ||
| 973 | File: protoimpl.DescBuilder{ | 1067 | File: protoimpl.DescBuilder{ | ||
| 974 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), | 1068 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), | ||
| 975 | RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_repo_proto_rawDesc), len(file_ermite_repo_proto_rawDesc)), | 1069 | RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_repo_proto_rawDesc), len(file_ermite_repo_proto_rawDesc)), | ||
| 976 | - | NumEnums: 1, | 1070 | + | NumEnums: 2, |
| 977 | NumMessages: 12, | 1071 | NumMessages: 12, | ||
| 978 | NumExtensions: 0, | 1072 | NumExtensions: 0, | ||
| 979 | NumServices: 1, | 1073 | NumServices: 1, | ||
M gen/ermite/token.pb.go +8 -2 generated file: collapsed
A issue_test.go +98 -0
| @@ -0,0 +1,98 @@ | |||
| 1 | + | // SPDX-License-Identifier: MIT | |
| 2 | + | ||
| 3 | + | package api_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "testing" | |
| 7 | + | ||
| 8 | + | "bnema.dev/ermite-api/gen/ermite" | |
| 9 | + | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | |
| 10 | + | "google.golang.org/protobuf/proto" | |
| 11 | + | "google.golang.org/protobuf/reflect/protoreflect" | |
| 12 | + | ) | |
| 13 | + | ||
| 14 | + | func TestIssueProcedures(t *testing.T) { | |
| 15 | + | tests := map[string]string{ | |
| 16 | + | ermiteconnect.IssueServiceCreateIssueProcedure: "CreateIssue", | |
| 17 | + | ermiteconnect.IssueServiceListIssuesProcedure: "ListIssues", | |
| 18 | + | ermiteconnect.IssueServiceGetIssueProcedure: "GetIssue", | |
| 19 | + | ermiteconnect.IssueServiceAddIssueCommentProcedure: "AddIssueComment", | |
| 20 | + | ermiteconnect.IssueServiceCloseIssueProcedure: "CloseIssue", | |
| 21 | + | ermiteconnect.IssueServiceReopenIssueProcedure: "ReopenIssue", | |
| 22 | + | ermiteconnect.IssueServiceListPendingIssuesProcedure: "ListPendingIssues", | |
| 23 | + | ermiteconnect.IssueServiceApproveIssueProcedure: "ApproveIssue", | |
| 24 | + | ermiteconnect.IssueServiceRejectIssueProcedure: "RejectIssue", | |
| 25 | + | } | |
| 26 | + | for got, name := range tests { | |
| 27 | + | if want := "/ermite.IssueService/" + name; got != want { | |
| 28 | + | t.Errorf("procedure = %q, want %q", got, want) | |
| 29 | + | } | |
| 30 | + | } | |
| 31 | + | } | |
| 32 | + | ||
| 33 | + | func TestIssueContract(t *testing.T) { | |
| 34 | + | for _, tt := range []struct { | |
| 35 | + | msg proto.Message | |
| 36 | + | fields map[string]int | |
| 37 | + | }{ | |
| 38 | + | {&ermite.Issue{}, map[string]int{"repo": 1, "number": 2, "title": 3, "body": 4, "state": 5, "author": 6, "created_at": 7, "updated_at": 8, "comment_count": 9}}, | |
| 39 | + | {&ermite.IssueComment{}, map[string]int{"id": 1, "author": 2, "text": 3, "created_at": 4}}, | |
| 40 | + | {&ermite.RepoSettings{}, map[string]int{"issues": 3}}, | |
| 41 | + | {&ermite.UpdateRepoRequest{}, map[string]int{"issues": 8}}, | |
| 42 | + | {&ermite.Event{}, map[string]int{"issue_opened": 17, "issue_closed": 18, "issue_reopened": 19, "issue_commented": 20, "issue_submitted": 21}}, | |
| 43 | + | {&ermite.IssueSubmitted{}, map[string]int{"repo": 1, "id": 2}}, | |
| 44 | + | {&ermite.PendingIssue{}, map[string]int{"id": 1, "repo": 2, "title": 3, "body": 4, "author": 5, "created_at": 6}}, | |
| 45 | + | {&ermite.ListPendingIssuesRequest{}, map[string]int{"repo": 1, "page_size": 2, "page_token": 3}}, | |
| 46 | + | {&ermite.ListPendingIssuesResponse{}, map[string]int{"issues": 1, "next_page_token": 2}}, | |
| 47 | + | {&ermite.ApproveIssueRequest{}, map[string]int{"repo": 1, "id": 2}}, | |
| 48 | + | {&ermite.ApproveIssueResponse{}, map[string]int{"issue": 1}}, | |
| 49 | + | {&ermite.RejectIssueRequest{}, map[string]int{"repo": 1, "id": 2, "ban": 3}}, | |
| 50 | + | } { | |
| 51 | + | md := tt.msg.ProtoReflect().Descriptor() | |
| 52 | + | for name, num := range tt.fields { | |
| 53 | + | if fd := md.Fields().ByName(protoreflect.Name(name)); fd == nil || int(fd.Number()) != num { | |
| 54 | + | t.Errorf("%s.%s = %v, want %d", md.Name(), name, fd, num) | |
| 55 | + | } | |
| 56 | + | } | |
| 57 | + | } | |
| 58 | + | if ermite.Scope_SCOPE_ISSUE_WRITE != 11 { | |
| 59 | + | t.Fatal("issue:write scope number changed") | |
| 60 | + | } | |
| 61 | + | for name, want := range map[string]int32{"ISSUE_STATE_UNSPECIFIED": 0, "ISSUE_STATE_OPEN": 1, "ISSUE_STATE_CLOSED": 2, "ISSUE_STATE_PENDING": 3} { | |
| 62 | + | if got := ermite.IssueState_value[name]; got != want { | |
| 63 | + | t.Errorf("%s = %d, want %d", name, got, want) | |
| 64 | + | } | |
| 65 | + | } | |
| 66 | + | for name, want := range map[string]int32{"ISSUES_MODE_UNSPECIFIED": 0, "ISSUES_MODE_OFF": 1, "ISSUES_MODE_OWNER": 2, "ISSUES_MODE_PUBLIC": 3} { | |
| 67 | + | if got := ermite.IssuesMode_value[name]; got != want { | |
| 68 | + | t.Errorf("%s = %d, want %d", name, got, want) | |
| 69 | + | } | |
| 70 | + | } | |
| 71 | + | mode := ermite.IssuesMode_ISSUES_MODE_OFF | |
| 72 | + | for _, in := range []proto.Message{ | |
| 73 | + | &ermite.UpdateRepoRequest{Repo: "r", Issues: &mode}, | |
| 74 | + | &ermite.Event{Kind: &ermite.Event_IssueOpened{IssueOpened: &ermite.IssueOpened{Issue: &ermite.Issue{Repo: "r", Number: 1}}}}, | |
| 75 | + | &ermite.Event{Kind: &ermite.Event_IssueClosed{IssueClosed: &ermite.IssueClosed{Issue: &ermite.Issue{Repo: "r", Number: 1}}}}, | |
| 76 | + | &ermite.Event{Kind: &ermite.Event_IssueReopened{IssueReopened: &ermite.IssueReopened{Issue: &ermite.Issue{Repo: "r", Number: 1}}}}, | |
| 77 | + | &ermite.Event{Kind: &ermite.Event_IssueSubmitted{IssueSubmitted: &ermite.IssueSubmitted{Repo: "r", Id: "p1"}}}, | |
| 78 | + | &ermite.PendingIssue{Id: "p1", Repo: "r", Title: "t", Author: "anon"}, | |
| 79 | + | &ermite.RejectIssueRequest{Repo: "r", Id: "p1", Ban: true}, | |
| 80 | + | &ermite.Event{Kind: &ermite.Event_IssueCommented{IssueCommented: &ermite.IssueCommented{Repo: "r", Number: 1, Comment: &ermite.IssueComment{Id: "c", Text: "hi"}}}}, | |
| 81 | + | } { | |
| 82 | + | b, err := proto.Marshal(in) | |
| 83 | + | if err != nil { | |
| 84 | + | t.Fatal(err) | |
| 85 | + | } | |
| 86 | + | out := in.ProtoReflect().New().Interface() | |
| 87 | + | if err := proto.Unmarshal(b, out); err != nil { | |
| 88 | + | t.Fatal(err) | |
| 89 | + | } | |
| 90 | + | if !proto.Equal(in, out) { | |
| 91 | + | t.Errorf("%T: round trip mismatch", in) | |
| 92 | + | } | |
| 93 | + | } | |
| 94 | + | fd := (&ermite.UpdateRepoRequest{}).ProtoReflect().Descriptor().Fields().ByName("issues") | |
| 95 | + | if !fd.HasOptionalKeyword() { | |
| 96 | + | t.Fatal("UpdateRepoRequest.issues must be optional") | |
| 97 | + | } | |
| 98 | + | } | |
| @@ -0,0 +1,98 @@ | |||||
| 1 | + | // SPDX-License-Identifier: MIT | |||
| 2 | + | ||||
| 3 | + | package api_test | |||
| 4 | + | ||||
| 5 | + | import ( | |||
| 6 | + | "testing" | |||
| 7 | + | ||||
| 8 | + | "bnema.dev/ermite-api/gen/ermite" | |||
| 9 | + | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | |||
| 10 | + | "google.golang.org/protobuf/proto" | |||
| 11 | + | "google.golang.org/protobuf/reflect/protoreflect" | |||
| 12 | + | ) | |||
| 13 | + | ||||
| 14 | + | func TestIssueProcedures(t *testing.T) { | |||
| 15 | + | tests := map[string]string{ | |||
| 16 | + | ermiteconnect.IssueServiceCreateIssueProcedure: "CreateIssue", | |||
| 17 | + | ermiteconnect.IssueServiceListIssuesProcedure: "ListIssues", | |||
| 18 | + | ermiteconnect.IssueServiceGetIssueProcedure: "GetIssue", | |||
| 19 | + | ermiteconnect.IssueServiceAddIssueCommentProcedure: "AddIssueComment", | |||
| 20 | + | ermiteconnect.IssueServiceCloseIssueProcedure: "CloseIssue", | |||
| 21 | + | ermiteconnect.IssueServiceReopenIssueProcedure: "ReopenIssue", | |||
| 22 | + | ermiteconnect.IssueServiceListPendingIssuesProcedure: "ListPendingIssues", | |||
| 23 | + | ermiteconnect.IssueServiceApproveIssueProcedure: "ApproveIssue", | |||
| 24 | + | ermiteconnect.IssueServiceRejectIssueProcedure: "RejectIssue", | |||
| 25 | + | } | |||
| 26 | + | for got, name := range tests { | |||
| 27 | + | if want := "/ermite.IssueService/" + name; got != want { | |||
| 28 | + | t.Errorf("procedure = %q, want %q", got, want) | |||
| 29 | + | } | |||
| 30 | + | } | |||
| 31 | + | } | |||
| 32 | + | ||||
| 33 | + | func TestIssueContract(t *testing.T) { | |||
| 34 | + | for _, tt := range []struct { | |||
| 35 | + | msg proto.Message | |||
| 36 | + | fields map[string]int | |||
| 37 | + | }{ | |||
| 38 | + | {&ermite.Issue{}, map[string]int{"repo": 1, "number": 2, "title": 3, "body": 4, "state": 5, "author": 6, "created_at": 7, "updated_at": 8, "comment_count": 9}}, | |||
| 39 | + | {&ermite.IssueComment{}, map[string]int{"id": 1, "author": 2, "text": 3, "created_at": 4}}, | |||
| 40 | + | {&ermite.RepoSettings{}, map[string]int{"issues": 3}}, | |||
| 41 | + | {&ermite.UpdateRepoRequest{}, map[string]int{"issues": 8}}, | |||
| 42 | + | {&ermite.Event{}, map[string]int{"issue_opened": 17, "issue_closed": 18, "issue_reopened": 19, "issue_commented": 20, "issue_submitted": 21}}, | |||
| 43 | + | {&ermite.IssueSubmitted{}, map[string]int{"repo": 1, "id": 2}}, | |||
| 44 | + | {&ermite.PendingIssue{}, map[string]int{"id": 1, "repo": 2, "title": 3, "body": 4, "author": 5, "created_at": 6}}, | |||
| 45 | + | {&ermite.ListPendingIssuesRequest{}, map[string]int{"repo": 1, "page_size": 2, "page_token": 3}}, | |||
| 46 | + | {&ermite.ListPendingIssuesResponse{}, map[string]int{"issues": 1, "next_page_token": 2}}, | |||
| 47 | + | {&ermite.ApproveIssueRequest{}, map[string]int{"repo": 1, "id": 2}}, | |||
| 48 | + | {&ermite.ApproveIssueResponse{}, map[string]int{"issue": 1}}, | |||
| 49 | + | {&ermite.RejectIssueRequest{}, map[string]int{"repo": 1, "id": 2, "ban": 3}}, | |||
| 50 | + | } { | |||
| 51 | + | md := tt.msg.ProtoReflect().Descriptor() | |||
| 52 | + | for name, num := range tt.fields { | |||
| 53 | + | if fd := md.Fields().ByName(protoreflect.Name(name)); fd == nil || int(fd.Number()) != num { | |||
| 54 | + | t.Errorf("%s.%s = %v, want %d", md.Name(), name, fd, num) | |||
| 55 | + | } | |||
| 56 | + | } | |||
| 57 | + | } | |||
| 58 | + | if ermite.Scope_SCOPE_ISSUE_WRITE != 11 { | |||
| 59 | + | t.Fatal("issue:write scope number changed") | |||
| 60 | + | } | |||
| 61 | + | for name, want := range map[string]int32{"ISSUE_STATE_UNSPECIFIED": 0, "ISSUE_STATE_OPEN": 1, "ISSUE_STATE_CLOSED": 2, "ISSUE_STATE_PENDING": 3} { | |||
| 62 | + | if got := ermite.IssueState_value[name]; got != want { | |||
| 63 | + | t.Errorf("%s = %d, want %d", name, got, want) | |||
| 64 | + | } | |||
| 65 | + | } | |||
| 66 | + | for name, want := range map[string]int32{"ISSUES_MODE_UNSPECIFIED": 0, "ISSUES_MODE_OFF": 1, "ISSUES_MODE_OWNER": 2, "ISSUES_MODE_PUBLIC": 3} { | |||
| 67 | + | if got := ermite.IssuesMode_value[name]; got != want { | |||
| 68 | + | t.Errorf("%s = %d, want %d", name, got, want) | |||
| 69 | + | } | |||
| 70 | + | } | |||
| 71 | + | mode := ermite.IssuesMode_ISSUES_MODE_OFF | |||
| 72 | + | for _, in := range []proto.Message{ | |||
| 73 | + | &ermite.UpdateRepoRequest{Repo: "r", Issues: &mode}, | |||
| 74 | + | &ermite.Event{Kind: &ermite.Event_IssueOpened{IssueOpened: &ermite.IssueOpened{Issue: &ermite.Issue{Repo: "r", Number: 1}}}}, | |||
| 75 | + | &ermite.Event{Kind: &ermite.Event_IssueClosed{IssueClosed: &ermite.IssueClosed{Issue: &ermite.Issue{Repo: "r", Number: 1}}}}, | |||
| 76 | + | &ermite.Event{Kind: &ermite.Event_IssueReopened{IssueReopened: &ermite.IssueReopened{Issue: &ermite.Issue{Repo: "r", Number: 1}}}}, | |||
| 77 | + | &ermite.Event{Kind: &ermite.Event_IssueSubmitted{IssueSubmitted: &ermite.IssueSubmitted{Repo: "r", Id: "p1"}}}, | |||
| 78 | + | &ermite.PendingIssue{Id: "p1", Repo: "r", Title: "t", Author: "anon"}, | |||
| 79 | + | &ermite.RejectIssueRequest{Repo: "r", Id: "p1", Ban: true}, | |||
| 80 | + | &ermite.Event{Kind: &ermite.Event_IssueCommented{IssueCommented: &ermite.IssueCommented{Repo: "r", Number: 1, Comment: &ermite.IssueComment{Id: "c", Text: "hi"}}}}, | |||
| 81 | + | } { | |||
| 82 | + | b, err := proto.Marshal(in) | |||
| 83 | + | if err != nil { | |||
| 84 | + | t.Fatal(err) | |||
| 85 | + | } | |||
| 86 | + | out := in.ProtoReflect().New().Interface() | |||
| 87 | + | if err := proto.Unmarshal(b, out); err != nil { | |||
| 88 | + | t.Fatal(err) | |||
| 89 | + | } | |||
| 90 | + | if !proto.Equal(in, out) { | |||
| 91 | + | t.Errorf("%T: round trip mismatch", in) | |||
| 92 | + | } | |||
| 93 | + | } | |||
| 94 | + | fd := (&ermite.UpdateRepoRequest{}).ProtoReflect().Descriptor().Fields().ByName("issues") | |||
| 95 | + | if !fd.HasOptionalKeyword() { | |||
| 96 | + | t.Fatal("UpdateRepoRequest.issues must be optional") | |||
| 97 | + | } | |||
| 98 | + | } | |||
M proto/ermite/event.proto +69 -7
| @@ -4,6 +4,7 @@ syntax = "proto3"; | |||
| 4 | 4 | ||
| 5 | 5 | package ermite; | |
| 6 | 6 | ||
| 7 | + | import "ermite/issue.proto"; | |
| 7 | 8 | import "ermite/merge_request.proto"; | |
| 8 | 9 | import "ermite/repo.proto"; | |
| 9 | 10 | import "ermite/run.proto"; | |
| @@ -18,9 +19,12 @@ service EventService { | |||
| 18 | 19 | // The events are repo_created, repo_updated, repo_deleted, pushed, gap and, | |
| 19 | 20 | // for merge requests, merge_request_opened, merge_request_merged, | |
| 20 | 21 | // merge_request_closed, comment_added, comment_edited, comment_deleted and | |
| 21 | - | // comment_resolved (a thread resolved or reopened). Each one is delivered on the | |
| 22 | - | // "repo:<name>" topic of its repository and on "home", subject to the | |
| 23 | - | // visibility of the repository. | |
| 22 | + | // comment_resolved (a thread resolved or reopened); for issues, issue_opened, | |
| 23 | + | // issue_closed, issue_reopened and issue_commented, and issue_submitted. Each | |
| 24 | + | // one is delivered on the "repo:<name>" topic of its repository and on | |
| 25 | + | // "home", subject to the visibility of the repository, except | |
| 26 | + | // issue_submitted: it is delivered only on the "owner" topic, never on | |
| 27 | + | // "home" or "repo:<name>", and carries no content (see IssueSubmitted). | |
| 24 | 28 | // | |
| 25 | 29 | // Servers with the feature "ci.runs" also publish run_updated and | |
| 26 | 30 | // job_updated, only on the "repo:<name>" topic of their repository (never on | |
| @@ -55,9 +59,17 @@ service EventService { | |||
| 55 | 59 | // WatchRequest selects the events to receive. | |
| 56 | 60 | message WatchRequest { | |
| 57 | 61 | // Topics are the subjects to follow: "home" for every repository visible to | |
| 58 | - | // the caller, or "repo:<name>" for one repository. Empty means "home". | |
| 59 | - | // Unknown topics are invalid_argument. A "repo:<name>" topic for a repository | |
| 60 | - | // that does not exist or is not visible is not_found. | |
| 62 | + | // the caller, "repo:<name>" for one repository, or "owner". Empty means | |
| 63 | + | // "home". Unknown topics are invalid_argument. A "repo:<name>" topic for a | |
| 64 | + | // repository that does not exist or is not visible is not_found. | |
| 65 | + | // | |
| 66 | + | // The "owner" topic needs owner rights: root, an owner session, or a token | |
| 67 | + | // that holds every scope with no repository or branch limit. Anyone else | |
| 68 | + | // gets the same invalid_argument as for an unknown topic, so the topic is | |
| 69 | + | // not revealed. It carries the merge request and issue events of every | |
| 70 | + | // repository (merge_request_opened, merge_request_merged, | |
| 71 | + | // merge_request_closed, comment_added, and the issue events), repo_updated | |
| 72 | + | // and repo_deleted, plus issue_submitted, which is delivered nowhere else. | |
| 61 | 73 | repeated string topics = 1; | |
| 62 | 74 | // ResumeAfter is the Event.id of the last event the client has seen. Empty | |
| 63 | 75 | // to receive only new events. | |
| @@ -109,6 +121,17 @@ message Event { | |||
| 109 | 121 | CommentDeleted comment_deleted = 15; | |
| 110 | 122 | // CommentResolved: a merge request comment was resolved or unresolved. | |
| 111 | 123 | CommentResolved comment_resolved = 16; | |
| 124 | + | // IssueOpened: an issue was opened. | |
| 125 | + | IssueOpened issue_opened = 17; | |
| 126 | + | // IssueClosed: an issue was closed. | |
| 127 | + | IssueClosed issue_closed = 18; | |
| 128 | + | // IssueReopened: an issue was reopened. | |
| 129 | + | IssueReopened issue_reopened = 19; | |
| 130 | + | // IssueCommented: a comment was added to an issue. | |
| 131 | + | IssueCommented issue_commented = 20; | |
| 132 | + | // IssueSubmitted: an issue is awaiting moderation. Delivered only on the | |
| 133 | + | // "owner" topic, never on "home" or "repo:<name>", and carries no content. | |
| 134 | + | IssueSubmitted issue_submitted = 21; | |
| 112 | 135 | } | |
| 113 | 136 | } | |
| 114 | 137 | ||
| @@ -209,10 +232,49 @@ message CommentResolved { | |||
| 209 | 232 | Comment comment = 3; | |
| 210 | 233 | } | |
| 211 | 234 | ||
| 235 | + | // IssueOpened reports a new issue. | |
| 236 | + | message IssueOpened { | |
| 237 | + | // Issue is the new issue, including its repository and number. | |
| 238 | + | Issue issue = 1; | |
| 239 | + | } | |
| 240 | + | ||
| 241 | + | // IssueClosed reports a closed issue. | |
| 242 | + | message IssueClosed { | |
| 243 | + | // Issue is the issue after closing, including its repository and number. | |
| 244 | + | Issue issue = 1; | |
| 245 | + | } | |
| 246 | + | ||
| 247 | + | // IssueReopened reports a reopened issue. | |
| 248 | + | message IssueReopened { | |
| 249 | + | // Issue is the issue after reopening, including its repository and number. | |
| 250 | + | Issue issue = 1; | |
| 251 | + | } | |
| 252 | + | ||
| 253 | + | // IssueCommented reports a new comment on an issue. | |
| 254 | + | message IssueCommented { | |
| 255 | + | // Repo is the name of the repository. | |
| 256 | + | string repo = 1; | |
| 257 | + | // Number is the number of the issue. | |
| 258 | + | int64 number = 2; | |
| 259 | + | // Comment is the new comment. | |
| 260 | + | IssueComment comment = 3; | |
| 261 | + | } | |
| 262 | + | ||
| 263 | + | // IssueSubmitted reports an issue awaiting moderation. It is delivered only | |
| 264 | + | // on the "owner" topic, never on "home" or "repo:<name>". It carries no title or body: content never travels in | |
| 265 | + | // events, read it with IssueService.ListPendingIssues. | |
| 266 | + | message IssueSubmitted { | |
| 267 | + | // Repo is the name of the repository. | |
| 268 | + | string repo = 1; | |
| 269 | + | // Id is the PendingIssue.id. | |
| 270 | + | string id = 2; | |
| 271 | + | } | |
| 272 | + | ||
| 212 | 273 | // Gap tells the client that events were lost: the requested resume point is | |
| 213 | 274 | // older than the server's buffer. It has no fields. The client should reload | |
| 214 | 275 | // the state it displays (repositories, refs, merge requests and their | |
| 215 | - | // comments, CI runs and their jobs) and carry on with the next events. | |
| 276 | + | // comments, issues and their comments, CI runs and their jobs) and carry on | |
| 277 | + | // with the next events. | |
| 216 | 278 | message Gap {} | |
| 217 | 279 | ||
| 218 | 280 | // RunUpdated reports a CI run that was created or whose status, conclusion or | |
| @@ -4,6 +4,7 @@ syntax = "proto3"; | |||||
| 4 | 4 | ||||
| 5 | package ermite; | 5 | package ermite; | ||
| 6 | 6 | ||||
| 7 | + | import "ermite/issue.proto"; | |||
| 7 | import "ermite/merge_request.proto"; | 8 | import "ermite/merge_request.proto"; | ||
| 8 | import "ermite/repo.proto"; | 9 | import "ermite/repo.proto"; | ||
| 9 | import "ermite/run.proto"; | 10 | import "ermite/run.proto"; | ||
| @@ -18,9 +19,12 @@ service EventService { | |||||
| 18 | // The events are repo_created, repo_updated, repo_deleted, pushed, gap and, | 19 | // The events are repo_created, repo_updated, repo_deleted, pushed, gap and, | ||
| 19 | // for merge requests, merge_request_opened, merge_request_merged, | 20 | // for merge requests, merge_request_opened, merge_request_merged, | ||
| 20 | // merge_request_closed, comment_added, comment_edited, comment_deleted and | 21 | // merge_request_closed, comment_added, comment_edited, comment_deleted and | ||
| 21 | - | // comment_resolved (a thread resolved or reopened). Each one is delivered on the | 22 | + | // comment_resolved (a thread resolved or reopened); for issues, issue_opened, |
| 22 | - | // "repo:<name>" topic of its repository and on "home", subject to the | 23 | + | // issue_closed, issue_reopened and issue_commented, and issue_submitted. Each |
| 23 | - | // visibility of the repository. | 24 | + | // one is delivered on the "repo:<name>" topic of its repository and on |
| 25 | + | // "home", subject to the visibility of the repository, except | |||
| 26 | + | // issue_submitted: it is delivered only on the "owner" topic, never on | |||
| 27 | + | // "home" or "repo:<name>", and carries no content (see IssueSubmitted). | |||
| 24 | // | 28 | // | ||
| 25 | // Servers with the feature "ci.runs" also publish run_updated and | 29 | // Servers with the feature "ci.runs" also publish run_updated and | ||
| 26 | // job_updated, only on the "repo:<name>" topic of their repository (never on | 30 | // job_updated, only on the "repo:<name>" topic of their repository (never on | ||
| @@ -55,9 +59,17 @@ service EventService { | |||||
| 55 | // WatchRequest selects the events to receive. | 59 | // WatchRequest selects the events to receive. | ||
| 56 | message WatchRequest { | 60 | message WatchRequest { | ||
| 57 | // Topics are the subjects to follow: "home" for every repository visible to | 61 | // Topics are the subjects to follow: "home" for every repository visible to | ||
| 58 | - | // the caller, or "repo:<name>" for one repository. Empty means "home". | 62 | + | // the caller, "repo:<name>" for one repository, or "owner". Empty means |
| 59 | - | // Unknown topics are invalid_argument. A "repo:<name>" topic for a repository | 63 | + | // "home". Unknown topics are invalid_argument. A "repo:<name>" topic for a |
| 60 | - | // that does not exist or is not visible is not_found. | 64 | + | // repository that does not exist or is not visible is not_found. |
| 65 | + | // | |||
| 66 | + | // The "owner" topic needs owner rights: root, an owner session, or a token | |||
| 67 | + | // that holds every scope with no repository or branch limit. Anyone else | |||
| 68 | + | // gets the same invalid_argument as for an unknown topic, so the topic is | |||
| 69 | + | // not revealed. It carries the merge request and issue events of every | |||
| 70 | + | // repository (merge_request_opened, merge_request_merged, | |||
| 71 | + | // merge_request_closed, comment_added, and the issue events), repo_updated | |||
| 72 | + | // and repo_deleted, plus issue_submitted, which is delivered nowhere else. | |||
| 61 | repeated string topics = 1; | 73 | repeated string topics = 1; | ||
| 62 | // ResumeAfter is the Event.id of the last event the client has seen. Empty | 74 | // ResumeAfter is the Event.id of the last event the client has seen. Empty | ||
| 63 | // to receive only new events. | 75 | // to receive only new events. | ||
| @@ -109,6 +121,17 @@ message Event { | |||||
| 109 | CommentDeleted comment_deleted = 15; | 121 | CommentDeleted comment_deleted = 15; | ||
| 110 | // CommentResolved: a merge request comment was resolved or unresolved. | 122 | // CommentResolved: a merge request comment was resolved or unresolved. | ||
| 111 | CommentResolved comment_resolved = 16; | 123 | CommentResolved comment_resolved = 16; | ||
| 124 | + | // IssueOpened: an issue was opened. | |||
| 125 | + | IssueOpened issue_opened = 17; | |||
| 126 | + | // IssueClosed: an issue was closed. | |||
| 127 | + | IssueClosed issue_closed = 18; | |||
| 128 | + | // IssueReopened: an issue was reopened. | |||
| 129 | + | IssueReopened issue_reopened = 19; | |||
| 130 | + | // IssueCommented: a comment was added to an issue. | |||
| 131 | + | IssueCommented issue_commented = 20; | |||
| 132 | + | // IssueSubmitted: an issue is awaiting moderation. Delivered only on the | |||
| 133 | + | // "owner" topic, never on "home" or "repo:<name>", and carries no content. | |||
| 134 | + | IssueSubmitted issue_submitted = 21; | |||
| 112 | } | 135 | } | ||
| 113 | } | 136 | } | ||
| 114 | 137 | ||||
| @@ -209,10 +232,49 @@ message CommentResolved { | |||||
| 209 | Comment comment = 3; | 232 | Comment comment = 3; | ||
| 210 | } | 233 | } | ||
| 211 | 234 | ||||
| 235 | + | // IssueOpened reports a new issue. | |||
| 236 | + | message IssueOpened { | |||
| 237 | + | // Issue is the new issue, including its repository and number. | |||
| 238 | + | Issue issue = 1; | |||
| 239 | + | } | |||
| 240 | + | ||||
| 241 | + | // IssueClosed reports a closed issue. | |||
| 242 | + | message IssueClosed { | |||
| 243 | + | // Issue is the issue after closing, including its repository and number. | |||
| 244 | + | Issue issue = 1; | |||
| 245 | + | } | |||
| 246 | + | ||||
| 247 | + | // IssueReopened reports a reopened issue. | |||
| 248 | + | message IssueReopened { | |||
| 249 | + | // Issue is the issue after reopening, including its repository and number. | |||
| 250 | + | Issue issue = 1; | |||
| 251 | + | } | |||
| 252 | + | ||||
| 253 | + | // IssueCommented reports a new comment on an issue. | |||
| 254 | + | message IssueCommented { | |||
| 255 | + | // Repo is the name of the repository. | |||
| 256 | + | string repo = 1; | |||
| 257 | + | // Number is the number of the issue. | |||
| 258 | + | int64 number = 2; | |||
| 259 | + | // Comment is the new comment. | |||
| 260 | + | IssueComment comment = 3; | |||
| 261 | + | } | |||
| 262 | + | ||||
| 263 | + | // IssueSubmitted reports an issue awaiting moderation. It is delivered only | |||
| 264 | + | // on the "owner" topic, never on "home" or "repo:<name>". It carries no title or body: content never travels in | |||
| 265 | + | // events, read it with IssueService.ListPendingIssues. | |||
| 266 | + | message IssueSubmitted { | |||
| 267 | + | // Repo is the name of the repository. | |||
| 268 | + | string repo = 1; | |||
| 269 | + | // Id is the PendingIssue.id. | |||
| 270 | + | string id = 2; | |||
| 271 | + | } | |||
| 272 | + | ||||
| 212 | // Gap tells the client that events were lost: the requested resume point is | 273 | // Gap tells the client that events were lost: the requested resume point is | ||
| 213 | // older than the server's buffer. It has no fields. The client should reload | 274 | // older than the server's buffer. It has no fields. The client should reload | ||
| 214 | // the state it displays (repositories, refs, merge requests and their | 275 | // the state it displays (repositories, refs, merge requests and their | ||
| 215 | - | // comments, CI runs and their jobs) and carry on with the next events. | 276 | + | // comments, issues and their comments, CI runs and their jobs) and carry on |
| 277 | + | // with the next events. | |||
| 216 | message Gap {} | 278 | message Gap {} | ||
| 217 | 279 | ||||
| 218 | // RunUpdated reports a CI run that was created or whose status, conclusion or | 280 | // RunUpdated reports a CI run that was created or whose status, conclusion or | ||
A proto/ermite/issue.proto +281 -0
| @@ -0,0 +1,281 @@ | |||
| 1 | + | // SPDX-License-Identifier: MIT | |
| 2 | + | ||
| 3 | + | syntax = "proto3"; | |
| 4 | + | ||
| 5 | + | package ermite; | |
| 6 | + | ||
| 7 | + | import "google/protobuf/timestamp.proto"; | |
| 8 | + | ||
| 9 | + | // IssueState is where an issue is in its life. | |
| 10 | + | enum IssueState { | |
| 11 | + | // Not set. In ListIssuesRequest.state it means every state. Never returned | |
| 12 | + | // by the server. | |
| 13 | + | ISSUE_STATE_UNSPECIFIED = 0; | |
| 14 | + | // The issue is open. | |
| 15 | + | ISSUE_STATE_OPEN = 1; | |
| 16 | + | // The issue is closed. | |
| 17 | + | ISSUE_STATE_CLOSED = 2; | |
| 18 | + | // Reserved for later use: awaiting moderation, owner-only. | |
| 19 | + | ISSUE_STATE_PENDING = 3; | |
| 20 | + | } | |
| 21 | + | ||
| 22 | + | // Issue is a discussion in a repository. | |
| 23 | + | message Issue { | |
| 24 | + | // Repo is the name of the repository. | |
| 25 | + | string repo = 1; | |
| 26 | + | // Number identifies the issue within its repository. | |
| 27 | + | int64 number = 2; | |
| 28 | + | // Title is the one-line title. | |
| 29 | + | string title = 3; | |
| 30 | + | // Body is the content of the issue. It may be empty. | |
| 31 | + | string body = 4; | |
| 32 | + | // State is where the issue is in its life. | |
| 33 | + | IssueState state = 5; | |
| 34 | + | // Author names who created the issue: the label of the token or session | |
| 35 | + | // that was used ("root" for the root token, "owner" for a web session), or, | |
| 36 | + | // for an issue approved from the public form, the unverified display name | |
| 37 | + | // the visitor typed (or "anonymous"). It is informational and never proves | |
| 38 | + | // identity: labels are not unique, the token may be gone, and a visitor can | |
| 39 | + | // type "owner". | |
| 40 | + | string author = 6; | |
| 41 | + | // CreatedAt is when the issue was created. | |
| 42 | + | google.protobuf.Timestamp created_at = 7; | |
| 43 | + | // UpdatedAt is when the issue last changed. | |
| 44 | + | google.protobuf.Timestamp updated_at = 8; | |
| 45 | + | // CommentCount is the number of comments on the issue. | |
| 46 | + | int32 comment_count = 9; | |
| 47 | + | } | |
| 48 | + | ||
| 49 | + | // IssueComment is a note on an issue. | |
| 50 | + | message IssueComment { | |
| 51 | + | // Id identifies the comment within its issue. Opaque. | |
| 52 | + | string id = 1; | |
| 53 | + | // Author names who wrote the comment, like Issue.author. | |
| 54 | + | string author = 2; | |
| 55 | + | // Text is the content of the comment. | |
| 56 | + | string text = 3; | |
| 57 | + | // CreatedAt is when the comment was written. | |
| 58 | + | google.protobuf.Timestamp created_at = 4; | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // IssueService manages issues and their comments. | |
| 62 | + | // | |
| 63 | + | // Servers that implement this service list "issues" in | |
| 64 | + | // GetVersionResponse.features. Issues and merge requests of a repository share | |
| 65 | + | // one number sequence. When the issues mode of the repository is off, every | |
| 66 | + | // call answers not_found, as for a repository that does not exist. | |
| 67 | + | // | |
| 68 | + | // Reading (ListIssues, GetIssue) needs the same access as reading the | |
| 69 | + | // repository: nothing for a public one, the repo:read scope for a private one. | |
| 70 | + | // Writing (CreateIssue, AddIssueComment, CloseIssue, ReopenIssue) needs the | |
| 71 | + | // owner or a token with the issue:write scope on the repository; branch | |
| 72 | + | // prefixes do not restrict it. A caller without credentials gets | |
| 73 | + | // unauthenticated, one with an insufficient scope gets permission_denied, and | |
| 74 | + | // one that cannot read the repository gets not_found. | |
| 75 | + | // | |
| 76 | + | // Text fields are normalized to NFC and stripped of control and Unicode | |
| 77 | + | // bidirectional characters (line breaks and tabs stay in bodies and comments). | |
| 78 | + | // The title is one line of 1 to 120 code points; body and comment text are at | |
| 79 | + | // most 10,000 code points and a comment must not be blank. A text that breaks | |
| 80 | + | // a rule is rejected with invalid_argument. A comment on an issue that already | |
| 81 | + | // holds 1,000 comments gives resource_exhausted. Closing an issue that is not | |
| 82 | + | // open, or reopening one that is not closed, gives failed_precondition. | |
| 83 | + | // | |
| 84 | + | // The ordinary RPCs only return issues in state OPEN or CLOSED, and | |
| 85 | + | // ListIssues with state ISSUE_STATE_PENDING is invalid_argument. Submissions | |
| 86 | + | // from the public form wait as PendingIssue records, reachable only through | |
| 87 | + | // the three moderation RPCs (ListPendingIssues, ApproveIssue, RejectIssue). | |
| 88 | + | // These need owner rights (root, an owner session, or a token holding every | |
| 89 | + | // scope with no repository or branch limit); anyone else gets not_found, | |
| 90 | + | // whatever the request holds. For the owner, a malformed pending issue id is | |
| 91 | + | // not_found and a malformed repository name is invalid_argument. | |
| 92 | + | service IssueService { | |
| 93 | + | // CreateIssue opens an issue. Needs the issue:write scope. | |
| 94 | + | rpc CreateIssue(CreateIssueRequest) returns (CreateIssueResponse); | |
| 95 | + | // ListIssues lists issues, highest number first, optionally in one state. | |
| 96 | + | rpc ListIssues(ListIssuesRequest) returns (ListIssuesResponse); | |
| 97 | + | // GetIssue returns an issue with its comments. | |
| 98 | + | rpc GetIssue(GetIssueRequest) returns (GetIssueResponse); | |
| 99 | + | // AddIssueComment adds a comment. Needs the issue:write scope. | |
| 100 | + | rpc AddIssueComment(AddIssueCommentRequest) returns (AddIssueCommentResponse); | |
| 101 | + | // CloseIssue closes an issue. Needs the issue:write scope. | |
| 102 | + | rpc CloseIssue(CloseIssueRequest) returns (CloseIssueResponse); | |
| 103 | + | // ReopenIssue reopens an issue. Needs the issue:write scope. | |
| 104 | + | rpc ReopenIssue(ReopenIssueRequest) returns (ReopenIssueResponse); | |
| 105 | + | // ListPendingIssues lists issues awaiting moderation, oldest first. Owner | |
| 106 | + | // rights only; anyone else gets NOT_FOUND. | |
| 107 | + | rpc ListPendingIssues(ListPendingIssuesRequest) returns (ListPendingIssuesResponse); | |
| 108 | + | // ApproveIssue turns a pending issue into an open issue with a new number. | |
| 109 | + | // Owner rights only; anyone else gets NOT_FOUND. | |
| 110 | + | rpc ApproveIssue(ApproveIssueRequest) returns (ApproveIssueResponse); | |
| 111 | + | // RejectIssue discards a pending issue, optionally banning its submitter. | |
| 112 | + | // Owner rights only; anyone else gets NOT_FOUND. | |
| 113 | + | rpc RejectIssue(RejectIssueRequest) returns (RejectIssueResponse); | |
| 114 | + | } | |
| 115 | + | ||
| 116 | + | // CreateIssueRequest describes the issue to open. | |
| 117 | + | message CreateIssueRequest { | |
| 118 | + | // Repo is the repository name. | |
| 119 | + | string repo = 1; | |
| 120 | + | // Title is the one-line title. Required. | |
| 121 | + | string title = 2; | |
| 122 | + | // Body is the optional content. | |
| 123 | + | string body = 3; | |
| 124 | + | } | |
| 125 | + | ||
| 126 | + | // CreateIssueResponse holds the new issue. | |
| 127 | + | message CreateIssueResponse { | |
| 128 | + | // Issue is the created issue. | |
| 129 | + | Issue issue = 1; | |
| 130 | + | } | |
| 131 | + | ||
| 132 | + | // ListIssuesRequest selects a page of issues. | |
| 133 | + | message ListIssuesRequest { | |
| 134 | + | // Repo is the repository name. | |
| 135 | + | string repo = 1; | |
| 136 | + | // State restricts the result to one state. ISSUE_STATE_UNSPECIFIED means | |
| 137 | + | // every state. | |
| 138 | + | IssueState state = 2; | |
| 139 | + | // PageSize is the maximum number of issues to return. 0 means the server | |
| 140 | + | // default; values above the server maximum are lowered to it. | |
| 141 | + | int32 page_size = 3; | |
| 142 | + | // PageToken is the next_page_token of a previous response, to continue the | |
| 143 | + | // same listing. Empty for the first page. Other fields must be unchanged. | |
| 144 | + | string page_token = 4; | |
| 145 | + | } | |
| 146 | + | ||
| 147 | + | // ListIssuesResponse is one page of issues. | |
| 148 | + | message ListIssuesResponse { | |
| 149 | + | // Issues are the issues of this page, highest number first. | |
| 150 | + | repeated Issue issues = 1; | |
| 151 | + | // NextPageToken is passed as page_token to get the next page. Empty when | |
| 152 | + | // there is no next page. | |
| 153 | + | string next_page_token = 2; | |
| 154 | + | } | |
| 155 | + | ||
| 156 | + | // GetIssueRequest selects an issue. | |
| 157 | + | message GetIssueRequest { | |
| 158 | + | // Repo is the repository name. | |
| 159 | + | string repo = 1; | |
| 160 | + | // Number is the issue number. | |
| 161 | + | int64 number = 2; | |
| 162 | + | } | |
| 163 | + | ||
| 164 | + | // GetIssueResponse holds an issue with its comments. | |
| 165 | + | message GetIssueResponse { | |
| 166 | + | // Issue is the issue. | |
| 167 | + | Issue issue = 1; | |
| 168 | + | // Comments are every comment of the issue, oldest first. | |
| 169 | + | repeated IssueComment comments = 2; | |
| 170 | + | } | |
| 171 | + | ||
| 172 | + | // AddIssueCommentRequest describes the comment to add. | |
| 173 | + | message AddIssueCommentRequest { | |
| 174 | + | // Repo is the repository name. | |
| 175 | + | string repo = 1; | |
| 176 | + | // Number is the issue number. | |
| 177 | + | int64 number = 2; | |
| 178 | + | // Text is the content. Required. | |
| 179 | + | string text = 3; | |
| 180 | + | } | |
| 181 | + | ||
| 182 | + | // AddIssueCommentResponse holds the new comment. | |
| 183 | + | message AddIssueCommentResponse { | |
| 184 | + | // Comment is the created comment. | |
| 185 | + | IssueComment comment = 1; | |
| 186 | + | } | |
| 187 | + | ||
| 188 | + | // CloseIssueRequest names the issue to close. | |
| 189 | + | message CloseIssueRequest { | |
| 190 | + | // Repo is the repository name. | |
| 191 | + | string repo = 1; | |
| 192 | + | // Number is the issue number. | |
| 193 | + | int64 number = 2; | |
| 194 | + | } | |
| 195 | + | ||
| 196 | + | // CloseIssueResponse holds the issue after closing. | |
| 197 | + | message CloseIssueResponse { | |
| 198 | + | // Issue is the closed issue. | |
| 199 | + | Issue issue = 1; | |
| 200 | + | } | |
| 201 | + | ||
| 202 | + | // ReopenIssueRequest names the issue to reopen. | |
| 203 | + | message ReopenIssueRequest { | |
| 204 | + | // Repo is the repository name. | |
| 205 | + | string repo = 1; | |
| 206 | + | // Number is the issue number. | |
| 207 | + | int64 number = 2; | |
| 208 | + | } | |
| 209 | + | ||
| 210 | + | // ReopenIssueResponse holds the issue after reopening. | |
| 211 | + | message ReopenIssueResponse { | |
| 212 | + | // Issue is the reopened issue. | |
| 213 | + | Issue issue = 1; | |
| 214 | + | } | |
| 215 | + | ||
| 216 | + | // PendingIssue is an issue awaiting moderation. It has no number yet. | |
| 217 | + | message PendingIssue { | |
| 218 | + | // Id identifies the pending issue. Opaque internal id, not a number. | |
| 219 | + | string id = 1; | |
| 220 | + | // Repo is the name of the repository. | |
| 221 | + | string repo = 2; | |
| 222 | + | // Title is the one-line title. | |
| 223 | + | string title = 3; | |
| 224 | + | // Body is the content. It may be empty. | |
| 225 | + | string body = 4; | |
| 226 | + | // Author is the optional display name given by the anonymous submitter. It | |
| 227 | + | // may be empty or "anonymous", and is not verified: it never proves | |
| 228 | + | // identity (a visitor can type "owner"). It becomes Issue.author on approval. | |
| 229 | + | string author = 5; | |
| 230 | + | // CreatedAt is when the issue was submitted. | |
| 231 | + | google.protobuf.Timestamp created_at = 6; | |
| 232 | + | } | |
| 233 | + | ||
| 234 | + | // ListPendingIssuesRequest selects a page of pending issues. | |
| 235 | + | message ListPendingIssuesRequest { | |
| 236 | + | // Repo is the repository name. Empty means every repository. | |
| 237 | + | string repo = 1; | |
| 238 | + | // PageSize is the maximum number of issues to return. 0 means the server | |
| 239 | + | // default; values above the server maximum are lowered to it. | |
| 240 | + | int32 page_size = 2; | |
| 241 | + | // PageToken is the next_page_token of a previous response, to continue the | |
| 242 | + | // same listing. Empty for the first page. Other fields must be unchanged. | |
| 243 | + | string page_token = 3; | |
| 244 | + | } | |
| 245 | + | ||
| 246 | + | // ListPendingIssuesResponse is one page of pending issues. | |
| 247 | + | message ListPendingIssuesResponse { | |
| 248 | + | // Issues are the pending issues of this page, oldest first. | |
| 249 | + | repeated PendingIssue issues = 1; | |
| 250 | + | // NextPageToken is passed as page_token to get the next page. Empty when | |
| 251 | + | // there is no next page. | |
| 252 | + | string next_page_token = 2; | |
| 253 | + | } | |
| 254 | + | ||
| 255 | + | // ApproveIssueRequest names the pending issue to approve. | |
| 256 | + | message ApproveIssueRequest { | |
| 257 | + | // Repo is the repository name. | |
| 258 | + | string repo = 1; | |
| 259 | + | // Id is the PendingIssue.id. | |
| 260 | + | string id = 2; | |
| 261 | + | } | |
| 262 | + | ||
| 263 | + | // ApproveIssueResponse holds the approved issue. | |
| 264 | + | message ApproveIssueResponse { | |
| 265 | + | // Issue is the approved issue, with its new number and state | |
| 266 | + | // ISSUE_STATE_OPEN. | |
| 267 | + | Issue issue = 1; | |
| 268 | + | } | |
| 269 | + | ||
| 270 | + | // RejectIssueRequest names the pending issue to reject. | |
| 271 | + | message RejectIssueRequest { | |
| 272 | + | // Repo is the repository name. | |
| 273 | + | string repo = 1; | |
| 274 | + | // Id is the PendingIssue.id. | |
| 275 | + | string id = 2; | |
| 276 | + | // Ban also bans the submitter for a while. | |
| 277 | + | bool ban = 3; | |
| 278 | + | } | |
| 279 | + | ||
| 280 | + | // RejectIssueResponse is empty: the pending issue is gone. | |
| 281 | + | message RejectIssueResponse {} | |
| @@ -0,0 +1,281 @@ | |||||
| 1 | + | // SPDX-License-Identifier: MIT | |||
| 2 | + | ||||
| 3 | + | syntax = "proto3"; | |||
| 4 | + | ||||
| 5 | + | package ermite; | |||
| 6 | + | ||||
| 7 | + | import "google/protobuf/timestamp.proto"; | |||
| 8 | + | ||||
| 9 | + | // IssueState is where an issue is in its life. | |||
| 10 | + | enum IssueState { | |||
| 11 | + | // Not set. In ListIssuesRequest.state it means every state. Never returned | |||
| 12 | + | // by the server. | |||
| 13 | + | ISSUE_STATE_UNSPECIFIED = 0; | |||
| 14 | + | // The issue is open. | |||
| 15 | + | ISSUE_STATE_OPEN = 1; | |||
| 16 | + | // The issue is closed. | |||
| 17 | + | ISSUE_STATE_CLOSED = 2; | |||
| 18 | + | // Reserved for later use: awaiting moderation, owner-only. | |||
| 19 | + | ISSUE_STATE_PENDING = 3; | |||
| 20 | + | } | |||
| 21 | + | ||||
| 22 | + | // Issue is a discussion in a repository. | |||
| 23 | + | message Issue { | |||
| 24 | + | // Repo is the name of the repository. | |||
| 25 | + | string repo = 1; | |||
| 26 | + | // Number identifies the issue within its repository. | |||
| 27 | + | int64 number = 2; | |||
| 28 | + | // Title is the one-line title. | |||
| 29 | + | string title = 3; | |||
| 30 | + | // Body is the content of the issue. It may be empty. | |||
| 31 | + | string body = 4; | |||
| 32 | + | // State is where the issue is in its life. | |||
| 33 | + | IssueState state = 5; | |||
| 34 | + | // Author names who created the issue: the label of the token or session | |||
| 35 | + | // that was used ("root" for the root token, "owner" for a web session), or, | |||
| 36 | + | // for an issue approved from the public form, the unverified display name | |||
| 37 | + | // the visitor typed (or "anonymous"). It is informational and never proves | |||
| 38 | + | // identity: labels are not unique, the token may be gone, and a visitor can | |||
| 39 | + | // type "owner". | |||
| 40 | + | string author = 6; | |||
| 41 | + | // CreatedAt is when the issue was created. | |||
| 42 | + | google.protobuf.Timestamp created_at = 7; | |||
| 43 | + | // UpdatedAt is when the issue last changed. | |||
| 44 | + | google.protobuf.Timestamp updated_at = 8; | |||
| 45 | + | // CommentCount is the number of comments on the issue. | |||
| 46 | + | int32 comment_count = 9; | |||
| 47 | + | } | |||
| 48 | + | ||||
| 49 | + | // IssueComment is a note on an issue. | |||
| 50 | + | message IssueComment { | |||
| 51 | + | // Id identifies the comment within its issue. Opaque. | |||
| 52 | + | string id = 1; | |||
| 53 | + | // Author names who wrote the comment, like Issue.author. | |||
| 54 | + | string author = 2; | |||
| 55 | + | // Text is the content of the comment. | |||
| 56 | + | string text = 3; | |||
| 57 | + | // CreatedAt is when the comment was written. | |||
| 58 | + | google.protobuf.Timestamp created_at = 4; | |||
| 59 | + | } | |||
| 60 | + | ||||
| 61 | + | // IssueService manages issues and their comments. | |||
| 62 | + | // | |||
| 63 | + | // Servers that implement this service list "issues" in | |||
| 64 | + | // GetVersionResponse.features. Issues and merge requests of a repository share | |||
| 65 | + | // one number sequence. When the issues mode of the repository is off, every | |||
| 66 | + | // call answers not_found, as for a repository that does not exist. | |||
| 67 | + | // | |||
| 68 | + | // Reading (ListIssues, GetIssue) needs the same access as reading the | |||
| 69 | + | // repository: nothing for a public one, the repo:read scope for a private one. | |||
| 70 | + | // Writing (CreateIssue, AddIssueComment, CloseIssue, ReopenIssue) needs the | |||
| 71 | + | // owner or a token with the issue:write scope on the repository; branch | |||
| 72 | + | // prefixes do not restrict it. A caller without credentials gets | |||
| 73 | + | // unauthenticated, one with an insufficient scope gets permission_denied, and | |||
| 74 | + | // one that cannot read the repository gets not_found. | |||
| 75 | + | // | |||
| 76 | + | // Text fields are normalized to NFC and stripped of control and Unicode | |||
| 77 | + | // bidirectional characters (line breaks and tabs stay in bodies and comments). | |||
| 78 | + | // The title is one line of 1 to 120 code points; body and comment text are at | |||
| 79 | + | // most 10,000 code points and a comment must not be blank. A text that breaks | |||
| 80 | + | // a rule is rejected with invalid_argument. A comment on an issue that already | |||
| 81 | + | // holds 1,000 comments gives resource_exhausted. Closing an issue that is not | |||
| 82 | + | // open, or reopening one that is not closed, gives failed_precondition. | |||
| 83 | + | // | |||
| 84 | + | // The ordinary RPCs only return issues in state OPEN or CLOSED, and | |||
| 85 | + | // ListIssues with state ISSUE_STATE_PENDING is invalid_argument. Submissions | |||
| 86 | + | // from the public form wait as PendingIssue records, reachable only through | |||
| 87 | + | // the three moderation RPCs (ListPendingIssues, ApproveIssue, RejectIssue). | |||
| 88 | + | // These need owner rights (root, an owner session, or a token holding every | |||
| 89 | + | // scope with no repository or branch limit); anyone else gets not_found, | |||
| 90 | + | // whatever the request holds. For the owner, a malformed pending issue id is | |||
| 91 | + | // not_found and a malformed repository name is invalid_argument. | |||
| 92 | + | service IssueService { | |||
| 93 | + | // CreateIssue opens an issue. Needs the issue:write scope. | |||
| 94 | + | rpc CreateIssue(CreateIssueRequest) returns (CreateIssueResponse); | |||
| 95 | + | // ListIssues lists issues, highest number first, optionally in one state. | |||
| 96 | + | rpc ListIssues(ListIssuesRequest) returns (ListIssuesResponse); | |||
| 97 | + | // GetIssue returns an issue with its comments. | |||
| 98 | + | rpc GetIssue(GetIssueRequest) returns (GetIssueResponse); | |||
| 99 | + | // AddIssueComment adds a comment. Needs the issue:write scope. | |||
| 100 | + | rpc AddIssueComment(AddIssueCommentRequest) returns (AddIssueCommentResponse); | |||
| 101 | + | // CloseIssue closes an issue. Needs the issue:write scope. | |||
| 102 | + | rpc CloseIssue(CloseIssueRequest) returns (CloseIssueResponse); | |||
| 103 | + | // ReopenIssue reopens an issue. Needs the issue:write scope. | |||
| 104 | + | rpc ReopenIssue(ReopenIssueRequest) returns (ReopenIssueResponse); | |||
| 105 | + | // ListPendingIssues lists issues awaiting moderation, oldest first. Owner | |||
| 106 | + | // rights only; anyone else gets NOT_FOUND. | |||
| 107 | + | rpc ListPendingIssues(ListPendingIssuesRequest) returns (ListPendingIssuesResponse); | |||
| 108 | + | // ApproveIssue turns a pending issue into an open issue with a new number. | |||
| 109 | + | // Owner rights only; anyone else gets NOT_FOUND. | |||
| 110 | + | rpc ApproveIssue(ApproveIssueRequest) returns (ApproveIssueResponse); | |||
| 111 | + | // RejectIssue discards a pending issue, optionally banning its submitter. | |||
| 112 | + | // Owner rights only; anyone else gets NOT_FOUND. | |||
| 113 | + | rpc RejectIssue(RejectIssueRequest) returns (RejectIssueResponse); | |||
| 114 | + | } | |||
| 115 | + | ||||
| 116 | + | // CreateIssueRequest describes the issue to open. | |||
| 117 | + | message CreateIssueRequest { | |||
| 118 | + | // Repo is the repository name. | |||
| 119 | + | string repo = 1; | |||
| 120 | + | // Title is the one-line title. Required. | |||
| 121 | + | string title = 2; | |||
| 122 | + | // Body is the optional content. | |||
| 123 | + | string body = 3; | |||
| 124 | + | } | |||
| 125 | + | ||||
| 126 | + | // CreateIssueResponse holds the new issue. | |||
| 127 | + | message CreateIssueResponse { | |||
| 128 | + | // Issue is the created issue. | |||
| 129 | + | Issue issue = 1; | |||
| 130 | + | } | |||
| 131 | + | ||||
| 132 | + | // ListIssuesRequest selects a page of issues. | |||
| 133 | + | message ListIssuesRequest { | |||
| 134 | + | // Repo is the repository name. | |||
| 135 | + | string repo = 1; | |||
| 136 | + | // State restricts the result to one state. ISSUE_STATE_UNSPECIFIED means | |||
| 137 | + | // every state. | |||
| 138 | + | IssueState state = 2; | |||
| 139 | + | // PageSize is the maximum number of issues to return. 0 means the server | |||
| 140 | + | // default; values above the server maximum are lowered to it. | |||
| 141 | + | int32 page_size = 3; | |||
| 142 | + | // PageToken is the next_page_token of a previous response, to continue the | |||
| 143 | + | // same listing. Empty for the first page. Other fields must be unchanged. | |||
| 144 | + | string page_token = 4; | |||
| 145 | + | } | |||
| 146 | + | ||||
| 147 | + | // ListIssuesResponse is one page of issues. | |||
| 148 | + | message ListIssuesResponse { | |||
| 149 | + | // Issues are the issues of this page, highest number first. | |||
| 150 | + | repeated Issue issues = 1; | |||
| 151 | + | // NextPageToken is passed as page_token to get the next page. Empty when | |||
| 152 | + | // there is no next page. | |||
| 153 | + | string next_page_token = 2; | |||
| 154 | + | } | |||
| 155 | + | ||||
| 156 | + | // GetIssueRequest selects an issue. | |||
| 157 | + | message GetIssueRequest { | |||
| 158 | + | // Repo is the repository name. | |||
| 159 | + | string repo = 1; | |||
| 160 | + | // Number is the issue number. | |||
| 161 | + | int64 number = 2; | |||
| 162 | + | } | |||
| 163 | + | ||||
| 164 | + | // GetIssueResponse holds an issue with its comments. | |||
| 165 | + | message GetIssueResponse { | |||
| 166 | + | // Issue is the issue. | |||
| 167 | + | Issue issue = 1; | |||
| 168 | + | // Comments are every comment of the issue, oldest first. | |||
| 169 | + | repeated IssueComment comments = 2; | |||
| 170 | + | } | |||
| 171 | + | ||||
| 172 | + | // AddIssueCommentRequest describes the comment to add. | |||
| 173 | + | message AddIssueCommentRequest { | |||
| 174 | + | // Repo is the repository name. | |||
| 175 | + | string repo = 1; | |||
| 176 | + | // Number is the issue number. | |||
| 177 | + | int64 number = 2; | |||
| 178 | + | // Text is the content. Required. | |||
| 179 | + | string text = 3; | |||
| 180 | + | } | |||
| 181 | + | ||||
| 182 | + | // AddIssueCommentResponse holds the new comment. | |||
| 183 | + | message AddIssueCommentResponse { | |||
| 184 | + | // Comment is the created comment. | |||
| 185 | + | IssueComment comment = 1; | |||
| 186 | + | } | |||
| 187 | + | ||||
| 188 | + | // CloseIssueRequest names the issue to close. | |||
| 189 | + | message CloseIssueRequest { | |||
| 190 | + | // Repo is the repository name. | |||
| 191 | + | string repo = 1; | |||
| 192 | + | // Number is the issue number. | |||
| 193 | + | int64 number = 2; | |||
| 194 | + | } | |||
| 195 | + | ||||
| 196 | + | // CloseIssueResponse holds the issue after closing. | |||
| 197 | + | message CloseIssueResponse { | |||
| 198 | + | // Issue is the closed issue. | |||
| 199 | + | Issue issue = 1; | |||
| 200 | + | } | |||
| 201 | + | ||||
| 202 | + | // ReopenIssueRequest names the issue to reopen. | |||
| 203 | + | message ReopenIssueRequest { | |||
| 204 | + | // Repo is the repository name. | |||
| 205 | + | string repo = 1; | |||
| 206 | + | // Number is the issue number. | |||
| 207 | + | int64 number = 2; | |||
| 208 | + | } | |||
| 209 | + | ||||
| 210 | + | // ReopenIssueResponse holds the issue after reopening. | |||
| 211 | + | message ReopenIssueResponse { | |||
| 212 | + | // Issue is the reopened issue. | |||
| 213 | + | Issue issue = 1; | |||
| 214 | + | } | |||
| 215 | + | ||||
| 216 | + | // PendingIssue is an issue awaiting moderation. It has no number yet. | |||
| 217 | + | message PendingIssue { | |||
| 218 | + | // Id identifies the pending issue. Opaque internal id, not a number. | |||
| 219 | + | string id = 1; | |||
| 220 | + | // Repo is the name of the repository. | |||
| 221 | + | string repo = 2; | |||
| 222 | + | // Title is the one-line title. | |||
| 223 | + | string title = 3; | |||
| 224 | + | // Body is the content. It may be empty. | |||
| 225 | + | string body = 4; | |||
| 226 | + | // Author is the optional display name given by the anonymous submitter. It | |||
| 227 | + | // may be empty or "anonymous", and is not verified: it never proves | |||
| 228 | + | // identity (a visitor can type "owner"). It becomes Issue.author on approval. | |||
| 229 | + | string author = 5; | |||
| 230 | + | // CreatedAt is when the issue was submitted. | |||
| 231 | + | google.protobuf.Timestamp created_at = 6; | |||
| 232 | + | } | |||
| 233 | + | ||||
| 234 | + | // ListPendingIssuesRequest selects a page of pending issues. | |||
| 235 | + | message ListPendingIssuesRequest { | |||
| 236 | + | // Repo is the repository name. Empty means every repository. | |||
| 237 | + | string repo = 1; | |||
| 238 | + | // PageSize is the maximum number of issues to return. 0 means the server | |||
| 239 | + | // default; values above the server maximum are lowered to it. | |||
| 240 | + | int32 page_size = 2; | |||
| 241 | + | // PageToken is the next_page_token of a previous response, to continue the | |||
| 242 | + | // same listing. Empty for the first page. Other fields must be unchanged. | |||
| 243 | + | string page_token = 3; | |||
| 244 | + | } | |||
| 245 | + | ||||
| 246 | + | // ListPendingIssuesResponse is one page of pending issues. | |||
| 247 | + | message ListPendingIssuesResponse { | |||
| 248 | + | // Issues are the pending issues of this page, oldest first. | |||
| 249 | + | repeated PendingIssue issues = 1; | |||
| 250 | + | // NextPageToken is passed as page_token to get the next page. Empty when | |||
| 251 | + | // there is no next page. | |||
| 252 | + | string next_page_token = 2; | |||
| 253 | + | } | |||
| 254 | + | ||||
| 255 | + | // ApproveIssueRequest names the pending issue to approve. | |||
| 256 | + | message ApproveIssueRequest { | |||
| 257 | + | // Repo is the repository name. | |||
| 258 | + | string repo = 1; | |||
| 259 | + | // Id is the PendingIssue.id. | |||
| 260 | + | string id = 2; | |||
| 261 | + | } | |||
| 262 | + | ||||
| 263 | + | // ApproveIssueResponse holds the approved issue. | |||
| 264 | + | message ApproveIssueResponse { | |||
| 265 | + | // Issue is the approved issue, with its new number and state | |||
| 266 | + | // ISSUE_STATE_OPEN. | |||
| 267 | + | Issue issue = 1; | |||
| 268 | + | } | |||
| 269 | + | ||||
| 270 | + | // RejectIssueRequest names the pending issue to reject. | |||
| 271 | + | message RejectIssueRequest { | |||
| 272 | + | // Repo is the repository name. | |||
| 273 | + | string repo = 1; | |||
| 274 | + | // Id is the PendingIssue.id. | |||
| 275 | + | string id = 2; | |||
| 276 | + | // Ban also bans the submitter for a while. | |||
| 277 | + | bool ban = 3; | |||
| 278 | + | } | |||
| 279 | + | ||||
| 280 | + | // RejectIssueResponse is empty: the pending issue is gone. | |||
| 281 | + | message RejectIssueResponse {} | |||
M proto/ermite/repo.proto +26 -4
| @@ -20,8 +20,20 @@ enum Visibility { | |||
| 20 | 20 | VISIBILITY_PRIVATE = 2; | |
| 21 | 21 | } | |
| 22 | 22 | ||
| 23 | + | // IssuesMode says who may write issues in a repository. | |
| 24 | + | enum IssuesMode { | |
| 25 | + | // Not set. | |
| 26 | + | ISSUES_MODE_UNSPECIFIED = 0; | |
| 27 | + | // Issues are disabled. | |
| 28 | + | ISSUES_MODE_OFF = 1; | |
| 29 | + | // Only the owner may write issues. | |
| 30 | + | ISSUES_MODE_OWNER = 2; | |
| 31 | + | // Issues are open to public participation. | |
| 32 | + | ISSUES_MODE_PUBLIC = 3; | |
| 33 | + | } | |
| 34 | + | ||
| 23 | 35 | // RepoSettings are the settings of a repository that govern its merge | |
| 24 | - | // requests. | |
| 36 | + | // requests and issues. | |
| 25 | 37 | message RepoSettings { | |
| 26 | 38 | // AllowedMergeModes are the modes with which a merge request of the | |
| 27 | 39 | // repository may be merged. It is never empty in a response and has no | |
| @@ -33,6 +45,8 @@ message RepoSettings { | |||
| 33 | 45 | // explicitly, so a later change of the server default never alters an | |
| 34 | 46 | // existing repository. | |
| 35 | 47 | bool failing_checks_block = 2; | |
| 48 | + | // Issues is the issue participation mode of the repository. | |
| 49 | + | IssuesMode issues = 3; | |
| 36 | 50 | } | |
| 37 | 51 | ||
| 38 | 52 | // Repo is the metadata of a repository. Git-owned state (refs, trees, history) | |
| @@ -53,7 +67,7 @@ message Repo { | |||
| 53 | 67 | google.protobuf.Timestamp created_at = 5; | |
| 54 | 68 | // PushedAt is the time of the last push. It is unset until the first push. | |
| 55 | 69 | google.protobuf.Timestamp pushed_at = 6; | |
| 56 | - | // Settings are the merge settings of the repository. Always set in a | |
| 70 | + | // Settings are the settings of the repository. Always set in a | |
| 57 | 71 | // response, with the defaults for a repository that never changed them. | |
| 58 | 72 | RepoSettings settings = 7; | |
| 59 | 73 | // Topics classify the repository, as on GitHub: at most 20, each 1-50 | |
| @@ -153,8 +167,10 @@ message UpdateRepoRequest { | |||
| 153 | 167 | string default_branch = 4; | |
| 154 | 168 | // UpdateMask lists the fields to change: "description", "visibility", | |
| 155 | 169 | // "default_branch", "topics", "settings.allowed_merge_modes" and/or | |
| 156 | - | // "settings.failing_checks_block". "settings" stands for both settings | |
| 157 | - | // paths. It must not be empty. Other paths are invalid_argument. | |
| 170 | + | // "settings.failing_checks_block". "settings" stands for both merge settings | |
| 171 | + | // paths. It must not be empty unless issues is set. Other paths are | |
| 172 | + | // invalid_argument, including "settings.issues" and "issues": the issues | |
| 173 | + | // field is applied outside the mask. | |
| 158 | 174 | google.protobuf.FieldMask update_mask = 5; | |
| 159 | 175 | // Settings holds the new merge settings. Only the fields named in | |
| 160 | 176 | // update_mask are used. allowed_merge_modes must then not be empty nor | |
| @@ -165,6 +181,12 @@ message UpdateRepoRequest { | |||
| 165 | 181 | // Topics replace the topics of the repository (see Repo.topics). Used only | |
| 166 | 182 | // if update_mask contains "topics"; an empty list then clears them. | |
| 167 | 183 | repeated string topics = 7; | |
| 184 | + | // Issues is the new issue participation mode. When absent it is unchanged. | |
| 185 | + | // It is applied whatever update_mask contains, and may be the only change | |
| 186 | + | // (an empty update_mask is then valid). When present it must not be | |
| 187 | + | // ISSUES_MODE_UNSPECIFIED: that is invalid_argument. Changing it needs the | |
| 188 | + | // repo:admin scope and a token with no branch limit, like any other field. | |
| 189 | + | optional IssuesMode issues = 8; | |
| 168 | 190 | } | |
| 169 | 191 | ||
| 170 | 192 | // UpdateRepoResponse holds the repository after the update. | |
| @@ -20,8 +20,20 @@ enum Visibility { | |||||
| 20 | VISIBILITY_PRIVATE = 2; | 20 | VISIBILITY_PRIVATE = 2; | ||
| 21 | } | 21 | } | ||
| 22 | 22 | ||||
| 23 | + | // IssuesMode says who may write issues in a repository. | |||
| 24 | + | enum IssuesMode { | |||
| 25 | + | // Not set. | |||
| 26 | + | ISSUES_MODE_UNSPECIFIED = 0; | |||
| 27 | + | // Issues are disabled. | |||
| 28 | + | ISSUES_MODE_OFF = 1; | |||
| 29 | + | // Only the owner may write issues. | |||
| 30 | + | ISSUES_MODE_OWNER = 2; | |||
| 31 | + | // Issues are open to public participation. | |||
| 32 | + | ISSUES_MODE_PUBLIC = 3; | |||
| 33 | + | } | |||
| 34 | + | ||||
| 23 | // RepoSettings are the settings of a repository that govern its merge | 35 | // RepoSettings are the settings of a repository that govern its merge | ||
| 24 | - | // requests. | 36 | + | // requests and issues. |
| 25 | message RepoSettings { | 37 | message RepoSettings { | ||
| 26 | // AllowedMergeModes are the modes with which a merge request of the | 38 | // AllowedMergeModes are the modes with which a merge request of the | ||
| 27 | // repository may be merged. It is never empty in a response and has no | 39 | // repository may be merged. It is never empty in a response and has no | ||
| @@ -33,6 +45,8 @@ message RepoSettings { | |||||
| 33 | // explicitly, so a later change of the server default never alters an | 45 | // explicitly, so a later change of the server default never alters an | ||
| 34 | // existing repository. | 46 | // existing repository. | ||
| 35 | bool failing_checks_block = 2; | 47 | bool failing_checks_block = 2; | ||
| 48 | + | // Issues is the issue participation mode of the repository. | |||
| 49 | + | IssuesMode issues = 3; | |||
| 36 | } | 50 | } | ||
| 37 | 51 | ||||
| 38 | // Repo is the metadata of a repository. Git-owned state (refs, trees, history) | 52 | // Repo is the metadata of a repository. Git-owned state (refs, trees, history) | ||
| @@ -53,7 +67,7 @@ message Repo { | |||||
| 53 | google.protobuf.Timestamp created_at = 5; | 67 | google.protobuf.Timestamp created_at = 5; | ||
| 54 | // PushedAt is the time of the last push. It is unset until the first push. | 68 | // PushedAt is the time of the last push. It is unset until the first push. | ||
| 55 | google.protobuf.Timestamp pushed_at = 6; | 69 | google.protobuf.Timestamp pushed_at = 6; | ||
| 56 | - | // Settings are the merge settings of the repository. Always set in a | 70 | + | // Settings are the settings of the repository. Always set in a |
| 57 | // response, with the defaults for a repository that never changed them. | 71 | // response, with the defaults for a repository that never changed them. | ||
| 58 | RepoSettings settings = 7; | 72 | RepoSettings settings = 7; | ||
| 59 | // Topics classify the repository, as on GitHub: at most 20, each 1-50 | 73 | // Topics classify the repository, as on GitHub: at most 20, each 1-50 | ||
| @@ -153,8 +167,10 @@ message UpdateRepoRequest { | |||||
| 153 | string default_branch = 4; | 167 | string default_branch = 4; | ||
| 154 | // UpdateMask lists the fields to change: "description", "visibility", | 168 | // UpdateMask lists the fields to change: "description", "visibility", | ||
| 155 | // "default_branch", "topics", "settings.allowed_merge_modes" and/or | 169 | // "default_branch", "topics", "settings.allowed_merge_modes" and/or | ||
| 156 | - | // "settings.failing_checks_block". "settings" stands for both settings | 170 | + | // "settings.failing_checks_block". "settings" stands for both merge settings |
| 157 | - | // paths. It must not be empty. Other paths are invalid_argument. | 171 | + | // paths. It must not be empty unless issues is set. Other paths are |
| 172 | + | // invalid_argument, including "settings.issues" and "issues": the issues | |||
| 173 | + | // field is applied outside the mask. | |||
| 158 | google.protobuf.FieldMask update_mask = 5; | 174 | google.protobuf.FieldMask update_mask = 5; | ||
| 159 | // Settings holds the new merge settings. Only the fields named in | 175 | // Settings holds the new merge settings. Only the fields named in | ||
| 160 | // update_mask are used. allowed_merge_modes must then not be empty nor | 176 | // update_mask are used. allowed_merge_modes must then not be empty nor | ||
| @@ -165,6 +181,12 @@ message UpdateRepoRequest { | |||||
| 165 | // Topics replace the topics of the repository (see Repo.topics). Used only | 181 | // Topics replace the topics of the repository (see Repo.topics). Used only | ||
| 166 | // if update_mask contains "topics"; an empty list then clears them. | 182 | // if update_mask contains "topics"; an empty list then clears them. | ||
| 167 | repeated string topics = 7; | 183 | repeated string topics = 7; | ||
| 184 | + | // Issues is the new issue participation mode. When absent it is unchanged. | |||
| 185 | + | // It is applied whatever update_mask contains, and may be the only change | |||
| 186 | + | // (an empty update_mask is then valid). When present it must not be | |||
| 187 | + | // ISSUES_MODE_UNSPECIFIED: that is invalid_argument. Changing it needs the | |||
| 188 | + | // repo:admin scope and a token with no branch limit, like any other field. | |||
| 189 | + | optional IssuesMode issues = 8; | |||
| 168 | } | 190 | } | ||
| 169 | 191 | ||||
| 170 | // UpdateRepoResponse holds the repository after the update. | 192 | // UpdateRepoResponse holds the repository after the update. | ||
M proto/ermite/token.proto +3 -0
| @@ -42,6 +42,9 @@ enum Scope { | |||
| 42 | 42 | // SCOPE_MR_REVIEW allows setting a verdict (approve, changes requested) on | |
| 43 | 43 | // merge request notes. Wire name: mr:review. | |
| 44 | 44 | SCOPE_MR_REVIEW = 10; | |
| 45 | + | // SCOPE_ISSUE_WRITE allows creating, commenting on, closing and reopening | |
| 46 | + | // issues. Wire name: issue:write. | |
| 47 | + | SCOPE_ISSUE_WRITE = 11; | |
| 45 | 48 | } | |
| 46 | 49 | ||
| 47 | 50 | // Token describes a stored token. It never contains the secret nor its hash. | |
| @@ -42,6 +42,9 @@ enum Scope { | |||||
| 42 | // SCOPE_MR_REVIEW allows setting a verdict (approve, changes requested) on | 42 | // SCOPE_MR_REVIEW allows setting a verdict (approve, changes requested) on | ||
| 43 | // merge request notes. Wire name: mr:review. | 43 | // merge request notes. Wire name: mr:review. | ||
| 44 | SCOPE_MR_REVIEW = 10; | 44 | SCOPE_MR_REVIEW = 10; | ||
| 45 | + | // SCOPE_ISSUE_WRITE allows creating, commenting on, closing and reopening | |||
| 46 | + | // issues. Wire name: issue:write. | |||
| 47 | + | SCOPE_ISSUE_WRITE = 11; | |||
| 45 | } | 48 | } | ||
| 46 | 49 | ||||
| 47 | // Token describes a stored token. It never contains the secret nor its hash. | 50 | // Token describes a stored token. It never contains the secret nor its hash. | ||