From 9e23e576ea787296c10f7edbb2a20bd9c47f5a4b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 12:11:17 +0000 Subject: [PATCH 01/14] feat(agent): add group-based SCM tools access control --- .stats.yml | 8 +- api.md | 7 +- src/gitpod/resources/groups/memberships.py | 146 +++++++++++++++++- src/gitpod/types/groups/__init__.py | 2 + .../groups/membership_retrieve_params.py | 17 ++ .../groups/membership_retrieve_response.py | 13 ++ .../types/organizations/agent_policy.py | 8 +- .../organizations/policy_update_params.py | 6 + src/gitpod/types/project_list_params.py | 8 + .../api_resources/groups/test_memberships.py | 93 +++++++++++ .../organizations/test_policies.py | 2 + tests/api_resources/test_projects.py | 2 + 12 files changed, 305 insertions(+), 7 deletions(-) create mode 100644 src/gitpod/types/groups/membership_retrieve_params.py create mode 100644 src/gitpod/types/groups/membership_retrieve_response.py diff --git a/.stats.yml b/.stats.yml index 0fdb5b6..2b7ac98 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 159 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-d62ef4b9187c1f3d36f428abc4b31d8a09ffd36e93d39b8136c60c8f463c838e.yml -openapi_spec_hash: d7f01b6f24e88eb46d744ecd28061f26 -config_hash: 26e4a10dfc6ec809322e60d889d15414 +configured_endpoints: 160 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-a19818e87979929d5484f97ec50318899c659c73733b4a700a41f28687ee2632.yml +openapi_spec_hash: f2d83905d1ed19d50c2f4641ecf29204 +config_hash: e84bdcd3fab4b185dd3dd79f70ea527d diff --git a/api.md b/api.md index 5476928..fc5a157 100644 --- a/api.md +++ b/api.md @@ -281,12 +281,17 @@ Methods: Types: ```python -from gitpod.types.groups import GroupMembership, MembershipCreateResponse +from gitpod.types.groups import ( + GroupMembership, + MembershipCreateResponse, + MembershipRetrieveResponse, +) ``` Methods: - client.groups.memberships.create(\*\*params) -> MembershipCreateResponse +- client.groups.memberships.retrieve(\*\*params) -> MembershipRetrieveResponse - client.groups.memberships.list(\*\*params) -> SyncMembersPage[GroupMembership] - client.groups.memberships.delete(\*\*params) -> object diff --git a/src/gitpod/resources/groups/memberships.py b/src/gitpod/resources/groups/memberships.py index 11b07f1..9ccee3c 100644 --- a/src/gitpod/resources/groups/memberships.py +++ b/src/gitpod/resources/groups/memberships.py @@ -16,10 +16,16 @@ ) from ...pagination import SyncMembersPage, AsyncMembersPage from ..._base_client import AsyncPaginator, make_request_options -from ...types.groups import membership_list_params, membership_create_params, membership_delete_params +from ...types.groups import ( + membership_list_params, + membership_create_params, + membership_delete_params, + membership_retrieve_params, +) from ...types.shared_params.subject import Subject from ...types.groups.group_membership import GroupMembership from ...types.groups.membership_create_response import MembershipCreateResponse +from ...types.groups.membership_retrieve_response import MembershipRetrieveResponse __all__ = ["MembershipsResource", "AsyncMembershipsResource"] @@ -108,6 +114,69 @@ def create( cast_to=MembershipCreateResponse, ) + def retrieve( + self, + *, + subject: Subject, + group_id: 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, + ) -> MembershipRetrieveResponse: + """ + Gets a specific membership by group ID and subject. + + Use this method to: + + - Check if a user or service account is a member of a group + - Verify group membership for access control + + ### Examples + + - Check user membership: + + Checks if a user is a member of a specific group. + + ```yaml + groupId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + subject: + id: "f53d2330-3795-4c5d-a1f3-453121af9c60" + principal: PRINCIPAL_USER + ``` + + ### Authorization + + All organization members can check group membership (transparency model). + + Args: + subject: Subject to check membership for + + 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.GroupService/GetMembership", + body=maybe_transform( + { + "subject": subject, + "group_id": group_id, + }, + membership_retrieve_params.MembershipRetrieveParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MembershipRetrieveResponse, + ) + def list( self, *, @@ -323,6 +392,69 @@ async def create( cast_to=MembershipCreateResponse, ) + async def retrieve( + self, + *, + subject: Subject, + group_id: 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, + ) -> MembershipRetrieveResponse: + """ + Gets a specific membership by group ID and subject. + + Use this method to: + + - Check if a user or service account is a member of a group + - Verify group membership for access control + + ### Examples + + - Check user membership: + + Checks if a user is a member of a specific group. + + ```yaml + groupId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + subject: + id: "f53d2330-3795-4c5d-a1f3-453121af9c60" + principal: PRINCIPAL_USER + ``` + + ### Authorization + + All organization members can check group membership (transparency model). + + Args: + subject: Subject to check membership for + + 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.GroupService/GetMembership", + body=await async_maybe_transform( + { + "subject": subject, + "group_id": group_id, + }, + membership_retrieve_params.MembershipRetrieveParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MembershipRetrieveResponse, + ) + def list( self, *, @@ -463,6 +595,9 @@ def __init__(self, memberships: MembershipsResource) -> None: self.create = to_raw_response_wrapper( memberships.create, ) + self.retrieve = to_raw_response_wrapper( + memberships.retrieve, + ) self.list = to_raw_response_wrapper( memberships.list, ) @@ -478,6 +613,9 @@ def __init__(self, memberships: AsyncMembershipsResource) -> None: self.create = async_to_raw_response_wrapper( memberships.create, ) + self.retrieve = async_to_raw_response_wrapper( + memberships.retrieve, + ) self.list = async_to_raw_response_wrapper( memberships.list, ) @@ -493,6 +631,9 @@ def __init__(self, memberships: MembershipsResource) -> None: self.create = to_streamed_response_wrapper( memberships.create, ) + self.retrieve = to_streamed_response_wrapper( + memberships.retrieve, + ) self.list = to_streamed_response_wrapper( memberships.list, ) @@ -508,6 +649,9 @@ def __init__(self, memberships: AsyncMembershipsResource) -> None: self.create = async_to_streamed_response_wrapper( memberships.create, ) + self.retrieve = async_to_streamed_response_wrapper( + memberships.retrieve, + ) self.list = async_to_streamed_response_wrapper( memberships.list, ) diff --git a/src/gitpod/types/groups/__init__.py b/src/gitpod/types/groups/__init__.py index f689e45..abbe99f 100644 --- a/src/gitpod/types/groups/__init__.py +++ b/src/gitpod/types/groups/__init__.py @@ -9,7 +9,9 @@ from .membership_create_params import MembershipCreateParams as MembershipCreateParams from .membership_delete_params import MembershipDeleteParams as MembershipDeleteParams from .membership_create_response import MembershipCreateResponse as MembershipCreateResponse +from .membership_retrieve_params import MembershipRetrieveParams as MembershipRetrieveParams from .role_assignment_list_params import RoleAssignmentListParams as RoleAssignmentListParams +from .membership_retrieve_response import MembershipRetrieveResponse as MembershipRetrieveResponse from .role_assignment_create_params import RoleAssignmentCreateParams as RoleAssignmentCreateParams from .role_assignment_delete_params import RoleAssignmentDeleteParams as RoleAssignmentDeleteParams from .role_assignment_create_response import RoleAssignmentCreateResponse as RoleAssignmentCreateResponse diff --git a/src/gitpod/types/groups/membership_retrieve_params.py b/src/gitpod/types/groups/membership_retrieve_params.py new file mode 100644 index 0000000..7934b5c --- /dev/null +++ b/src/gitpod/types/groups/membership_retrieve_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo +from ..shared_params.subject import Subject + +__all__ = ["MembershipRetrieveParams"] + + +class MembershipRetrieveParams(TypedDict, total=False): + subject: Required[Subject] + """Subject to check membership for""" + + group_id: Annotated[str, PropertyInfo(alias="groupId")] diff --git a/src/gitpod/types/groups/membership_retrieve_response.py b/src/gitpod/types/groups/membership_retrieve_response.py new file mode 100644 index 0000000..bfa92f8 --- /dev/null +++ b/src/gitpod/types/groups/membership_retrieve_response.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .group_membership import GroupMembership + +__all__ = ["MembershipRetrieveResponse"] + + +class MembershipRetrieveResponse(BaseModel): + member: Optional[GroupMembership] = None + """The membership if found, nil if subject is not a member""" diff --git a/src/gitpod/types/organizations/agent_policy.py b/src/gitpod/types/organizations/agent_policy.py index 7f5e1de..92827dd 100644 --- a/src/gitpod/types/organizations/agent_policy.py +++ b/src/gitpod/types/organizations/agent_policy.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Optional from pydantic import Field as FieldInfo @@ -29,3 +29,9 @@ class AgentPolicy(BaseModel): scm_tools_disabled controls whether SCM (Source Control Management) tools are disabled for agents """ + + scm_tools_allowed_group_id: Optional[str] = FieldInfo(alias="scmToolsAllowedGroupId", default=None) + """ + scm_tools_allowed_group_id restricts SCM tools access to members of this group. + Empty means no restriction (all users can use SCM tools if not disabled). + """ diff --git a/src/gitpod/types/organizations/policy_update_params.py b/src/gitpod/types/organizations/policy_update_params.py index 50cfaae..6c5f5eb 100644 --- a/src/gitpod/types/organizations/policy_update_params.py +++ b/src/gitpod/types/organizations/policy_update_params.py @@ -131,6 +131,12 @@ class AgentPolicy(TypedDict, total=False): agents """ + scm_tools_allowed_group_id: Annotated[Optional[str], PropertyInfo(alias="scmToolsAllowedGroupId")] + """ + scm_tools_allowed_group_id restricts SCM tools access to members of this group. + Empty means no restriction (all users can use SCM tools if not disabled). + """ + scm_tools_disabled: Annotated[Optional[bool], PropertyInfo(alias="scmToolsDisabled")] """ scm_tools_disabled controls whether SCM (Source Control Management) tools are diff --git a/src/gitpod/types/project_list_params.py b/src/gitpod/types/project_list_params.py index ea25cc9..0ce45e8 100644 --- a/src/gitpod/types/project_list_params.py +++ b/src/gitpod/types/project_list_params.py @@ -2,10 +2,12 @@ from __future__ import annotations +from typing import List from typing_extensions import Annotated, TypedDict from .._types import SequenceNotStr from .._utils import PropertyInfo +from .runner_kind import RunnerKind __all__ = ["ProjectListParams", "Filter", "Pagination"] @@ -31,6 +33,12 @@ class Filter(TypedDict, total=False): from these runners """ + runner_kinds: Annotated[List[RunnerKind], PropertyInfo(alias="runnerKinds")] + """ + runner_kinds filters the response to only projects that use environment classes + from runners of these kinds + """ + search: str """ search performs case-insensitive search across project name, project ID, and diff --git a/tests/api_resources/groups/test_memberships.py b/tests/api_resources/groups/test_memberships.py index b0de9f5..88c7c32 100644 --- a/tests/api_resources/groups/test_memberships.py +++ b/tests/api_resources/groups/test_memberships.py @@ -13,6 +13,7 @@ from gitpod.types.groups import ( GroupMembership, MembershipCreateResponse, + MembershipRetrieveResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -61,6 +62,52 @@ def test_streaming_response_create(self, client: Gitpod) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + membership = client.groups.memberships.retrieve( + subject={}, + ) + assert_matches_type(MembershipRetrieveResponse, membership, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_retrieve_with_all_params(self, client: Gitpod) -> None: + membership = client.groups.memberships.retrieve( + subject={ + "id": "f53d2330-3795-4c5d-a1f3-453121af9c60", + "principal": "PRINCIPAL_USER", + }, + group_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(MembershipRetrieveResponse, membership, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.groups.memberships.with_raw_response.retrieve( + subject={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + membership = response.parse() + assert_matches_type(MembershipRetrieveResponse, membership, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.groups.memberships.with_streaming_response.retrieve( + subject={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + membership = response.parse() + assert_matches_type(MembershipRetrieveResponse, membership, path=["response"]) + + assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="Prism tests are disabled") @parametrize def test_method_list(self, client: Gitpod) -> None: @@ -185,6 +232,52 @@ async def test_streaming_response_create(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_retrieve(self, async_client: AsyncGitpod) -> None: + membership = await async_client.groups.memberships.retrieve( + subject={}, + ) + assert_matches_type(MembershipRetrieveResponse, membership, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncGitpod) -> None: + membership = await async_client.groups.memberships.retrieve( + subject={ + "id": "f53d2330-3795-4c5d-a1f3-453121af9c60", + "principal": "PRINCIPAL_USER", + }, + group_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(MembershipRetrieveResponse, membership, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.groups.memberships.with_raw_response.retrieve( + subject={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + membership = await response.parse() + assert_matches_type(MembershipRetrieveResponse, membership, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.groups.memberships.with_streaming_response.retrieve( + subject={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + membership = await response.parse() + assert_matches_type(MembershipRetrieveResponse, membership, path=["response"]) + + assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="Prism tests are disabled") @parametrize async def test_method_list(self, async_client: AsyncGitpod) -> None: diff --git a/tests/api_resources/organizations/test_policies.py b/tests/api_resources/organizations/test_policies.py index 1d74334..eed1d45 100644 --- a/tests/api_resources/organizations/test_policies.py +++ b/tests/api_resources/organizations/test_policies.py @@ -67,6 +67,7 @@ def test_method_update_with_all_params(self, client: Gitpod) -> None: agent_policy={ "command_deny_list": ["string"], "mcp_disabled": True, + "scm_tools_allowed_group_id": "scmToolsAllowedGroupId", "scm_tools_disabled": True, }, allowed_editor_ids=["string"], @@ -177,6 +178,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> agent_policy={ "command_deny_list": ["string"], "mcp_disabled": True, + "scm_tools_allowed_group_id": "scmToolsAllowedGroupId", "scm_tools_disabled": True, }, allowed_editor_ids=["string"], diff --git a/tests/api_resources/test_projects.py b/tests/api_resources/test_projects.py index 0408e8a..6acd6e1 100644 --- a/tests/api_resources/test_projects.py +++ b/tests/api_resources/test_projects.py @@ -210,6 +210,7 @@ def test_method_list_with_all_params(self, client: Gitpod) -> None: filter={ "project_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], "runner_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "runner_kinds": ["RUNNER_KIND_UNSPECIFIED"], "search": "search", }, pagination={ @@ -506,6 +507,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> N filter={ "project_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], "runner_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "runner_kinds": ["RUNNER_KIND_UNSPECIFIED"], "search": "search", }, pagination={ From af8d70859c29a43ffd66f949bb70712491458c3d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 15:47:55 +0000 Subject: [PATCH 02/14] fix: use async_to_httpx_files in patch method --- src/gitpod/_base_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gitpod/_base_client.py b/src/gitpod/_base_client.py index a1f4ce1..1613979 100644 --- a/src/gitpod/_base_client.py +++ b/src/gitpod/_base_client.py @@ -1774,7 +1774,7 @@ async def patch( options: RequestOptions = {}, ) -> ResponseT: opts = FinalRequestOptions.construct( - method="patch", url=path, json_data=body, files=to_httpx_files(files), **options + method="patch", url=path, json_data=body, files=await async_to_httpx_files(files), **options ) return await self.request(cast_to, opts) From 34dd0fe4f13576840288a518b7c7c70f8d39d8f4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 18 Dec 2025 22:25:09 +0000 Subject: [PATCH 03/14] chore(internal): codegen related update --- scripts/lint | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/lint b/scripts/lint index 6a98ee4..1b2951b 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,8 +4,13 @@ set -e cd "$(dirname "$0")/.." -echo "==> Running lints" -rye run lint +if [ "$1" = "--fix" ]; then + echo "==> Running lints with --fix" + rye run fix:ruff +else + echo "==> Running lints" + rye run lint +fi echo "==> Making sure it imports" rye run python -c 'import gitpod' From 36acefc6f9ab2cbbde739b885e0734a9f476115b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Fri, 19 Dec 2025 16:44:40 +0100 Subject: [PATCH 04/14] chore: pin GitHub Actions to SHA --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/publish-pypi.yml | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d60bafb..a69c2e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/gitpod-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Install Rye run: | @@ -44,7 +44,7 @@ jobs: id-token: write runs-on: ${{ github.repository == 'stainless-sdks/gitpod-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Install Rye run: | @@ -63,7 +63,7 @@ jobs: - name: Get GitHub OIDC Token if: github.repository == 'stainless-sdks/gitpod-python' id: github-oidc - uses: actions/github-script@v6 + uses: actions/github-script@00f12e3e20659f42342b1c0226afda7f7c042325 # v6 with: script: core.setOutput('github_token', await core.getIDToken()); @@ -81,7 +81,7 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/gitpod-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Install Rye run: | diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 483b8de..3343ab6 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -17,10 +17,10 @@ jobs: id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Install Rye - uses: eifinger/setup-rye@v4 + uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8 # v4 with: version: '0.44.0' @@ -31,7 +31,7 @@ jobs: run: rye build --clean - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1 with: # No token needed! Trusted publishing handles authentication packages-dir: dist/ From 00a06ee9c649042e55a50cfc1cc7ae2680966540 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 19 Dec 2025 18:54:18 +0000 Subject: [PATCH 05/14] codegen metadata --- .stats.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2b7ac98..f59d5bf 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-a19818e87979929d5484f97ec50318899c659c73733b4a700a41f28687ee2632.yml -openapi_spec_hash: f2d83905d1ed19d50c2f4641ecf29204 -config_hash: e84bdcd3fab4b185dd3dd79f70ea527d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-8b86b2ad546df57ba9b530cb8d31733d99c4b629bbcac61bc10775bbd577e6b4.yml +openapi_spec_hash: 9d895493e3b1ad702e554d9e2b19e8bc +config_hash: 8e1b089e9f5af438fd56b523014af4f2 From c0e59ade25f1d13024bb78d5f525c8f55e52676c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 5 Jan 2026 04:07:40 +0000 Subject: [PATCH 06/14] chore(internal): codegen related update --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 01fd4f2..30d8cd5 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 Gitpod + Copyright 2026 Gitpod Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 830d7e8f7f3b38959a3713fe37e24a050150a60a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 08:18:04 +0000 Subject: [PATCH 07/14] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f59d5bf..756ee10 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-8b86b2ad546df57ba9b530cb8d31733d99c4b629bbcac61bc10775bbd577e6b4.yml -openapi_spec_hash: 9d895493e3b1ad702e554d9e2b19e8bc +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-de9c92c5d163d0aaf84f2638cda7e3715a36bf85c5dbe89cea6657fe94201b07.yml +openapi_spec_hash: d010871ad88365048994b21eed2c36d9 config_hash: 8e1b089e9f5af438fd56b523014af4f2 From 052b48ad57f64a7c09d05c898ea6638da0c886db Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 10:23:28 +0000 Subject: [PATCH 08/14] feat(skills): add organization-level skills support --- .stats.yml | 4 ++-- src/gitpod/resources/agents.py | 4 ++++ src/gitpod/types/agent_create_prompt_params.py | 2 ++ src/gitpod/types/agent_list_prompts_params.py | 2 ++ src/gitpod/types/agent_update_prompt_params.py | 3 +++ src/gitpod/types/prompt_spec.py | 3 +++ tests/api_resources/test_agents.py | 6 ++++++ 7 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 756ee10..3c02fdf 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-de9c92c5d163d0aaf84f2638cda7e3715a36bf85c5dbe89cea6657fe94201b07.yml -openapi_spec_hash: d010871ad88365048994b21eed2c36d9 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-643adebfc36ae5f3c31dc2305867f8259c9ec13420989ec37b78cdf87283a279.yml +openapi_spec_hash: 5d04ebe79f446da15639adddf9bffc9b config_hash: 8e1b089e9f5af438fd56b523014af4f2 diff --git a/src/gitpod/resources/agents.py b/src/gitpod/resources/agents.py index 3fdedd4..9c2e9d1 100644 --- a/src/gitpod/resources/agents.py +++ b/src/gitpod/resources/agents.py @@ -120,6 +120,7 @@ def create_prompt( command: str | Omit = omit, description: str | Omit = omit, is_command: bool | Omit = omit, + is_skill: bool | Omit = omit, is_template: bool | Omit = omit, name: str | Omit = omit, prompt: str | Omit = omit, @@ -154,6 +155,7 @@ def create_prompt( "command": command, "description": description, "is_command": is_command, + "is_skill": is_skill, "is_template": is_template, "name": name, "prompt": prompt, @@ -768,6 +770,7 @@ async def create_prompt( command: str | Omit = omit, description: str | Omit = omit, is_command: bool | Omit = omit, + is_skill: bool | Omit = omit, is_template: bool | Omit = omit, name: str | Omit = omit, prompt: str | Omit = omit, @@ -802,6 +805,7 @@ async def create_prompt( "command": command, "description": description, "is_command": is_command, + "is_skill": is_skill, "is_template": is_template, "name": name, "prompt": prompt, diff --git a/src/gitpod/types/agent_create_prompt_params.py b/src/gitpod/types/agent_create_prompt_params.py index c5b2231..ec2daa9 100644 --- a/src/gitpod/types/agent_create_prompt_params.py +++ b/src/gitpod/types/agent_create_prompt_params.py @@ -16,6 +16,8 @@ class AgentCreatePromptParams(TypedDict, total=False): is_command: Annotated[bool, PropertyInfo(alias="isCommand")] + is_skill: Annotated[bool, PropertyInfo(alias="isSkill")] + is_template: Annotated[bool, PropertyInfo(alias="isTemplate")] name: str diff --git a/src/gitpod/types/agent_list_prompts_params.py b/src/gitpod/types/agent_list_prompts_params.py index 9756b72..6c3ac23 100644 --- a/src/gitpod/types/agent_list_prompts_params.py +++ b/src/gitpod/types/agent_list_prompts_params.py @@ -26,6 +26,8 @@ class Filter(TypedDict, total=False): is_command: Annotated[bool, PropertyInfo(alias="isCommand")] + is_skill: Annotated[bool, PropertyInfo(alias="isSkill")] + is_template: Annotated[bool, PropertyInfo(alias="isTemplate")] diff --git a/src/gitpod/types/agent_update_prompt_params.py b/src/gitpod/types/agent_update_prompt_params.py index 8d5e292..e4ade3b 100644 --- a/src/gitpod/types/agent_update_prompt_params.py +++ b/src/gitpod/types/agent_update_prompt_params.py @@ -40,6 +40,9 @@ class Spec(TypedDict, total=False): is_command: Annotated[Optional[bool], PropertyInfo(alias="isCommand")] """Whether this prompt is a command""" + is_skill: Annotated[Optional[bool], PropertyInfo(alias="isSkill")] + """Whether this prompt is a skill""" + is_template: Annotated[Optional[bool], PropertyInfo(alias="isTemplate")] """Whether this prompt is a template""" diff --git a/src/gitpod/types/prompt_spec.py b/src/gitpod/types/prompt_spec.py index 7db3c11..ddeaacb 100644 --- a/src/gitpod/types/prompt_spec.py +++ b/src/gitpod/types/prompt_spec.py @@ -16,6 +16,9 @@ class PromptSpec(BaseModel): is_command: Optional[bool] = FieldInfo(alias="isCommand", default=None) """is_command indicates if this prompt is a command""" + is_skill: Optional[bool] = FieldInfo(alias="isSkill", default=None) + """is_skill indicates if this prompt is a skill (workflow instructions for agents)""" + is_template: Optional[bool] = FieldInfo(alias="isTemplate", default=None) """is_template indicates if this prompt is a template""" diff --git a/tests/api_resources/test_agents.py b/tests/api_resources/test_agents.py index 9a37aaf..8314ecc 100644 --- a/tests/api_resources/test_agents.py +++ b/tests/api_resources/test_agents.py @@ -77,6 +77,7 @@ def test_method_create_prompt_with_all_params(self, client: Gitpod) -> None: command="command", description="x", is_command=True, + is_skill=True, is_template=True, name="x", prompt="x", @@ -242,6 +243,7 @@ def test_method_list_prompts_with_all_params(self, client: Gitpod) -> None: "command": "command", "command_prefix": "commandPrefix", "is_command": True, + "is_skill": True, "is_template": True, }, pagination={ @@ -501,6 +503,7 @@ def test_method_update_prompt_with_all_params(self, client: Gitpod) -> None: spec={ "command": "command", "is_command": True, + "is_skill": True, "is_template": True, "prompt": "prompt", }, @@ -584,6 +587,7 @@ async def test_method_create_prompt_with_all_params(self, async_client: AsyncGit command="command", description="x", is_command=True, + is_skill=True, is_template=True, name="x", prompt="x", @@ -749,6 +753,7 @@ async def test_method_list_prompts_with_all_params(self, async_client: AsyncGitp "command": "command", "command_prefix": "commandPrefix", "is_command": True, + "is_skill": True, "is_template": True, }, pagination={ @@ -1008,6 +1013,7 @@ async def test_method_update_prompt_with_all_params(self, async_client: AsyncGit spec={ "command": "command", "is_command": True, + "is_skill": True, "is_template": True, "prompt": "prompt", }, From 05569c0e75fbd8fe107edb2119650030a1c21eed Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 12:15:32 +0000 Subject: [PATCH 09/14] feat(prebuild): expose snapshot completion percentage in prebuild status --- .stats.yml | 4 ++-- src/gitpod/types/prebuild_status.py | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3c02fdf..4eb2c94 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-643adebfc36ae5f3c31dc2305867f8259c9ec13420989ec37b78cdf87283a279.yml -openapi_spec_hash: 5d04ebe79f446da15639adddf9bffc9b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-3c080e16ecc8c0377535643430e1abc1425a0b8f474fd6f211cac5e617b7ba28.yml +openapi_spec_hash: 154065951ac8ea5188227ec10c2c10c8 config_hash: 8e1b089e9f5af438fd56b523014af4f2 diff --git a/src/gitpod/types/prebuild_status.py b/src/gitpod/types/prebuild_status.py index 7059215..dcb1fd0 100644 --- a/src/gitpod/types/prebuild_status.py +++ b/src/gitpod/types/prebuild_status.py @@ -36,6 +36,14 @@ class PrebuildStatus(BaseModel): logs. """ + snapshot_completion_percentage: Optional[int] = FieldInfo(alias="snapshotCompletionPercentage", default=None) + """ + snapshot_completion_percentage is the progress of snapshot creation (0-100). + Only populated when phase is SNAPSHOTTING and progress is available from the + cloud provider. This value may update infrequently or remain at 0 depending on + the provider. + """ + status_version: Optional[str] = FieldInfo(alias="statusVersion", default=None) """ status_version is incremented each time the status is updated. Used for From c1223c3b9ae3ba1e2c088e0c740abc26648517c2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 10:08:22 +0000 Subject: [PATCH 10/14] feat(api): add ImageInput to UserInputBlock proto --- .stats.yml | 4 +-- src/gitpod/types/user_input_block_param.py | 29 +++++++++++++++++++--- tests/api_resources/test_agents.py | 6 +++-- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4eb2c94..9d944b9 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-3c080e16ecc8c0377535643430e1abc1425a0b8f474fd6f211cac5e617b7ba28.yml -openapi_spec_hash: 154065951ac8ea5188227ec10c2c10c8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-665d1d0e7f0040c5fbbb664487724af4ecc58d3c702e8099ceef4a05ba589369.yml +openapi_spec_hash: 3688253b79ec0cf6d41ff586d71e9f07 config_hash: 8e1b089e9f5af438fd56b523014af4f2 diff --git a/src/gitpod/types/user_input_block_param.py b/src/gitpod/types/user_input_block_param.py index e62eecf..5a6b87e 100644 --- a/src/gitpod/types/user_input_block_param.py +++ b/src/gitpod/types/user_input_block_param.py @@ -4,11 +4,26 @@ from typing import Union from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict +from typing_extensions import Annotated, TypedDict +from .._types import Base64FileInput from .._utils import PropertyInfo +from .._models import set_pydantic_config -__all__ = ["UserInputBlockParam", "Text"] +__all__ = ["UserInputBlockParam", "Image", "Text"] + + +class Image(TypedDict, total=False): + """ + ImageInput allows sending images to the agent. + Media type is inferred from magic bytes by the backend. + """ + + data: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] + """Raw image data (max 4MB). Supported formats: PNG, JPEG, WebP.""" + + +set_pydantic_config(Image, {"arbitrary_types_allowed": True}) class Text(TypedDict, total=False): @@ -16,9 +31,15 @@ class Text(TypedDict, total=False): class UserInputBlockParam(TypedDict, total=False): - text: Required[Text] - id: str created_at: Annotated[Union[str, datetime], PropertyInfo(alias="createdAt", format="iso8601")] """Timestamp when this block was created. Used for debugging and support bundles.""" + + image: Image + """ + ImageInput allows sending images to the agent. Media type is inferred from magic + bytes by the backend. + """ + + text: Text diff --git a/tests/api_resources/test_agents.py b/tests/api_resources/test_agents.py index 8314ecc..b92173b 100644 --- a/tests/api_resources/test_agents.py +++ b/tests/api_resources/test_agents.py @@ -359,9 +359,10 @@ def test_method_send_to_execution_with_all_params(self, client: Gitpod) -> None: agent = client.agents.send_to_execution( agent_execution_id="6fa1a3c7-fbb7-49d1-ba56-1890dc7c4c35", user_input={ - "text": {"content": "Generate a report based on the latest logs."}, "id": "id", "created_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "image": {"data": "U3RhaW5sZXNzIHJvY2tz"}, + "text": {"content": "Generate a report based on the latest logs."}, }, ) assert_matches_type(object, agent, path=["response"]) @@ -869,9 +870,10 @@ async def test_method_send_to_execution_with_all_params(self, async_client: Asyn agent = await async_client.agents.send_to_execution( agent_execution_id="6fa1a3c7-fbb7-49d1-ba56-1890dc7c4c35", user_input={ - "text": {"content": "Generate a report based on the latest logs."}, "id": "id", "created_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "image": {"data": "U3RhaW5sZXNzIHJvY2tz"}, + "text": {"content": "Generate a report based on the latest logs."}, }, ) assert_matches_type(object, agent, path=["response"]) From 5a4e22212bb973211caf4cffa1dc40ec2a428ae1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 07:34:51 +0000 Subject: [PATCH 11/14] feat(api): add recommended editors configuration to project settings --- .stats.yml | 6 ++-- api.md | 1 + src/gitpod/resources/projects/projects.py | 13 ++++++++ src/gitpod/types/__init__.py | 2 ++ src/gitpod/types/project.py | 4 +++ src/gitpod/types/project_update_params.py | 8 +++++ src/gitpod/types/recommended_editors.py | 30 +++++++++++++++++ src/gitpod/types/recommended_editors_param.py | 33 +++++++++++++++++++ tests/api_resources/test_projects.py | 2 ++ 9 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 src/gitpod/types/recommended_editors.py create mode 100644 src/gitpod/types/recommended_editors_param.py diff --git a/.stats.yml b/.stats.yml index 9d944b9..c430d10 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-665d1d0e7f0040c5fbbb664487724af4ecc58d3c702e8099ceef4a05ba589369.yml -openapi_spec_hash: 3688253b79ec0cf6d41ff586d71e9f07 -config_hash: 8e1b089e9f5af438fd56b523014af4f2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-6f686822d27e00f05b67afc31efefd873ce20db2be25174500da54a30f650875.yml +openapi_spec_hash: 24bd6ab0ff2eed7121942da895863810 +config_hash: 06c6c8640b0bb0692f8f2361c6660f8a diff --git a/api.md b/api.md index fc5a157..29f93a4 100644 --- a/api.md +++ b/api.md @@ -498,6 +498,7 @@ from gitpod.types import ( ProjectMetadata, ProjectPhase, ProjectPrebuildConfiguration, + RecommendedEditors, ProjectCreateResponse, ProjectRetrieveResponse, ProjectUpdateResponse, diff --git a/src/gitpod/resources/projects/projects.py b/src/gitpod/resources/projects/projects.py index 4a4bd61..c3f7da6 100644 --- a/src/gitpod/resources/projects/projects.py +++ b/src/gitpod/resources/projects/projects.py @@ -46,6 +46,7 @@ from ...types.project_create_response import ProjectCreateResponse from ...types.project_update_response import ProjectUpdateResponse from ...types.project_retrieve_response import ProjectRetrieveResponse +from ...types.recommended_editors_param import RecommendedEditorsParam from ...types.environment_initializer_param import EnvironmentInitializerParam from ...types.project_prebuild_configuration_param import ProjectPrebuildConfigurationParam from ...types.project_create_from_environment_response import ProjectCreateFromEnvironmentResponse @@ -244,6 +245,7 @@ def update( name: Optional[str] | Omit = omit, prebuild_configuration: Optional[ProjectPrebuildConfigurationParam] | Omit = omit, project_id: str | Omit = omit, + recommended_editors: Optional[RecommendedEditorsParam] | Omit = omit, technical_description: Optional[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. @@ -313,6 +315,10 @@ def update( project_id: project_id specifies the project identifier + recommended_editors: 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: technical_description is a detailed technical description of the project This field is not returned by default in GetProject or ListProjects responses 8KB max @@ -334,6 +340,7 @@ def update( "name": name, "prebuild_configuration": prebuild_configuration, "project_id": project_id, + "recommended_editors": recommended_editors, "technical_description": technical_description, }, project_update_params.ProjectUpdateParams, @@ -716,6 +723,7 @@ async def update( name: Optional[str] | Omit = omit, prebuild_configuration: Optional[ProjectPrebuildConfigurationParam] | Omit = omit, project_id: str | Omit = omit, + recommended_editors: Optional[RecommendedEditorsParam] | Omit = omit, technical_description: Optional[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. @@ -785,6 +793,10 @@ async def update( project_id: project_id specifies the project identifier + recommended_editors: 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: technical_description is a detailed technical description of the project This field is not returned by default in GetProject or ListProjects responses 8KB max @@ -806,6 +818,7 @@ async def update( "name": name, "prebuild_configuration": prebuild_configuration, "project_id": project_id, + "recommended_editors": recommended_editors, "technical_description": technical_description, }, project_update_params.ProjectUpdateParams, diff --git a/src/gitpod/types/__init__.py b/src/gitpod/types/__init__.py index c374878..bd85a24 100644 --- a/src/gitpod/types/__init__.py +++ b/src/gitpod/types/__init__.py @@ -94,6 +94,7 @@ from .organization_member import OrganizationMember as OrganizationMember from .prebuild_spec_param import PrebuildSpecParam as PrebuildSpecParam from .project_list_params import ProjectListParams as ProjectListParams +from .recommended_editors import RecommendedEditors as RecommendedEditors from .environment_metadata import EnvironmentMetadata as EnvironmentMetadata from .event_watch_response import EventWatchResponse as EventWatchResponse from .exception_info_param import ExceptionInfoParam as ExceptionInfoParam @@ -154,6 +155,7 @@ from .exception_mechanism_param import ExceptionMechanismParam as ExceptionMechanismParam from .organization_leave_params import OrganizationLeaveParams as OrganizationLeaveParams from .project_retrieve_response import ProjectRetrieveResponse as ProjectRetrieveResponse +from .recommended_editors_param import RecommendedEditorsParam as RecommendedEditorsParam from .secret_get_value_response import SecretGetValueResponse as SecretGetValueResponse from .user_set_suspended_params import UserSetSuspendedParams as UserSetSuspendedParams from .agent_create_prompt_params import AgentCreatePromptParams as AgentCreatePromptParams diff --git a/src/gitpod/types/project.py b/src/gitpod/types/project.py index f5039be..d8b80a1 100644 --- a/src/gitpod/types/project.py +++ b/src/gitpod/types/project.py @@ -8,6 +8,7 @@ from .project_phase import ProjectPhase from .shared.subject import Subject from .project_metadata import ProjectMetadata +from .recommended_editors import RecommendedEditors from .environment_initializer import EnvironmentInitializer from .project_prebuild_configuration import ProjectPrebuildConfiguration from .shared.project_environment_class import ProjectEnvironmentClass @@ -64,6 +65,9 @@ class Project(BaseModel): ) """prebuild_configuration defines how prebuilds are created for this project.""" + recommended_editors: Optional[RecommendedEditors] = FieldInfo(alias="recommendedEditors", default=None) + """recommended_editors specifies the editors recommended for this project.""" + technical_description: Optional[str] = FieldInfo(alias="technicalDescription", default=None) """ technical_description is a detailed technical description of the project This diff --git a/src/gitpod/types/project_update_params.py b/src/gitpod/types/project_update_params.py index c27e98a..64fb758 100644 --- a/src/gitpod/types/project_update_params.py +++ b/src/gitpod/types/project_update_params.py @@ -6,6 +6,7 @@ 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 @@ -50,6 +51,13 @@ class ProjectUpdateParams(TypedDict, total=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 diff --git a/src/gitpod/types/recommended_editors.py b/src/gitpod/types/recommended_editors.py new file mode 100644 index 0000000..0caf253 --- /dev/null +++ b/src/gitpod/types/recommended_editors.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from .._models import BaseModel + +__all__ = ["RecommendedEditors", "Editors"] + + +class Editors(BaseModel): + """EditorVersions contains the recommended versions for an editor.""" + + versions: Optional[List[str]] = None + """ + versions is the list of recommended versions for this editor. If empty, all + available versions are recommended. Examples for JetBrains: ["2025.1", "2024.3"] + """ + + +class RecommendedEditors(BaseModel): + """RecommendedEditors contains the map of recommended editors and their versions.""" + + editors: Optional[Dict[str, Editors]] = None + """ + editors maps editor aliases to their recommended versions. Key is the editor + alias (e.g., "intellij", "goland", "vscode"). Value contains the list of + recommended versions for that editor. If versions list is empty, all available + versions are recommended. Example: {"intellij": {versions: ["2025.1", + "2024.3"]}, "goland": {}} + """ diff --git a/src/gitpod/types/recommended_editors_param.py b/src/gitpod/types/recommended_editors_param.py new file mode 100644 index 0000000..7da0dae --- /dev/null +++ b/src/gitpod/types/recommended_editors_param.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict +from typing_extensions import TypedDict + +from .._types import SequenceNotStr + +__all__ = ["RecommendedEditorsParam", "Editors"] + + +class Editors(TypedDict, total=False): + """EditorVersions contains the recommended versions for an editor.""" + + versions: SequenceNotStr[str] + """ + versions is the list of recommended versions for this editor. If empty, all + available versions are recommended. Examples for JetBrains: ["2025.1", "2024.3"] + """ + + +class RecommendedEditorsParam(TypedDict, total=False): + """RecommendedEditors contains the map of recommended editors and their versions.""" + + editors: Dict[str, Editors] + """ + editors maps editor aliases to their recommended versions. Key is the editor + alias (e.g., "intellij", "goland", "vscode"). Value contains the list of + recommended versions for that editor. If versions list is empty, all available + versions are recommended. Example: {"intellij": {versions: ["2025.1", + "2024.3"]}, "goland": {}} + """ diff --git a/tests/api_resources/test_projects.py b/tests/api_resources/test_projects.py index 6acd6e1..8e3985a 100644 --- a/tests/api_resources/test_projects.py +++ b/tests/api_resources/test_projects.py @@ -169,6 +169,7 @@ def test_method_update_with_all_params(self, client: Gitpod) -> None: "trigger": {"daily_schedule": {"hour_utc": 2}}, }, project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + recommended_editors={"editors": {"foo": {"versions": ["string"]}}}, technical_description="technicalDescription", ) assert_matches_type(ProjectUpdateResponse, project, path=["response"]) @@ -466,6 +467,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> "trigger": {"daily_schedule": {"hour_utc": 2}}, }, project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + recommended_editors={"editors": {"foo": {"versions": ["string"]}}}, technical_description="technicalDescription", ) assert_matches_type(ProjectUpdateResponse, project, path=["response"]) From f219e0bc8115e3f0c6deeb40414fe21faa3e81c4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 16:29:18 +0000 Subject: [PATCH 12/14] codegen metadata --- .stats.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index c430d10..b40352b 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-6f686822d27e00f05b67afc31efefd873ce20db2be25174500da54a30f650875.yml -openapi_spec_hash: 24bd6ab0ff2eed7121942da895863810 -config_hash: 06c6c8640b0bb0692f8f2361c6660f8a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-d27df409d7979dbb29733500872b84823b37257c1b3a93f7ba2b0d95bd4faac6.yml +openapi_spec_hash: 1c7c624b62b6a216486c8150074d5237 +config_hash: d3267594264bfb76d2ee7e881d5f8a5a From d0bf7faa87bcfd60d81cba84c50bd59ad0614c2f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 12:48:03 +0000 Subject: [PATCH 13/14] feat(db): add webhooks table with trigger reference --- .stats.yml | 4 ++-- src/gitpod/types/groups/resource_role.py | 2 ++ src/gitpod/types/shared/resource_type.py | 1 + src/gitpod/types/shared_params/resource_type.py | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b40352b..e42a5ca 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-d27df409d7979dbb29733500872b84823b37257c1b3a93f7ba2b0d95bd4faac6.yml -openapi_spec_hash: 1c7c624b62b6a216486c8150074d5237 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-3935e467f9c15925790aada293124db82bb5d6840eeac52d81fbac6a9b0fd154.yml +openapi_spec_hash: b417d7f10ea430216e9b70e4468a3212 config_hash: d3267594264bfb76d2ee7e881d5f8a5a diff --git a/src/gitpod/types/groups/resource_role.py b/src/gitpod/types/groups/resource_role.py index 17dcb32..cd2e164 100644 --- a/src/gitpod/types/groups/resource_role.py +++ b/src/gitpod/types/groups/resource_role.py @@ -53,4 +53,6 @@ "RESOURCE_ROLE_WORKFLOW_EXECUTOR", "RESOURCE_ROLE_SNAPSHOT_ADMIN", "RESOURCE_ROLE_SNAPSHOT_RUNNER", + "RESOURCE_ROLE_WEBHOOK_ADMIN", + "RESOURCE_ROLE_WEBHOOK_VIEWER", ] diff --git a/src/gitpod/types/shared/resource_type.py b/src/gitpod/types/shared/resource_type.py index 5aec70e..1a18f4e 100644 --- a/src/gitpod/types/shared/resource_type.py +++ b/src/gitpod/types/shared/resource_type.py @@ -47,4 +47,5 @@ "RESOURCE_TYPE_CUSTOM_DOMAIN", "RESOURCE_TYPE_ROLE_ASSIGNMENT_CHANGED", "RESOURCE_TYPE_GROUP_MEMBERSHIP_CHANGED", + "RESOURCE_TYPE_WEBHOOK", ] diff --git a/src/gitpod/types/shared_params/resource_type.py b/src/gitpod/types/shared_params/resource_type.py index 4c567f1..793bab2 100644 --- a/src/gitpod/types/shared_params/resource_type.py +++ b/src/gitpod/types/shared_params/resource_type.py @@ -49,4 +49,5 @@ "RESOURCE_TYPE_CUSTOM_DOMAIN", "RESOURCE_TYPE_ROLE_ASSIGNMENT_CHANGED", "RESOURCE_TYPE_GROUP_MEMBERSHIP_CHANGED", + "RESOURCE_TYPE_WEBHOOK", ] From 81110a4c7a34be72a717549bb9a74bf52f470eb4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 12:48:24 +0000 Subject: [PATCH 14/14] release: 0.6.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 25 +++++++++++++++++++++++++ pyproject.toml | 2 +- src/gitpod/_version.py | 2 +- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 383dd5a..4208b5c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.5.2" + ".": "0.6.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 0124d5c..e6b615d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Changelog +## 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) + +### Features + +* **agent:** add group-based SCM tools access control ([9e23e57](https://github.com/gitpod-io/gitpod-sdk-python/commit/9e23e576ea787296c10f7edbb2a20bd9c47f5a4b)) +* **api:** add ImageInput to UserInputBlock proto ([c1223c3](https://github.com/gitpod-io/gitpod-sdk-python/commit/c1223c3b9ae3ba1e2c088e0c740abc26648517c2)) +* **api:** add recommended editors configuration to project settings ([5a4e222](https://github.com/gitpod-io/gitpod-sdk-python/commit/5a4e22212bb973211caf4cffa1dc40ec2a428ae1)) +* **db:** add webhooks table with trigger reference ([d0bf7fa](https://github.com/gitpod-io/gitpod-sdk-python/commit/d0bf7faa87bcfd60d81cba84c50bd59ad0614c2f)) +* **prebuild:** expose snapshot completion percentage in prebuild status ([05569c0](https://github.com/gitpod-io/gitpod-sdk-python/commit/05569c0e75fbd8fe107edb2119650030a1c21eed)) +* **skills:** add organization-level skills support ([052b48a](https://github.com/gitpod-io/gitpod-sdk-python/commit/052b48ad57f64a7c09d05c898ea6638da0c886db)) + + +### Bug Fixes + +* use async_to_httpx_files in patch method ([af8d708](https://github.com/gitpod-io/gitpod-sdk-python/commit/af8d70859c29a43ffd66f949bb70712491458c3d)) + + +### Chores + +* **internal:** codegen related update ([c0e59ad](https://github.com/gitpod-io/gitpod-sdk-python/commit/c0e59ade25f1d13024bb78d5f525c8f55e52676c)) +* **internal:** codegen related update ([34dd0fe](https://github.com/gitpod-io/gitpod-sdk-python/commit/34dd0fe4f13576840288a518b7c7c70f8d39d8f4)) +* pin GitHub Actions to SHA ([36acefc](https://github.com/gitpod-io/gitpod-sdk-python/commit/36acefc6f9ab2cbbde739b885e0734a9f476115b)) + ## 0.5.2 (2025-12-16) Full Changelog: [v0.5.1...v0.5.2](https://github.com/gitpod-io/gitpod-sdk-python/compare/v0.5.1...v0.5.2) diff --git a/pyproject.toml b/pyproject.toml index d864376..6136eaf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "gitpod-sdk" -version = "0.5.2" +version = "0.6.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 de507a3..850eb95 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.5.2" # x-release-please-version +__version__ = "0.6.0" # x-release-please-version