diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 4208b5c..1b77f50 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.6.0"
+ ".": "0.7.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index e42a5ca..d64cbf2 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-3935e467f9c15925790aada293124db82bb5d6840eeac52d81fbac6a9b0fd154.yml
-openapi_spec_hash: b417d7f10ea430216e9b70e4468a3212
-config_hash: d3267594264bfb76d2ee7e881d5f8a5a
+configured_endpoints: 161
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-baa13045a9492d958fc06db0dcee2fd99972435f8b9a707831cf4da8d84db194.yml
+openapi_spec_hash: 5e7adb5d5cdf924eb7c0e4ddf1b81260
+config_hash: d930f7e17a525d153b810339251607b7
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e6b615d..adb2ba7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,23 @@
# Changelog
+## 0.7.0 (2026-01-16)
+
+Full Changelog: [v0.6.0...v0.7.0](https://github.com/gitpod-io/gitpod-sdk-python/compare/v0.6.0...v0.7.0)
+
+### Features
+
+* [api] sorting for `ListMembers` ([838e74c](https://github.com/gitpod-io/gitpod-sdk-python/commit/838e74c4da4b57590a6dd0af19bdd20faf7d2805))
+* [backend] Introduce role and member status filtering for `ListMembers` ([34fb372](https://github.com/gitpod-io/gitpod-sdk-python/commit/34fb372aef655ae57fc99d5b37e152c75d831af5))
+* **api:** add draft and state fields to PullRequest proto ([e0023da](https://github.com/gitpod-io/gitpod-sdk-python/commit/e0023da5a30344c2fc87ebce55e26101c4ad40b5))
+* **api:** add ListSCMOrganizations endpoint ([9c8f7ea](https://github.com/gitpod-io/gitpod-sdk-python/commit/9c8f7eadd38bc0326ecf1be48706003fa258257c))
+* **api:** add search, creator, and status filters to ListWorkflows ([ddd18c0](https://github.com/gitpod-io/gitpod-sdk-python/commit/ddd18c09beb0f24e076818783d2dae09ca9b9f8b))
+* **api:** improve SearchRepositories pagination with next_page and total_count ([2847a10](https://github.com/gitpod-io/gitpod-sdk-python/commit/2847a10e6cbb09be83b012e8a6fcabd32f49e019))
+* **client:** add support for binary request streaming ([be5a823](https://github.com/gitpod-io/gitpod-sdk-python/commit/be5a8235224ff1ecf25464e716191fbf3c7c7fb1))
+* **dashboard:** show tier badge in org selector ([89fd8fe](https://github.com/gitpod-io/gitpod-sdk-python/commit/89fd8fef7f9de200e4aecd563c965d4209427052))
+* Define SCIMConfiguration database schema ([03bd185](https://github.com/gitpod-io/gitpod-sdk-python/commit/03bd1858ec2aefbd4c20a71c206135c441afa99c))
+* move agent mode from Spec to Status, add AgentModeChange signals ([a55115b](https://github.com/gitpod-io/gitpod-sdk-python/commit/a55115ba054078dcb689222cc150b2b1f56077bf))
+* **secrets:** add ServiceAccountSecret entity with full support ([30e17c5](https://github.com/gitpod-io/gitpod-sdk-python/commit/30e17c55b991286527f64c8857b04dd9b5a2ba7b))
+
## 0.6.0 (2026-01-09)
Full Changelog: [v0.5.2...v0.6.0](https://github.com/gitpod-io/gitpod-sdk-python/compare/v0.5.2...v0.6.0)
diff --git a/api.md b/api.md
index 29f93a4..ed7817a 100644
--- a/api.md
+++ b/api.md
@@ -10,11 +10,13 @@ from gitpod.types import (
FieldValue,
Gateway,
OrganizationRole,
+ OrganizationTier,
Principal,
ProjectEnvironmentClass,
ResourceType,
RunsOn,
SecretRef,
+ State,
Subject,
Task,
TaskExecution,
@@ -337,7 +339,6 @@ from gitpod.types import (
InviteDomains,
Organization,
OrganizationMember,
- OrganizationTier,
OrganizationCreateResponse,
OrganizationRetrieveResponse,
OrganizationUpdateResponse,
@@ -567,6 +568,7 @@ from gitpod.types import (
RunnerCheckAuthenticationForHostResponse,
RunnerCreateLogsTokenResponse,
RunnerCreateRunnerTokenResponse,
+ RunnerListScmOrganizationsResponse,
RunnerParseContextURLResponse,
RunnerSearchRepositoriesResponse,
)
@@ -582,6 +584,7 @@ Methods:
- client.runners.check_authentication_for_host(\*\*params) -> RunnerCheckAuthenticationForHostResponse
- client.runners.create_logs_token(\*\*params) -> RunnerCreateLogsTokenResponse
- client.runners.create_runner_token(\*\*params) -> RunnerCreateRunnerTokenResponse
+- client.runners.list_scm_organizations(\*\*params) -> RunnerListScmOrganizationsResponse
- client.runners.parse_context_url(\*\*params) -> RunnerParseContextURLResponse
- client.runners.search_repositories(\*\*params) -> RunnerSearchRepositoriesResponse
diff --git a/pyproject.toml b/pyproject.toml
index 6136eaf..4f4d826 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "gitpod-sdk"
-version = "0.6.0"
+version = "0.7.0"
description = "The official Python library for the gitpod API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/gitpod/_base_client.py b/src/gitpod/_base_client.py
index 1613979..e6ccedf 100644
--- a/src/gitpod/_base_client.py
+++ b/src/gitpod/_base_client.py
@@ -9,6 +9,7 @@
import inspect
import logging
import platform
+import warnings
import email.utils
from types import TracebackType
from random import random
@@ -51,9 +52,11 @@
ResponseT,
AnyMapping,
PostParser,
+ BinaryTypes,
RequestFiles,
HttpxSendArgs,
RequestOptions,
+ AsyncBinaryTypes,
HttpxRequestFiles,
ModelBuilderProtocol,
not_given,
@@ -477,8 +480,19 @@ def _build_request(
retries_taken: int = 0,
) -> httpx.Request:
if log.isEnabledFor(logging.DEBUG):
- log.debug("Request options: %s", model_dump(options, exclude_unset=True))
-
+ log.debug(
+ "Request options: %s",
+ model_dump(
+ options,
+ exclude_unset=True,
+ # Pydantic v1 can't dump every type we support in content, so we exclude it for now.
+ exclude={
+ "content",
+ }
+ if PYDANTIC_V1
+ else {},
+ ),
+ )
kwargs: dict[str, Any] = {}
json_data = options.json_data
@@ -532,7 +546,13 @@ def _build_request(
is_body_allowed = options.method.lower() != "get"
if is_body_allowed:
- if isinstance(json_data, bytes):
+ if options.content is not None and json_data is not None:
+ raise TypeError("Passing both `content` and `json_data` is not supported")
+ if options.content is not None and files is not None:
+ raise TypeError("Passing both `content` and `files` is not supported")
+ if options.content is not None:
+ kwargs["content"] = options.content
+ elif isinstance(json_data, bytes):
kwargs["content"] = json_data
else:
kwargs["json"] = json_data if is_given(json_data) else None
@@ -1194,6 +1214,7 @@ def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
files: RequestFiles | None = None,
stream: Literal[False] = False,
@@ -1206,6 +1227,7 @@ def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
files: RequestFiles | None = None,
stream: Literal[True],
@@ -1219,6 +1241,7 @@ def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
files: RequestFiles | None = None,
stream: bool,
@@ -1231,13 +1254,25 @@ def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
files: RequestFiles | None = None,
stream: bool = False,
stream_cls: type[_StreamT] | None = None,
) -> ResponseT | _StreamT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="post", url=path, json_data=body, files=to_httpx_files(files), **options
+ method="post", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
)
return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
@@ -1247,11 +1282,23 @@ def patch(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
) -> ResponseT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="patch", url=path, json_data=body, files=to_httpx_files(files), **options
+ method="patch", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
)
return self.request(cast_to, opts)
@@ -1261,11 +1308,23 @@ def put(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
) -> ResponseT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="put", url=path, json_data=body, files=to_httpx_files(files), **options
+ method="put", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
)
return self.request(cast_to, opts)
@@ -1275,9 +1334,19 @@ def delete(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
) -> ResponseT:
- opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options)
return self.request(cast_to, opts)
def get_api_list(
@@ -1717,6 +1786,7 @@ async def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
stream: Literal[False] = False,
@@ -1729,6 +1799,7 @@ async def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
stream: Literal[True],
@@ -1742,6 +1813,7 @@ async def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
stream: bool,
@@ -1754,13 +1826,25 @@ async def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
stream: bool = False,
stream_cls: type[_AsyncStreamT] | None = None,
) -> ResponseT | _AsyncStreamT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="post", url=path, json_data=body, files=await async_to_httpx_files(files), **options
+ method="post", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options
)
return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)
@@ -1770,11 +1854,28 @@ async def patch(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
) -> ResponseT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="patch", url=path, json_data=body, files=await async_to_httpx_files(files), **options
+ method="patch",
+ url=path,
+ json_data=body,
+ content=content,
+ files=await async_to_httpx_files(files),
+ **options,
)
return await self.request(cast_to, opts)
@@ -1784,11 +1885,23 @@ async def put(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
) -> ResponseT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="put", url=path, json_data=body, files=await async_to_httpx_files(files), **options
+ method="put", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options
)
return await self.request(cast_to, opts)
@@ -1798,9 +1911,19 @@ async def delete(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
options: RequestOptions = {},
) -> ResponseT:
- opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options)
return await self.request(cast_to, opts)
def get_api_list(
diff --git a/src/gitpod/_models.py b/src/gitpod/_models.py
index ca9500b..29070e0 100644
--- a/src/gitpod/_models.py
+++ b/src/gitpod/_models.py
@@ -3,7 +3,20 @@
import os
import inspect
import weakref
-from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast
+from typing import (
+ IO,
+ TYPE_CHECKING,
+ Any,
+ Type,
+ Union,
+ Generic,
+ TypeVar,
+ Callable,
+ Iterable,
+ Optional,
+ AsyncIterable,
+ cast,
+)
from datetime import date, datetime
from typing_extensions import (
List,
@@ -787,6 +800,7 @@ class FinalRequestOptionsInput(TypedDict, total=False):
timeout: float | Timeout | None
files: HttpxRequestFiles | None
idempotency_key: str
+ content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None]
json_data: Body
extra_json: AnyMapping
follow_redirects: bool
@@ -805,6 +819,7 @@ class FinalRequestOptions(pydantic.BaseModel):
post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven()
follow_redirects: Union[bool, None] = None
+ content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None
# It should be noted that we cannot use `json` here as that would override
# a BaseModel method in an incompatible fashion.
json_data: Union[Body, None] = None
diff --git a/src/gitpod/_types.py b/src/gitpod/_types.py
index ab7cbe2..dbebac0 100644
--- a/src/gitpod/_types.py
+++ b/src/gitpod/_types.py
@@ -13,9 +13,11 @@
Mapping,
TypeVar,
Callable,
+ Iterable,
Iterator,
Optional,
Sequence,
+ AsyncIterable,
)
from typing_extensions import (
Set,
@@ -56,6 +58,13 @@
else:
Base64FileInput = Union[IO[bytes], PathLike]
FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8.
+
+
+# Used for sending raw binary data / streaming data in request bodies
+# e.g. for file uploads without multipart encoding
+BinaryTypes = Union[bytes, bytearray, IO[bytes], Iterable[bytes]]
+AsyncBinaryTypes = Union[bytes, bytearray, IO[bytes], AsyncIterable[bytes]]
+
FileTypes = Union[
# file (or bytes)
FileContent,
diff --git a/src/gitpod/_version.py b/src/gitpod/_version.py
index 850eb95..88739dd 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.6.0" # x-release-please-version
+__version__ = "0.7.0" # x-release-please-version
diff --git a/src/gitpod/resources/organizations/organizations.py b/src/gitpod/resources/organizations/organizations.py
index c1ec57e..c9de4ae 100644
--- a/src/gitpod/resources/organizations/organizations.py
+++ b/src/gitpod/resources/organizations/organizations.py
@@ -507,6 +507,7 @@ def list_members(
page_size: int | Omit = omit,
filter: organization_list_members_params.Filter | Omit = omit,
pagination: organization_list_members_params.Pagination | Omit = omit,
+ sort: organization_list_members_params.Sort | 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,
@@ -551,6 +552,11 @@ def list_members(
pagination: pagination contains the pagination options for listing members
+ sort: sort specifies the order of results. When unspecified, the authenticated user is
+ returned first, followed by other members sorted by name ascending. When an
+ explicit sort is specified, results are sorted purely by the requested field
+ without any special handling for the authenticated user.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -567,6 +573,7 @@ def list_members(
"organization_id": organization_id,
"filter": filter,
"pagination": pagination,
+ "sort": sort,
},
organization_list_members_params.OrganizationListMembersParams,
),
@@ -1086,6 +1093,7 @@ def list_members(
page_size: int | Omit = omit,
filter: organization_list_members_params.Filter | Omit = omit,
pagination: organization_list_members_params.Pagination | Omit = omit,
+ sort: organization_list_members_params.Sort | 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,
@@ -1130,6 +1138,11 @@ def list_members(
pagination: pagination contains the pagination options for listing members
+ sort: sort specifies the order of results. When unspecified, the authenticated user is
+ returned first, followed by other members sorted by name ascending. When an
+ explicit sort is specified, results are sorted purely by the requested field
+ without any special handling for the authenticated user.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -1146,6 +1159,7 @@ def list_members(
"organization_id": organization_id,
"filter": filter,
"pagination": pagination,
+ "sort": sort,
},
organization_list_members_params.OrganizationListMembersParams,
),
diff --git a/src/gitpod/resources/runners/runners.py b/src/gitpod/resources/runners/runners.py
index 1c445f8..0ba69c1 100644
--- a/src/gitpod/resources/runners/runners.py
+++ b/src/gitpod/resources/runners/runners.py
@@ -19,6 +19,7 @@
runner_parse_context_url_params,
runner_create_runner_token_params,
runner_search_repositories_params,
+ runner_list_scm_organizations_params,
runner_check_authentication_for_host_params,
)
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -60,6 +61,7 @@
from ...types.runner_parse_context_url_response import RunnerParseContextURLResponse
from ...types.runner_create_runner_token_response import RunnerCreateRunnerTokenResponse
from ...types.runner_search_repositories_response import RunnerSearchRepositoriesResponse
+from ...types.runner_list_scm_organizations_response import RunnerListScmOrganizationsResponse
from ...types.runner_check_authentication_for_host_response import RunnerCheckAuthenticationForHostResponse
__all__ = ["RunnersResource", "AsyncRunnersResource"]
@@ -608,6 +610,75 @@ def create_runner_token(
cast_to=RunnerCreateRunnerTokenResponse,
)
+ def list_scm_organizations(
+ self,
+ *,
+ token: str | Omit = omit,
+ page_size: int | Omit = omit,
+ runner_id: str | Omit = omit,
+ scm_host: 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,
+ ) -> RunnerListScmOrganizationsResponse:
+ """
+ Lists SCM organizations the user belongs to.
+
+ Use this method to:
+
+ - Get all organizations for a user on a specific SCM host
+ - Check organization admin permissions for webhook creation
+
+ ### Examples
+
+ - List GitHub organizations:
+
+ Lists all organizations the user belongs to on GitHub.
+
+ ```yaml
+ runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ scmHost: "github.com"
+ ```
+
+ Args:
+ scm_host: The SCM host to list organizations from (e.g., "github.com", "gitlab.com")
+
+ 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.RunnerService/ListSCMOrganizations",
+ body=maybe_transform(
+ {
+ "runner_id": runner_id,
+ "scm_host": scm_host,
+ },
+ runner_list_scm_organizations_params.RunnerListScmOrganizationsParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "token": token,
+ "page_size": page_size,
+ },
+ runner_list_scm_organizations_params.RunnerListScmOrganizationsParams,
+ ),
+ ),
+ cast_to=RunnerListScmOrganizationsResponse,
+ )
+
def parse_context_url(
self,
*,
@@ -1304,6 +1375,75 @@ async def create_runner_token(
cast_to=RunnerCreateRunnerTokenResponse,
)
+ async def list_scm_organizations(
+ self,
+ *,
+ token: str | Omit = omit,
+ page_size: int | Omit = omit,
+ runner_id: str | Omit = omit,
+ scm_host: 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,
+ ) -> RunnerListScmOrganizationsResponse:
+ """
+ Lists SCM organizations the user belongs to.
+
+ Use this method to:
+
+ - Get all organizations for a user on a specific SCM host
+ - Check organization admin permissions for webhook creation
+
+ ### Examples
+
+ - List GitHub organizations:
+
+ Lists all organizations the user belongs to on GitHub.
+
+ ```yaml
+ runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ scmHost: "github.com"
+ ```
+
+ Args:
+ scm_host: The SCM host to list organizations from (e.g., "github.com", "gitlab.com")
+
+ 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.RunnerService/ListSCMOrganizations",
+ body=await async_maybe_transform(
+ {
+ "runner_id": runner_id,
+ "scm_host": scm_host,
+ },
+ runner_list_scm_organizations_params.RunnerListScmOrganizationsParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "token": token,
+ "page_size": page_size,
+ },
+ runner_list_scm_organizations_params.RunnerListScmOrganizationsParams,
+ ),
+ ),
+ cast_to=RunnerListScmOrganizationsResponse,
+ )
+
async def parse_context_url(
self,
*,
@@ -1483,6 +1623,9 @@ def __init__(self, runners: RunnersResource) -> None:
self.create_runner_token = to_raw_response_wrapper(
runners.create_runner_token,
)
+ self.list_scm_organizations = to_raw_response_wrapper(
+ runners.list_scm_organizations,
+ )
self.parse_context_url = to_raw_response_wrapper(
runners.parse_context_url,
)
@@ -1527,6 +1670,9 @@ def __init__(self, runners: AsyncRunnersResource) -> None:
self.create_runner_token = async_to_raw_response_wrapper(
runners.create_runner_token,
)
+ self.list_scm_organizations = async_to_raw_response_wrapper(
+ runners.list_scm_organizations,
+ )
self.parse_context_url = async_to_raw_response_wrapper(
runners.parse_context_url,
)
@@ -1571,6 +1717,9 @@ def __init__(self, runners: RunnersResource) -> None:
self.create_runner_token = to_streamed_response_wrapper(
runners.create_runner_token,
)
+ self.list_scm_organizations = to_streamed_response_wrapper(
+ runners.list_scm_organizations,
+ )
self.parse_context_url = to_streamed_response_wrapper(
runners.parse_context_url,
)
@@ -1615,6 +1764,9 @@ def __init__(self, runners: AsyncRunnersResource) -> None:
self.create_runner_token = async_to_streamed_response_wrapper(
runners.create_runner_token,
)
+ self.list_scm_organizations = async_to_streamed_response_wrapper(
+ runners.list_scm_organizations,
+ )
self.parse_context_url = async_to_streamed_response_wrapper(
runners.parse_context_url,
)
diff --git a/src/gitpod/types/__init__.py b/src/gitpod/types/__init__.py
index bd85a24..7306513 100644
--- a/src/gitpod/types/__init__.py
+++ b/src/gitpod/types/__init__.py
@@ -10,6 +10,7 @@
from .secret import Secret as Secret
from .shared import (
Task as Task,
+ State as State,
RunsOn as RunsOn,
Gateway as Gateway,
Subject as Subject,
@@ -24,6 +25,7 @@
TaskExecution as TaskExecution,
EnvironmentClass as EnvironmentClass,
OrganizationRole as OrganizationRole,
+ OrganizationTier as OrganizationTier,
AutomationTrigger as AutomationTrigger,
TaskExecutionSpec as TaskExecutionSpec,
TaskExecutionPhase as TaskExecutionPhase,
@@ -71,7 +73,6 @@
from .error_event_param import ErrorEventParam as ErrorEventParam
from .event_list_params import EventListParams as EventListParams
from .group_list_params import GroupListParams as GroupListParams
-from .organization_tier import OrganizationTier as OrganizationTier
from .prebuild_metadata import PrebuildMetadata as PrebuildMetadata
from .runner_capability import RunnerCapability as RunnerCapability
from .runner_spec_param import RunnerSpecParam as RunnerSpecParam
@@ -220,6 +221,7 @@
from .runner_search_repositories_response import RunnerSearchRepositoriesResponse as RunnerSearchRepositoriesResponse
from .environment_create_logs_token_params import EnvironmentCreateLogsTokenParams as EnvironmentCreateLogsTokenParams
from .project_prebuild_configuration_param import ProjectPrebuildConfigurationParam as ProjectPrebuildConfigurationParam
+from .runner_list_scm_organizations_params import RunnerListScmOrganizationsParams as RunnerListScmOrganizationsParams
from .user_get_authenticated_user_response import UserGetAuthenticatedUserResponse as UserGetAuthenticatedUserResponse
from .environment_create_from_project_params import (
EnvironmentCreateFromProjectParams as EnvironmentCreateFromProjectParams,
@@ -230,6 +232,9 @@
from .project_create_from_environment_params import (
ProjectCreateFromEnvironmentParams as ProjectCreateFromEnvironmentParams,
)
+from .runner_list_scm_organizations_response import (
+ RunnerListScmOrganizationsResponse as RunnerListScmOrganizationsResponse,
+)
from .environment_create_from_project_response import (
EnvironmentCreateFromProjectResponse as EnvironmentCreateFromProjectResponse,
)
diff --git a/src/gitpod/types/account_membership.py b/src/gitpod/types/account_membership.py
index 10f2603..6f443a8 100644
--- a/src/gitpod/types/account_membership.py
+++ b/src/gitpod/types/account_membership.py
@@ -6,6 +6,7 @@
from .._models import BaseModel
from .shared.organization_role import OrganizationRole
+from .shared.organization_tier import OrganizationTier
__all__ = ["AccountMembership"]
@@ -25,6 +26,9 @@ class AccountMembership(BaseModel):
organization_member_count: Optional[int] = FieldInfo(alias="organizationMemberCount", default=None)
"""
- organization_name is the member count of the organization the user is a member
- of
+ organization_member_count is the member count of the organization the user is a
+ member of
"""
+
+ organization_tier: Optional[OrganizationTier] = FieldInfo(alias="organizationTier", default=None)
+ """organization_tier is the tier of the organization (Free, Core, Enterprise)"""
diff --git a/src/gitpod/types/agent_code_context.py b/src/gitpod/types/agent_code_context.py
index 05c1832..ece7309 100644
--- a/src/gitpod/types/agent_code_context.py
+++ b/src/gitpod/types/agent_code_context.py
@@ -5,6 +5,7 @@
from pydantic import Field as FieldInfo
from .._models import BaseModel
+from .shared.state import State
__all__ = ["AgentCodeContext", "ContextURL", "PullRequest", "PullRequestRepository"]
@@ -40,12 +41,18 @@ class PullRequest(BaseModel):
author: Optional[str] = None
"""Author name as provided by the SCM system"""
+ draft: Optional[bool] = None
+ """Whether this is a draft pull request"""
+
from_branch: Optional[str] = FieldInfo(alias="fromBranch", default=None)
"""Source branch name (the branch being merged from)"""
repository: Optional[PullRequestRepository] = None
"""Repository information"""
+ state: Optional[State] = None
+ """Current state of the pull request"""
+
title: Optional[str] = None
"""Pull request title"""
diff --git a/src/gitpod/types/agent_code_context_param.py b/src/gitpod/types/agent_code_context_param.py
index 8080145..821f296 100644
--- a/src/gitpod/types/agent_code_context_param.py
+++ b/src/gitpod/types/agent_code_context_param.py
@@ -6,6 +6,7 @@
from typing_extensions import Annotated, TypedDict
from .._utils import PropertyInfo
+from .shared.state import State
__all__ = ["AgentCodeContextParam", "ContextURL", "PullRequest", "PullRequestRepository"]
@@ -41,12 +42,18 @@ class PullRequest(TypedDict, total=False):
author: str
"""Author name as provided by the SCM system"""
+ draft: bool
+ """Whether this is a draft pull request"""
+
from_branch: Annotated[str, PropertyInfo(alias="fromBranch")]
"""Source branch name (the branch being merged from)"""
repository: PullRequestRepository
"""Repository information"""
+ state: State
+ """Current state of the pull request"""
+
title: str
"""Pull request title"""
diff --git a/src/gitpod/types/agent_execution.py b/src/gitpod/types/agent_execution.py
index 384da90..ad11938 100644
--- a/src/gitpod/types/agent_execution.py
+++ b/src/gitpod/types/agent_execution.py
@@ -259,9 +259,6 @@ class Spec(BaseModel):
limits: Optional[SpecLimits] = None
- mode: Optional[AgentMode] = None
- """mode is the operational mode for this agent execution"""
-
session: Optional[str] = None
spec_version: Optional[str] = FieldInfo(alias="specVersion", default=None)
@@ -355,6 +352,12 @@ class Status(BaseModel):
judgement: Optional[str] = None
"""judgement is the judgement of the agent run produced by the judgement prompt."""
+ mode: Optional[AgentMode] = None
+ """
+ mode is the current operational mode of the agent execution. This is set by the
+ agent when entering different modes (e.g., Ralph mode via /ona:ralph command).
+ """
+
outputs: Optional[Dict[str, StatusOutputs]] = None
"""
outputs is a map of key-value pairs that can be set by the agent during
diff --git a/src/gitpod/types/agent_mode.py b/src/gitpod/types/agent_mode.py
index de414c7..d7bd23b 100644
--- a/src/gitpod/types/agent_mode.py
+++ b/src/gitpod/types/agent_mode.py
@@ -4,4 +4,6 @@
__all__ = ["AgentMode"]
-AgentMode: TypeAlias = Literal["AGENT_MODE_UNSPECIFIED", "AGENT_MODE_EXECUTION", "AGENT_MODE_PLANNING"]
+AgentMode: TypeAlias = Literal[
+ "AGENT_MODE_UNSPECIFIED", "AGENT_MODE_EXECUTION", "AGENT_MODE_PLANNING", "AGENT_MODE_RALPH"
+]
diff --git a/src/gitpod/types/groups/resource_role.py b/src/gitpod/types/groups/resource_role.py
index cd2e164..33ecbb7 100644
--- a/src/gitpod/types/groups/resource_role.py
+++ b/src/gitpod/types/groups/resource_role.py
@@ -8,6 +8,7 @@
"RESOURCE_ROLE_UNSPECIFIED",
"RESOURCE_ROLE_ORG_ADMIN",
"RESOURCE_ROLE_ORG_MEMBER",
+ "RESOURCE_ROLE_ORG_RUNNERS_ADMIN",
"RESOURCE_ROLE_GROUP_ADMIN",
"RESOURCE_ROLE_GROUP_VIEWER",
"RESOURCE_ROLE_USER_IDENTITY",
diff --git a/src/gitpod/types/organization.py b/src/gitpod/types/organization.py
index edf88f1..e833b09 100644
--- a/src/gitpod/types/organization.py
+++ b/src/gitpod/types/organization.py
@@ -7,7 +7,7 @@
from .._models import BaseModel
from .invite_domains import InviteDomains
-from .organization_tier import OrganizationTier
+from .shared.organization_tier import OrganizationTier
__all__ = ["Organization"]
diff --git a/src/gitpod/types/organization_list_members_params.py b/src/gitpod/types/organization_list_members_params.py
index 06c529e..2e5f87e 100644
--- a/src/gitpod/types/organization_list_members_params.py
+++ b/src/gitpod/types/organization_list_members_params.py
@@ -2,11 +2,14 @@
from __future__ import annotations
-from typing_extensions import Required, Annotated, TypedDict
+from typing import List
+from typing_extensions import Literal, Required, Annotated, TypedDict
from .._utils import PropertyInfo
+from .shared.user_status import UserStatus
+from .shared.organization_role import OrganizationRole
-__all__ = ["OrganizationListMembersParams", "Filter", "Pagination"]
+__all__ = ["OrganizationListMembersParams", "Filter", "Pagination", "Sort"]
class OrganizationListMembersParams(TypedDict, total=False):
@@ -22,11 +25,26 @@ class OrganizationListMembersParams(TypedDict, total=False):
pagination: Pagination
"""pagination contains the pagination options for listing members"""
+ sort: Sort
+ """sort specifies the order of results.
+
+ When unspecified, the authenticated user is returned first, followed by other
+ members sorted by name ascending. When an explicit sort is specified, results
+ are sorted purely by the requested field without any special handling for the
+ authenticated user.
+ """
+
class Filter(TypedDict, total=False):
+ roles: List[OrganizationRole]
+ """roles filters members by their organization role"""
+
search: str
"""search performs case-insensitive search across member name and email"""
+ statuses: List[UserStatus]
+ """status filters members by their user status"""
+
class Pagination(TypedDict, total=False):
"""pagination contains the pagination options for listing members"""
@@ -42,3 +60,17 @@ class Pagination(TypedDict, total=False):
Maximum 100.
"""
+
+
+class Sort(TypedDict, total=False):
+ """sort specifies the order of results.
+
+ When unspecified, the authenticated user is
+ returned first, followed by other members sorted by name ascending. When an explicit
+ sort is specified, results are sorted purely by the requested field without any
+ special handling for the authenticated user.
+ """
+
+ field: Literal["SORT_FIELD_UNSPECIFIED", "SORT_FIELD_NAME", "SORT_FIELD_DATE_JOINED"]
+
+ order: Literal["SORT_ORDER_UNSPECIFIED", "SORT_ORDER_ASC", "SORT_ORDER_DESC"]
diff --git a/src/gitpod/types/runner_list_scm_organizations_params.py b/src/gitpod/types/runner_list_scm_organizations_params.py
new file mode 100644
index 0000000..bd1f788
--- /dev/null
+++ b/src/gitpod/types/runner_list_scm_organizations_params.py
@@ -0,0 +1,20 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["RunnerListScmOrganizationsParams"]
+
+
+class RunnerListScmOrganizationsParams(TypedDict, total=False):
+ token: str
+
+ page_size: Annotated[int, PropertyInfo(alias="pageSize")]
+
+ runner_id: Annotated[str, PropertyInfo(alias="runnerId")]
+
+ scm_host: Annotated[str, PropertyInfo(alias="scmHost")]
+ """The SCM host to list organizations from (e.g., "github.com", "gitlab.com")"""
diff --git a/src/gitpod/types/runner_list_scm_organizations_response.py b/src/gitpod/types/runner_list_scm_organizations_response.py
new file mode 100644
index 0000000..8e9db07
--- /dev/null
+++ b/src/gitpod/types/runner_list_scm_organizations_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__ = ["RunnerListScmOrganizationsResponse", "Organization"]
+
+
+class Organization(BaseModel):
+ is_admin: Optional[bool] = FieldInfo(alias="isAdmin", default=None)
+ """
+ Whether the user has admin permissions in this organization. Admin permissions
+ typically allow creating organization-level webhooks.
+ """
+
+ name: Optional[str] = None
+ """Organization name/slug (e.g., "gitpod-io")"""
+
+ url: Optional[str] = None
+ """Organization URL (e.g., "https://github.com/gitpod-io")"""
+
+
+class RunnerListScmOrganizationsResponse(BaseModel):
+ organizations: Optional[List[Organization]] = None
+ """List of organizations the user belongs to"""
diff --git a/src/gitpod/types/runner_parse_context_url_response.py b/src/gitpod/types/runner_parse_context_url_response.py
index c712e40..c18fd7d 100644
--- a/src/gitpod/types/runner_parse_context_url_response.py
+++ b/src/gitpod/types/runner_parse_context_url_response.py
@@ -5,6 +5,7 @@
from pydantic import Field as FieldInfo
from .._models import BaseModel
+from .shared.state import State
__all__ = ["RunnerParseContextURLResponse", "Git", "Issue", "Pr", "PullRequest", "PullRequestRepository"]
@@ -71,12 +72,18 @@ class PullRequest(BaseModel):
author: Optional[str] = None
"""Author name as provided by the SCM system"""
+ draft: Optional[bool] = None
+ """Whether this is a draft pull request"""
+
from_branch: Optional[str] = FieldInfo(alias="fromBranch", default=None)
"""Source branch name (the branch being merged from)"""
repository: Optional[PullRequestRepository] = None
"""Repository information"""
+ state: Optional[State] = None
+ """Current state of the pull request"""
+
title: Optional[str] = None
"""Pull request title"""
diff --git a/src/gitpod/types/runner_search_repositories_response.py b/src/gitpod/types/runner_search_repositories_response.py
index 65597de..e4f7350 100644
--- a/src/gitpod/types/runner_search_repositories_response.py
+++ b/src/gitpod/types/runner_search_repositories_response.py
@@ -10,7 +10,12 @@
class Pagination(BaseModel):
- """Pagination information for the response"""
+ """
+ Pagination information for the response.
+ Token format: "NEXT_PAGE/TOTAL_PAGES/TOTAL_COUNT" (e.g., "2/40/1000").
+ Use -1 for unknown values (e.g., "2/-1/-1" when totals unavailable).
+ Empty token means no more pages.
+ """
next_token: Optional[str] = FieldInfo(alias="nextToken", default=None)
"""Token passed for retrieving the next set of results.
@@ -29,10 +34,18 @@ class Repository(BaseModel):
class RunnerSearchRepositoriesResponse(BaseModel):
last_page: Optional[int] = FieldInfo(alias="lastPage", default=None)
- """Last page in the responses"""
+ """Deprecated: Use pagination token instead.
+
+ Total pages can be extracted from token.
+ """
pagination: Optional[Pagination] = None
- """Pagination information for the response"""
+ """
+ Pagination information for the response. Token format:
+ "NEXT_PAGE/TOTAL_PAGES/TOTAL_COUNT" (e.g., "2/40/1000"). Use -1 for unknown
+ values (e.g., "2/-1/-1" when totals unavailable). Empty token means no more
+ pages.
+ """
repositories: Optional[List[Repository]] = None
"""List of repositories matching the search criteria"""
diff --git a/src/gitpod/types/secret_scope.py b/src/gitpod/types/secret_scope.py
index f66b672..1d01cb3 100644
--- a/src/gitpod/types/secret_scope.py
+++ b/src/gitpod/types/secret_scope.py
@@ -16,5 +16,8 @@ class SecretScope(BaseModel):
project_id: Optional[str] = FieldInfo(alias="projectId", default=None)
"""project_id is the Project ID this Secret belongs to"""
+ service_account_id: Optional[str] = FieldInfo(alias="serviceAccountId", default=None)
+ """service_account_id is the Service Account ID this Secret belongs to"""
+
user_id: Optional[str] = FieldInfo(alias="userId", default=None)
"""user_id is the User ID this Secret belongs to"""
diff --git a/src/gitpod/types/secret_scope_param.py b/src/gitpod/types/secret_scope_param.py
index d68e56b..b7cf4f4 100644
--- a/src/gitpod/types/secret_scope_param.py
+++ b/src/gitpod/types/secret_scope_param.py
@@ -16,5 +16,8 @@ class SecretScopeParam(TypedDict, total=False):
project_id: Annotated[str, PropertyInfo(alias="projectId")]
"""project_id is the Project ID this Secret belongs to"""
+ service_account_id: Annotated[str, PropertyInfo(alias="serviceAccountId")]
+ """service_account_id is the Service Account ID this Secret belongs to"""
+
user_id: Annotated[str, PropertyInfo(alias="userId")]
"""user_id is the User ID this Secret belongs to"""
diff --git a/src/gitpod/types/shared/__init__.py b/src/gitpod/types/shared/__init__.py
index 50c1315..de9766f 100644
--- a/src/gitpod/types/shared/__init__.py
+++ b/src/gitpod/types/shared/__init__.py
@@ -1,6 +1,7 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .task import Task as Task
+from .state import State as State
from .gateway import Gateway as Gateway
from .runs_on import RunsOn as RunsOn
from .subject import Subject as Subject
@@ -15,6 +16,7 @@
from .task_execution import TaskExecution as TaskExecution
from .environment_class import EnvironmentClass as EnvironmentClass
from .organization_role import OrganizationRole as OrganizationRole
+from .organization_tier import OrganizationTier as OrganizationTier
from .automation_trigger import AutomationTrigger as AutomationTrigger
from .task_execution_spec import TaskExecutionSpec as TaskExecutionSpec
from .task_execution_phase import TaskExecutionPhase as TaskExecutionPhase
diff --git a/src/gitpod/types/organization_tier.py b/src/gitpod/types/shared/organization_tier.py
similarity index 100%
rename from src/gitpod/types/organization_tier.py
rename to src/gitpod/types/shared/organization_tier.py
diff --git a/src/gitpod/types/shared/resource_type.py b/src/gitpod/types/shared/resource_type.py
index 1a18f4e..599108b 100644
--- a/src/gitpod/types/shared/resource_type.py
+++ b/src/gitpod/types/shared/resource_type.py
@@ -48,4 +48,6 @@
"RESOURCE_TYPE_ROLE_ASSIGNMENT_CHANGED",
"RESOURCE_TYPE_GROUP_MEMBERSHIP_CHANGED",
"RESOURCE_TYPE_WEBHOOK",
+ "RESOURCE_TYPE_SCIM_CONFIGURATION",
+ "RESOURCE_TYPE_SERVICE_ACCOUNT_SECRET",
]
diff --git a/src/gitpod/types/shared/state.py b/src/gitpod/types/shared/state.py
new file mode 100644
index 0000000..92aa0de
--- /dev/null
+++ b/src/gitpod/types/shared/state.py
@@ -0,0 +1,7 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal, TypeAlias
+
+__all__ = ["State"]
+
+State: TypeAlias = Literal["STATE_UNSPECIFIED", "STATE_OPEN", "STATE_CLOSED", "STATE_MERGED"]
diff --git a/src/gitpod/types/shared_params/__init__.py b/src/gitpod/types/shared_params/__init__.py
index 4673c76..093bf76 100644
--- a/src/gitpod/types/shared_params/__init__.py
+++ b/src/gitpod/types/shared_params/__init__.py
@@ -1,11 +1,13 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+from .state import State as State
from .runs_on import RunsOn as RunsOn
from .subject import Subject as Subject
from .principal import Principal as Principal
from .task_spec import TaskSpec as TaskSpec
from .secret_ref import SecretRef as SecretRef
from .field_value import FieldValue as FieldValue
+from .user_status import UserStatus as UserStatus
from .resource_type import ResourceType as ResourceType
from .task_metadata import TaskMetadata as TaskMetadata
from .environment_class import EnvironmentClass as EnvironmentClass
diff --git a/src/gitpod/types/shared_params/resource_type.py b/src/gitpod/types/shared_params/resource_type.py
index 793bab2..9d489e4 100644
--- a/src/gitpod/types/shared_params/resource_type.py
+++ b/src/gitpod/types/shared_params/resource_type.py
@@ -50,4 +50,6 @@
"RESOURCE_TYPE_ROLE_ASSIGNMENT_CHANGED",
"RESOURCE_TYPE_GROUP_MEMBERSHIP_CHANGED",
"RESOURCE_TYPE_WEBHOOK",
+ "RESOURCE_TYPE_SCIM_CONFIGURATION",
+ "RESOURCE_TYPE_SERVICE_ACCOUNT_SECRET",
]
diff --git a/src/gitpod/types/shared_params/state.py b/src/gitpod/types/shared_params/state.py
new file mode 100644
index 0000000..1d81f94
--- /dev/null
+++ b/src/gitpod/types/shared_params/state.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypeAlias
+
+__all__ = ["State"]
+
+State: TypeAlias = Literal["STATE_UNSPECIFIED", "STATE_OPEN", "STATE_CLOSED", "STATE_MERGED"]
diff --git a/src/gitpod/types/shared_params/user_status.py b/src/gitpod/types/shared_params/user_status.py
new file mode 100644
index 0000000..fd8ac19
--- /dev/null
+++ b/src/gitpod/types/shared_params/user_status.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypeAlias
+
+__all__ = ["UserStatus"]
+
+UserStatus: TypeAlias = Literal[
+ "USER_STATUS_UNSPECIFIED", "USER_STATUS_ACTIVE", "USER_STATUS_SUSPENDED", "USER_STATUS_LEFT"
+]
diff --git a/tests/api_resources/test_agents.py b/tests/api_resources/test_agents.py
index b92173b..f4f2aad 100644
--- a/tests/api_resources/test_agents.py
+++ b/tests/api_resources/test_agents.py
@@ -410,6 +410,7 @@ def test_method_start_execution_with_all_params(self, client: Gitpod) -> None:
"pull_request": {
"id": "id",
"author": "author",
+ "draft": True,
"from_branch": "fromBranch",
"repository": {
"clone_url": "cloneUrl",
@@ -417,6 +418,7 @@ def test_method_start_execution_with_all_params(self, client: Gitpod) -> None:
"name": "name",
"owner": "owner",
},
+ "state": "STATE_UNSPECIFIED",
"title": "title",
"to_branch": "toBranch",
"url": "url",
@@ -921,6 +923,7 @@ async def test_method_start_execution_with_all_params(self, async_client: AsyncG
"pull_request": {
"id": "id",
"author": "author",
+ "draft": True,
"from_branch": "fromBranch",
"repository": {
"clone_url": "cloneUrl",
@@ -928,6 +931,7 @@ async def test_method_start_execution_with_all_params(self, async_client: AsyncG
"name": "name",
"owner": "owner",
},
+ "state": "STATE_UNSPECIFIED",
"title": "title",
"to_branch": "toBranch",
"url": "url",
diff --git a/tests/api_resources/test_organizations.py b/tests/api_resources/test_organizations.py
index 8cda4e7..b404eb7 100644
--- a/tests/api_resources/test_organizations.py
+++ b/tests/api_resources/test_organizations.py
@@ -266,11 +266,19 @@ def test_method_list_members_with_all_params(self, client: Gitpod) -> None:
organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047",
token="token",
page_size=0,
- filter={"search": "search"},
+ filter={
+ "roles": ["ORGANIZATION_ROLE_UNSPECIFIED"],
+ "search": "search",
+ "statuses": ["USER_STATUS_UNSPECIFIED"],
+ },
pagination={
"token": "token",
"page_size": 20,
},
+ sort={
+ "field": "SORT_FIELD_UNSPECIFIED",
+ "order": "SORT_ORDER_UNSPECIFIED",
+ },
)
assert_matches_type(SyncMembersPage[OrganizationMember], organization, path=["response"])
@@ -595,11 +603,19 @@ async def test_method_list_members_with_all_params(self, async_client: AsyncGitp
organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047",
token="token",
page_size=0,
- filter={"search": "search"},
+ filter={
+ "roles": ["ORGANIZATION_ROLE_UNSPECIFIED"],
+ "search": "search",
+ "statuses": ["USER_STATUS_UNSPECIFIED"],
+ },
pagination={
"token": "token",
"page_size": 20,
},
+ sort={
+ "field": "SORT_FIELD_UNSPECIFIED",
+ "order": "SORT_ORDER_UNSPECIFIED",
+ },
)
assert_matches_type(AsyncMembersPage[OrganizationMember], organization, path=["response"])
diff --git a/tests/api_resources/test_runners.py b/tests/api_resources/test_runners.py
index 9ce4674..5cf72fe 100644
--- a/tests/api_resources/test_runners.py
+++ b/tests/api_resources/test_runners.py
@@ -17,6 +17,7 @@
RunnerParseContextURLResponse,
RunnerCreateRunnerTokenResponse,
RunnerSearchRepositoriesResponse,
+ RunnerListScmOrganizationsResponse,
RunnerCheckAuthenticationForHostResponse,
)
from gitpod.pagination import SyncRunnersPage, AsyncRunnersPage
@@ -363,6 +364,45 @@ def test_streaming_response_create_runner_token(self, client: Gitpod) -> None:
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list_scm_organizations(self, client: Gitpod) -> None:
+ runner = client.runners.list_scm_organizations()
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list_scm_organizations_with_all_params(self, client: Gitpod) -> None:
+ runner = client.runners.list_scm_organizations(
+ token="token",
+ page_size=0,
+ runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ scm_host="github.com",
+ )
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_list_scm_organizations(self, client: Gitpod) -> None:
+ response = client.runners.with_raw_response.list_scm_organizations()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ runner = response.parse()
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_list_scm_organizations(self, client: Gitpod) -> None:
+ with client.runners.with_streaming_response.list_scm_organizations() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ runner = response.parse()
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_parse_context_url(self, client: Gitpod) -> None:
@@ -786,6 +826,45 @@ async def test_streaming_response_create_runner_token(self, async_client: AsyncG
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list_scm_organizations(self, async_client: AsyncGitpod) -> None:
+ runner = await async_client.runners.list_scm_organizations()
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list_scm_organizations_with_all_params(self, async_client: AsyncGitpod) -> None:
+ runner = await async_client.runners.list_scm_organizations(
+ token="token",
+ page_size=0,
+ runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ scm_host="github.com",
+ )
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_list_scm_organizations(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.runners.with_raw_response.list_scm_organizations()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ runner = await response.parse()
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_list_scm_organizations(self, async_client: AsyncGitpod) -> None:
+ async with async_client.runners.with_streaming_response.list_scm_organizations() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ runner = await response.parse()
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_parse_context_url(self, async_client: AsyncGitpod) -> None:
diff --git a/tests/api_resources/test_secrets.py b/tests/api_resources/test_secrets.py
index 6a54d36..680a9d7 100644
--- a/tests/api_resources/test_secrets.py
+++ b/tests/api_resources/test_secrets.py
@@ -41,6 +41,7 @@ def test_method_create_with_all_params(self, client: Gitpod) -> None:
scope={
"organization_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"project_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ "service_account_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
},
value="postgresql://user:pass@localhost:5432/db",
@@ -86,6 +87,7 @@ def test_method_list_with_all_params(self, client: Gitpod) -> None:
"scope": {
"organization_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"project_id": "b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ "service_account_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
},
},
@@ -252,6 +254,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncGitpod) ->
scope={
"organization_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"project_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ "service_account_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
},
value="postgresql://user:pass@localhost:5432/db",
@@ -297,6 +300,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> N
"scope": {
"organization_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"project_id": "b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ "service_account_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
},
},
diff --git a/tests/test_client.py b/tests/test_client.py
index f948b8a..81db6c8 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -8,10 +8,11 @@
import json
import asyncio
import inspect
+import dataclasses
import tracemalloc
-from typing import Any, Union, cast
+from typing import Any, Union, TypeVar, Callable, Iterable, Iterator, Optional, Coroutine, cast
from unittest import mock
-from typing_extensions import Literal
+from typing_extensions import Literal, AsyncIterator, override
import httpx
import pytest
@@ -36,6 +37,7 @@
from .utils import update_env
+T = TypeVar("T")
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
bearer_token = "My Bearer Token"
@@ -50,6 +52,57 @@ def _low_retry_timeout(*_args: Any, **_kwargs: Any) -> float:
return 0.1
+def mirror_request_content(request: httpx.Request) -> httpx.Response:
+ return httpx.Response(200, content=request.content)
+
+
+# note: we can't use the httpx.MockTransport class as it consumes the request
+# body itself, which means we can't test that the body is read lazily
+class MockTransport(httpx.BaseTransport, httpx.AsyncBaseTransport):
+ def __init__(
+ self,
+ handler: Callable[[httpx.Request], httpx.Response]
+ | Callable[[httpx.Request], Coroutine[Any, Any, httpx.Response]],
+ ) -> None:
+ self.handler = handler
+
+ @override
+ def handle_request(
+ self,
+ request: httpx.Request,
+ ) -> httpx.Response:
+ assert not inspect.iscoroutinefunction(self.handler), "handler must not be a coroutine function"
+ assert inspect.isfunction(self.handler), "handler must be a function"
+ return self.handler(request)
+
+ @override
+ async def handle_async_request(
+ self,
+ request: httpx.Request,
+ ) -> httpx.Response:
+ assert inspect.iscoroutinefunction(self.handler), "handler must be a coroutine function"
+ return await self.handler(request)
+
+
+@dataclasses.dataclass
+class Counter:
+ value: int = 0
+
+
+def _make_sync_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> Iterator[T]:
+ for item in iterable:
+ if counter:
+ counter.value += 1
+ yield item
+
+
+async def _make_async_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> AsyncIterator[T]:
+ for item in iterable:
+ if counter:
+ counter.value += 1
+ yield item
+
+
def _get_open_connections(client: Gitpod | AsyncGitpod) -> int:
transport = client._client._transport
assert isinstance(transport, httpx.HTTPTransport) or isinstance(transport, httpx.AsyncHTTPTransport)
@@ -511,6 +564,70 @@ def test_multipart_repeating_array(self, client: Gitpod) -> None:
b"",
]
+ @pytest.mark.respx(base_url=base_url)
+ def test_binary_content_upload(self, respx_mock: MockRouter, client: Gitpod) -> None:
+ respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+
+ file_content = b"Hello, this is a test file."
+
+ response = client.post(
+ "/upload",
+ content=file_content,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+
+ def test_binary_content_upload_with_iterator(self) -> None:
+ file_content = b"Hello, this is a test file."
+ counter = Counter()
+ iterator = _make_sync_iterator([file_content], counter=counter)
+
+ def mock_handler(request: httpx.Request) -> httpx.Response:
+ assert counter.value == 0, "the request body should not have been read"
+ return httpx.Response(200, content=request.read())
+
+ with Gitpod(
+ base_url=base_url,
+ bearer_token=bearer_token,
+ _strict_response_validation=True,
+ http_client=httpx.Client(transport=MockTransport(handler=mock_handler)),
+ ) as client:
+ response = client.post(
+ "/upload",
+ content=iterator,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+ assert counter.value == 1
+
+ @pytest.mark.respx(base_url=base_url)
+ def test_binary_content_upload_with_body_is_deprecated(self, respx_mock: MockRouter, client: Gitpod) -> None:
+ respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+
+ file_content = b"Hello, this is a test file."
+
+ with pytest.deprecated_call(
+ match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead."
+ ):
+ response = client.post(
+ "/upload",
+ body=file_content,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+
@pytest.mark.respx(base_url=base_url)
def test_basic_union_response(self, respx_mock: MockRouter, client: Gitpod) -> None:
class Model1(BaseModel):
@@ -1364,6 +1481,72 @@ def test_multipart_repeating_array(self, async_client: AsyncGitpod) -> None:
b"",
]
+ @pytest.mark.respx(base_url=base_url)
+ async def test_binary_content_upload(self, respx_mock: MockRouter, async_client: AsyncGitpod) -> None:
+ respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+
+ file_content = b"Hello, this is a test file."
+
+ response = await async_client.post(
+ "/upload",
+ content=file_content,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+
+ async def test_binary_content_upload_with_asynciterator(self) -> None:
+ file_content = b"Hello, this is a test file."
+ counter = Counter()
+ iterator = _make_async_iterator([file_content], counter=counter)
+
+ async def mock_handler(request: httpx.Request) -> httpx.Response:
+ assert counter.value == 0, "the request body should not have been read"
+ return httpx.Response(200, content=await request.aread())
+
+ async with AsyncGitpod(
+ base_url=base_url,
+ bearer_token=bearer_token,
+ _strict_response_validation=True,
+ http_client=httpx.AsyncClient(transport=MockTransport(handler=mock_handler)),
+ ) as client:
+ response = await client.post(
+ "/upload",
+ content=iterator,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+ assert counter.value == 1
+
+ @pytest.mark.respx(base_url=base_url)
+ async def test_binary_content_upload_with_body_is_deprecated(
+ self, respx_mock: MockRouter, async_client: AsyncGitpod
+ ) -> None:
+ respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+
+ file_content = b"Hello, this is a test file."
+
+ with pytest.deprecated_call(
+ match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead."
+ ):
+ response = await async_client.post(
+ "/upload",
+ body=file_content,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+
@pytest.mark.respx(base_url=base_url)
async def test_basic_union_response(self, respx_mock: MockRouter, async_client: AsyncGitpod) -> None:
class Model1(BaseModel):