From 812b7e231ddfc5f5d69af2756ea4ad10ffe1bef6 Mon Sep 17 00:00:00 2001 From: NathanFlurry Date: Tue, 13 Aug 2024 07:34:43 +0000 Subject: [PATCH] chore(build): add patching build tags (#1048) ## Changes --- .../build-tags-missing-exclusive-key.md | 10 ++ fern/definition/servers/builds.yml | 25 +++- fern/definition/servers/common.yml | 4 - sdks/full/go/servers/builds.go | 62 +++++++- sdks/full/go/servers/builds/client.go | 78 ++++++++++ sdks/full/go/servers/types.go | 3 - sdks/full/openapi/openapi.yml | 95 ++++++++++-- sdks/full/openapi_compat/openapi.yml | 95 ++++++++++-- sdks/full/rust-cli/.openapi-generator/FILES | 2 + sdks/full/rust-cli/README.md | 2 + sdks/full/rust-cli/docs/ServersBuild.md | 2 - sdks/full/rust-cli/docs/ServersBuildsApi.md | 31 ++++ .../docs/ServersCreateBuildRequest.md | 1 - .../docs/ServersCreateBuildResponse.md | 1 - .../docs/ServersPatchBuildTagsRequest.md | 12 ++ .../rust-cli/src/apis/servers_builds_api.rs | 44 ++++++ sdks/full/rust-cli/src/models/mod.rs | 2 + .../full/rust-cli/src/models/servers_build.rs | 9 +- .../models/servers_create_build_request.rs | 5 +- .../models/servers_create_build_response.rs | 5 +- .../servers_patch_build_tags_request.rs | 32 ++++ sdks/full/rust/.openapi-generator/FILES | 2 + sdks/full/rust/README.md | 2 + sdks/full/rust/docs/ServersBuild.md | 2 - sdks/full/rust/docs/ServersBuildsApi.md | 31 ++++ .../rust/docs/ServersCreateBuildRequest.md | 1 - .../rust/docs/ServersCreateBuildResponse.md | 1 - .../rust/docs/ServersPatchBuildTagsRequest.md | 12 ++ sdks/full/rust/src/apis/servers_builds_api.rs | 44 ++++++ sdks/full/rust/src/models/mod.rs | 2 + sdks/full/rust/src/models/servers_build.rs | 9 +- .../models/servers_create_build_request.rs | 5 +- .../models/servers_create_build_response.rs | 5 +- .../servers_patch_build_tags_request.rs | 32 ++++ sdks/full/typescript/archive.tgz | 4 +- .../servers/resources/builds/client/Client.ts | 141 +++++++++++++++++- sdks/runtime/typescript/archive.tgz | 4 +- svc/Cargo.lock | 61 ++++++++ svc/Cargo.toml | 4 +- svc/api/servers/Cargo.toml | 1 + svc/api/servers/src/route/builds.rs | 122 ++++++++------- svc/api/servers/src/route/mod.rs | 4 + svc/pkg/build/Cargo.toml | 43 ++++++ svc/pkg/build/Service.toml | 12 ++ svc/pkg/build/ops/create/src/lib.rs | 6 +- svc/pkg/build/src/lib.rs | 2 + svc/pkg/build/src/ops/get.rs | 78 ++++++++++ svc/pkg/build/src/ops/mod.rs | 2 + svc/pkg/build/src/ops/patch_tags.rs | 80 ++++++++++ svc/pkg/build/src/types.rs | 28 ++++ svc/pkg/build/tests/patch_tags.rs | 134 +++++++++++++++++ 51 files changed, 1242 insertions(+), 152 deletions(-) create mode 100644 errors/builds/build-tags-missing-exclusive-key.md create mode 100644 sdks/full/rust-cli/docs/ServersPatchBuildTagsRequest.md create mode 100644 sdks/full/rust-cli/src/models/servers_patch_build_tags_request.rs create mode 100644 sdks/full/rust/docs/ServersPatchBuildTagsRequest.md create mode 100644 sdks/full/rust/src/models/servers_patch_build_tags_request.rs create mode 100644 svc/pkg/build/Cargo.toml create mode 100644 svc/pkg/build/Service.toml create mode 100644 svc/pkg/build/src/lib.rs create mode 100644 svc/pkg/build/src/ops/get.rs create mode 100644 svc/pkg/build/src/ops/mod.rs create mode 100644 svc/pkg/build/src/ops/patch_tags.rs create mode 100644 svc/pkg/build/src/types.rs create mode 100644 svc/pkg/build/tests/patch_tags.rs diff --git a/errors/builds/build-tags-missing-exclusive-key.md b/errors/builds/build-tags-missing-exclusive-key.md new file mode 100644 index 0000000000..786d651298 --- /dev/null +++ b/errors/builds/build-tags-missing-exclusive-key.md @@ -0,0 +1,10 @@ +--- +name = "BUILDS_TAGS_MISSING_EXCLUSIVE_KEY" +description = "Provided exclusive key that's not in the tags." +http_status = 400 +--- + +# Tags Missing Exclusive Key + +Provided exclusive key that's not in the tags. + diff --git a/fern/definition/servers/builds.yml b/fern/definition/servers/builds.yml index c32e8ca565..63279c0b54 100644 --- a/fern/definition/servers/builds.yml +++ b/fern/definition/servers/builds.yml @@ -39,6 +39,15 @@ service: game_id: optional response: ListBuildsResponse + patchTags: + path: /{build_id}/tags + method: PATCH + path-parameters: + build_id: uuid + request: + body: PatchBuildTagsRequest + response: PatchBuildTagsResponse + prepareBuild: path: /prepare method: POST @@ -65,10 +74,19 @@ types: docs: A list of builds for the game associated with the token. type: list + PatchBuildTagsRequest: + properties: + tags: unknown + exclusive_tags: + docs: Removes the given tag keys from all other builds. + type: optional> + + PatchBuildTagsResponse: + properties: {} + CreateBuildRequest: properties: name: string - tags: unknown image_tag: docs: A tag given to the game build. type: string @@ -80,10 +98,7 @@ types: CreateBuildResponse: properties: - build: - type: uuid - upload: - type: uuid + build: uuid image_presigned_request: optional image_presigned_requests: optional> diff --git a/fern/definition/servers/common.yml b/fern/definition/servers/common.yml index 49a1d86bb8..9a5128543d 100644 --- a/fern/definition/servers/common.yml +++ b/fern/definition/servers/common.yml @@ -78,15 +78,11 @@ types: Build: properties: id: uuid - upload: uuid name: string created_at: commons.Timestamp content_length: docs: Unsigned 64 bit integer. type: long - completed_at: - docs: Whether or not this build has completely been uploaded. - type: optional tags: docs: Tags of this build type: map diff --git a/sdks/full/go/servers/builds.go b/sdks/full/go/servers/builds.go index 7346d8a630..550581ac73 100644 --- a/sdks/full/go/servers/builds.go +++ b/sdks/full/go/servers/builds.go @@ -21,8 +21,7 @@ type ListBuildsRequest struct { } type CreateBuildRequest struct { - Name string `json:"name"` - Tags interface{} `json:"tags,omitempty"` + Name string `json:"name"` // A tag given to the game build. ImageTag string `json:"image_tag"` ImageFile *upload.PrepareFile `json:"image_file,omitempty"` @@ -58,7 +57,6 @@ func (c *CreateBuildRequest) String() string { type CreateBuildResponse struct { Build uuid.UUID `json:"build"` - Upload uuid.UUID `json:"upload"` ImagePresignedRequest *upload.PresignedRequest `json:"image_presigned_request,omitempty"` ImagePresignedRequests []*upload.PresignedRequest `json:"image_presigned_requests,omitempty"` @@ -146,3 +144,61 @@ func (l *ListBuildsResponse) String() string { } return fmt.Sprintf("%#v", l) } + +type PatchBuildTagsRequest struct { + Tags interface{} `json:"tags,omitempty"` + // Removes the given tag keys from all other builds. + ExclusiveTags []string `json:"exclusive_tags,omitempty"` + + _rawJSON json.RawMessage +} + +func (p *PatchBuildTagsRequest) UnmarshalJSON(data []byte) error { + type unmarshaler PatchBuildTagsRequest + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *p = PatchBuildTagsRequest(value) + p._rawJSON = json.RawMessage(data) + return nil +} + +func (p *PatchBuildTagsRequest) String() string { + if len(p._rawJSON) > 0 { + if value, err := core.StringifyJSON(p._rawJSON); err == nil { + return value + } + } + if value, err := core.StringifyJSON(p); err == nil { + return value + } + return fmt.Sprintf("%#v", p) +} + +type PatchBuildTagsResponse struct { + _rawJSON json.RawMessage +} + +func (p *PatchBuildTagsResponse) UnmarshalJSON(data []byte) error { + type unmarshaler PatchBuildTagsResponse + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *p = PatchBuildTagsResponse(value) + p._rawJSON = json.RawMessage(data) + return nil +} + +func (p *PatchBuildTagsResponse) String() string { + if len(p._rawJSON) > 0 { + if value, err := core.StringifyJSON(p._rawJSON); err == nil { + return value + } + } + if value, err := core.StringifyJSON(p); err == nil { + return value + } + return fmt.Sprintf("%#v", p) +} diff --git a/sdks/full/go/servers/builds/client.go b/sdks/full/go/servers/builds/client.go index 451183d962..bae536b5ad 100644 --- a/sdks/full/go/servers/builds/client.go +++ b/sdks/full/go/servers/builds/client.go @@ -213,6 +213,84 @@ func (c *Client) ListBuilds(ctx context.Context, gameId uuid.UUID, request *serv return response, nil } +func (c *Client) PatchTags(ctx context.Context, gameId uuid.UUID, buildId uuid.UUID, request *servers.PatchBuildTagsRequest) (*servers.PatchBuildTagsResponse, error) { + baseURL := "https://api.rivet.gg" + if c.baseURL != "" { + baseURL = c.baseURL + } + endpointURL := fmt.Sprintf(baseURL+"/"+"games/%v/builds/%v/tags", gameId, buildId) + + errorDecoder := func(statusCode int, body io.Reader) error { + raw, err := io.ReadAll(body) + if err != nil { + return err + } + apiError := core.NewAPIError(statusCode, errors.New(string(raw))) + decoder := json.NewDecoder(bytes.NewReader(raw)) + switch statusCode { + case 500: + value := new(sdk.InternalError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 429: + value := new(sdk.RateLimitError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 403: + value := new(sdk.ForbiddenError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 408: + value := new(sdk.UnauthorizedError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 404: + value := new(sdk.NotFoundError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 400: + value := new(sdk.BadRequestError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + } + return apiError + } + + var response *servers.PatchBuildTagsResponse + if err := c.caller.Call( + ctx, + &core.CallParams{ + URL: endpointURL, + Method: http.MethodPatch, + Headers: c.header, + Request: request, + Response: &response, + ErrorDecoder: errorDecoder, + }, + ); err != nil { + return nil, err + } + return response, nil +} + // Creates a new game build for the given game. func (c *Client) PrepareBuild(ctx context.Context, gameId uuid.UUID, request *servers.CreateBuildRequest) (*servers.CreateBuildResponse, error) { baseURL := "https://api.rivet.gg" diff --git a/sdks/full/go/servers/types.go b/sdks/full/go/servers/types.go index 54ae0ed1af..0ece05ca39 100644 --- a/sdks/full/go/servers/types.go +++ b/sdks/full/go/servers/types.go @@ -70,13 +70,10 @@ func (b BuildKind) Ptr() *BuildKind { type Build struct { Id uuid.UUID `json:"id"` - Upload uuid.UUID `json:"upload"` Name string `json:"name"` CreatedAt sdk.Timestamp `json:"created_at"` // Unsigned 64 bit integer. ContentLength int64 `json:"content_length"` - // Whether or not this build has completely been uploaded. - CompletedAt *sdk.Timestamp `json:"completed_at,omitempty"` // Tags of this build Tags map[string]string `json:"tags,omitempty"` diff --git a/sdks/full/openapi/openapi.yml b/sdks/full/openapi/openapi.yml index f977703e72..a70b922147 100644 --- a/sdks/full/openapi/openapi.yml +++ b/sdks/full/openapi/openapi.yml @@ -9320,6 +9320,74 @@ paths: schema: $ref: '#/components/schemas/ErrorBody' security: *ref_0 + /games/{game_id}/builds/{build_id}/tags: + patch: + operationId: servers_builds_patchTags + tags: + - ServersBuilds + parameters: + - name: game_id + in: path + required: true + schema: + type: string + format: uuid + - name: build_id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ServersPatchBuildTagsResponse' + '400': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '403': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '404': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '408': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '429': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '500': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + security: *ref_0 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ServersPatchBuildTagsRequest' /games/{game_id}/builds/prepare: post: description: Creates a new game build for the given game. @@ -14155,12 +14223,25 @@ components: description: A list of builds for the game associated with the token. required: - builds + ServersPatchBuildTagsRequest: + type: object + properties: + tags: {} + exclusive_tags: + type: array + items: + type: string + description: Removes the given tag keys from all other builds. + required: + - tags + ServersPatchBuildTagsResponse: + type: object + properties: {} ServersCreateBuildRequest: type: object properties: name: type: string - tags: {} image_tag: type: string description: A tag given to the game build. @@ -14174,7 +14255,6 @@ components: $ref: '#/components/schemas/ServersBuildCompression' required: - name - - tags - image_tag - image_file ServersCreateBuildResponse: @@ -14183,9 +14263,6 @@ components: build: type: string format: uuid - upload: - type: string - format: uuid image_presigned_request: $ref: '#/components/schemas/UploadPresignedRequest' image_presigned_requests: @@ -14194,7 +14271,6 @@ components: $ref: '#/components/schemas/UploadPresignedRequest' required: - build - - upload ServersBuildKind: type: string enum: @@ -14339,9 +14415,6 @@ components: id: type: string format: uuid - upload: - type: string - format: uuid name: type: string created_at: @@ -14350,9 +14423,6 @@ components: type: integer format: int64 description: Unsigned 64 bit integer. - completed_at: - $ref: '#/components/schemas/Timestamp' - description: Whether or not this build has completely been uploaded. tags: type: object additionalProperties: @@ -14360,7 +14430,6 @@ components: description: Tags of this build required: - id - - upload - name - created_at - content_length diff --git a/sdks/full/openapi_compat/openapi.yml b/sdks/full/openapi_compat/openapi.yml index 31fd4b87f9..c20f6ea8fc 100644 --- a/sdks/full/openapi_compat/openapi.yml +++ b/sdks/full/openapi_compat/openapi.yml @@ -4404,9 +4404,6 @@ components: type: object ServersBuild: properties: - completed_at: - $ref: '#/components/schemas/Timestamp' - description: Whether or not this build has completely been uploaded. content_length: description: Unsigned 64 bit integer. format: int64 @@ -4423,12 +4420,8 @@ components: type: string description: Tags of this build type: object - upload: - format: uuid - type: string required: - id - - upload - name - created_at - content_length @@ -4459,10 +4452,8 @@ components: type: boolean name: type: string - tags: {} required: - name - - tags - image_tag - image_file type: object @@ -4477,12 +4468,8 @@ components: items: $ref: '#/components/schemas/UploadPresignedRequest' type: array - upload: - format: uuid - type: string required: - build - - upload type: object ServersCreateServerNetworkRequest: properties: @@ -4635,6 +4622,20 @@ components: - bridge - host type: string + ServersPatchBuildTagsRequest: + properties: + exclusive_tags: + description: Removes the given tag keys from all other builds. + items: + type: string + type: array + tags: {} + required: + - tags + type: object + ServersPatchBuildTagsResponse: + properties: {} + type: object ServersPort: properties: internal_port: @@ -9201,6 +9202,74 @@ paths: security: *id001 tags: - ServersBuilds + /games/{game_id}/builds/{build_id}/tags: + patch: + operationId: servers_builds_patchTags + parameters: + - in: path + name: game_id + required: true + schema: + format: uuid + type: string + - in: path + name: build_id + required: true + schema: + format: uuid + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ServersPatchBuildTagsRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ServersPatchBuildTagsResponse' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '408': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '429': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + security: *id001 + tags: + - ServersBuilds /games/{game_id}/servers: get: description: Lists all servers associated with the token used. Can be filtered diff --git a/sdks/full/rust-cli/.openapi-generator/FILES b/sdks/full/rust-cli/.openapi-generator/FILES index bc993ad026..41798ccc66 100644 --- a/sdks/full/rust-cli/.openapi-generator/FILES +++ b/sdks/full/rust-cli/.openapi-generator/FILES @@ -366,6 +366,7 @@ docs/ServersLogStream.md docs/ServersLogsApi.md docs/ServersNetwork.md docs/ServersNetworkMode.md +docs/ServersPatchBuildTagsRequest.md docs/ServersPort.md docs/ServersPortProtocol.md docs/ServersPortRouting.md @@ -743,6 +744,7 @@ src/models/servers_list_servers_response.rs src/models/servers_log_stream.rs src/models/servers_network.rs src/models/servers_network_mode.rs +src/models/servers_patch_build_tags_request.rs src/models/servers_port.rs src/models/servers_port_protocol.rs src/models/servers_port_routing.rs diff --git a/sdks/full/rust-cli/README.md b/sdks/full/rust-cli/README.md index 8f9008098d..6052b89e02 100644 --- a/sdks/full/rust-cli/README.md +++ b/sdks/full/rust-cli/README.md @@ -174,6 +174,7 @@ Class | Method | HTTP request | Description *ServersBuildsApi* | [**servers_builds_complete_build**](docs/ServersBuildsApi.md#servers_builds_complete_build) | **POST** /games/{game_id}/builds/{build_id}/complete | *ServersBuildsApi* | [**servers_builds_get_build**](docs/ServersBuildsApi.md#servers_builds_get_build) | **GET** /games/{game_id}/builds/{build_id} | *ServersBuildsApi* | [**servers_builds_list_builds**](docs/ServersBuildsApi.md#servers_builds_list_builds) | **GET** /games/{game_id}/builds | +*ServersBuildsApi* | [**servers_builds_patch_tags**](docs/ServersBuildsApi.md#servers_builds_patch_tags) | **PATCH** /games/{game_id}/builds/{build_id}/tags | *ServersBuildsApi* | [**servers_builds_prepare_build**](docs/ServersBuildsApi.md#servers_builds_prepare_build) | **POST** /games/{game_id}/builds/prepare | *ServersLogsApi* | [**servers_logs_get_server_logs**](docs/ServersLogsApi.md#servers_logs_get_server_logs) | **GET** /games/{game_id}/servers/{server_id}/logs | @@ -501,6 +502,7 @@ Class | Method | HTTP request | Description - [ServersLogStream](docs/ServersLogStream.md) - [ServersNetwork](docs/ServersNetwork.md) - [ServersNetworkMode](docs/ServersNetworkMode.md) + - [ServersPatchBuildTagsRequest](docs/ServersPatchBuildTagsRequest.md) - [ServersPort](docs/ServersPort.md) - [ServersPortProtocol](docs/ServersPortProtocol.md) - [ServersPortRouting](docs/ServersPortRouting.md) diff --git a/sdks/full/rust-cli/docs/ServersBuild.md b/sdks/full/rust-cli/docs/ServersBuild.md index a1cfb90183..3b59873414 100644 --- a/sdks/full/rust-cli/docs/ServersBuild.md +++ b/sdks/full/rust-cli/docs/ServersBuild.md @@ -4,13 +4,11 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**completed_at** | Option<**String**> | RFC3339 timestamp | [optional] **content_length** | **i64** | Unsigned 64 bit integer. | **created_at** | **String** | RFC3339 timestamp | **id** | [**uuid::Uuid**](uuid::Uuid.md) | | **name** | **String** | | **tags** | **::std::collections::HashMap** | Tags of this build | -**upload** | [**uuid::Uuid**](uuid::Uuid.md) | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/sdks/full/rust-cli/docs/ServersBuildsApi.md b/sdks/full/rust-cli/docs/ServersBuildsApi.md index bbc2592b8e..47701334e8 100644 --- a/sdks/full/rust-cli/docs/ServersBuildsApi.md +++ b/sdks/full/rust-cli/docs/ServersBuildsApi.md @@ -7,6 +7,7 @@ Method | HTTP request | Description [**servers_builds_complete_build**](ServersBuildsApi.md#servers_builds_complete_build) | **POST** /games/{game_id}/builds/{build_id}/complete | [**servers_builds_get_build**](ServersBuildsApi.md#servers_builds_get_build) | **GET** /games/{game_id}/builds/{build_id} | [**servers_builds_list_builds**](ServersBuildsApi.md#servers_builds_list_builds) | **GET** /games/{game_id}/builds | +[**servers_builds_patch_tags**](ServersBuildsApi.md#servers_builds_patch_tags) | **PATCH** /games/{game_id}/builds/{build_id}/tags | [**servers_builds_prepare_build**](ServersBuildsApi.md#servers_builds_prepare_build) | **POST** /games/{game_id}/builds/prepare | @@ -107,6 +108,36 @@ Name | Type | Description | Required | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +## servers_builds_patch_tags + +> serde_json::Value servers_builds_patch_tags(game_id, build_id, servers_patch_build_tags_request) + + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**game_id** | **uuid::Uuid** | | [required] | +**build_id** | **uuid::Uuid** | | [required] | +**servers_patch_build_tags_request** | [**ServersPatchBuildTagsRequest**](ServersPatchBuildTagsRequest.md) | | [required] | + +### Return type + +[**serde_json::Value**](serde_json::Value.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + ## servers_builds_prepare_build > crate::models::ServersCreateBuildResponse servers_builds_prepare_build(game_id, servers_create_build_request) diff --git a/sdks/full/rust-cli/docs/ServersCreateBuildRequest.md b/sdks/full/rust-cli/docs/ServersCreateBuildRequest.md index eb725e3361..aaa8cd7b48 100644 --- a/sdks/full/rust-cli/docs/ServersCreateBuildRequest.md +++ b/sdks/full/rust-cli/docs/ServersCreateBuildRequest.md @@ -10,7 +10,6 @@ Name | Type | Description | Notes **kind** | Option<[**crate::models::ServersBuildKind**](ServersBuildKind.md)> | | [optional] **multipart_upload** | Option<**bool**> | | [optional] **name** | **String** | | -**tags** | Option<[**serde_json::Value**](.md)> | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/sdks/full/rust-cli/docs/ServersCreateBuildResponse.md b/sdks/full/rust-cli/docs/ServersCreateBuildResponse.md index 0793e6acd2..dde77ec612 100644 --- a/sdks/full/rust-cli/docs/ServersCreateBuildResponse.md +++ b/sdks/full/rust-cli/docs/ServersCreateBuildResponse.md @@ -7,7 +7,6 @@ Name | Type | Description | Notes **build** | [**uuid::Uuid**](uuid::Uuid.md) | | **image_presigned_request** | Option<[**crate::models::UploadPresignedRequest**](UploadPresignedRequest.md)> | | [optional] **image_presigned_requests** | Option<[**Vec**](UploadPresignedRequest.md)> | | [optional] -**upload** | [**uuid::Uuid**](uuid::Uuid.md) | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/sdks/full/rust-cli/docs/ServersPatchBuildTagsRequest.md b/sdks/full/rust-cli/docs/ServersPatchBuildTagsRequest.md new file mode 100644 index 0000000000..fc559cc4cf --- /dev/null +++ b/sdks/full/rust-cli/docs/ServersPatchBuildTagsRequest.md @@ -0,0 +1,12 @@ +# ServersPatchBuildTagsRequest + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**exclusive_tags** | Option<**Vec**> | Removes the given tag keys from all other builds. | [optional] +**tags** | Option<[**serde_json::Value**](.md)> | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/sdks/full/rust-cli/src/apis/servers_builds_api.rs b/sdks/full/rust-cli/src/apis/servers_builds_api.rs index 6e78d49658..5a9fbcc584 100644 --- a/sdks/full/rust-cli/src/apis/servers_builds_api.rs +++ b/sdks/full/rust-cli/src/apis/servers_builds_api.rs @@ -54,6 +54,19 @@ pub enum ServersBuildsListBuildsError { UnknownValue(serde_json::Value), } +/// struct for typed errors of method [`servers_builds_patch_tags`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ServersBuildsPatchTagsError { + Status400(crate::models::ErrorBody), + Status403(crate::models::ErrorBody), + Status404(crate::models::ErrorBody), + Status408(crate::models::ErrorBody), + Status429(crate::models::ErrorBody), + Status500(crate::models::ErrorBody), + UnknownValue(serde_json::Value), +} + /// struct for typed errors of method [`servers_builds_prepare_build`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -173,6 +186,37 @@ pub async fn servers_builds_list_builds(configuration: &configuration::Configura } } +pub async fn servers_builds_patch_tags(configuration: &configuration::Configuration, game_id: &str, build_id: &str, servers_patch_build_tags_request: crate::models::ServersPatchBuildTagsRequest) -> Result> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/games/{game_id}/builds/{build_id}/tags", local_var_configuration.base_path, game_id=crate::apis::urlencode(game_id), build_id=crate::apis::urlencode(build_id)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::PATCH, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_token) = local_var_configuration.bearer_access_token { + local_var_req_builder = local_var_req_builder.bearer_auth(local_var_token.to_owned()); + }; + local_var_req_builder = local_var_req_builder.json(&servers_patch_build_tags_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + /// Creates a new game build for the given game. pub async fn servers_builds_prepare_build(configuration: &configuration::Configuration, game_id: &str, servers_create_build_request: crate::models::ServersCreateBuildRequest) -> Result> { let local_var_configuration = configuration; diff --git a/sdks/full/rust-cli/src/models/mod.rs b/sdks/full/rust-cli/src/models/mod.rs index a0f0d782b9..cc06ff9f91 100644 --- a/sdks/full/rust-cli/src/models/mod.rs +++ b/sdks/full/rust-cli/src/models/mod.rs @@ -640,6 +640,8 @@ pub mod servers_network; pub use self::servers_network::ServersNetwork; pub mod servers_network_mode; pub use self::servers_network_mode::ServersNetworkMode; +pub mod servers_patch_build_tags_request; +pub use self::servers_patch_build_tags_request::ServersPatchBuildTagsRequest; pub mod servers_port; pub use self::servers_port::ServersPort; pub mod servers_port_protocol; diff --git a/sdks/full/rust-cli/src/models/servers_build.rs b/sdks/full/rust-cli/src/models/servers_build.rs index 3eb27290a8..fdd8d54e66 100644 --- a/sdks/full/rust-cli/src/models/servers_build.rs +++ b/sdks/full/rust-cli/src/models/servers_build.rs @@ -13,9 +13,6 @@ #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] pub struct ServersBuild { - /// RFC3339 timestamp - #[serde(rename = "completed_at", skip_serializing_if = "Option::is_none")] - pub completed_at: Option, /// Unsigned 64 bit integer. #[serde(rename = "content_length")] pub content_length: i64, @@ -29,20 +26,16 @@ pub struct ServersBuild { /// Tags of this build #[serde(rename = "tags")] pub tags: ::std::collections::HashMap, - #[serde(rename = "upload")] - pub upload: uuid::Uuid, } impl ServersBuild { - pub fn new(content_length: i64, created_at: String, id: uuid::Uuid, name: String, tags: ::std::collections::HashMap, upload: uuid::Uuid) -> ServersBuild { + pub fn new(content_length: i64, created_at: String, id: uuid::Uuid, name: String, tags: ::std::collections::HashMap) -> ServersBuild { ServersBuild { - completed_at: None, content_length, created_at, id, name, tags, - upload, } } } diff --git a/sdks/full/rust-cli/src/models/servers_create_build_request.rs b/sdks/full/rust-cli/src/models/servers_create_build_request.rs index 3bc0d3a7d7..11fbb21d1a 100644 --- a/sdks/full/rust-cli/src/models/servers_create_build_request.rs +++ b/sdks/full/rust-cli/src/models/servers_create_build_request.rs @@ -26,12 +26,10 @@ pub struct ServersCreateBuildRequest { pub multipart_upload: Option, #[serde(rename = "name")] pub name: String, - #[serde(rename = "tags", deserialize_with = "Option::deserialize")] - pub tags: Option, } impl ServersCreateBuildRequest { - pub fn new(image_file: crate::models::UploadPrepareFile, image_tag: String, name: String, tags: Option) -> ServersCreateBuildRequest { + pub fn new(image_file: crate::models::UploadPrepareFile, image_tag: String, name: String) -> ServersCreateBuildRequest { ServersCreateBuildRequest { compression: None, image_file: Box::new(image_file), @@ -39,7 +37,6 @@ impl ServersCreateBuildRequest { kind: None, multipart_upload: None, name, - tags, } } } diff --git a/sdks/full/rust-cli/src/models/servers_create_build_response.rs b/sdks/full/rust-cli/src/models/servers_create_build_response.rs index 9bce4b6134..c277171564 100644 --- a/sdks/full/rust-cli/src/models/servers_create_build_response.rs +++ b/sdks/full/rust-cli/src/models/servers_create_build_response.rs @@ -19,17 +19,14 @@ pub struct ServersCreateBuildResponse { pub image_presigned_request: Option>, #[serde(rename = "image_presigned_requests", skip_serializing_if = "Option::is_none")] pub image_presigned_requests: Option>, - #[serde(rename = "upload")] - pub upload: uuid::Uuid, } impl ServersCreateBuildResponse { - pub fn new(build: uuid::Uuid, upload: uuid::Uuid) -> ServersCreateBuildResponse { + pub fn new(build: uuid::Uuid) -> ServersCreateBuildResponse { ServersCreateBuildResponse { build, image_presigned_request: None, image_presigned_requests: None, - upload, } } } diff --git a/sdks/full/rust-cli/src/models/servers_patch_build_tags_request.rs b/sdks/full/rust-cli/src/models/servers_patch_build_tags_request.rs new file mode 100644 index 0000000000..3857d9654a --- /dev/null +++ b/sdks/full/rust-cli/src/models/servers_patch_build_tags_request.rs @@ -0,0 +1,32 @@ +/* + * Rivet API + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 0.0.1 + * + * Generated by: https://openapi-generator.tech + */ + + + + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ServersPatchBuildTagsRequest { + /// Removes the given tag keys from all other builds. + #[serde(rename = "exclusive_tags", skip_serializing_if = "Option::is_none")] + pub exclusive_tags: Option>, + #[serde(rename = "tags", deserialize_with = "Option::deserialize")] + pub tags: Option, +} + +impl ServersPatchBuildTagsRequest { + pub fn new(tags: Option) -> ServersPatchBuildTagsRequest { + ServersPatchBuildTagsRequest { + exclusive_tags: None, + tags, + } + } +} + + diff --git a/sdks/full/rust/.openapi-generator/FILES b/sdks/full/rust/.openapi-generator/FILES index bc993ad026..41798ccc66 100644 --- a/sdks/full/rust/.openapi-generator/FILES +++ b/sdks/full/rust/.openapi-generator/FILES @@ -366,6 +366,7 @@ docs/ServersLogStream.md docs/ServersLogsApi.md docs/ServersNetwork.md docs/ServersNetworkMode.md +docs/ServersPatchBuildTagsRequest.md docs/ServersPort.md docs/ServersPortProtocol.md docs/ServersPortRouting.md @@ -743,6 +744,7 @@ src/models/servers_list_servers_response.rs src/models/servers_log_stream.rs src/models/servers_network.rs src/models/servers_network_mode.rs +src/models/servers_patch_build_tags_request.rs src/models/servers_port.rs src/models/servers_port_protocol.rs src/models/servers_port_routing.rs diff --git a/sdks/full/rust/README.md b/sdks/full/rust/README.md index 8f9008098d..6052b89e02 100644 --- a/sdks/full/rust/README.md +++ b/sdks/full/rust/README.md @@ -174,6 +174,7 @@ Class | Method | HTTP request | Description *ServersBuildsApi* | [**servers_builds_complete_build**](docs/ServersBuildsApi.md#servers_builds_complete_build) | **POST** /games/{game_id}/builds/{build_id}/complete | *ServersBuildsApi* | [**servers_builds_get_build**](docs/ServersBuildsApi.md#servers_builds_get_build) | **GET** /games/{game_id}/builds/{build_id} | *ServersBuildsApi* | [**servers_builds_list_builds**](docs/ServersBuildsApi.md#servers_builds_list_builds) | **GET** /games/{game_id}/builds | +*ServersBuildsApi* | [**servers_builds_patch_tags**](docs/ServersBuildsApi.md#servers_builds_patch_tags) | **PATCH** /games/{game_id}/builds/{build_id}/tags | *ServersBuildsApi* | [**servers_builds_prepare_build**](docs/ServersBuildsApi.md#servers_builds_prepare_build) | **POST** /games/{game_id}/builds/prepare | *ServersLogsApi* | [**servers_logs_get_server_logs**](docs/ServersLogsApi.md#servers_logs_get_server_logs) | **GET** /games/{game_id}/servers/{server_id}/logs | @@ -501,6 +502,7 @@ Class | Method | HTTP request | Description - [ServersLogStream](docs/ServersLogStream.md) - [ServersNetwork](docs/ServersNetwork.md) - [ServersNetworkMode](docs/ServersNetworkMode.md) + - [ServersPatchBuildTagsRequest](docs/ServersPatchBuildTagsRequest.md) - [ServersPort](docs/ServersPort.md) - [ServersPortProtocol](docs/ServersPortProtocol.md) - [ServersPortRouting](docs/ServersPortRouting.md) diff --git a/sdks/full/rust/docs/ServersBuild.md b/sdks/full/rust/docs/ServersBuild.md index a1cfb90183..3b59873414 100644 --- a/sdks/full/rust/docs/ServersBuild.md +++ b/sdks/full/rust/docs/ServersBuild.md @@ -4,13 +4,11 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**completed_at** | Option<**String**> | RFC3339 timestamp | [optional] **content_length** | **i64** | Unsigned 64 bit integer. | **created_at** | **String** | RFC3339 timestamp | **id** | [**uuid::Uuid**](uuid::Uuid.md) | | **name** | **String** | | **tags** | **::std::collections::HashMap** | Tags of this build | -**upload** | [**uuid::Uuid**](uuid::Uuid.md) | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/sdks/full/rust/docs/ServersBuildsApi.md b/sdks/full/rust/docs/ServersBuildsApi.md index bbc2592b8e..47701334e8 100644 --- a/sdks/full/rust/docs/ServersBuildsApi.md +++ b/sdks/full/rust/docs/ServersBuildsApi.md @@ -7,6 +7,7 @@ Method | HTTP request | Description [**servers_builds_complete_build**](ServersBuildsApi.md#servers_builds_complete_build) | **POST** /games/{game_id}/builds/{build_id}/complete | [**servers_builds_get_build**](ServersBuildsApi.md#servers_builds_get_build) | **GET** /games/{game_id}/builds/{build_id} | [**servers_builds_list_builds**](ServersBuildsApi.md#servers_builds_list_builds) | **GET** /games/{game_id}/builds | +[**servers_builds_patch_tags**](ServersBuildsApi.md#servers_builds_patch_tags) | **PATCH** /games/{game_id}/builds/{build_id}/tags | [**servers_builds_prepare_build**](ServersBuildsApi.md#servers_builds_prepare_build) | **POST** /games/{game_id}/builds/prepare | @@ -107,6 +108,36 @@ Name | Type | Description | Required | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +## servers_builds_patch_tags + +> serde_json::Value servers_builds_patch_tags(game_id, build_id, servers_patch_build_tags_request) + + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**game_id** | **uuid::Uuid** | | [required] | +**build_id** | **uuid::Uuid** | | [required] | +**servers_patch_build_tags_request** | [**ServersPatchBuildTagsRequest**](ServersPatchBuildTagsRequest.md) | | [required] | + +### Return type + +[**serde_json::Value**](serde_json::Value.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + ## servers_builds_prepare_build > crate::models::ServersCreateBuildResponse servers_builds_prepare_build(game_id, servers_create_build_request) diff --git a/sdks/full/rust/docs/ServersCreateBuildRequest.md b/sdks/full/rust/docs/ServersCreateBuildRequest.md index eb725e3361..aaa8cd7b48 100644 --- a/sdks/full/rust/docs/ServersCreateBuildRequest.md +++ b/sdks/full/rust/docs/ServersCreateBuildRequest.md @@ -10,7 +10,6 @@ Name | Type | Description | Notes **kind** | Option<[**crate::models::ServersBuildKind**](ServersBuildKind.md)> | | [optional] **multipart_upload** | Option<**bool**> | | [optional] **name** | **String** | | -**tags** | Option<[**serde_json::Value**](.md)> | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/sdks/full/rust/docs/ServersCreateBuildResponse.md b/sdks/full/rust/docs/ServersCreateBuildResponse.md index 0793e6acd2..dde77ec612 100644 --- a/sdks/full/rust/docs/ServersCreateBuildResponse.md +++ b/sdks/full/rust/docs/ServersCreateBuildResponse.md @@ -7,7 +7,6 @@ Name | Type | Description | Notes **build** | [**uuid::Uuid**](uuid::Uuid.md) | | **image_presigned_request** | Option<[**crate::models::UploadPresignedRequest**](UploadPresignedRequest.md)> | | [optional] **image_presigned_requests** | Option<[**Vec**](UploadPresignedRequest.md)> | | [optional] -**upload** | [**uuid::Uuid**](uuid::Uuid.md) | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/sdks/full/rust/docs/ServersPatchBuildTagsRequest.md b/sdks/full/rust/docs/ServersPatchBuildTagsRequest.md new file mode 100644 index 0000000000..fc559cc4cf --- /dev/null +++ b/sdks/full/rust/docs/ServersPatchBuildTagsRequest.md @@ -0,0 +1,12 @@ +# ServersPatchBuildTagsRequest + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**exclusive_tags** | Option<**Vec**> | Removes the given tag keys from all other builds. | [optional] +**tags** | Option<[**serde_json::Value**](.md)> | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/sdks/full/rust/src/apis/servers_builds_api.rs b/sdks/full/rust/src/apis/servers_builds_api.rs index 6e78d49658..5a9fbcc584 100644 --- a/sdks/full/rust/src/apis/servers_builds_api.rs +++ b/sdks/full/rust/src/apis/servers_builds_api.rs @@ -54,6 +54,19 @@ pub enum ServersBuildsListBuildsError { UnknownValue(serde_json::Value), } +/// struct for typed errors of method [`servers_builds_patch_tags`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ServersBuildsPatchTagsError { + Status400(crate::models::ErrorBody), + Status403(crate::models::ErrorBody), + Status404(crate::models::ErrorBody), + Status408(crate::models::ErrorBody), + Status429(crate::models::ErrorBody), + Status500(crate::models::ErrorBody), + UnknownValue(serde_json::Value), +} + /// struct for typed errors of method [`servers_builds_prepare_build`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -173,6 +186,37 @@ pub async fn servers_builds_list_builds(configuration: &configuration::Configura } } +pub async fn servers_builds_patch_tags(configuration: &configuration::Configuration, game_id: &str, build_id: &str, servers_patch_build_tags_request: crate::models::ServersPatchBuildTagsRequest) -> Result> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/games/{game_id}/builds/{build_id}/tags", local_var_configuration.base_path, game_id=crate::apis::urlencode(game_id), build_id=crate::apis::urlencode(build_id)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::PATCH, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_token) = local_var_configuration.bearer_access_token { + local_var_req_builder = local_var_req_builder.bearer_auth(local_var_token.to_owned()); + }; + local_var_req_builder = local_var_req_builder.json(&servers_patch_build_tags_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + /// Creates a new game build for the given game. pub async fn servers_builds_prepare_build(configuration: &configuration::Configuration, game_id: &str, servers_create_build_request: crate::models::ServersCreateBuildRequest) -> Result> { let local_var_configuration = configuration; diff --git a/sdks/full/rust/src/models/mod.rs b/sdks/full/rust/src/models/mod.rs index a0f0d782b9..cc06ff9f91 100644 --- a/sdks/full/rust/src/models/mod.rs +++ b/sdks/full/rust/src/models/mod.rs @@ -640,6 +640,8 @@ pub mod servers_network; pub use self::servers_network::ServersNetwork; pub mod servers_network_mode; pub use self::servers_network_mode::ServersNetworkMode; +pub mod servers_patch_build_tags_request; +pub use self::servers_patch_build_tags_request::ServersPatchBuildTagsRequest; pub mod servers_port; pub use self::servers_port::ServersPort; pub mod servers_port_protocol; diff --git a/sdks/full/rust/src/models/servers_build.rs b/sdks/full/rust/src/models/servers_build.rs index 3eb27290a8..fdd8d54e66 100644 --- a/sdks/full/rust/src/models/servers_build.rs +++ b/sdks/full/rust/src/models/servers_build.rs @@ -13,9 +13,6 @@ #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] pub struct ServersBuild { - /// RFC3339 timestamp - #[serde(rename = "completed_at", skip_serializing_if = "Option::is_none")] - pub completed_at: Option, /// Unsigned 64 bit integer. #[serde(rename = "content_length")] pub content_length: i64, @@ -29,20 +26,16 @@ pub struct ServersBuild { /// Tags of this build #[serde(rename = "tags")] pub tags: ::std::collections::HashMap, - #[serde(rename = "upload")] - pub upload: uuid::Uuid, } impl ServersBuild { - pub fn new(content_length: i64, created_at: String, id: uuid::Uuid, name: String, tags: ::std::collections::HashMap, upload: uuid::Uuid) -> ServersBuild { + pub fn new(content_length: i64, created_at: String, id: uuid::Uuid, name: String, tags: ::std::collections::HashMap) -> ServersBuild { ServersBuild { - completed_at: None, content_length, created_at, id, name, tags, - upload, } } } diff --git a/sdks/full/rust/src/models/servers_create_build_request.rs b/sdks/full/rust/src/models/servers_create_build_request.rs index 3bc0d3a7d7..11fbb21d1a 100644 --- a/sdks/full/rust/src/models/servers_create_build_request.rs +++ b/sdks/full/rust/src/models/servers_create_build_request.rs @@ -26,12 +26,10 @@ pub struct ServersCreateBuildRequest { pub multipart_upload: Option, #[serde(rename = "name")] pub name: String, - #[serde(rename = "tags", deserialize_with = "Option::deserialize")] - pub tags: Option, } impl ServersCreateBuildRequest { - pub fn new(image_file: crate::models::UploadPrepareFile, image_tag: String, name: String, tags: Option) -> ServersCreateBuildRequest { + pub fn new(image_file: crate::models::UploadPrepareFile, image_tag: String, name: String) -> ServersCreateBuildRequest { ServersCreateBuildRequest { compression: None, image_file: Box::new(image_file), @@ -39,7 +37,6 @@ impl ServersCreateBuildRequest { kind: None, multipart_upload: None, name, - tags, } } } diff --git a/sdks/full/rust/src/models/servers_create_build_response.rs b/sdks/full/rust/src/models/servers_create_build_response.rs index 9bce4b6134..c277171564 100644 --- a/sdks/full/rust/src/models/servers_create_build_response.rs +++ b/sdks/full/rust/src/models/servers_create_build_response.rs @@ -19,17 +19,14 @@ pub struct ServersCreateBuildResponse { pub image_presigned_request: Option>, #[serde(rename = "image_presigned_requests", skip_serializing_if = "Option::is_none")] pub image_presigned_requests: Option>, - #[serde(rename = "upload")] - pub upload: uuid::Uuid, } impl ServersCreateBuildResponse { - pub fn new(build: uuid::Uuid, upload: uuid::Uuid) -> ServersCreateBuildResponse { + pub fn new(build: uuid::Uuid) -> ServersCreateBuildResponse { ServersCreateBuildResponse { build, image_presigned_request: None, image_presigned_requests: None, - upload, } } } diff --git a/sdks/full/rust/src/models/servers_patch_build_tags_request.rs b/sdks/full/rust/src/models/servers_patch_build_tags_request.rs new file mode 100644 index 0000000000..3857d9654a --- /dev/null +++ b/sdks/full/rust/src/models/servers_patch_build_tags_request.rs @@ -0,0 +1,32 @@ +/* + * Rivet API + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 0.0.1 + * + * Generated by: https://openapi-generator.tech + */ + + + + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ServersPatchBuildTagsRequest { + /// Removes the given tag keys from all other builds. + #[serde(rename = "exclusive_tags", skip_serializing_if = "Option::is_none")] + pub exclusive_tags: Option>, + #[serde(rename = "tags", deserialize_with = "Option::deserialize")] + pub tags: Option, +} + +impl ServersPatchBuildTagsRequest { + pub fn new(tags: Option) -> ServersPatchBuildTagsRequest { + ServersPatchBuildTagsRequest { + exclusive_tags: None, + tags, + } + } +} + + diff --git a/sdks/full/typescript/archive.tgz b/sdks/full/typescript/archive.tgz index d8f93d25b9..c38867344c 100644 --- a/sdks/full/typescript/archive.tgz +++ b/sdks/full/typescript/archive.tgz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a905f05340ac499a8dc7d406919029e4658f8587b053e4010a15af3b5e40f09a -size 544919 +oid sha256:22e35eaf05ecd0072588f05b430e7f879cfb9496e9ee8d0c6f0f61be9c493aab +size 545988 diff --git a/sdks/full/typescript/src/api/resources/servers/resources/builds/client/Client.ts b/sdks/full/typescript/src/api/resources/servers/resources/builds/client/Client.ts index 468c5b38f1..a9d7571657 100644 --- a/sdks/full/typescript/src/api/resources/servers/resources/builds/client/Client.ts +++ b/sdks/full/typescript/src/api/resources/servers/resources/builds/client/Client.ts @@ -323,6 +323,144 @@ export class Builds { } } + /** + * @param {string} gameId + * @param {string} buildId + * @param {Rivet.servers.PatchBuildTagsRequest} request + * @param {Builds.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Rivet.InternalError} + * @throws {@link Rivet.RateLimitError} + * @throws {@link Rivet.ForbiddenError} + * @throws {@link Rivet.UnauthorizedError} + * @throws {@link Rivet.NotFoundError} + * @throws {@link Rivet.BadRequestError} + * + * @example + * await client.servers.builds.patchTags("d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32", "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32", { + * tags: { + * "key": "value" + * }, + * exclusiveTags: ["string"] + * }) + */ + public async patchTags( + gameId: string, + buildId: string, + request: Rivet.servers.PatchBuildTagsRequest, + requestOptions?: Builds.RequestOptions + ): Promise { + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: urlJoin( + (await core.Supplier.get(this._options.environment)) ?? environments.RivetEnvironment.Production, + `/games/${encodeURIComponent(gameId)}/builds/${encodeURIComponent(buildId)}/tags` + ), + method: "PATCH", + headers: { + Authorization: await this._getAuthorizationHeader(), + }, + contentType: "application/json", + requestType: "json", + body: serializers.servers.PatchBuildTagsRequest.jsonOrThrow(request, { unrecognizedObjectKeys: "strip" }), + timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : 180000, + maxRetries: requestOptions?.maxRetries, + abortSignal: requestOptions?.abortSignal, + }); + if (_response.ok) { + return serializers.servers.PatchBuildTagsResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }); + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 500: + throw new Rivet.InternalError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 429: + throw new Rivet.RateLimitError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 403: + throw new Rivet.ForbiddenError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 408: + throw new Rivet.UnauthorizedError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 404: + throw new Rivet.NotFoundError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 400: + throw new Rivet.BadRequestError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + default: + throw new errors.RivetError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.RivetError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + }); + case "timeout": + throw new errors.RivetTimeoutError(); + case "unknown": + throw new errors.RivetError({ + message: _response.error.errorMessage, + }); + } + } + /** * Creates a new game build for the given game. * @@ -340,9 +478,6 @@ export class Builds { * @example * await client.servers.builds.prepareBuild("d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32", { * name: "string", - * tags: { - * "key": "value" - * }, * imageTag: "string", * imageFile: {}, * multipartUpload: true, diff --git a/sdks/runtime/typescript/archive.tgz b/sdks/runtime/typescript/archive.tgz index 845d84907e..eba805dcac 100644 --- a/sdks/runtime/typescript/archive.tgz +++ b/sdks/runtime/typescript/archive.tgz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fff34c21863eb214e8bb34ece330baa6f5fdfa9b728203f7792bad9188131685 -size 282610 +oid sha256:071fe51bfbef89bc2a91dd2e8ebb87f64c74a2b87605c9b1f79d5877c32cd197 +size 282615 diff --git a/svc/Cargo.lock b/svc/Cargo.lock index a52936264c..2b7824faac 100644 --- a/svc/Cargo.lock +++ b/svc/Cargo.lock @@ -797,6 +797,7 @@ version = "0.0.1" dependencies = [ "api-helper", "base64 0.13.1", + "build", "build-create", "build-get", "build-list-for-game", @@ -1573,6 +1574,38 @@ dependencies = [ "memchr", ] +[[package]] +name = "build" +version = "0.0.1" +dependencies = [ + "acme-lib", + "anyhow", + "chirp-workflow", + "cloudflare", + "faker-build", + "faker-game", + "http 0.2.12", + "include_dir", + "indoc 1.0.9", + "ip-info", + "lazy_static", + "linode", + "nomad-util", + "rand", + "reqwest 0.11.27", + "rivet-metrics", + "rivet-operation", + "rivet-runtime", + "s3-util", + "serde", + "serde_json", + "sqlx 0.7.4 (git+https://github.com/rivet-gg/sqlx?rev=08d6e61aa0572e7ec557abbedb72cebb96e1ac5b)", + "ssh2", + "strum 0.26.3", + "token-create", + "trust-dns-resolver", +] + [[package]] name = "build-create" version = "0.0.1" @@ -4390,6 +4423,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.9" @@ -8743,6 +8782,15 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros 0.26.4", +] + [[package]] name = "strum_macros" version = "0.24.3" @@ -8769,6 +8817,19 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.72", +] + [[package]] name = "subtle" version = "2.6.1" diff --git a/svc/Cargo.toml b/svc/Cargo.toml index 5c18538a12..765ab6139d 100644 --- a/svc/Cargo.toml +++ b/svc/Cargo.toml @@ -19,9 +19,7 @@ members = [ "api/servers", "api/status", "api/traefik-provider", - "pkg/build/ops/create", - "pkg/build/ops/get", - "pkg/build/ops/list-for-game", + "pkg/build", "pkg/build/standalone/default-create", "pkg/captcha/ops/hcaptcha-config-get", "pkg/captcha/ops/hcaptcha-verify", diff --git a/svc/api/servers/Cargo.toml b/svc/api/servers/Cargo.toml index 8cb3ca050e..22160dbbe6 100644 --- a/svc/api/servers/Cargo.toml +++ b/svc/api/servers/Cargo.toml @@ -35,6 +35,7 @@ build-create = { path = "../../pkg/build/ops/create" } build-get = { path = "../../pkg/build/ops/get" } build-list-for-game = { path = "../../pkg/build/ops/list-for-game" } cluster = { path = "../../pkg/cluster" } +build = { path = "../../pkg/build" } ds-log-read = { path = "../../pkg/ds-log/ops/read" } ds-server-create = { path = "../../pkg/ds/ops/server-create" } ds-server-delete = { path = "../../pkg/ds/ops/server-delete" } diff --git a/svc/api/servers/src/route/builds.rs b/svc/api/servers/src/route/builds.rs index a459383310..ef3ef80146 100644 --- a/svc/api/servers/src/route/builds.rs +++ b/svc/api/servers/src/route/builds.rs @@ -11,6 +11,44 @@ use util::timestamp; use crate::auth::Auth; +// MARK: GET /games/{}/builds/{} +pub async fn get( + ctx: Ctx, + game_id: Uuid, + build_id: Uuid, + _watch_index: WatchIndexQuery, +) -> GlobalResult { + ctx.auth().check_game(ctx.op_ctx(), game_id, true).await?; + + let builds_res = op!([ctx] build_get { + build_ids: vec![build_id.into()], + }) + .await?; + let build = unwrap!(builds_res.builds.first()); + + let uploads_res = op!([ctx] upload_get { + upload_ids: builds_res + .builds + .iter() + .filter_map(|build| build.upload_id) + .collect::>(), + }) + .await?; + let upload = unwrap!(uploads_res.uploads.first()); + + let build = models::ServersBuild { + id: unwrap!(build.build_id).as_uuid(), + name: build.display_name.clone(), + created_at: timestamp::to_string(build.create_ts)?, + content_length: upload.content_length.api_try_into()?, + tags: build.tags.clone(), + }; + + Ok(models::ServersGetBuildResponse { + build: Box::new(build), + }) +} + // MARK: GET /games/{}/builds #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GetQuery { @@ -49,30 +87,25 @@ pub async fn list( let mut builds = builds_res .builds .iter() - .map(|build| { - let upload = uploads_res + .filter_map(|build| { + if let Some(upload) = uploads_res .uploads .iter() - .find(|u| u.upload_id == build.upload_id); - if upload.is_none() { - tracing::warn!("unable to find upload for build"); + .find(|u| u.upload_id == build.upload_id) + { + Some((build, upload)) + } else { + None } - + }) + .map(|(build, upload)| { GlobalResult::Ok(( build.create_ts, models::ServersBuild { id: unwrap!(build.build_id).as_uuid(), - upload: unwrap!(build.upload_id).as_uuid(), name: build.display_name.clone(), created_at: timestamp::to_string(build.create_ts)?, - content_length: upload - .map_or(0, |upload| upload.content_length) - .api_try_into()?, - completed_at: upload - .as_ref() - .and_then(|x| x.complete_ts) - .map(timestamp::to_string) - .transpose()?, + content_length: upload.content_length.api_try_into()?, tags: build.tags.clone(), }, )) @@ -88,50 +121,31 @@ pub async fn list( }) } -// MARK: GET /games/{}/builds/{} -pub async fn get( +// MARK: PATCH /games/{}/builds/{}/tags +pub async fn patch_tags( ctx: Ctx, game_id: Uuid, build_id: Uuid, - _watch_index: WatchIndexQuery, -) -> GlobalResult { - ctx.auth().check_game(ctx.op_ctx(), game_id, true).await?; + body: models::ServersPatchBuildTagsRequest, +) -> GlobalResult { + ctx.auth().check_game(ctx.op_ctx(), game_id, false).await?; - let builds_res = op!([ctx] build_get { - build_ids: vec![build_id.into()], + let tags: HashMap = + serde_json::from_value::>(unwrap!(body.tags))?; + + ctx.op(build::ops::get::Input { + build_ids: vec![build_id], }) .await?; - let build = unwrap!(builds_res.builds.first()); - let uploads_res = op!([ctx] upload_get { - upload_ids: builds_res - .builds - .iter() - .filter_map(|build| build.upload_id) - .collect::>(), + ctx.op(build::ops::patch_tags::Input { + build_id, + tags, + exclusive_tags: body.exclusive_tags, }) .await?; - let upload = uploads_res.uploads.first(); - - let build = models::ServersBuild { - id: unwrap!(build.build_id).as_uuid(), - upload: unwrap!(build.upload_id).as_uuid(), - name: build.display_name.clone(), - created_at: timestamp::to_string(build.create_ts)?, - content_length: upload - .map_or(0, |upload| upload.content_length) - .api_try_into()?, - completed_at: upload - .as_ref() - .and_then(|x| x.complete_ts) - .map(timestamp::to_string) - .transpose()?, - tags: build.tags.clone(), - }; - Ok(models::ServersGetBuildResponse { - build: Box::new(build), - }) + Ok(json!({})) } // MARK: POST /games/{}/builds/prepare @@ -160,11 +174,6 @@ pub async fn create_build( Some(models::ServersBuildCompression::Lz4) => backend::build::BuildCompression::Lz4, }; - // Verify that tags are valid - let tags: HashMap = body - .tags - .map_or(Ok(HashMap::new()), serde_json::from_value)?; - let create_res = op!([ctx] build_create { game_id: Some(game_id.into()), display_name: body.name, @@ -173,9 +182,9 @@ pub async fn create_build( multipart: multipart_upload, kind: kind as i32, compression: compression as i32, - tags: tags, }) .await?; + let build_id = unwrap_ref!(create_res.build_id).as_uuid(); let image_presigned_request = if !multipart_upload { Some(Box::new( @@ -201,8 +210,7 @@ pub async fn create_build( }; Ok(models::ServersCreateBuildResponse { - build: unwrap_ref!(create_res.build_id).as_uuid(), - upload: unwrap_ref!(create_res.upload_id).as_uuid(), + build: build_id, image_presigned_request, image_presigned_requests, }) diff --git a/svc/api/servers/src/route/mod.rs b/svc/api/servers/src/route/mod.rs index 817cb14d5c..fd8f5a49cd 100644 --- a/svc/api/servers/src/route/mod.rs +++ b/svc/api/servers/src/route/mod.rs @@ -55,6 +55,10 @@ define_router! { GET: builds::get(), }, + "games" / Uuid / "builds" / Uuid / "tags": { + PATCH: builds::patch_tags(body: models::ServersPatchBuildTagsRequest), + }, + "games" / Uuid / "builds" / "prepare": { POST: builds::create_build(body: models::ServersCreateBuildRequest), }, diff --git a/svc/pkg/build/Cargo.toml b/svc/pkg/build/Cargo.toml new file mode 100644 index 0000000000..0aa253f214 --- /dev/null +++ b/svc/pkg/build/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "build" +version = "0.0.1" +edition = "2018" +authors = ["Rivet Gaming, LLC "] +license = "Apache-2.0" + +[dependencies] +acme-lib = "0.9" +anyhow = "1.0" +chirp-workflow = { path = "../../../lib/chirp-workflow/core" } +cloudflare = { git = "https://github.com/cloudflare/cloudflare-rs.git", rev = "f14720e42184ee176a97676e85ef2d2d85bc3aae" } +http = "0.2" +include_dir = "0.7.3" +indoc = "1.0" +lazy_static = "1.4" +nomad-util = { path = "../../../lib/nomad-util" } +rand = "0.8" +reqwest = { version = "0.11", features = ["json"] } +rivet-metrics = { path = "../../../lib/metrics" } +rivet-operation = { path = "../../../lib/operation/core" } +rivet-runtime = { path = "../../../lib/runtime" } +s3-util = { path = "../../../lib/s3-util" } +serde = { version = "1.0.198", features = ["derive"] } +serde_json = "1.0" +ssh2 = "0.9.4" +trust-dns-resolver = { version = "0.23.2", features = ["dns-over-native-tls"] } +strum = { version = "0.26", features = ["derive"] } + +ip-info = { path = "../ip/ops/info" } +linode = { path = "../linode" } +token-create = { path = "../token/ops/create" } + +[dependencies.sqlx] +git = "https://github.com/rivet-gg/sqlx" +rev = "08d6e61aa0572e7ec557abbedb72cebb96e1ac5b" +default-features = false +features = [ "json" ] + +[dev-dependencies] +faker-game = { path = "../faker/ops/game" } +faker-build = { path = "../faker/ops/build" } + diff --git a/svc/pkg/build/Service.toml b/svc/pkg/build/Service.toml new file mode 100644 index 0000000000..e9e21622b3 --- /dev/null +++ b/svc/pkg/build/Service.toml @@ -0,0 +1,12 @@ +[service] +name = "build" + +[runtime] +kind = "rust" + +[package] + +[secrets] + +[databases] +db-build = {} diff --git a/svc/pkg/build/ops/create/src/lib.rs b/svc/pkg/build/ops/create/src/lib.rs index ca79af8972..9cca98250b 100644 --- a/svc/pkg/build/ops/create/src/lib.rs +++ b/svc/pkg/build/ops/create/src/lib.rs @@ -107,11 +107,10 @@ async fn handle( image_tag, create_ts, kind, - compression, - tags + compression ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9) + ($1, $2, $3, $4, $5, $6, $7, $8) ", build_id, game_id, @@ -121,7 +120,6 @@ async fn handle( ctx.ts(), kind as i32, compression as i32, - serde_json::to_value(ctx.tags.clone())?, ) .await?; diff --git a/svc/pkg/build/src/lib.rs b/svc/pkg/build/src/lib.rs new file mode 100644 index 0000000000..414c60d29e --- /dev/null +++ b/svc/pkg/build/src/lib.rs @@ -0,0 +1,2 @@ +pub mod ops; +pub mod types; diff --git a/svc/pkg/build/src/ops/get.rs b/svc/pkg/build/src/ops/get.rs new file mode 100644 index 0000000000..2640354827 --- /dev/null +++ b/svc/pkg/build/src/ops/get.rs @@ -0,0 +1,78 @@ +use chirp_workflow::prelude::*; +use serde_json::Value; +use std::convert::TryInto; + +use crate::types; + +#[derive(Debug)] +pub struct Input { + pub build_ids: Vec, +} + +#[derive(Debug)] +pub struct Output { + pub builds: Vec, +} + +#[derive(sqlx::FromRow)] +struct BuildRow { + build_id: Uuid, + game_id: Uuid, + upload_id: Uuid, + display_name: String, + image_tag: String, + create_ts: i64, + kind: i64, + compression: i64, + tags: Value, +} + +impl TryInto for BuildRow { + type Error = GlobalError; + + fn try_into(self) -> GlobalResult { + Ok(types::Build { + build_id: self.build_id, + game_id: self.game_id, + upload_id: self.upload_id, + display_name: self.display_name, + image_tag: self.image_tag, + create_ts: self.create_ts, + kind: unwrap!(types::BuildKind::from_repr(self.kind.try_into()?)), + compression: unwrap!(types::BuildCompression::from_repr( + self.compression.try_into()? + )), + tags: serde_json::from_value(self.tags)?, + }) + } +} + +#[operation] +pub async fn get(ctx: &OperationCtx, input: &Input) -> GlobalResult { + let builds = sql_fetch_all!( + [ctx, BuildRow] + " + SELECT + build_id, + game_id, + upload_id, + display_name, + image_tag, + create_ts, + kind, + compression, + tags + FROM + db_build.builds + WHERE + build_id = ANY($1) + ", + &input.build_ids, + ) + .await? + .into_iter() + .map(|build| build.try_into()) + .collect::>>()?; + + Ok(Output { builds }) +} diff --git a/svc/pkg/build/src/ops/mod.rs b/svc/pkg/build/src/ops/mod.rs new file mode 100644 index 0000000000..fd247f77b9 --- /dev/null +++ b/svc/pkg/build/src/ops/mod.rs @@ -0,0 +1,2 @@ +pub mod get; +pub mod patch_tags; diff --git a/svc/pkg/build/src/ops/patch_tags.rs b/svc/pkg/build/src/ops/patch_tags.rs new file mode 100644 index 0000000000..bf3f084489 --- /dev/null +++ b/svc/pkg/build/src/ops/patch_tags.rs @@ -0,0 +1,80 @@ +use futures_util::FutureExt; +use std::collections::HashMap; + +use chirp_workflow::prelude::*; + +#[derive(Debug)] +pub struct Input { + pub build_id: Uuid, + pub tags: HashMap, + pub exclusive_tags: Option>, +} + +#[derive(Debug)] +pub struct Output {} + +#[operation] +pub async fn patch_tags(ctx: &OperationCtx, input: &Input) -> GlobalResult { + // Validate tags don't overlap + if let Some(exclusive_tags) = &input.exclusive_tags { + ensure_with!( + exclusive_tags.iter().all(|k| input.tags.contains_key(k)), + BUILDS_TAGS_MISSING_EXCLUSIVE_KEY + ); + } + + let tags_json = serde_json::to_value(&input.tags)?; + + rivet_pools::utils::crdb::tx(&ctx.crdb().await?, |tx| { + let ctx = ctx.clone(); + let build_id = input.build_id.clone(); + let tags_json = tags_json.clone(); + let exclusive_tags = input.exclusive_tags.clone(); + + async move { + // Remove the exclusive tag from other builds + if let Some(exclusive_tags) = &exclusive_tags { + sql_execute!( + [ctx, @tx tx] + " + UPDATE db_build.builds b + SET tags = ( + SELECT jsonb_object_agg(key, value) + FROM jsonb_each(tags) + WHERE NOT (key = ANY($2::text[])) + ) + WHERE + b.game_id = ( + SELECT game_id + FROM db_build.builds + WHERE build_id = $1 + ) + AND tags ?| $2::text[]; + ", + &build_id, + &exclusive_tags, + ) + .await?; + } + + // Add tag to current build + sql_execute!( + [ctx, @tx tx] + " + UPDATE db_build.builds + SET tags = tags || $2 + WHERE build_id = $1 + ", + &build_id, + &tags_json, + ) + .await?; + + Ok(()) + } + .boxed() + }) + .await?; + + Ok(Output {}) +} diff --git a/svc/pkg/build/src/types.rs b/svc/pkg/build/src/types.rs new file mode 100644 index 0000000000..8b0325448c --- /dev/null +++ b/svc/pkg/build/src/types.rs @@ -0,0 +1,28 @@ +use chirp_workflow::prelude::*; +use std::collections::HashMap; +use strum::FromRepr; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, FromRepr)] +pub enum BuildKind { + DockerImage = 0, + OciBundle = 1, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, FromRepr)] +pub enum BuildCompression { + None = 0, + Lz4 = 1, +} + +#[derive(Debug)] +pub struct Build { + pub build_id: Uuid, + pub game_id: Uuid, + pub upload_id: Uuid, + pub display_name: String, + pub image_tag: String, + pub create_ts: i64, + pub kind: BuildKind, + pub compression: BuildCompression, + pub tags: HashMap, +} diff --git a/svc/pkg/build/tests/patch_tags.rs b/svc/pkg/build/tests/patch_tags.rs new file mode 100644 index 0000000000..a9df84d7b0 --- /dev/null +++ b/svc/pkg/build/tests/patch_tags.rs @@ -0,0 +1,134 @@ +use chirp_workflow::prelude::*; +use rivet_operation::prelude::proto::backend; +use std::collections::HashMap; + +#[workflow_test] +async fn patch_tags_works(ctx: TestCtx) { + let game_res = op!([ctx] faker_game { + ..Default::default() + }) + .await + .unwrap(); + + let build_res = op!([ctx] faker_build { + game_id: game_res.game_id, + image: backend::faker::Image::MmLobbyAutoReady as i32, + }) + .await + .unwrap(); + let build_id = build_res.build_id.as_ref().unwrap().as_uuid(); + + ctx.op(build::ops::patch_tags::Input { + build_id, + tags: HashMap::from([("tag1".to_string(), "value1".to_string())]), + exclusive_tags: None, + }) + .await + .unwrap(); + + let build = ctx + .op(build::ops::get::Input { + build_ids: vec![build_id], + }) + .await + .unwrap() + .builds; + assert_eq!( + build[0].tags, + HashMap::from([("tag1".to_string(), "value1".to_string())]) + ); +} + +#[workflow_test] +async fn patch_tags_overlapping_keys_error(ctx: TestCtx) { + let game_res = op!([ctx] faker_game { + ..Default::default() + }) + .await + .unwrap(); + + let build_res = op!([ctx] faker_build { + game_id: game_res.game_id, + image: backend::faker::Image::MmLobbyAutoReady as i32, + }) + .await + .unwrap(); + let build_id = build_res.build_id.as_ref().unwrap().as_uuid(); + + ctx.op(build::ops::patch_tags::Input { + build_id, + tags: HashMap::from([("tag1".to_string(), "value1".to_string())]), + exclusive_tags: Some(vec!["tag1".to_string(), "tag2".to_string()]), + }) + .await + .unwrap_err(); +} + +#[workflow_test] +async fn patch_tags_exclusive_removes_tag_on_other_build(ctx: TestCtx) { + let game_res = op!([ctx] faker_game { + ..Default::default() + }) + .await + .unwrap(); + + let build_a_res = op!([ctx] faker_build { + game_id: game_res.game_id, + image: backend::faker::Image::MmLobbyAutoReady as i32, + }) + .await + .unwrap(); + let build_a_id = build_a_res.build_id.as_ref().unwrap().as_uuid(); + + let build_b_res = op!([ctx] faker_build { + game_id: game_res.game_id, + image: backend::faker::Image::MmLobbyAutoReady as i32, + }) + .await + .unwrap(); + let build_b_id = build_b_res.build_id.as_ref().unwrap().as_uuid(); + + ctx.op(build::ops::patch_tags::Input { + build_id: build_a_id, + tags: HashMap::from([ + ("tag1".to_string(), "value1".to_string()), + ("tag2".to_string(), "value2".to_string()), + ("tag3".to_string(), "value3".to_string()), + ]), + exclusive_tags: None, + }) + .await + .unwrap(); + + ctx.op(build::ops::patch_tags::Input { + build_id: build_b_id, + tags: HashMap::from([("tag1".to_string(), "value2".to_string())]), + exclusive_tags: Some(vec!["tag1".to_string()]), + }) + .await + .unwrap(); + + let builds = ctx + .op(build::ops::get::Input { + build_ids: vec![build_a_id, build_b_id], + }) + .await + .unwrap() + .builds; + + let build_a = builds.iter().find(|b| b.build_id == build_a_id).unwrap(); + let build_b = builds.iter().find(|b| b.build_id == build_b_id).unwrap(); + + assert_eq!( + build_a.tags, + HashMap::from([ + ("tag2".to_string(), "value2".to_string()), + ("tag3".to_string(), "value3".to_string()), + ]) + ); + + assert_eq!( + build_b.tags, + HashMap::from([("tag1".to_string(), "value2".to_string())]) + ); +}