From 255bd90fadb010fbc75f2b38ec1e79b219cf06ef Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 11 Feb 2026 13:32:16 +0000
Subject: [PATCH 1/2] feat(api): add bulk_create/bulk_delete/bulk_update
methods to projects
---
.stats.yml | 8 +-
api.md | 6 +
src/gitpod/resources/projects/projects.py | 384 +++++++++++++-
src/gitpod/types/__init__.py | 6 +
.../types/project_bulk_create_params.py | 55 ++
.../types/project_bulk_create_response.py | 29 ++
.../types/project_bulk_delete_params.py | 14 +
.../types/project_bulk_delete_response.py | 28 +
.../types/project_bulk_update_params.py | 69 +++
.../types/project_bulk_update_response.py | 29 ++
tests/api_resources/test_projects.py | 479 ++++++++++++++++++
11 files changed, 1101 insertions(+), 6 deletions(-)
create mode 100644 src/gitpod/types/project_bulk_create_params.py
create mode 100644 src/gitpod/types/project_bulk_create_response.py
create mode 100644 src/gitpod/types/project_bulk_delete_params.py
create mode 100644 src/gitpod/types/project_bulk_delete_response.py
create mode 100644 src/gitpod/types/project_bulk_update_params.py
create mode 100644 src/gitpod/types/project_bulk_update_response.py
diff --git a/.stats.yml b/.stats.yml
index 592d8a4..cca37c7 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 172
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-b97dcde84128bcf3740b0cf3c2c005e1dcd1cdac9b0768a28bd734f8d83c9fa2.yml
-openapi_spec_hash: 1172889d2eb3f0453514c6caae3459b3
-config_hash: 49d499b8ab46cede0e3461ef7cd549ca
+configured_endpoints: 175
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-8f6ee769411e2d21a2f437d49eb2f16880fcef0db52ac1985f2a3963af45f6a0.yml
+openapi_spec_hash: 28f2d9d7e36f1f0ecd13052054449249
+config_hash: 3f1278a7a2a9285f57e81f148743e99e
diff --git a/api.md b/api.md
index ce41da2..cd3547f 100644
--- a/api.md
+++ b/api.md
@@ -555,6 +555,9 @@ from gitpod.types import (
ProjectCreateResponse,
ProjectRetrieveResponse,
ProjectUpdateResponse,
+ ProjectBulkCreateResponse,
+ ProjectBulkDeleteResponse,
+ ProjectBulkUpdateResponse,
ProjectCreateFromEnvironmentResponse,
)
```
@@ -566,6 +569,9 @@ Methods:
- client.projects.update(\*\*params) -> ProjectUpdateResponse
- client.projects.list(\*\*params) -> SyncProjectsPage[Project]
- client.projects.delete(\*\*params) -> object
+- client.projects.bulk_create(\*\*params) -> ProjectBulkCreateResponse
+- client.projects.bulk_delete(\*\*params) -> ProjectBulkDeleteResponse
+- client.projects.bulk_update(\*\*params) -> ProjectBulkUpdateResponse
- client.projects.create_from_environment(\*\*params) -> ProjectCreateFromEnvironmentResponse
## EnvironmentClases
diff --git a/src/gitpod/resources/projects/projects.py b/src/gitpod/resources/projects/projects.py
index c3f7da6..ac2caee 100644
--- a/src/gitpod/resources/projects/projects.py
+++ b/src/gitpod/resources/projects/projects.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-from typing import Optional
+from typing import Iterable, Optional
import httpx
@@ -12,9 +12,12 @@
project_delete_params,
project_update_params,
project_retrieve_params,
+ project_bulk_create_params,
+ project_bulk_delete_params,
+ project_bulk_update_params,
project_create_from_environment_params,
)
-from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
from ..._utils import maybe_transform, async_maybe_transform
from .policies import (
PoliciesResource,
@@ -47,6 +50,9 @@
from ...types.project_update_response import ProjectUpdateResponse
from ...types.project_retrieve_response import ProjectRetrieveResponse
from ...types.recommended_editors_param import RecommendedEditorsParam
+from ...types.project_bulk_create_response import ProjectBulkCreateResponse
+from ...types.project_bulk_delete_response import ProjectBulkDeleteResponse
+from ...types.project_bulk_update_response import ProjectBulkUpdateResponse
from ...types.environment_initializer_param import EnvironmentInitializerParam
from ...types.project_prebuild_configuration_param import ProjectPrebuildConfigurationParam
from ...types.project_create_from_environment_response import ProjectCreateFromEnvironmentResponse
@@ -473,6 +479,172 @@ def delete(
cast_to=object,
)
+ def bulk_create(
+ self,
+ *,
+ projects: Iterable[project_bulk_create_params.Project] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ProjectBulkCreateResponse:
+ """
+ Creates multiple projects in a single request.
+
+ Use this method to:
+
+ - Onboard multiple repositories at once
+ - Import a batch of projects during initial setup
+
+ Returns successfully created projects and details about any failures. Each
+ project in the request is processed independently — partial success is possible.
+
+ ### Examples
+
+ - Create multiple projects:
+
+ Creates several projects in one request.
+
+ ```yaml
+ projects:
+ - name: "Frontend"
+ initializer:
+ specs:
+ - git:
+ remoteUri: "https://github.com/org/frontend"
+ - name: "Backend"
+ initializer:
+ specs:
+ - git:
+ remoteUri: "https://github.com/org/backend"
+ ```
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/gitpod.v1.ProjectService/CreateProjects",
+ body=maybe_transform({"projects": projects}, project_bulk_create_params.ProjectBulkCreateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ProjectBulkCreateResponse,
+ )
+
+ def bulk_delete(
+ self,
+ *,
+ project_ids: SequenceNotStr[str] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ProjectBulkDeleteResponse:
+ """
+ Deletes multiple projects in a single request.
+
+ Use this method to:
+
+ - Remove multiple unused projects at once
+ - Clean up projects in batch
+
+ Returns successfully deleted project IDs and details about any failures. Each
+ project in the request is processed independently — partial success is possible.
+
+ ### Examples
+
+ - Delete multiple projects:
+
+ Permanently removes several projects in one request.
+
+ ```yaml
+ projectIds:
+ - "b0e12f6c-4c67-429d-a4a6-d9838b5da047"
+ - "c1f23g7d-5d78-430e-b5b7-e0949c6eb158"
+ ```
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/gitpod.v1.ProjectService/DeleteProjects",
+ body=maybe_transform({"project_ids": project_ids}, project_bulk_delete_params.ProjectBulkDeleteParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ProjectBulkDeleteResponse,
+ )
+
+ def bulk_update(
+ self,
+ *,
+ projects: Iterable[project_bulk_update_params.Project] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ProjectBulkUpdateResponse:
+ """
+ Updates multiple projects in a single request.
+
+ Use this method to:
+
+ - Modify settings across multiple projects at once
+ - Apply configuration changes in batch
+
+ Returns successfully updated projects and details about any failures. Each
+ project in the request is processed independently — partial success is possible.
+
+ ### Examples
+
+ - Update multiple projects:
+
+ Updates several projects in one request.
+
+ ```yaml
+ projects:
+ - projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047"
+ name: "Updated Frontend"
+ - projectId: "c1f23g7d-5d78-430e-b5b7-e0949c6eb158"
+ name: "Updated Backend"
+ ```
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/gitpod.v1.ProjectService/UpdateProjects",
+ body=maybe_transform({"projects": projects}, project_bulk_update_params.ProjectBulkUpdateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ProjectBulkUpdateResponse,
+ )
+
def create_from_environment(
self,
*,
@@ -951,6 +1123,178 @@ async def delete(
cast_to=object,
)
+ async def bulk_create(
+ self,
+ *,
+ projects: Iterable[project_bulk_create_params.Project] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ProjectBulkCreateResponse:
+ """
+ Creates multiple projects in a single request.
+
+ Use this method to:
+
+ - Onboard multiple repositories at once
+ - Import a batch of projects during initial setup
+
+ Returns successfully created projects and details about any failures. Each
+ project in the request is processed independently — partial success is possible.
+
+ ### Examples
+
+ - Create multiple projects:
+
+ Creates several projects in one request.
+
+ ```yaml
+ projects:
+ - name: "Frontend"
+ initializer:
+ specs:
+ - git:
+ remoteUri: "https://github.com/org/frontend"
+ - name: "Backend"
+ initializer:
+ specs:
+ - git:
+ remoteUri: "https://github.com/org/backend"
+ ```
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/gitpod.v1.ProjectService/CreateProjects",
+ body=await async_maybe_transform(
+ {"projects": projects}, project_bulk_create_params.ProjectBulkCreateParams
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ProjectBulkCreateResponse,
+ )
+
+ async def bulk_delete(
+ self,
+ *,
+ project_ids: SequenceNotStr[str] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ProjectBulkDeleteResponse:
+ """
+ Deletes multiple projects in a single request.
+
+ Use this method to:
+
+ - Remove multiple unused projects at once
+ - Clean up projects in batch
+
+ Returns successfully deleted project IDs and details about any failures. Each
+ project in the request is processed independently — partial success is possible.
+
+ ### Examples
+
+ - Delete multiple projects:
+
+ Permanently removes several projects in one request.
+
+ ```yaml
+ projectIds:
+ - "b0e12f6c-4c67-429d-a4a6-d9838b5da047"
+ - "c1f23g7d-5d78-430e-b5b7-e0949c6eb158"
+ ```
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/gitpod.v1.ProjectService/DeleteProjects",
+ body=await async_maybe_transform(
+ {"project_ids": project_ids}, project_bulk_delete_params.ProjectBulkDeleteParams
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ProjectBulkDeleteResponse,
+ )
+
+ async def bulk_update(
+ self,
+ *,
+ projects: Iterable[project_bulk_update_params.Project] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ProjectBulkUpdateResponse:
+ """
+ Updates multiple projects in a single request.
+
+ Use this method to:
+
+ - Modify settings across multiple projects at once
+ - Apply configuration changes in batch
+
+ Returns successfully updated projects and details about any failures. Each
+ project in the request is processed independently — partial success is possible.
+
+ ### Examples
+
+ - Update multiple projects:
+
+ Updates several projects in one request.
+
+ ```yaml
+ projects:
+ - projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047"
+ name: "Updated Frontend"
+ - projectId: "c1f23g7d-5d78-430e-b5b7-e0949c6eb158"
+ name: "Updated Backend"
+ ```
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/gitpod.v1.ProjectService/UpdateProjects",
+ body=await async_maybe_transform(
+ {"projects": projects}, project_bulk_update_params.ProjectBulkUpdateParams
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ProjectBulkUpdateResponse,
+ )
+
async def create_from_environment(
self,
*,
@@ -1029,6 +1373,15 @@ def __init__(self, projects: ProjectsResource) -> None:
self.delete = to_raw_response_wrapper(
projects.delete,
)
+ self.bulk_create = to_raw_response_wrapper(
+ projects.bulk_create,
+ )
+ self.bulk_delete = to_raw_response_wrapper(
+ projects.bulk_delete,
+ )
+ self.bulk_update = to_raw_response_wrapper(
+ projects.bulk_update,
+ )
self.create_from_environment = to_raw_response_wrapper(
projects.create_from_environment,
)
@@ -1061,6 +1414,15 @@ def __init__(self, projects: AsyncProjectsResource) -> None:
self.delete = async_to_raw_response_wrapper(
projects.delete,
)
+ self.bulk_create = async_to_raw_response_wrapper(
+ projects.bulk_create,
+ )
+ self.bulk_delete = async_to_raw_response_wrapper(
+ projects.bulk_delete,
+ )
+ self.bulk_update = async_to_raw_response_wrapper(
+ projects.bulk_update,
+ )
self.create_from_environment = async_to_raw_response_wrapper(
projects.create_from_environment,
)
@@ -1093,6 +1455,15 @@ def __init__(self, projects: ProjectsResource) -> None:
self.delete = to_streamed_response_wrapper(
projects.delete,
)
+ self.bulk_create = to_streamed_response_wrapper(
+ projects.bulk_create,
+ )
+ self.bulk_delete = to_streamed_response_wrapper(
+ projects.bulk_delete,
+ )
+ self.bulk_update = to_streamed_response_wrapper(
+ projects.bulk_update,
+ )
self.create_from_environment = to_streamed_response_wrapper(
projects.create_from_environment,
)
@@ -1125,6 +1496,15 @@ def __init__(self, projects: AsyncProjectsResource) -> None:
self.delete = async_to_streamed_response_wrapper(
projects.delete,
)
+ self.bulk_create = async_to_streamed_response_wrapper(
+ projects.bulk_create,
+ )
+ self.bulk_delete = async_to_streamed_response_wrapper(
+ projects.bulk_delete,
+ )
+ self.bulk_update = async_to_streamed_response_wrapper(
+ projects.bulk_update,
+ )
self.create_from_environment = async_to_streamed_response_wrapper(
projects.create_from_environment,
)
diff --git a/src/gitpod/types/__init__.py b/src/gitpod/types/__init__.py
index b6f524e..05178ab 100644
--- a/src/gitpod/types/__init__.py
+++ b/src/gitpod/types/__init__.py
@@ -172,6 +172,9 @@
from .organization_join_response import OrganizationJoinResponse as OrganizationJoinResponse
from .organization_update_params import OrganizationUpdateParams as OrganizationUpdateParams
from .prebuild_retrieve_response import PrebuildRetrieveResponse as PrebuildRetrieveResponse
+from .project_bulk_create_params import ProjectBulkCreateParams as ProjectBulkCreateParams
+from .project_bulk_delete_params import ProjectBulkDeleteParams as ProjectBulkDeleteParams
+from .project_bulk_update_params import ProjectBulkUpdateParams as ProjectBulkUpdateParams
from .runner_configuration_param import RunnerConfigurationParam as RunnerConfigurationParam
from .secret_update_value_params import SecretUpdateValueParams as SecretUpdateValueParams
from .agent_stop_execution_params import AgentStopExecutionParams as AgentStopExecutionParams
@@ -192,6 +195,9 @@
from .organization_retrieve_params import OrganizationRetrieveParams as OrganizationRetrieveParams
from .organization_set_role_params import OrganizationSetRoleParams as OrganizationSetRoleParams
from .organization_update_response import OrganizationUpdateResponse as OrganizationUpdateResponse
+from .project_bulk_create_response import ProjectBulkCreateResponse as ProjectBulkCreateResponse
+from .project_bulk_delete_response import ProjectBulkDeleteResponse as ProjectBulkDeleteResponse
+from .project_bulk_update_response import ProjectBulkUpdateResponse as ProjectBulkUpdateResponse
from .agent_delete_execution_params import AgentDeleteExecutionParams as AgentDeleteExecutionParams
from .environment_initializer_param import EnvironmentInitializerParam as EnvironmentInitializerParam
from .environment_retrieve_response import EnvironmentRetrieveResponse as EnvironmentRetrieveResponse
diff --git a/src/gitpod/types/project_bulk_create_params.py b/src/gitpod/types/project_bulk_create_params.py
new file mode 100644
index 0000000..5a7eea4
--- /dev/null
+++ b/src/gitpod/types/project_bulk_create_params.py
@@ -0,0 +1,55 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Iterable
+from typing_extensions import Required, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+from .environment_initializer_param import EnvironmentInitializerParam
+from .project_prebuild_configuration_param import ProjectPrebuildConfigurationParam
+
+__all__ = ["ProjectBulkCreateParams", "Project"]
+
+
+class ProjectBulkCreateParams(TypedDict, total=False):
+ projects: Iterable[Project]
+
+
+class Project(TypedDict, total=False):
+ initializer: Required[EnvironmentInitializerParam]
+ """initializer is the content initializer"""
+
+ automations_file_path: Annotated[str, PropertyInfo(alias="automationsFilePath")]
+ """
+ automations_file_path is the path to the automations file relative to the repo
+ root path must not be absolute (start with a /):
+
+ ```
+ this.matches('^$|^[^/].*')
+ ```
+ """
+
+ devcontainer_file_path: Annotated[str, PropertyInfo(alias="devcontainerFilePath")]
+ """
+ devcontainer_file_path is the path to the devcontainer file relative to the repo
+ root path must not be absolute (start with a /):
+
+ ```
+ this.matches('^$|^[^/].*')
+ ```
+ """
+
+ name: str
+
+ prebuild_configuration: Annotated[ProjectPrebuildConfigurationParam, PropertyInfo(alias="prebuildConfiguration")]
+ """
+ prebuild_configuration defines how prebuilds are created for this project. If
+ not set, prebuilds are disabled for the project.
+ """
+
+ technical_description: Annotated[str, PropertyInfo(alias="technicalDescription")]
+ """
+ technical_description is a detailed technical description of the project This
+ field is not returned by default in GetProject or ListProjects responses 8KB max
+ """
diff --git a/src/gitpod/types/project_bulk_create_response.py b/src/gitpod/types/project_bulk_create_response.py
new file mode 100644
index 0000000..9da4397
--- /dev/null
+++ b/src/gitpod/types/project_bulk_create_response.py
@@ -0,0 +1,29 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from pydantic import Field as FieldInfo
+
+from .project import Project
+from .._models import BaseModel
+
+__all__ = ["ProjectBulkCreateResponse", "FailedProject"]
+
+
+class FailedProject(BaseModel):
+ error: Optional[str] = None
+ """error describes why the project creation failed"""
+
+ index: Optional[int] = None
+ """index is the position in the request array (0-based)"""
+
+ name: Optional[str] = None
+ """name is the project name that failed"""
+
+
+class ProjectBulkCreateResponse(BaseModel):
+ created_projects: Optional[List[Project]] = FieldInfo(alias="createdProjects", default=None)
+ """created_projects contains the successfully created projects"""
+
+ failed_projects: Optional[List[FailedProject]] = FieldInfo(alias="failedProjects", default=None)
+ """failed_projects contains details about projects that failed to create"""
diff --git a/src/gitpod/types/project_bulk_delete_params.py b/src/gitpod/types/project_bulk_delete_params.py
new file mode 100644
index 0000000..9a28eff
--- /dev/null
+++ b/src/gitpod/types/project_bulk_delete_params.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from .._types import SequenceNotStr
+from .._utils import PropertyInfo
+
+__all__ = ["ProjectBulkDeleteParams"]
+
+
+class ProjectBulkDeleteParams(TypedDict, total=False):
+ project_ids: Annotated[SequenceNotStr[str], PropertyInfo(alias="projectIds")]
diff --git a/src/gitpod/types/project_bulk_delete_response.py b/src/gitpod/types/project_bulk_delete_response.py
new file mode 100644
index 0000000..f419601
--- /dev/null
+++ b/src/gitpod/types/project_bulk_delete_response.py
@@ -0,0 +1,28 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["ProjectBulkDeleteResponse", "FailedProject"]
+
+
+class FailedProject(BaseModel):
+ error: Optional[str] = None
+ """error describes why the project deletion failed"""
+
+ index: Optional[int] = None
+ """index is the position in the request array (0-based)"""
+
+ project_id: Optional[str] = FieldInfo(alias="projectId", default=None)
+ """project_id is the project ID that failed"""
+
+
+class ProjectBulkDeleteResponse(BaseModel):
+ deleted_project_ids: Optional[List[str]] = FieldInfo(alias="deletedProjectIds", default=None)
+ """deleted_project_ids contains the IDs of successfully deleted projects"""
+
+ failed_projects: Optional[List[FailedProject]] = FieldInfo(alias="failedProjects", default=None)
+ """failed_projects contains details about projects that failed to delete"""
diff --git a/src/gitpod/types/project_bulk_update_params.py b/src/gitpod/types/project_bulk_update_params.py
new file mode 100644
index 0000000..255cb11
--- /dev/null
+++ b/src/gitpod/types/project_bulk_update_params.py
@@ -0,0 +1,69 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Iterable, Optional
+from typing_extensions import Annotated, TypedDict
+
+from .._utils import PropertyInfo
+from .recommended_editors_param import RecommendedEditorsParam
+from .environment_initializer_param import EnvironmentInitializerParam
+from .project_prebuild_configuration_param import ProjectPrebuildConfigurationParam
+
+__all__ = ["ProjectBulkUpdateParams", "Project"]
+
+
+class ProjectBulkUpdateParams(TypedDict, total=False):
+ projects: Iterable[Project]
+
+
+class Project(TypedDict, total=False):
+ automations_file_path: Annotated[Optional[str], PropertyInfo(alias="automationsFilePath")]
+ """
+ automations_file_path is the path to the automations file relative to the repo
+ root path must not be absolute (start with a /):
+
+ ```
+ this.matches('^$|^[^/].*')
+ ```
+ """
+
+ devcontainer_file_path: Annotated[Optional[str], PropertyInfo(alias="devcontainerFilePath")]
+ """
+ devcontainer_file_path is the path to the devcontainer file relative to the repo
+ root path must not be absolute (start with a /):
+
+ ```
+ this.matches('^$|^[^/].*')
+ ```
+ """
+
+ initializer: Optional[EnvironmentInitializerParam]
+ """initializer is the content initializer"""
+
+ name: Optional[str]
+
+ prebuild_configuration: Annotated[
+ Optional[ProjectPrebuildConfigurationParam], PropertyInfo(alias="prebuildConfiguration")
+ ]
+ """
+ prebuild_configuration defines how prebuilds are created for this project. If
+ not provided, the existing prebuild configuration is not modified. To disable
+ prebuilds, set enabled to false.
+ """
+
+ project_id: Annotated[str, PropertyInfo(alias="projectId")]
+ """project_id specifies the project identifier"""
+
+ recommended_editors: Annotated[Optional[RecommendedEditorsParam], PropertyInfo(alias="recommendedEditors")]
+ """
+ recommended_editors specifies the editors recommended for this project. If not
+ provided, the existing recommended editors are not modified. To clear all
+ recommended editors, set to an empty RecommendedEditors message.
+ """
+
+ technical_description: Annotated[Optional[str], PropertyInfo(alias="technicalDescription")]
+ """
+ technical_description is a detailed technical description of the project This
+ field is not returned by default in GetProject or ListProjects responses 8KB max
+ """
diff --git a/src/gitpod/types/project_bulk_update_response.py b/src/gitpod/types/project_bulk_update_response.py
new file mode 100644
index 0000000..c8a3f26
--- /dev/null
+++ b/src/gitpod/types/project_bulk_update_response.py
@@ -0,0 +1,29 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from pydantic import Field as FieldInfo
+
+from .project import Project
+from .._models import BaseModel
+
+__all__ = ["ProjectBulkUpdateResponse", "FailedProject"]
+
+
+class FailedProject(BaseModel):
+ error: Optional[str] = None
+ """error describes why the project update failed"""
+
+ index: Optional[int] = None
+ """index is the position in the request array (0-based)"""
+
+ project_id: Optional[str] = FieldInfo(alias="projectId", default=None)
+ """project_id is the project ID that failed"""
+
+
+class ProjectBulkUpdateResponse(BaseModel):
+ failed_projects: Optional[List[FailedProject]] = FieldInfo(alias="failedProjects", default=None)
+ """failed_projects contains details about projects that failed to update"""
+
+ updated_projects: Optional[List[Project]] = FieldInfo(alias="updatedProjects", default=None)
+ """updated_projects contains the successfully updated projects"""
diff --git a/tests/api_resources/test_projects.py b/tests/api_resources/test_projects.py
index 8e3985a..b51a14b 100644
--- a/tests/api_resources/test_projects.py
+++ b/tests/api_resources/test_projects.py
@@ -14,6 +14,9 @@
ProjectCreateResponse,
ProjectUpdateResponse,
ProjectRetrieveResponse,
+ ProjectBulkCreateResponse,
+ ProjectBulkDeleteResponse,
+ ProjectBulkUpdateResponse,
ProjectCreateFromEnvironmentResponse,
)
from gitpod.pagination import SyncProjectsPage, AsyncProjectsPage
@@ -279,6 +282,244 @@ def test_streaming_response_delete(self, client: Gitpod) -> None:
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_bulk_create(self, client: Gitpod) -> None:
+ project = client.projects.bulk_create()
+ assert_matches_type(ProjectBulkCreateResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_bulk_create_with_all_params(self, client: Gitpod) -> None:
+ project = client.projects.bulk_create(
+ projects=[
+ {
+ "initializer": {
+ "specs": [
+ {
+ "context_url": {"url": "https://example.com"},
+ "git": {
+ "checkout_location": "checkoutLocation",
+ "clone_target": "cloneTarget",
+ "remote_uri": "https://github.com/org/frontend",
+ "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED",
+ "upstream_remote_uri": "upstreamRemoteUri",
+ },
+ }
+ ]
+ },
+ "automations_file_path": "automationsFilePath",
+ "devcontainer_file_path": "devcontainerFilePath",
+ "name": "Frontend",
+ "prebuild_configuration": {
+ "enabled": True,
+ "enable_jetbrains_warmup": True,
+ "environment_class_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
+ "executor": {
+ "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ "principal": "PRINCIPAL_UNSPECIFIED",
+ },
+ "timeout": "+9125115.360s",
+ "trigger": {"daily_schedule": {"hour_utc": 23}},
+ },
+ "technical_description": "technicalDescription",
+ },
+ {
+ "initializer": {
+ "specs": [
+ {
+ "context_url": {"url": "https://example.com"},
+ "git": {
+ "checkout_location": "checkoutLocation",
+ "clone_target": "cloneTarget",
+ "remote_uri": "https://github.com/org/backend",
+ "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED",
+ "upstream_remote_uri": "upstreamRemoteUri",
+ },
+ }
+ ]
+ },
+ "automations_file_path": "automationsFilePath",
+ "devcontainer_file_path": "devcontainerFilePath",
+ "name": "Backend",
+ "prebuild_configuration": {
+ "enabled": True,
+ "enable_jetbrains_warmup": True,
+ "environment_class_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
+ "executor": {
+ "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ "principal": "PRINCIPAL_UNSPECIFIED",
+ },
+ "timeout": "+9125115.360s",
+ "trigger": {"daily_schedule": {"hour_utc": 23}},
+ },
+ "technical_description": "technicalDescription",
+ },
+ ],
+ )
+ assert_matches_type(ProjectBulkCreateResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_bulk_create(self, client: Gitpod) -> None:
+ response = client.projects.with_raw_response.bulk_create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ project = response.parse()
+ assert_matches_type(ProjectBulkCreateResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_bulk_create(self, client: Gitpod) -> None:
+ with client.projects.with_streaming_response.bulk_create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ project = response.parse()
+ assert_matches_type(ProjectBulkCreateResponse, project, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_bulk_delete(self, client: Gitpod) -> None:
+ project = client.projects.bulk_delete()
+ assert_matches_type(ProjectBulkDeleteResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_bulk_delete_with_all_params(self, client: Gitpod) -> None:
+ project = client.projects.bulk_delete(
+ project_ids=["b0e12f6c-4c67-429d-a4a6-d9838b5da047", "c1f23g7d-5d78-430e-b5b7-e0949c6eb158"],
+ )
+ assert_matches_type(ProjectBulkDeleteResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_bulk_delete(self, client: Gitpod) -> None:
+ response = client.projects.with_raw_response.bulk_delete()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ project = response.parse()
+ assert_matches_type(ProjectBulkDeleteResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_bulk_delete(self, client: Gitpod) -> None:
+ with client.projects.with_streaming_response.bulk_delete() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ project = response.parse()
+ assert_matches_type(ProjectBulkDeleteResponse, project, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_bulk_update(self, client: Gitpod) -> None:
+ project = client.projects.bulk_update()
+ assert_matches_type(ProjectBulkUpdateResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_bulk_update_with_all_params(self, client: Gitpod) -> None:
+ project = client.projects.bulk_update(
+ projects=[
+ {
+ "automations_file_path": "automationsFilePath",
+ "devcontainer_file_path": "devcontainerFilePath",
+ "initializer": {
+ "specs": [
+ {
+ "context_url": {"url": "https://example.com"},
+ "git": {
+ "checkout_location": "checkoutLocation",
+ "clone_target": "cloneTarget",
+ "remote_uri": "remoteUri",
+ "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED",
+ "upstream_remote_uri": "upstreamRemoteUri",
+ },
+ }
+ ]
+ },
+ "name": "Updated Frontend",
+ "prebuild_configuration": {
+ "enabled": True,
+ "enable_jetbrains_warmup": True,
+ "environment_class_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
+ "executor": {
+ "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ "principal": "PRINCIPAL_UNSPECIFIED",
+ },
+ "timeout": "+9125115.360s",
+ "trigger": {"daily_schedule": {"hour_utc": 23}},
+ },
+ "project_id": "b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ "recommended_editors": {"editors": {"foo": {"versions": ["string"]}}},
+ "technical_description": "technicalDescription",
+ },
+ {
+ "automations_file_path": "automationsFilePath",
+ "devcontainer_file_path": "devcontainerFilePath",
+ "initializer": {
+ "specs": [
+ {
+ "context_url": {"url": "https://example.com"},
+ "git": {
+ "checkout_location": "checkoutLocation",
+ "clone_target": "cloneTarget",
+ "remote_uri": "remoteUri",
+ "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED",
+ "upstream_remote_uri": "upstreamRemoteUri",
+ },
+ }
+ ]
+ },
+ "name": "Updated Backend",
+ "prebuild_configuration": {
+ "enabled": True,
+ "enable_jetbrains_warmup": True,
+ "environment_class_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
+ "executor": {
+ "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ "principal": "PRINCIPAL_UNSPECIFIED",
+ },
+ "timeout": "+9125115.360s",
+ "trigger": {"daily_schedule": {"hour_utc": 23}},
+ },
+ "project_id": "c1f23g7d-5d78-430e-b5b7-e0949c6eb158",
+ "recommended_editors": {"editors": {"foo": {"versions": ["string"]}}},
+ "technical_description": "technicalDescription",
+ },
+ ],
+ )
+ assert_matches_type(ProjectBulkUpdateResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_bulk_update(self, client: Gitpod) -> None:
+ response = client.projects.with_raw_response.bulk_update()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ project = response.parse()
+ assert_matches_type(ProjectBulkUpdateResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_bulk_update(self, client: Gitpod) -> None:
+ with client.projects.with_streaming_response.bulk_update() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ project = response.parse()
+ assert_matches_type(ProjectBulkUpdateResponse, project, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_create_from_environment(self, client: Gitpod) -> None:
@@ -577,6 +818,244 @@ async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> Non
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_bulk_create(self, async_client: AsyncGitpod) -> None:
+ project = await async_client.projects.bulk_create()
+ assert_matches_type(ProjectBulkCreateResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_bulk_create_with_all_params(self, async_client: AsyncGitpod) -> None:
+ project = await async_client.projects.bulk_create(
+ projects=[
+ {
+ "initializer": {
+ "specs": [
+ {
+ "context_url": {"url": "https://example.com"},
+ "git": {
+ "checkout_location": "checkoutLocation",
+ "clone_target": "cloneTarget",
+ "remote_uri": "https://github.com/org/frontend",
+ "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED",
+ "upstream_remote_uri": "upstreamRemoteUri",
+ },
+ }
+ ]
+ },
+ "automations_file_path": "automationsFilePath",
+ "devcontainer_file_path": "devcontainerFilePath",
+ "name": "Frontend",
+ "prebuild_configuration": {
+ "enabled": True,
+ "enable_jetbrains_warmup": True,
+ "environment_class_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
+ "executor": {
+ "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ "principal": "PRINCIPAL_UNSPECIFIED",
+ },
+ "timeout": "+9125115.360s",
+ "trigger": {"daily_schedule": {"hour_utc": 23}},
+ },
+ "technical_description": "technicalDescription",
+ },
+ {
+ "initializer": {
+ "specs": [
+ {
+ "context_url": {"url": "https://example.com"},
+ "git": {
+ "checkout_location": "checkoutLocation",
+ "clone_target": "cloneTarget",
+ "remote_uri": "https://github.com/org/backend",
+ "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED",
+ "upstream_remote_uri": "upstreamRemoteUri",
+ },
+ }
+ ]
+ },
+ "automations_file_path": "automationsFilePath",
+ "devcontainer_file_path": "devcontainerFilePath",
+ "name": "Backend",
+ "prebuild_configuration": {
+ "enabled": True,
+ "enable_jetbrains_warmup": True,
+ "environment_class_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
+ "executor": {
+ "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ "principal": "PRINCIPAL_UNSPECIFIED",
+ },
+ "timeout": "+9125115.360s",
+ "trigger": {"daily_schedule": {"hour_utc": 23}},
+ },
+ "technical_description": "technicalDescription",
+ },
+ ],
+ )
+ assert_matches_type(ProjectBulkCreateResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_bulk_create(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.projects.with_raw_response.bulk_create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ project = await response.parse()
+ assert_matches_type(ProjectBulkCreateResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_bulk_create(self, async_client: AsyncGitpod) -> None:
+ async with async_client.projects.with_streaming_response.bulk_create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ project = await response.parse()
+ assert_matches_type(ProjectBulkCreateResponse, project, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_bulk_delete(self, async_client: AsyncGitpod) -> None:
+ project = await async_client.projects.bulk_delete()
+ assert_matches_type(ProjectBulkDeleteResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_bulk_delete_with_all_params(self, async_client: AsyncGitpod) -> None:
+ project = await async_client.projects.bulk_delete(
+ project_ids=["b0e12f6c-4c67-429d-a4a6-d9838b5da047", "c1f23g7d-5d78-430e-b5b7-e0949c6eb158"],
+ )
+ assert_matches_type(ProjectBulkDeleteResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_bulk_delete(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.projects.with_raw_response.bulk_delete()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ project = await response.parse()
+ assert_matches_type(ProjectBulkDeleteResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_bulk_delete(self, async_client: AsyncGitpod) -> None:
+ async with async_client.projects.with_streaming_response.bulk_delete() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ project = await response.parse()
+ assert_matches_type(ProjectBulkDeleteResponse, project, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_bulk_update(self, async_client: AsyncGitpod) -> None:
+ project = await async_client.projects.bulk_update()
+ assert_matches_type(ProjectBulkUpdateResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_bulk_update_with_all_params(self, async_client: AsyncGitpod) -> None:
+ project = await async_client.projects.bulk_update(
+ projects=[
+ {
+ "automations_file_path": "automationsFilePath",
+ "devcontainer_file_path": "devcontainerFilePath",
+ "initializer": {
+ "specs": [
+ {
+ "context_url": {"url": "https://example.com"},
+ "git": {
+ "checkout_location": "checkoutLocation",
+ "clone_target": "cloneTarget",
+ "remote_uri": "remoteUri",
+ "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED",
+ "upstream_remote_uri": "upstreamRemoteUri",
+ },
+ }
+ ]
+ },
+ "name": "Updated Frontend",
+ "prebuild_configuration": {
+ "enabled": True,
+ "enable_jetbrains_warmup": True,
+ "environment_class_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
+ "executor": {
+ "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ "principal": "PRINCIPAL_UNSPECIFIED",
+ },
+ "timeout": "+9125115.360s",
+ "trigger": {"daily_schedule": {"hour_utc": 23}},
+ },
+ "project_id": "b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ "recommended_editors": {"editors": {"foo": {"versions": ["string"]}}},
+ "technical_description": "technicalDescription",
+ },
+ {
+ "automations_file_path": "automationsFilePath",
+ "devcontainer_file_path": "devcontainerFilePath",
+ "initializer": {
+ "specs": [
+ {
+ "context_url": {"url": "https://example.com"},
+ "git": {
+ "checkout_location": "checkoutLocation",
+ "clone_target": "cloneTarget",
+ "remote_uri": "remoteUri",
+ "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED",
+ "upstream_remote_uri": "upstreamRemoteUri",
+ },
+ }
+ ]
+ },
+ "name": "Updated Backend",
+ "prebuild_configuration": {
+ "enabled": True,
+ "enable_jetbrains_warmup": True,
+ "environment_class_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
+ "executor": {
+ "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ "principal": "PRINCIPAL_UNSPECIFIED",
+ },
+ "timeout": "+9125115.360s",
+ "trigger": {"daily_schedule": {"hour_utc": 23}},
+ },
+ "project_id": "c1f23g7d-5d78-430e-b5b7-e0949c6eb158",
+ "recommended_editors": {"editors": {"foo": {"versions": ["string"]}}},
+ "technical_description": "technicalDescription",
+ },
+ ],
+ )
+ assert_matches_type(ProjectBulkUpdateResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_bulk_update(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.projects.with_raw_response.bulk_update()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ project = await response.parse()
+ assert_matches_type(ProjectBulkUpdateResponse, project, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_bulk_update(self, async_client: AsyncGitpod) -> None:
+ async with async_client.projects.with_streaming_response.bulk_update() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ project = await response.parse()
+ assert_matches_type(ProjectBulkUpdateResponse, project, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_create_from_environment(self, async_client: AsyncGitpod) -> None:
From b0914882eab12f4d7a3cada905252f778ac0cfd7 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 11 Feb 2026 13:32:36 +0000
Subject: [PATCH 2/2] release: 0.9.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 8 ++++++++
pyproject.toml | 2 +-
src/gitpod/_version.py | 2 +-
4 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 6538ca9..6d78745 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.8.0"
+ ".": "0.9.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b5584ae..b73455e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## 0.9.0 (2026-02-11)
+
+Full Changelog: [v0.8.0...v0.9.0](https://github.com/gitpod-io/gitpod-sdk-python/compare/v0.8.0...v0.9.0)
+
+### Features
+
+* **api:** add bulk_create/bulk_delete/bulk_update methods to projects ([255bd90](https://github.com/gitpod-io/gitpod-sdk-python/commit/255bd90fadb010fbc75f2b38ec1e79b219cf06ef))
+
## 0.8.0 (2026-02-11)
Full Changelog: [v0.7.0...v0.8.0](https://github.com/gitpod-io/gitpod-sdk-python/compare/v0.7.0...v0.8.0)
diff --git a/pyproject.toml b/pyproject.toml
index 6e89f84..bdf6bae 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "gitpod-sdk"
-version = "0.8.0"
+version = "0.9.0"
description = "The official Python library for the gitpod API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/gitpod/_version.py b/src/gitpod/_version.py
index 58df503..b6b19f6 100644
--- a/src/gitpod/_version.py
+++ b/src/gitpod/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "gitpod"
-__version__ = "0.8.0" # x-release-please-version
+__version__ = "0.9.0" # x-release-please-version